1 /* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <ui/KeyCharacterMap.h> 18 #include <ui/Input.h> 19 20 #include <android_runtime/AndroidRuntime.h> 21 #include <nativehelper/jni.h> 22 #include <nativehelper/JNIHelp.h> 23 24 #include "android_view_KeyEvent.h" 25 26 namespace android { 27 28 static struct { 29 jclass clazz; 30 } gKeyEventClassInfo; 31 32 static struct { 33 jfieldID keyCode; 34 jfieldID metaState; 35 } gFallbackActionClassInfo; 36 37 38 static jint nativeLoad(JNIEnv *env, jobject clazz, jint deviceId) { 39 KeyCharacterMap* map; 40 status_t status = KeyCharacterMap::loadByDeviceId(deviceId, &map); 41 if (status) { 42 String8 msg; 43 msg.appendFormat("Could not load key character map for device %d due to error %d. " 44 "Refer to the log for details.", deviceId, status); 45 jniThrowException(env, "android/view/KeyCharacterMap$KeyCharacterMapUnavailableException", 46 msg.string()); 47 return 0; 48 } 49 return reinterpret_cast<jint>(map); 50 } 51 52 static void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) { 53 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 54 delete map; 55 } 56 57 static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jint ptr, 58 jint keyCode, jint metaState) { 59 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 60 return map->getCharacter(keyCode, metaState); 61 } 62 63 static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 64 jint metaState, jobject fallbackActionObj) { 65 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 66 KeyCharacterMap::FallbackAction fallbackAction; 67 68 bool result = map->getFallbackAction(keyCode, metaState, &fallbackAction); 69 if (result) { 70 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, 71 fallbackAction.keyCode); 72 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, 73 fallbackAction.metaState); 74 } 75 return result; 76 } 77 78 static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 79 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 80 return map->getNumber(keyCode); 81 } 82 83 static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 84 jcharArray charsArray, jint metaState) { 85 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 86 87 jsize numChars = env->GetArrayLength(charsArray); 88 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL)); 89 if (!chars) { 90 return 0; 91 } 92 93 char16_t result = map->getMatch(keyCode, chars, size_t(numChars), metaState); 94 95 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); 96 return result; 97 } 98 99 static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 100 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 101 return map->getDisplayLabel(keyCode); 102 } 103 104 static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jint ptr) { 105 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 106 return map->getKeyboardType(); 107 } 108 109 static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint deviceId, 110 jcharArray charsArray) { 111 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 112 113 jchar* chars = env->GetCharArrayElements(charsArray, NULL); 114 if (!chars) { 115 return NULL; 116 } 117 jsize numChars = env->GetArrayLength(charsArray); 118 119 Vector<KeyEvent> events; 120 jobjectArray result = NULL; 121 if (map->getEvents(deviceId, chars, size_t(numChars), events)) { 122 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); 123 if (result) { 124 for (size_t i = 0; i < events.size(); i++) { 125 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); 126 if (!keyEventObj) break; // threw OOM exception 127 env->SetObjectArrayElement(result, jsize(i), keyEventObj); 128 env->DeleteLocalRef(keyEventObj); 129 } 130 } 131 } 132 133 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); 134 return result; 135 } 136 137 138 /* 139 * JNI registration. 140 */ 141 142 static JNINativeMethod g_methods[] = { 143 /* name, signature, funcPtr */ 144 { "nativeLoad", "(I)I", 145 (void*)nativeLoad }, 146 { "nativeDispose", "(I)V", 147 (void*)nativeDispose }, 148 { "nativeGetCharacter", "(III)C", 149 (void*)nativeGetCharacter }, 150 { "nativeGetFallbackAction", "(IIILandroid/view/KeyCharacterMap$FallbackAction;)Z", 151 (void*)nativeGetFallbackAction }, 152 { "nativeGetNumber", "(II)C", 153 (void*)nativeGetNumber }, 154 { "nativeGetMatch", "(II[CI)C", 155 (void*)nativeGetMatch }, 156 { "nativeGetDisplayLabel", "(II)C", 157 (void*)nativeGetDisplayLabel }, 158 { "nativeGetKeyboardType", "(I)I", 159 (void*)nativeGetKeyboardType }, 160 { "nativeGetEvents", "(II[C)[Landroid/view/KeyEvent;", 161 (void*)nativeGetEvents }, 162 }; 163 164 #define FIND_CLASS(var, className) \ 165 var = env->FindClass(className); \ 166 LOG_FATAL_IF(! var, "Unable to find class " className); 167 168 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 169 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 170 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 171 172 int register_android_text_KeyCharacterMap(JNIEnv* env) 173 { 174 FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); 175 gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz)); 176 177 jclass clazz; 178 FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction"); 179 180 GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz, 181 "keyCode", "I"); 182 183 GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz, 184 "metaState", "I"); 185 186 return AndroidRuntime::registerNativeMethods(env, 187 "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); 188 } 189 190 }; // namespace android 191