146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown/*
246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Copyright (C) 2010 The Android Open Source Project
346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * you may not use this file except in compliance with the License.
646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * You may obtain a copy of the License at
746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
1046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Unless required by applicable law or agreed to in writing, software
1146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * See the License for the specific language governing permissions and
1446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * limitations under the License.
1546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown */
1646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define LOG_TAG "KeyEvent-JNI"
1846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include "JNIHelp.h"
2046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
2146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <android_runtime/AndroidRuntime.h>
2287eac99a21772ae56018cb81db6966557b459554Ruben Brunk#include <android_runtime/Log.h>
2346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <utils/Log.h>
249d3b1a424c5c61e24e9659d15fb353026a00d925Jeff Brown#include <input/Input.h>
25337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright#include <ScopedUtfChars.h>
2646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include "android_view_KeyEvent.h"
2746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
2846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownnamespace android {
2946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
3046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown// ----------------------------------------------------------------------------
3146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
3246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic struct {
3346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jclass clazz;
3446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
351f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    jmethodID obtain;
361f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    jmethodID recycle;
3746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
38c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    jfieldID mDeviceId;
39c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    jfieldID mSource;
4046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mMetaState;
4146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mAction;
4246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mKeyCode;
4346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mScanCode;
4446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mRepeatCount;
4546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mFlags;
4646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mDownTime;
4746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mEventTime;
4846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mCharacters;
4946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} gKeyEventClassInfo;
5046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
5146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown// ----------------------------------------------------------------------------
5246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
5346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownjobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
541f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz,
551f2451007c660091b7b090c1ea332f9044515d2dJeff Brown            gKeyEventClassInfo.obtain,
5646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            nanoseconds_to_milliseconds(event->getDownTime()),
5746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            nanoseconds_to_milliseconds(event->getEventTime()),
5846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getAction(),
5946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getKeyCode(),
6046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getRepeatCount(),
6146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getMetaState(),
6246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getDeviceId(),
6346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            event->getScanCode(),
64c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown            event->getFlags(),
651f2451007c660091b7b090c1ea332f9044515d2dJeff Brown            event->getSource(),
661f2451007c660091b7b090c1ea332f9044515d2dJeff Brown            NULL);
671f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    if (env->ExceptionCheck()) {
683762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("An exception occurred while obtaining a key event.");
691f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        LOGE_EX(env);
701f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        env->ExceptionClear();
711f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        return NULL;
721f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    }
731f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    return eventObj;
7446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown}
7546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
761f2451007c660091b7b090c1ea332f9044515d2dJeff Brownstatus_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
7746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        KeyEvent* event) {
78c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
79c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
8046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint metaState = env->GetIntField(eventObj, gKeyEventClassInfo.mMetaState);
8146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint action = env->GetIntField(eventObj, gKeyEventClassInfo.mAction);
8246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint keyCode = env->GetIntField(eventObj, gKeyEventClassInfo.mKeyCode);
8346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint scanCode = env->GetIntField(eventObj, gKeyEventClassInfo.mScanCode);
8446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint repeatCount = env->GetIntField(eventObj, gKeyEventClassInfo.mRepeatCount);
8546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint flags = env->GetIntField(eventObj, gKeyEventClassInfo.mFlags);
8646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime);
8746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
8846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
89c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    event->initialize(deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
9046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            milliseconds_to_nanoseconds(downTime),
9146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            milliseconds_to_nanoseconds(eventTime));
921f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    return OK;
931f2451007c660091b7b090c1ea332f9044515d2dJeff Brown}
941f2451007c660091b7b090c1ea332f9044515d2dJeff Brown
951f2451007c660091b7b090c1ea332f9044515d2dJeff Brownstatus_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj) {
961f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    env->CallVoidMethod(eventObj, gKeyEventClassInfo.recycle);
971f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    if (env->ExceptionCheck()) {
988564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("An exception occurred while recycling a key event.");
991f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        LOGW_EX(env);
1001f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        env->ExceptionClear();
1011f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        return UNKNOWN_ERROR;
1021f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    }
1031f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    return OK;
10446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown}
10546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
106337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wrightstatic jstring android_view_KeyEvent_nativeKeyCodeToString(JNIEnv* env, jobject clazz,
107337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright        jint keyCode) {
108337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright    return env->NewStringUTF(KeyEvent::getLabel(keyCode));
1093c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn}
1103c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn
111337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wrightstatic jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject clazz,
112337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright        jstring label) {
113337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright    ScopedUtfChars keyLabel(env, label);
114337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright    return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str());
1153c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn}
1163c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn
1171f2451007c660091b7b090c1ea332f9044515d2dJeff Brown
11846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown// ----------------------------------------------------------------------------
11946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1203c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackbornstatic const JNINativeMethod g_methods[] = {
121337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright    { "nativeKeyCodeToString", "(I)Ljava/lang/String;",
122337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright        (void*)android_view_KeyEvent_nativeKeyCodeToString},
123337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright    { "nativeKeyCodeFromString", "(Ljava/lang/String;)I",
124337d9d2edc262141f9b8f684e53aae5e47f0ae13Michael Wright        (void*)android_view_KeyEvent_nativeKeyCodeFromString},
1253c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn};
1263c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn
12746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define FIND_CLASS(var, className) \
12846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->FindClass(className); \
12946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find class " className); \
13046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = jclass(env->NewGlobalRef(var));
13146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1321f2451007c660091b7b090c1ea332f9044515d2dJeff Brown#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
1331f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
1341f2451007c660091b7b090c1ea332f9044515d2dJeff Brown        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
1351f2451007c660091b7b090c1ea332f9044515d2dJeff Brown
13646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
13746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
13846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find method" methodName);
13946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
14046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
14146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
14246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
14346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
14446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownint register_android_view_KeyEvent(JNIEnv* env) {
145c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
1461f2451007c660091b7b090c1ea332f9044515d2dJeff Brown
1471f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    GET_STATIC_METHOD_ID(gKeyEventClassInfo.obtain, gKeyEventClassInfo.clazz,
1481f2451007c660091b7b090c1ea332f9044515d2dJeff Brown            "obtain", "(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;");
1491f2451007c660091b7b090c1ea332f9044515d2dJeff Brown    GET_METHOD_ID(gKeyEventClassInfo.recycle, gKeyEventClassInfo.clazz,
1501f2451007c660091b7b090c1ea332f9044515d2dJeff Brown            "recycle", "()V");
15146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
152c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
153c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown            "mDeviceId", "I");
154c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mSource, gKeyEventClassInfo.clazz,
155c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown            "mSource", "I");
15646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mMetaState, gKeyEventClassInfo.clazz,
15746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mMetaState", "I");
15846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mAction, gKeyEventClassInfo.clazz,
15946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mAction", "I");
16046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mKeyCode, gKeyEventClassInfo.clazz,
16146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mKeyCode", "I");
16246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mScanCode, gKeyEventClassInfo.clazz,
16346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mScanCode", "I");
16446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mRepeatCount, gKeyEventClassInfo.clazz,
16546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mRepeatCount", "I");
16646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mFlags, gKeyEventClassInfo.clazz,
16746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mFlags", "I");
16846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mDownTime, gKeyEventClassInfo.clazz,
16946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mDownTime", "J");
17046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mEventTime, gKeyEventClassInfo.clazz,
17146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mEventTime", "J");
17246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz,
17346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mCharacters", "Ljava/lang/String;");
17446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1753c80a4a044865bdf1289c7896baffa1c082d835cDianne Hackborn    return AndroidRuntime::registerNativeMethods(
176c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown        env, "android/view/KeyEvent", g_methods, NELEM(g_methods));
17746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown}
17846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
17946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} // namespace android
180