19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright 2006, The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/KeyCharacterMap.h>
186b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <ui/Input.h>
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
216b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <nativehelper/jni.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <nativehelper/JNIHelp.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
246b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include "android_view_KeyEvent.h"
256b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
286b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic struct {
296b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jclass clazz;
306b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown} gKeyEventClassInfo;
316b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
3249ed71db425c5054e3ad9526496a7e116c89556bJeff Brownstatic struct {
3349ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    jfieldID keyCode;
3449ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    jfieldID metaState;
3549ed71db425c5054e3ad9526496a7e116c89556bJeff Brown} gFallbackActionClassInfo;
3649ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
3749ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
381e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brownstatic jint nativeLoad(JNIEnv *env, jobject clazz, jstring fileStr) {
391e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    const char* file = env->GetStringUTFChars(fileStr, NULL);
401e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown
416b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map;
421e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    status_t status = KeyCharacterMap::load(String8(file), &map);
431e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    jint result;
446b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (status) {
456b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        String8 msg;
461e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown        msg.appendFormat("Could not load key character map '%s' due to error %d.  "
471e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown                "Refer to the log for details.", file, status);
486b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        jniThrowException(env, "android/view/KeyCharacterMap$KeyCharacterMapUnavailableException",
496b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                msg.string());
501e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown        result = 0;
511e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    } else {
521e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown        result = reinterpret_cast<jint>(map);
536b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
541e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown
551e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    env->ReleaseStringUTFChars(fileStr, file);
561e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    return result;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
596b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) {
606b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
616b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    delete map;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
646b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jchar nativeGetCharacter(JNIEnv *env, jobject clazz, jint ptr,
656b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        jint keyCode, jint metaState) {
666b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
676b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return map->getCharacter(keyCode, metaState);
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7049ed71db425c5054e3ad9526496a7e116c89556bJeff Brownstatic jboolean nativeGetFallbackAction(JNIEnv *env, jobject clazz, jint ptr, jint keyCode,
7149ed71db425c5054e3ad9526496a7e116c89556bJeff Brown        jint metaState, jobject fallbackActionObj) {
7249ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
7349ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    KeyCharacterMap::FallbackAction fallbackAction;
7449ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
7549ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    bool result = map->getFallbackAction(keyCode, metaState, &fallbackAction);
7649ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    if (result) {
7749ed71db425c5054e3ad9526496a7e116c89556bJeff Brown        env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.keyCode,
7849ed71db425c5054e3ad9526496a7e116c89556bJeff Brown                fallbackAction.keyCode);
7949ed71db425c5054e3ad9526496a7e116c89556bJeff Brown        env->SetIntField(fallbackActionObj, gFallbackActionClassInfo.metaState,
8049ed71db425c5054e3ad9526496a7e116c89556bJeff Brown                fallbackAction.metaState);
8149ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    }
8249ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    return result;
8349ed71db425c5054e3ad9526496a7e116c89556bJeff Brown}
8449ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
856b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jchar nativeGetNumber(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) {
866b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
876b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return map->getNumber(keyCode);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
906b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jchar nativeGetMatch(JNIEnv *env, jobject clazz, jint ptr, jint keyCode,
916b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        jcharArray charsArray, jint metaState) {
926b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
946b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jsize numChars = env->GetArrayLength(charsArray);
956b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jchar* chars = static_cast<jchar*>(env->GetPrimitiveArrayCritical(charsArray, NULL));
966b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (!chars) {
976b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return 0;
986b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1006b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    char16_t result = map->getMatch(keyCode, chars, size_t(numChars), metaState);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1026b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
1036b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return result;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1066b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keyCode) {
1076b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
1086b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return map->getDisplayLabel(keyCode);
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1116b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jint ptr) {
1126b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
1136b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return map->getKeyboardType();
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1166b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jint ptr, jint deviceId,
1176b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        jcharArray charsArray) {
1186b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    KeyCharacterMap* map = reinterpret_cast<KeyCharacterMap*>(ptr);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1206b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jchar* chars = env->GetCharArrayElements(charsArray, NULL);
1216b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (!chars) {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1246b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jsize numChars = env->GetArrayLength(charsArray);
1256b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
1266b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    Vector<KeyEvent> events;
1276b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    jobjectArray result = NULL;
1286b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (map->getEvents(deviceId, chars, size_t(numChars), events)) {
1296b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
1306b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        if (result) {
1316b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            for (size_t i = 0; i < events.size(); i++) {
1326b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i));
1336b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                if (!keyEventObj) break; // threw OOM exception
1346b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                env->SetObjectArrayElement(result, jsize(i), keyEventObj);
1356b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                env->DeleteLocalRef(keyEventObj);
1366b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            }
1376b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        }
1386b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
1396b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
1406b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    env->ReleaseCharArrayElements(charsArray, chars, JNI_ABORT);
1416b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return result;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1446b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * JNI registration.
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod g_methods[] = {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* name, signature, funcPtr */
1511e08fe90df18930691b0c2ec22e5db25d7fcb4cfJeff Brown    { "nativeLoad", "(Ljava/lang/String;)I",
1526b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeLoad },
1536b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeDispose", "(I)V",
1546b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeDispose },
1556b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetCharacter", "(III)C",
1566b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetCharacter },
15749ed71db425c5054e3ad9526496a7e116c89556bJeff Brown    { "nativeGetFallbackAction", "(IIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
15849ed71db425c5054e3ad9526496a7e116c89556bJeff Brown            (void*)nativeGetFallbackAction },
1596b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetNumber", "(II)C",
1606b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetNumber },
1616b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetMatch", "(II[CI)C",
1626b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetMatch },
1636b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetDisplayLabel", "(II)C",
1646b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetDisplayLabel },
1656b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetKeyboardType", "(I)I",
1666b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetKeyboardType },
1676b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    { "nativeGetEvents", "(II[C)[Landroid/view/KeyEvent;",
1686b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            (void*)nativeGetEvents },
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1716b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#define FIND_CLASS(var, className) \
1726b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        var = env->FindClass(className); \
17317cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro        LOG_FATAL_IF(! var, "Unable to find class " className);
1746b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
17549ed71db425c5054e3ad9526496a7e116c89556bJeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
17649ed71db425c5054e3ad9526496a7e116c89556bJeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
17749ed71db425c5054e3ad9526496a7e116c89556bJeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
17849ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_text_KeyCharacterMap(JNIEnv* env)
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1816b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
18217cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18417cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    jclass clazz;
18517cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction");
18649ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
18717cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz,
18849ed71db425c5054e3ad9526496a7e116c89556bJeff Brown            "keyCode", "I");
18949ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
19017cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz,
19149ed71db425c5054e3ad9526496a7e116c89556bJeff Brown            "metaState", "I");
19249ed71db425c5054e3ad9526496a7e116c89556bJeff Brown
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env,
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "android/view/KeyCharacterMap", g_methods, NELEM(g_methods));
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; // namespace android
198