/* * Copyright 2006, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "android_os_Parcel.h" #include "android_view_KeyEvent.h" #include "core_jni_helpers.h" namespace android { static struct { jclass clazz; jmethodID ctor; } gKeyCharacterMapClassInfo; static struct { jclass clazz; } gKeyEventClassInfo; static struct { jfieldID keyCode; jfieldID metaState; } gFallbackActionClassInfo; class NativeKeyCharacterMap { public: NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr map) : mDeviceId(deviceId), mMap(std::move(map)) {} ~NativeKeyCharacterMap() { } inline int32_t getDeviceId() const { return mDeviceId; } inline const std::shared_ptr getMap() const { return mMap; } private: int32_t mDeviceId; std::shared_ptr mMap; }; jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, const std::shared_ptr kcm) { NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm); if (!nativeMap) { return nullptr; } return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor, reinterpret_cast(nativeMap)); } static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) { return android_view_KeyCharacterMap_create(env, deviceId, nullptr); } static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (!parcel) { return 0; } int32_t deviceId = parcel->readInt32(); if (parcel->errorCheck()) { return 0; } std::shared_ptr kcm = nullptr; // Check if map is a null character map if (parcel->readBool()) { kcm = KeyCharacterMap::readFromParcel(parcel); if (!kcm.get()) { return 0; } } NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm); return reinterpret_cast(map); } static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); Parcel* parcel = parcelForJavaObject(env, parcelObj); if (!parcel || !map) { return; } parcel->writeInt32(map->getDeviceId()); if (!map->getMap()) { parcel->writeBool(false); return; } parcel->writeBool(true); map->getMap()->writeToParcel(parcel); } static void nativeDispose(JNIEnv *env, jobject clazz, jlong ptr) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); delete map; } // Return the associated character or combining accent, or 0 if none. static jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, jint metaState) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(0); } return map->getMap()->getCharacter(keyCode, metaState); } static jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, jint metaState, jobject fallbackActionObj) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(false); } KeyCharacterMap::FallbackAction fallbackAction; bool result = map->getMap()->getFallbackAction(keyCode, metaState, &fallbackAction); if (result) { env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode, fallbackAction.keyCode); env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState, fallbackAction.metaState); } return result; } // Return the number of a key code, or 0 if none. static jchar nativeGetNumber(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(0); } return map->getMap()->getNumber(keyCode); } // Return the matched key code and meta state, or 0 if none. static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode, jcharArray charsArray, jint metaState) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(0); } jsize numChars = env->GetArrayLength(charsArray); jchar* chars = static_cast(env->GetPrimitiveArrayCritical(charsArray, NULL)); if (!chars) { return 0; } char16_t result = map->getMap()->getMatch(keyCode, reinterpret_cast(chars), size_t(numChars), metaState); env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT); return result; } // Return the associated display label, or 0 if none. static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(0); } return map->getMap()->getDisplayLabel(keyCode); } // Return the associated keyboard type, or 0 if none. static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return static_cast(0); } return static_cast(map->getMap()->getKeyboardType()); } static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, jcharArray charsArray) { NativeKeyCharacterMap* map = reinterpret_cast(ptr); if (!map || !map->getMap()) { return env->NewObjectArray(0 /* size */, gKeyEventClassInfo.clazz, NULL); } jchar* chars = env->GetCharArrayElements(charsArray, NULL); if (!chars) { return NULL; } jsize numChars = env->GetArrayLength(charsArray); Vector events; jobjectArray result = NULL; if (map->getMap()->getEvents(map->getDeviceId(), reinterpret_cast(chars), size_t(numChars), events)) { result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL); if (result) { for (size_t i = 0; i < events.size(); i++) { jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i)); if (!keyEventObj) break; // threw OOM exception env->SetObjectArrayElement(result, jsize(i), keyEventObj); env->DeleteLocalRef(keyEventObj); } } } env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT); return result; } static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) { const std::shared_ptr& map1 = (reinterpret_cast(ptr1))->getMap(); const std::shared_ptr& map2 = (reinterpret_cast(ptr2))->getMap(); if (map1 == nullptr || map2 == nullptr) { return map1 == map2; } return static_cast(*map1 == *map2); } /* * JNI registration. */ static const JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel}, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, {"nativeDispose", "(J)V", (void*)nativeDispose}, {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter}, {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", (void*)nativeGetFallbackAction}, {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber}, {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch}, {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel}, {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType}, {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents}, {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", (void*)nativeObtainEmptyKeyCharacterMap}, {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, }; int register_android_view_KeyCharacterMap(JNIEnv* env) { gKeyCharacterMapClassInfo.clazz = FindClassOrDie(env, "android/view/KeyCharacterMap"); gKeyCharacterMapClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyCharacterMapClassInfo.clazz); gKeyCharacterMapClassInfo.ctor = GetMethodIDOrDie(env, gKeyCharacterMapClassInfo.clazz, "", "(J)V"); gKeyEventClassInfo.clazz = FindClassOrDie(env, "android/view/KeyEvent"); gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyEventClassInfo.clazz); jclass clazz = FindClassOrDie(env, "android/view/KeyCharacterMap$FallbackAction"); gFallbackActionClassInfo.keyCode = GetFieldIDOrDie(env, clazz, "keyCode", "I"); gFallbackActionClassInfo.metaState = GetFieldIDOrDie(env, clazz, "metaState", "I"); return RegisterMethodsOrDie(env, "android/view/KeyCharacterMap", g_methods, NELEM(g_methods)); } }; // namespace android