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 <android_runtime/AndroidRuntime.h> 18 19 #include <binder/Parcel.h> 20 #include <input/Input.h> 21 #include <input/InputDevice.h> 22 #include <input/KeyCharacterMap.h> 23 24 #include <jni.h> 25 #include <nativehelper/JNIHelp.h> 26 27 #include "android_os_Parcel.h" 28 #include "android_view_KeyEvent.h" 29 30 #include "core_jni_helpers.h" 31 32 namespace android { 33 34 static struct { 35 jclass clazz; 36 jmethodID ctor; 37 } gKeyCharacterMapClassInfo; 38 39 static struct { 40 jclass clazz; 41 } gKeyEventClassInfo; 42 43 static struct { 44 jfieldID keyCode; 45 jfieldID metaState; 46 } gFallbackActionClassInfo; 47 48 49 class NativeKeyCharacterMap { 50 public: 51 NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) 52 : mDeviceId(deviceId), mMap(std::move(map)) {} 53 54 ~NativeKeyCharacterMap() { 55 } 56 57 inline int32_t getDeviceId() const { 58 return mDeviceId; 59 } 60 61 inline const std::shared_ptr<KeyCharacterMap> getMap() const { return mMap; } 62 63 private: 64 int32_t mDeviceId; 65 std::shared_ptr<KeyCharacterMap> mMap; 66 }; 67 68 jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, 69 const std::shared_ptr<KeyCharacterMap> kcm) { 70 NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm); 71 if (!nativeMap) { 72 return nullptr; 73 } 74 75 return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor, 76 reinterpret_cast<jlong>(nativeMap)); 77 } 78 79 static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) { 80 return android_view_KeyCharacterMap_create(env, deviceId, nullptr); 81 } 82 83 static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { 84 Parcel* parcel = parcelForJavaObject(env, parcelObj); 85 if (!parcel) { 86 return 0; 87 } 88 89 int32_t deviceId = parcel->readInt32(); 90 if (parcel->errorCheck()) { 91 return 0; 92 } 93 94 std::shared_ptr<KeyCharacterMap> kcm = nullptr; 95 // Check if map is a null character map 96 if (parcel->readBool()) { 97 kcm = KeyCharacterMap::readFromParcel(parcel); 98 if (!kcm.get()) { 99 return 0; 100 } 101 } 102 NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm); 103 return reinterpret_cast<jlong>(map); 104 } 105 106 static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) { 107 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 108 Parcel* parcel = parcelForJavaObject(env, parcelObj); 109 if (!parcel || !map) { 110 return; 111 } 112 parcel->writeInt32(map->getDeviceId()); 113 if (!map->getMap()) { 114 parcel->writeBool(false); 115 return; 116 } 117 parcel->writeBool(true); 118 map->getMap()->writeToParcel(parcel); 119 } 120 121 static void nativeDispose(JNIEnv *env, jobject clazz, jlong ptr) { 122 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 123 delete map; 124 } 125 126 // Return the associated character or combining accent, or 0 if none. 127 static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jlong ptr, 128 jint keyCode, jint metaState) { 129 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 130 if (!map || !map->getMap()) { 131 return static_cast<jchar>(0); 132 } 133 return map->getMap()->getCharacter(keyCode, metaState); 134 } 135 136 static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, 137 jint metaState, jobject fallbackActionObj) { 138 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 139 if (!map || !map->getMap()) { 140 return static_cast<jboolean>(false); 141 } 142 KeyCharacterMap::FallbackAction fallbackAction; 143 144 bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction); 145 if (result) { 146 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, 147 fallbackAction.keyCode); 148 env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, 149 fallbackAction.metaState); 150 } 151 return result; 152 } 153 154 // Return the number of a key code, or 0 if none. 155 static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { 156 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 157 if (!map || !map->getMap()) { 158 return static_cast<jchar>(0); 159 } 160 return map->getMap()->getNumber(keyCode); 161 } 162 163 // Return the matched key code and meta state, or 0 if none. 164 static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, 165 jcharArray charsArray, jint metaState) { 166 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 167 if (!map || !map->getMap()) { 168 return static_cast<jchar>(0); 169 } 170 jsize numChars = env->GetArrayLength(charsArray); 171 jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL)); 172 if (!chars) { 173 return 0; 174 } 175 176 char16_t result = map->getMap()->getMatch(keyCode, reinterpret_cast<char16_t*>(chars), 177 size_t(numChars), metaState); 178 179 env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); 180 return result; 181 } 182 183 // Return the associated display label, or 0 if none. 184 static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { 185 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 186 if (!map || !map->getMap()) { 187 return static_cast<jchar>(0); 188 } 189 return map->getMap()->getDisplayLabel(keyCode); 190 } 191 192 // Return the associated keyboard type, or 0 if none. 193 static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) { 194 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 195 if (!map || !map->getMap()) { 196 return static_cast<jint>(0); 197 } 198 return static_cast<jint>(map->getMap()->getKeyboardType()); 199 } 200 201 static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, 202 jcharArray charsArray) { 203 NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr); 204 if (!map || !map->getMap()) { 205 return env->NewObjectArray(0 /* size */, gKeyEventClassInfo.clazz, NULL); 206 } 207 jchar* chars = env->GetCharArrayElements(charsArray, NULL); 208 if (!chars) { 209 return NULL; 210 } 211 jsize numChars = env->GetArrayLength(charsArray); 212 213 Vector<KeyEvent> events; 214 jobjectArray result = NULL; 215 if (map->getMap()->getEvents(map->getDeviceId(), reinterpret_cast<char16_t*>(chars), 216 size_t(numChars), events)) { 217 result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); 218 if (result) { 219 for (size_t i = 0; i < events.size(); i++) { 220 jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); 221 if (!keyEventObj) break; // threw OOM exception 222 env->SetObjectArrayElement(result, jsize(i), keyEventObj); 223 env->DeleteLocalRef(keyEventObj); 224 } 225 } 226 } 227 228 env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); 229 return result; 230 } 231 232 static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) { 233 const std::shared_ptr<KeyCharacterMap>& map1 = 234 (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap(); 235 const std::shared_ptr<KeyCharacterMap>& map2 = 236 (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap(); 237 if (map1 == nullptr || map2 == nullptr) { 238 return map1 == map2; 239 } 240 return static_cast<jboolean>(*map1 == *map2); 241 } 242 243 /* 244 * JNI registration. 245 */ 246 247 static const JNINativeMethod g_methods[] = { 248 /* name, signature, funcPtr */ 249 {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel}, 250 {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, 251 {"nativeDispose", "(J)V", (void*)nativeDispose}, 252 {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter}, 253 {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", 254 (void*)nativeGetFallbackAction}, 255 {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber}, 256 {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch}, 257 {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel}, 258 {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType}, 259 {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents}, 260 {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", 261 (void*)nativeObtainEmptyKeyCharacterMap}, 262 {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, 263 }; 264 265 int register_android_view_KeyCharacterMap(JNIEnv* env) 266 { 267 gKeyCharacterMapClassInfo.clazz = FindClassOrDie(env, "android/view/KeyCharacterMap"); 268 gKeyCharacterMapClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyCharacterMapClassInfo.clazz); 269 270 gKeyCharacterMapClassInfo.ctor = GetMethodIDOrDie(env, gKeyCharacterMapClassInfo.clazz, 271 "<init>", "(J)V"); 272 273 gKeyEventClassInfo.clazz = FindClassOrDie(env, "android/view/KeyEvent"); 274 gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyEventClassInfo.clazz); 275 276 jclass clazz = FindClassOrDie(env, "android/view/KeyCharacterMap$FallbackAction"); 277 278 gFallbackActionClassInfo.keyCode = GetFieldIDOrDie(env, clazz, "keyCode", "I"); 279 gFallbackActionClassInfo.metaState = GetFieldIDOrDie(env, clazz, "metaState", "I"); 280 281 return RegisterMethodsOrDie(env, "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); 282 } 283 284 }; // namespace android 285