/**************************************************************************** ** ** Copyright (C) 2012 BogDan Vatra ** Copyright (C) 2016 Olivier Goffart ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "androidjniinput.h" #include "androidjnimain.h" #include "qandroidplatformintegration.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE using namespace QtAndroid; namespace QtAndroidInput { static bool m_ignoreMouseEvents = false; static bool m_softwareKeyboardVisible = false; static QRect m_softwareKeyboardRect; static QList m_touchPoints; static QPointer m_mouseGrabber; void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd) { #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd; #endif QJNIObjectPrivate::callStaticMethod(applicationClass(), "updateSelection", "(IIII)V", selStart, selEnd, candidatesStart, candidatesEnd); } void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) { QJNIObjectPrivate::callStaticMethod(applicationClass(), "showSoftwareKeyboard", "(IIIIII)V", left, top, width, height, inputHints, enterKeyType ); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType; #endif } void resetSoftwareKeyboard() { QJNIObjectPrivate::callStaticMethod(applicationClass(), "resetSoftwareKeyboard"); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ RESETSOFTWAREKEYBOARD"); #endif } void hideSoftwareKeyboard() { QJNIObjectPrivate::callStaticMethod(applicationClass(), "hideSoftwareKeyboard"); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ HIDESOFTWAREKEYBOARD"); #endif } bool isSoftwareKeyboardVisible() { return m_softwareKeyboardVisible; } QRect softwareKeyboardRect() { return m_softwareKeyboardRect; } void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl) { QJNIObjectPrivate::callStaticMethod(applicationClass(), "updateHandles", "(IIIIIIIIZ)V", mode, editMenuPos.x(), editMenuPos.y(), editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl); } static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { if (m_ignoreMouseEvents) return; QPoint globalPos(x,y); QWindow *tlw = topLevelWindowAt(globalPos); m_mouseGrabber = tlw; QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos; QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, Qt::MouseButtons(Qt::LeftButton)); } static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { QPoint globalPos(x,y); QWindow *tlw = m_mouseGrabber.data(); if (!tlw) tlw = topLevelWindowAt(globalPos); QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos; QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos , Qt::MouseButtons(Qt::NoButton)); m_ignoreMouseEvents = false; m_mouseGrabber = 0; } static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { if (m_ignoreMouseEvents) return; QPoint globalPos(x,y); QWindow *tlw = m_mouseGrabber.data(); if (!tlw) tlw = topLevelWindowAt(globalPos); QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton)); } static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta) { if (m_ignoreMouseEvents) return; QPoint globalPos(x,y); QWindow *tlw = m_mouseGrabber.data(); if (!tlw) tlw = topLevelWindowAt(globalPos); QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; QPoint angleDelta(hdelta * 120, vdelta * 120); QWindowSystemInterface::handleWheelEvent(tlw, localPos, globalPos, QPoint(), angleDelta); } static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) QMetaObject::invokeMethod(inputContext, "longPress", Q_ARG(int, x), Q_ARG(int, y)); //### TODO: add proper API for Qt 5.2 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue("QT_NECESSITAS_COMPATIBILITY_LONG_PRESS"); if (!rightMouseFromLongPress) return; m_ignoreMouseEvents = true; QPoint globalPos(x,y); QWindow *tlw = topLevelWindowAt(globalPos); QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; // Release left button QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, Qt::MouseButtons(Qt::NoButton)); // Press right button QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, Qt::MouseButtons(Qt::RightButton)); } static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/) { m_touchPoints.clear(); } static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat major, jfloat minor, jfloat rotation, jfloat pressure) { Qt::TouchPointState state = Qt::TouchPointStationary; switch (action) { case 0: state = Qt::TouchPointPressed; break; case 1: state = Qt::TouchPointMoved; break; case 2: state = Qt::TouchPointStationary; break; case 3: state = Qt::TouchPointReleased; break; } const int dw = desktopWidthPixels(); const int dh = desktopHeightPixels(); QWindowSystemInterface::TouchPoint touchPoint; touchPoint.id = id; touchPoint.pressure = pressure; touchPoint.rotation = qRadiansToDegrees(rotation); touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh)); touchPoint.state = state; touchPoint.area = QRectF(x - double(minor), y - double(major), double(minor * 2), double(major * 2)); m_touchPoints.push_back(touchPoint); if (state == Qt::TouchPointPressed) { QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) QMetaObject::invokeMethod(inputContext, "touchDown", Q_ARG(int, x), Q_ARG(int, y)); } } static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint /*action*/) { if (m_touchPoints.isEmpty()) return; QMutexLocker lock(QtAndroid::platformInterfaceMutex()); QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration(); if (!platformIntegration) return; QTouchDevice *touchDevice = platformIntegration->touchDevice(); if (touchDevice == 0) { touchDevice = new QTouchDevice; touchDevice->setType(QTouchDevice::TouchScreen); touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); QWindowSystemInterface::registerTouchDevice(touchDevice); platformIntegration->setTouchDevice(touchDevice); } QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint()); QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints); } static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/) { #if QT_CONFIG(tabletevent) return true; #else return false; #endif // QT_CONFIG(tabletevent) } static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action, jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure) { #if QT_CONFIG(tabletevent) QPointF globalPosF(x, y); QPoint globalPos((int)x, (int)y); QWindow *tlw = topLevelWindowAt(globalPos); QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF; // Galaxy Note with plain Android: // 0 1 0 stylus press // 2 1 0 stylus drag // 1 1 0 stylus release // 0 1 2 stylus press with side-button held // 2 1 2 stylus drag with side-button held // 1 1 2 stylus release with side-button held // Galaxy Note 4 with Samsung firmware: // 0 1 0 stylus press // 2 1 0 stylus drag // 1 1 0 stylus release // 211 1 2 stylus press with side-button held // 213 1 2 stylus drag with side-button held // 212 1 2 stylus release with side-button held // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed Qt::MouseButtons buttons = Qt::NoButton; switch (action) { case 1: // ACTION_UP case 212: // stylus release while side-button held on Galaxy Note 4 buttons = Qt::NoButton; break; default: // action is press or drag if (buttonState == 0) buttons = Qt::LeftButton; else // 2 means RightButton buttons = Qt::MouseButtons(buttonState); break; } #ifdef QT_DEBUG_ANDROID_STYLUS qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons; #endif QWindowSystemInterface::handleTabletEvent(tlw, ulong(time), localPos, globalPosF, QTabletEvent::Stylus, pointerType, buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier); #endif // QT_CONFIG(tabletevent) } static int mapAndroidKey(int key) { // 0--9 0x00000007 -- 0x00000010 if (key >= 0x00000007 && key <= 0x00000010) return Qt::Key_0 + key - 0x00000007; // A--Z 0x0000001d -- 0x00000036 if (key >= 0x0000001d && key <= 0x00000036) return Qt::Key_A + key - 0x0000001d; // F1--F12 0x00000083 -- 0x0000008e if (key >= 0x00000083 && key <= 0x0000008e) return Qt::Key_F1 + key - 0x00000083; // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 if (key >= 0x00000090 && key <= 0x00000099) return Qt::KeypadModifier + Qt::Key_0 + key - 0x00000090; // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb switch (key) { case 0x00000000: // KEYCODE_UNKNOWN return Qt::Key_unknown; case 0x00000001: // KEYCODE_SOFT_LEFT return Qt::Key_Left; case 0x00000002: // KEYCODE_SOFT_RIGHT return Qt::Key_Right; // 0x00000003: // KEYCODE_HOME is never delivered to applications. case 0x00000004: // KEYCODE_BACK return Qt::Key_Back; case 0x00000005: // KEYCODE_CALL return Qt::Key_Call; case 0x00000006: // KEYCODE_ENDCALL return Qt::Key_Hangup; // 0--9 0x00000007 -- 0x00000010 case 0x00000011: // KEYCODE_STAR return Qt::Key_Asterisk; case 0x00000012: // KEYCODE_POUND return Qt::Key_NumberSign; case 0x00000013: //KEYCODE_DPAD_UP return Qt::Key_Up; case 0x00000014: // KEYCODE_DPAD_DOWN return Qt::Key_Down; case 0x00000015: //KEYCODE_DPAD_LEFT return Qt::Key_Left; case 0x00000016: //KEYCODE_DPAD_RIGHT return Qt::Key_Right; case 0x00000017: // KEYCODE_DPAD_CENTER return Qt::Key_Enter; case 0x00000018: // KEYCODE_VOLUME_UP return Qt::Key_VolumeUp; case 0x00000019: // KEYCODE_VOLUME_DOWN return Qt::Key_VolumeDown; case 0x0000001a: return Qt::Key_PowerOff; case 0x0000001b: // KEYCODE_CAMERA return Qt::Key_Camera; case 0x0000001c: // KEYCODE_CLEAR return Qt::Key_Clear; // A--Z 0x0000001d -- 0x00000036 case 0x00000037: // KEYCODE_COMMA return Qt::Key_Comma; case 0x00000038: // KEYCODE_PERIOD return Qt::Key_Period; case 0x00000039: // KEYCODE_ALT_LEFT case 0x0000003a: // KEYCODE_ALT_RIGHT return Qt::Key_Alt; case 0x0000003b: // KEYCODE_SHIFT_LEFT case 0x0000003c: // KEYCODE_SHIFT_RIGHT return Qt::Key_Shift; case 0x0000003d: // KEYCODE_TAB return Qt::Key_Tab; case 0x0000003e: // KEYCODE_SPACE return Qt::Key_Space; case 0x0000003f: // KEYCODE_SYM return Qt::Key_Meta; case 0x00000040: // KEYCODE_EXPLORER return Qt::Key_Explorer; case 0x00000041: //KEYCODE_ENVELOPE return Qt::Key_LaunchMail; case 0x00000042: // KEYCODE_ENTER return Qt::Key_Return; case 0x00000043: // KEYCODE_DEL return Qt::Key_Backspace; case 0x00000044: // KEYCODE_GRAVE return Qt::Key_QuoteLeft; case 0x00000045: // KEYCODE_MINUS return Qt::Key_Minus; case 0x00000046: // KEYCODE_EQUALS return Qt::Key_Equal; case 0x00000047: // KEYCODE_LEFT_BRACKET return Qt::Key_BracketLeft; case 0x00000048: // KEYCODE_RIGHT_BRACKET return Qt::Key_BracketRight; case 0x00000049: // KEYCODE_BACKSLASH return Qt::Key_Backslash; case 0x0000004a: // KEYCODE_SEMICOLON return Qt::Key_Semicolon; case 0x0000004b: // KEYCODE_APOSTROPHE return Qt::Key_Apostrophe; case 0x0000004c: // KEYCODE_SLASH return Qt::Key_Slash; case 0x0000004d: // KEYCODE_AT return Qt::Key_At; case 0x0000004e: // KEYCODE_NUM return Qt::Key_Alt; case 0x0000004f: // KEYCODE_HEADSETHOOK return 0; case 0x00000050: // KEYCODE_FOCUS return Qt::Key_CameraFocus; case 0x00000051: // KEYCODE_PLUS return Qt::Key_Plus; case 0x00000052: // KEYCODE_MENU return Qt::Key_Menu; case 0x00000053: // KEYCODE_NOTIFICATION return 0; case 0x00000054: // KEYCODE_SEARCH return Qt::Key_Search; case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE return Qt::Key_MediaPlay; case 0x00000056: // KEYCODE_MEDIA_STOP return Qt::Key_MediaStop; case 0x00000057: // KEYCODE_MEDIA_NEXT return Qt::Key_MediaNext; case 0x00000058: // KEYCODE_MEDIA_PREVIOUS return Qt::Key_MediaPrevious; case 0x00000059: // KEYCODE_MEDIA_REWIND return Qt::Key_AudioRewind; case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD return Qt::Key_AudioForward; case 0x0000005b: // KEYCODE_MUTE return Qt::Key_MicMute; case 0x0000005c: // KEYCODE_PAGE_UP return Qt::Key_PageUp; case 0x0000005d: // KEYCODE_PAGE_DOWN return Qt::Key_PageDown; case 0x0000005e: // KEYCODE_PICTSYMBOLS return 0; case 0x00000060: // KEYCODE_BUTTON_A case 0x00000061: // KEYCODE_BUTTON_B case 0x00000062: // KEYCODE_BUTTON_B case 0x00000063: // KEYCODE_BUTTON_X case 0x00000064: // KEYCODE_BUTTON_Y case 0x00000065: // KEYCODE_BUTTON_Z case 0x00000066: // KEYCODE_BUTTON_L1 case 0x00000067: // KEYCODE_BUTTON_R1 case 0x00000068: // KEYCODE_BUTTON_L2 case 0x00000069: // KEYCODE_BUTTON_R2 case 0x0000006a: // KEYCODE_BUTTON_THUMBL case 0x0000006b: // KEYCODE_BUTTON_THUMBR case 0x0000006c: // KEYCODE_BUTTON_START case 0x0000006d: // KEYCODE_BUTTON_SELECT case 0x0000006e: // KEYCODE_BUTTON_MODE return 0; case 0x0000006f: // KEYCODE_ESCAPE return Qt::Key_Escape; case 0x00000070: // KEYCODE_FORWARD_DEL return Qt::Key_Delete; case 0x00000071: // KEYCODE_CTRL_LEFT case 0x00000072: // KEYCODE_CTRL_RIGHT return Qt::Key_Control; case 0x00000073: // KEYCODE_CAPS_LOCK return Qt::Key_CapsLock; case 0x00000074: // KEYCODE_SCROLL_LOCK return Qt::Key_ScrollLock; case 0x00000075: // KEYCODE_META_LEFT case 0x00000076: // KEYCODE_META_RIGHT return Qt::Key_Meta; case 0x00000077: // KEYCODE_FUNCTION return 0; case 0x00000078: // KEYCODE_SYSRQ return Qt::Key_Print; case 0x00000079: // KEYCODE_BREAK return Qt::Key_Pause; case 0x0000007a: // KEYCODE_MOVE_HOME return Qt::Key_Home; case 0x0000007b: // KEYCODE_MOVE_END return Qt::Key_End; case 0x0000007c: // KEYCODE_MOVE_INSERT return Qt::Key_Insert; case 0x0000007d: // KEYCODE_FORWARD return Qt::Key_Forward; case 0x0000007e: // KEYCODE_MEDIA_PLAY return Qt::Key_MediaPlay; case 0x0000007f: // KEYCODE_MEDIA_PAUSE return Qt::Key_MediaPause; case 0x00000080: // KEYCODE_MEDIA_CLOSE case 0x00000081: // KEYCODE_MEDIA_EJECT return Qt::Key_Eject; case 0x00000082: // KEYCODE_MEDIA_RECORD return Qt::Key_MediaRecord; // F1--F12 0x00000083 -- 0x0000008e case 0x0000008f: // KEYCODE_NUM_LOCK return Qt::Key_NumLock; // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 case 0x0000009a: // KEYCODE_NUMPAD_DIVIDE return Qt::KeypadModifier + Qt::Key_Slash; case 0x0000009b: // KEYCODE_NUMPAD_MULTIPLY return Qt::KeypadModifier + Qt::Key_Asterisk; case 0x0000009c: // KEYCODE_NUMPAD_SUBTRACT return Qt::KeypadModifier + Qt::Key_Minus; case 0x0000009d: // KEYCODE_NUMPAD_ADD return Qt::KeypadModifier + Qt::Key_Plus; case 0x0000009e: // KEYCODE_NUMPAD_DOT return Qt::KeypadModifier + Qt::Key_Period; case 0x0000009f: // KEYCODE_NUMPAD_COMMA return Qt::KeypadModifier + Qt::Key_Comma; case 0x000000a0: // KEYCODE_NUMPAD_ENTER return Qt::Key_Enter; case 0x000000a1: // KEYCODE_NUMPAD_EQUALS return Qt::KeypadModifier + Qt::Key_Equal; case 0x000000a2: // KEYCODE_NUMPAD_LEFT_PAREN return Qt::Key_ParenLeft; case 0x000000a3: // KEYCODE_NUMPAD_RIGHT_PAREN return Qt::Key_ParenRight; case 0x000000a4: // KEYCODE_VOLUME_MUTE return Qt::Key_VolumeMute; case 0x000000a5: // KEYCODE_INFO return Qt::Key_Info; case 0x000000a6: // KEYCODE_CHANNEL_UP return Qt::Key_ChannelUp; case 0x000000a7: // KEYCODE_CHANNEL_DOWN return Qt::Key_ChannelDown; case 0x000000a8: // KEYCODE_ZOOM_IN return Qt::Key_ZoomIn; case 0x000000a9: // KEYCODE_ZOOM_OUT return Qt::Key_ZoomOut; case 0x000000aa: // KEYCODE_TV case 0x000000ab: // KEYCODE_WINDOW return 0; case 0x000000ac: // KEYCODE_GUIDE return Qt::Key_Guide; case 0x000000ad: // KEYCODE_DVR return 0; case 0x000000ae: // KEYCODE_BOOKMARK return Qt::Key_AddFavorite; case 0x000000af: // KEYCODE_CAPTIONS return Qt::Key_Subtitle; case 0x000000b0: // KEYCODE_SETTINGS return Qt::Key_Settings; case 0x000000b1: // KEYCODE_TV_POWER case 0x000000b2: // KEYCODE_TV_INPUT case 0x000000b3: // KEYCODE_STB_POWER case 0x000000b4: // KEYCODE_STB_INPUT case 0x000000b5: // KEYCODE_AVR_POWER case 0x000000b6: // KEYCODE_AVR_INPUT return 0; case 0x000000b7: // KEYCODE_PROG_RED return Qt::Key_Red; case 0x000000b8: // KEYCODE_PROG_GREEN return Qt::Key_Green; case 0x000000b9: // KEYCODE_PROG_YELLOW return Qt::Key_Yellow; case 0x000000ba: // KEYCODE_PROG_BLUE return Qt::Key_Blue; // 0x000000bb: // KEYCODE_APP_SWITCH is not sent by the Android O.S. // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb case 0x000000cc: // KEYCODE_LANGUAGE_SWITCH case 0x000000cd: // KEYCODE_MANNER_MODE do we need such a thing? case 0x000000ce: // KEYCODE_3D_MODE case 0x000000cf: // KEYCODE_CONTACTS return 0; case 0x000000d0: // KEYCODE_CALENDAR return Qt::Key_Calendar; case 0x000000d1: // KEYCODE_MUSIC return Qt::Key_Music; case 0x000000d2: // KEYCODE_CALCULATOR return Qt::Key_Calculator; // 0x000000d3 -- 0x000000da some japanese specific keys, someone who understand what is about should check ! // 0x000000db: // KEYCODE_ASSIST not delivered to applications. case 0x000000dc: // KEYCODE_BRIGHTNESS_DOWN return Qt::Key_KeyboardBrightnessDown; case 0x000000dd: // KEYCODE_BRIGHTNESS_UP return Qt::Key_KeyboardBrightnessUp; case 0x000000de: // KEYCODE_MEDIA_AUDIO_TRACK return Qt::Key_AudioCycleTrack; default: qWarning() << "Unhandled key code " << key << '!'; return 0; } } static Qt::KeyboardModifiers mapAndroidModifiers(jint modifiers) { Qt::KeyboardModifiers qmodifiers; if (modifiers & 0x00000001) // META_SHIFT_ON qmodifiers |= Qt::ShiftModifier; if (modifiers & 0x00000002) // META_ALT_ON qmodifiers |= Qt::AltModifier; if (modifiers & 0x00000004) // META_SYM_ON qmodifiers |= Qt::MetaModifier; if (modifiers & 0x00001000) // META_CTRL_ON qmodifiers |= Qt::ControlModifier; return qmodifiers; } // maps 0 to the empty string, and anything else to a single-character string static inline QString toString(jint unicode) { return unicode ? QString(QChar(unicode)) : QString(); } static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) { QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, mapAndroidKey(key), mapAndroidModifiers(modifier), toString(unicode), autoRepeat); } static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) { QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, mapAndroidKey(key), mapAndroidModifiers(modifier), toString(unicode), autoRepeat); } static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility) { m_softwareKeyboardVisible = visibility; if (!visibility) m_softwareKeyboardRect = QRect(); QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) { inputContext->emitInputPanelVisibleChanged(); if (!visibility) { inputContext->emitKeyboardRectChanged(); QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection); } } #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext; #endif } static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h) { QRect r = QRect(x, y, w, h); if (r == m_softwareKeyboardRect) return; m_softwareKeyboardRect = r; QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) inputContext->emitKeyboardRectChanged(); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect; #endif } static void handleLocationChanged(JNIEnv */*env*/, jobject /*thiz*/, int id, int x, int y) { #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ handleLocationChanged" << id << x << y; #endif QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection, Q_ARG(int, id), Q_ARG(int, x), Q_ARG(int, y)); } static JNINativeMethod methods[] = { {"touchBegin","(I)V",(void*)touchBegin}, {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd}, {"touchEnd","(II)V",(void*)touchEnd}, {"mouseDown", "(III)V", (void *)mouseDown}, {"mouseUp", "(III)V", (void *)mouseUp}, {"mouseMove", "(III)V", (void *)mouseMove}, {"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, {"longPress", "(III)V", (void *)longPress}, {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported}, {"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent}, {"keyDown", "(IIIZ)V", (void *)keyDown}, {"keyUp", "(IIIZ)V", (void *)keyUp}, {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}, {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged}, {"handleLocationChanged", "(III)V", (void *)handleLocationChanged} }; bool registerNatives(JNIEnv *env) { jclass appClass = QtAndroid::applicationClass(); if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); return false; } return true; } } QT_END_NAMESPACE