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, jstring fileStr) { 39 const char* file = env->GetStringUTFChars(fileStr, NULL); 40 41 KeyCharacterMap* map; 42 status_t status = KeyCharacterMap::load(String8(file), &map); 43 jint result; 44 if (status) { 45 String8 msg; 46 msg.appendFormat("Could not load key character map '%s' due to error %d. " 47 "Refer to the log for details.", file, status); 48 jniThrowException(env, "android/view/KeyCharacterMap$KeyCharacterMapUnavailableException", 49 msg.string()); 50 result = 0; 51 } else { 52 result = reinterpret_cast<jint>(map); 53 } 54 55 env->ReleaseStringUTFChars(fileStr, file); 56 return result; 57 } 58 59 static void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) { 60 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 61 delete map; 62 } 63 64 static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jint ptr, 65 jint keyCode, jint metaState) { 66 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 67 return map->getCharacter(keyCode, metaState); 68 } 69 70 static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 71 jint metaState, jobject fallbackActionObj) { 72 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 73 KeyCharacterMap::FallbackAction fallbackAction; 74 75 bool result = map->getFallbackAction(keyCode, metaState, &fallbackAction); 76 if (result) { 77 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, 78 fallbackAction.keyCode); 79 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, 80 fallbackAction.metaState); 81 } 82 return result; 83 } 84 85 static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 86 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 87 return map->getNumber(keyCode); 88 } 89 90 static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode, 91 jcharArray charsArray, jint metaState) { 92 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 93 94 jsize numChars = env->GetArrayLength(charsArray); 95 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL)); 96 if (!chars) { 97 return 0; 98 } 99 100 char16_t result = map->getMatch(keyCode, chars, size_t(numChars), metaState); 101 102 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); 103 return result; 104 } 105 106 static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) { 107 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 108 return map->getDisplayLabel(keyCode); 109 } 110 111 static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jint ptr) { 112 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 113 return map->getKeyboardType(); 114 } 115 116 static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint deviceId, 117 jcharArray charsArray) { 118 KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr); 119 120 jchar* chars = env->GetCharArrayElements(charsArray, NULL); 121 if (!chars) { 122 return NULL; 123 } 124 jsize numChars = env->GetArrayLength(charsArray); 125 126 Vector<KeyEvent> events; 127 jobjectArray result = NULL; 128 if (map->getEvents(deviceId, chars, size_t(numChars), events)) { 129 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); 130 if (result) { 131 for (size_t i = 0; i < events.size(); i++) { 132 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); 133 if (!keyEventObj) break; // threw OOM exception 134 env->SetObjectArrayElement(result, jsize(i), keyEventObj); 135 env->DeleteLocalRef(keyEventObj); 136 } 137 } 138 } 139 140 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); 141 return result; 142 } 143 144 145 /* 146 * JNI registration. 147 */ 148 149 static JNINativeMethod g_methods[] = { 150 /* name, signature, funcPtr */ 151 { "nativeLoad", "(Ljava/lang/String;)I", 152 (void*)nativeLoad }, 153 { "nativeDispose", "(I)V", 154 (void*)nativeDispose }, 155 { "nativeGetCharacter", "(III)C", 156 (void*)nativeGetCharacter }, 157 { "nativeGetFallbackAction", "(IIILandroid/view/KeyCharacterMap$FallbackAction;)Z", 158 (void*)nativeGetFallbackAction }, 159 { "nativeGetNumber", "(II)C", 160 (void*)nativeGetNumber }, 161 { "nativeGetMatch", "(II[CI)C", 162 (void*)nativeGetMatch }, 163 { "nativeGetDisplayLabel", "(II)C", 164 (void*)nativeGetDisplayLabel }, 165 { "nativeGetKeyboardType", "(I)I", 166 (void*)nativeGetKeyboardType }, 167 { "nativeGetEvents", "(II[C)[Landroid/view/KeyEvent;", 168 (void*)nativeGetEvents }, 169 }; 170 171 #define FIND_CLASS(var, className) \ 172 var = env->FindClass(className); \ 173 LOG_FATAL_IF(! var, "Unable to find class " className); 174 175 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 176 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 177 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 178 179 int register_android_text_KeyCharacterMap(JNIEnv* env) 180 { 181 FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); 182 gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz)); 183 184 jclass clazz; 185 FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction"); 186 187 GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz, 188 "keyCode", "I"); 189 190 GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz, 191 "metaState", "I"); 192 193 return AndroidRuntime::registerNativeMethods(env, 194 "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); 195 } 196 197 }; // namespace android 198