1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
4 ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
5 ** Contact: http://www.qt.io/licensing/
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include <QtGui/qtguiglobal.h>
42 
43 #include "androidjniinput.h"
44 #include "androidjnimain.h"
45 #include "qandroidplatformintegration.h"
46 
47 #include <qpa/qwindowsysteminterface.h>
48 #include <QTouchEvent>
49 #include <QPointer>
50 
51 #include <QGuiApplication>
52 #include <QDebug>
53 #include <QtMath>
54 
55 QT_BEGIN_NAMESPACE
56 
57 using namespace QtAndroid;
58 
59 namespace QtAndroidInput
60 {
61     static bool m_ignoreMouseEvents = false;
62     static bool m_softwareKeyboardVisible = false;
63     static QRect m_softwareKeyboardRect;
64 
65     static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
66 
67     static QPointer<QWindow> m_mouseGrabber;
68 
updateSelection(int selStart,int selEnd,int candidatesStart,int candidatesEnd)69     void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
70     {
71 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
72         qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
73 #endif
74         QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
75                                                   "updateSelection",
76                                                   "(IIII)V",
77                                                   selStart,
78                                                   selEnd,
79                                                   candidatesStart,
80                                                   candidatesEnd);
81     }
82 
showSoftwareKeyboard(int left,int top,int width,int height,int inputHints,int enterKeyType)83     void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
84     {
85         QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
86                                                   "showSoftwareKeyboard",
87                                                   "(IIIIII)V",
88                                                   left,
89                                                   top,
90                                                   width,
91                                                   height,
92                                                   inputHints,
93                                                   enterKeyType
94                                                  );
95 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
96         qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
97 #endif
98     }
99 
resetSoftwareKeyboard()100     void resetSoftwareKeyboard()
101     {
102         QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard");
103 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
104         qDebug("@@@ RESETSOFTWAREKEYBOARD");
105 #endif
106     }
107 
hideSoftwareKeyboard()108     void hideSoftwareKeyboard()
109     {
110         QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard");
111 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
112         qDebug("@@@ HIDESOFTWAREKEYBOARD");
113 #endif
114     }
115 
isSoftwareKeyboardVisible()116     bool isSoftwareKeyboardVisible()
117     {
118         return m_softwareKeyboardVisible;
119     }
120 
softwareKeyboardRect()121     QRect softwareKeyboardRect()
122     {
123         return m_softwareKeyboardRect;
124     }
125 
updateHandles(int mode,QPoint editMenuPos,uint32_t editButtons,QPoint cursor,QPoint anchor,bool rtl)126     void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
127     {
128         QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
129                                                   mode, editMenuPos.x(), editMenuPos.y(), editButtons,
130                                                   cursor.x(), cursor.y(),
131                                                   anchor.x(), anchor.y(), rtl);
132     }
133 
mouseDown(JNIEnv *,jobject,jint,jint x,jint y)134     static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
135     {
136         if (m_ignoreMouseEvents)
137             return;
138 
139         QPoint globalPos(x,y);
140         QWindow *tlw = topLevelWindowAt(globalPos);
141         m_mouseGrabber = tlw;
142         QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
143         QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
144                                                  Qt::MouseButtons(Qt::LeftButton),
145                                                  Qt::LeftButton, QEvent::MouseButtonPress);
146     }
147 
mouseUp(JNIEnv *,jobject,jint,jint x,jint y)148     static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
149     {
150         QPoint globalPos(x,y);
151         QWindow *tlw = m_mouseGrabber.data();
152         if (!tlw)
153             tlw = topLevelWindowAt(globalPos);
154         QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
155         QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
156                                                  Qt::MouseButtons(Qt::NoButton),
157                                                  Qt::LeftButton, QEvent::MouseButtonRelease);
158         m_ignoreMouseEvents = false;
159         m_mouseGrabber = 0;
160     }
161 
mouseMove(JNIEnv *,jobject,jint,jint x,jint y)162     static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
163     {
164 
165         if (m_ignoreMouseEvents)
166             return;
167 
168         QPoint globalPos(x,y);
169         QWindow *tlw = m_mouseGrabber.data();
170         if (!tlw)
171             tlw = topLevelWindowAt(globalPos);
172         QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
173         QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
174                                                  Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton),
175                                                  Qt::NoButton, QEvent::MouseMove);
176     }
177 
mouseWheel(JNIEnv *,jobject,jint,jint x,jint y,jfloat hdelta,jfloat vdelta)178     static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta)
179     {
180         if (m_ignoreMouseEvents)
181             return;
182 
183         QPoint globalPos(x,y);
184         QWindow *tlw = m_mouseGrabber.data();
185         if (!tlw)
186             tlw = topLevelWindowAt(globalPos);
187         QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
188         QPoint angleDelta(hdelta * 120, vdelta * 120);
189 
190         QWindowSystemInterface::handleWheelEvent(tlw,
191                                                  localPos,
192                                                  globalPos,
193                                                  QPoint(),
194                                                  angleDelta);
195     }
196 
longPress(JNIEnv *,jobject,jint,jint x,jint y)197     static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
198     {
199         QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
200         if (inputContext && qGuiApp)
201             QMetaObject::invokeMethod(inputContext, "longPress", Q_ARG(int, x), Q_ARG(int, y));
202 
203         //### TODO: add proper API for Qt 5.2
204         static bool rightMouseFromLongPress = qEnvironmentVariableIntValue("QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
205         if (!rightMouseFromLongPress)
206             return;
207         m_ignoreMouseEvents = true;
208         QPoint globalPos(x,y);
209         QWindow *tlw = topLevelWindowAt(globalPos);
210         QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
211 
212         // Click right button if no other button is already pressed.
213         if (!m_mouseGrabber) {
214             QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
215                                                      Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
216                                                      QEvent::MouseButtonPress);
217             QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
218                                                      Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
219                                                      QEvent::MouseButtonRelease);
220         }
221     }
222 
touchBegin(JNIEnv *,jobject,jint)223     static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
224     {
225         m_touchPoints.clear();
226     }
227 
touchAdd(JNIEnv *,jobject,jint,jint id,jint action,jboolean,jint x,jint y,jfloat major,jfloat minor,jfloat rotation,jfloat pressure)228     static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y,
229         jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
230     {
231         Qt::TouchPointState state = Qt::TouchPointStationary;
232         switch (action) {
233         case 0:
234             state = Qt::TouchPointPressed;
235             break;
236         case 1:
237             state = Qt::TouchPointMoved;
238             break;
239         case 2:
240             state = Qt::TouchPointStationary;
241             break;
242         case 3:
243             state = Qt::TouchPointReleased;
244             break;
245         }
246 
247         const int dw = desktopWidthPixels();
248         const int dh = desktopHeightPixels();
249         QWindowSystemInterface::TouchPoint touchPoint;
250         touchPoint.id = id;
251         touchPoint.pressure = pressure;
252         touchPoint.rotation = qRadiansToDegrees(rotation);
253         touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
254         touchPoint.state = state;
255         touchPoint.area = QRectF(x - double(minor),
256                                  y - double(major),
257                                  double(minor * 2),
258                                  double(major * 2));
259         m_touchPoints.push_back(touchPoint);
260 
261         if (state == Qt::TouchPointPressed) {
262             QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
263             if (inputContext && qGuiApp)
264                 QMetaObject::invokeMethod(inputContext, "touchDown", Q_ARG(int, x), Q_ARG(int, y));
265         }
266     }
267 
touchEnd(JNIEnv *,jobject,jint,jint)268     static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint /*action*/)
269     {
270         if (m_touchPoints.isEmpty())
271             return;
272 
273         QMutexLocker lock(QtAndroid::platformInterfaceMutex());
274         QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
275         if (!platformIntegration)
276             return;
277 
278         QTouchDevice *touchDevice = platformIntegration->touchDevice();
279         if (touchDevice == 0) {
280             touchDevice = new QTouchDevice;
281             touchDevice->setType(QTouchDevice::TouchScreen);
282             touchDevice->setCapabilities(QTouchDevice::Position
283                                          | QTouchDevice::Area
284                                          | QTouchDevice::Pressure
285                                          | QTouchDevice::NormalizedPosition);
286             QWindowSystemInterface::registerTouchDevice(touchDevice);
287             platformIntegration->setTouchDevice(touchDevice);
288         }
289 
290         QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
291         QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
292     }
293 
isTabletEventSupported(JNIEnv *,jobject)294     static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/)
295     {
296 #if QT_CONFIG(tabletevent)
297         return true;
298 #else
299         return false;
300 #endif // QT_CONFIG(tabletevent)
301     }
302 
tabletEvent(JNIEnv *,jobject,jint,jint deviceId,jlong time,jint action,jint pointerType,jint buttonState,jfloat x,jfloat y,jfloat pressure)303     static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action,
304         jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
305     {
306 #if QT_CONFIG(tabletevent)
307         QPointF globalPosF(x, y);
308         QPoint globalPos((int)x, (int)y);
309         QWindow *tlw = topLevelWindowAt(globalPos);
310         QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF;
311 
312         // Galaxy Note with plain Android:
313         // 0 1 0    stylus press
314         // 2 1 0    stylus drag
315         // 1 1 0    stylus release
316         // 0 1 2    stylus press with side-button held
317         // 2 1 2    stylus drag with side-button held
318         // 1 1 2    stylus release with side-button held
319         // Galaxy Note 4 with Samsung firmware:
320         // 0 1 0    stylus press
321         // 2 1 0    stylus drag
322         // 1 1 0    stylus release
323         // 211 1 2  stylus press with side-button held
324         // 213 1 2  stylus drag with side-button held
325         // 212 1 2  stylus release with side-button held
326         // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed
327         Qt::MouseButtons buttons = Qt::NoButton;
328         switch (action) {
329         case 1:     // ACTION_UP
330         case 212:   // stylus release while side-button held on Galaxy Note 4
331             buttons = Qt::NoButton;
332             break;
333         default:    // action is press or drag
334             if (buttonState == 0)
335                 buttons = Qt::LeftButton;
336             else // 2 means RightButton
337                 buttons = Qt::MouseButtons(buttonState);
338             break;
339         }
340 
341 #ifdef QT_DEBUG_ANDROID_STYLUS
342         qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
343 #endif
344 
345         QWindowSystemInterface::handleTabletEvent(tlw, ulong(time),
346             localPos, globalPosF, QTabletEvent::Stylus, pointerType,
347             buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier);
348 #endif // QT_CONFIG(tabletevent)
349     }
350 
mapAndroidKey(int key)351     static int mapAndroidKey(int key)
352     {
353         // 0--9        0x00000007 -- 0x00000010
354         if (key >= 0x00000007 && key <= 0x00000010)
355             return Qt::Key_0 + key - 0x00000007;
356 
357         // A--Z        0x0000001d -- 0x00000036
358         if (key >= 0x0000001d && key <= 0x00000036)
359             return Qt::Key_A + key - 0x0000001d;
360 
361         // F1--F12     0x00000083 -- 0x0000008e
362         if (key >= 0x00000083 && key <= 0x0000008e)
363             return Qt::Key_F1 + key - 0x00000083;
364 
365         // NUMPAD_0--NUMPAD_9     0x00000090 -- 0x00000099
366         if (key >= 0x00000090 && key <= 0x00000099)
367             return Qt::KeypadModifier + Qt::Key_0 + key - 0x00000090;
368 
369         // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb
370 
371         switch (key) {
372         case 0x00000000: // KEYCODE_UNKNOWN
373             return Qt::Key_unknown;
374 
375         case 0x00000001: // KEYCODE_SOFT_LEFT
376             return Qt::Key_Left;
377 
378         case 0x00000002: // KEYCODE_SOFT_RIGHT
379             return Qt::Key_Right;
380 
381         // 0x00000003: // KEYCODE_HOME is never delivered to applications.
382 
383         case 0x00000004: // KEYCODE_BACK
384             return Qt::Key_Back;
385 
386         case 0x00000005: // KEYCODE_CALL
387             return Qt::Key_Call;
388 
389         case 0x00000006: // KEYCODE_ENDCALL
390             return Qt::Key_Hangup;
391 
392        // 0--9        0x00000007 -- 0x00000010
393 
394         case 0x00000011: // KEYCODE_STAR
395             return Qt::Key_Asterisk;
396 
397         case 0x00000012: // KEYCODE_POUND
398             return Qt::Key_NumberSign;
399 
400         case 0x00000013: //KEYCODE_DPAD_UP
401             return Qt::Key_Up;
402 
403         case 0x00000014: // KEYCODE_DPAD_DOWN
404             return Qt::Key_Down;
405 
406         case 0x00000015: //KEYCODE_DPAD_LEFT
407             return Qt::Key_Left;
408 
409         case 0x00000016: //KEYCODE_DPAD_RIGHT
410             return Qt::Key_Right;
411 
412         case 0x00000017: // KEYCODE_DPAD_CENTER
413             return Qt::Key_Enter;
414 
415         case 0x00000018: // KEYCODE_VOLUME_UP
416             return Qt::Key_VolumeUp;
417 
418         case 0x00000019: // KEYCODE_VOLUME_DOWN
419             return Qt::Key_VolumeDown;
420 
421         case 0x0000001a:
422             return Qt::Key_PowerOff;
423 
424         case 0x0000001b: // KEYCODE_CAMERA
425             return Qt::Key_Camera;
426 
427         case 0x0000001c: // KEYCODE_CLEAR
428             return Qt::Key_Clear;
429 
430         // A--Z        0x0000001d -- 0x00000036
431 
432         case 0x00000037: // KEYCODE_COMMA
433             return Qt::Key_Comma;
434 
435         case 0x00000038: // KEYCODE_PERIOD
436             return Qt::Key_Period;
437 
438         case 0x00000039: // KEYCODE_ALT_LEFT
439         case 0x0000003a: // KEYCODE_ALT_RIGHT
440             return Qt::Key_Alt;
441 
442         case 0x0000003b: // KEYCODE_SHIFT_LEFT
443         case 0x0000003c: // KEYCODE_SHIFT_RIGHT
444             return Qt::Key_Shift;
445 
446         case 0x0000003d: // KEYCODE_TAB
447             return Qt::Key_Tab;
448 
449         case 0x0000003e: // KEYCODE_SPACE
450             return Qt::Key_Space;
451 
452         case 0x0000003f: // KEYCODE_SYM
453             return Qt::Key_Meta;
454 
455         case 0x00000040: // KEYCODE_EXPLORER
456             return Qt::Key_Explorer;
457 
458         case 0x00000041: //KEYCODE_ENVELOPE
459             return Qt::Key_LaunchMail;
460 
461         case 0x00000042: // KEYCODE_ENTER
462             return Qt::Key_Return;
463 
464         case 0x00000043: // KEYCODE_DEL
465             return Qt::Key_Backspace;
466 
467         case 0x00000044: // KEYCODE_GRAVE
468             return Qt::Key_QuoteLeft;
469 
470         case 0x00000045: // KEYCODE_MINUS
471             return Qt::Key_Minus;
472 
473         case 0x00000046: // KEYCODE_EQUALS
474             return Qt::Key_Equal;
475 
476         case 0x00000047: // KEYCODE_LEFT_BRACKET
477             return Qt::Key_BracketLeft;
478 
479         case 0x00000048: // KEYCODE_RIGHT_BRACKET
480             return Qt::Key_BracketRight;
481 
482         case 0x00000049: // KEYCODE_BACKSLASH
483             return Qt::Key_Backslash;
484 
485         case 0x0000004a: // KEYCODE_SEMICOLON
486             return Qt::Key_Semicolon;
487 
488         case 0x0000004b: // KEYCODE_APOSTROPHE
489             return Qt::Key_Apostrophe;
490 
491         case 0x0000004c: // KEYCODE_SLASH
492             return Qt::Key_Slash;
493 
494         case 0x0000004d: // KEYCODE_AT
495             return Qt::Key_At;
496 
497         case 0x0000004e: // KEYCODE_NUM
498             return Qt::Key_Alt;
499 
500         case 0x0000004f: // KEYCODE_HEADSETHOOK
501             return 0;
502 
503         case 0x00000050: // KEYCODE_FOCUS
504             return Qt::Key_CameraFocus;
505 
506         case 0x00000051: // KEYCODE_PLUS
507             return Qt::Key_Plus;
508 
509         case 0x00000052: // KEYCODE_MENU
510             return Qt::Key_Menu;
511 
512         case 0x00000053: // KEYCODE_NOTIFICATION
513             return 0;
514 
515         case 0x00000054: // KEYCODE_SEARCH
516             return Qt::Key_Search;
517 
518         case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE
519             return Qt::Key_MediaPlay;
520 
521         case 0x00000056: // KEYCODE_MEDIA_STOP
522             return Qt::Key_MediaStop;
523 
524         case 0x00000057: // KEYCODE_MEDIA_NEXT
525             return Qt::Key_MediaNext;
526 
527         case 0x00000058: // KEYCODE_MEDIA_PREVIOUS
528             return Qt::Key_MediaPrevious;
529 
530         case 0x00000059: // KEYCODE_MEDIA_REWIND
531             return Qt::Key_AudioRewind;
532 
533         case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD
534             return Qt::Key_AudioForward;
535 
536         case 0x0000005b: // KEYCODE_MUTE
537             return Qt::Key_MicMute;
538 
539         case 0x0000005c: // KEYCODE_PAGE_UP
540             return Qt::Key_PageUp;
541 
542         case 0x0000005d: // KEYCODE_PAGE_DOWN
543             return Qt::Key_PageDown;
544 
545         case 0x0000005e: // KEYCODE_PICTSYMBOLS
546             return 0;
547 
548         case 0x00000060: // KEYCODE_BUTTON_A
549         case 0x00000061: // KEYCODE_BUTTON_B
550         case 0x00000062: // KEYCODE_BUTTON_B
551         case 0x00000063: // KEYCODE_BUTTON_X
552         case 0x00000064: // KEYCODE_BUTTON_Y
553         case 0x00000065: // KEYCODE_BUTTON_Z
554         case 0x00000066: // KEYCODE_BUTTON_L1
555         case 0x00000067: // KEYCODE_BUTTON_R1
556         case 0x00000068: // KEYCODE_BUTTON_L2
557         case 0x00000069: // KEYCODE_BUTTON_R2
558         case 0x0000006a: // KEYCODE_BUTTON_THUMBL
559         case 0x0000006b: // KEYCODE_BUTTON_THUMBR
560         case 0x0000006c: // KEYCODE_BUTTON_START
561         case 0x0000006d: // KEYCODE_BUTTON_SELECT
562         case 0x0000006e: // KEYCODE_BUTTON_MODE
563             return 0;
564 
565         case 0x0000006f: // KEYCODE_ESCAPE
566             return Qt::Key_Escape;
567 
568         case 0x00000070: // KEYCODE_FORWARD_DEL
569             return Qt::Key_Delete;
570 
571         case 0x00000071: // KEYCODE_CTRL_LEFT
572         case 0x00000072: // KEYCODE_CTRL_RIGHT
573             return Qt::Key_Control;
574 
575         case 0x00000073: // KEYCODE_CAPS_LOCK
576             return Qt::Key_CapsLock;
577 
578         case 0x00000074: // KEYCODE_SCROLL_LOCK
579             return Qt::Key_ScrollLock;
580 
581         case 0x00000075: // KEYCODE_META_LEFT
582         case 0x00000076: // KEYCODE_META_RIGHT
583             return Qt::Key_Meta;
584 
585         case 0x00000077: // KEYCODE_FUNCTION
586             return 0;
587 
588         case 0x00000078: // KEYCODE_SYSRQ
589             return Qt::Key_Print;
590 
591         case 0x00000079: // KEYCODE_BREAK
592             return Qt::Key_Pause;
593 
594         case 0x0000007a: // KEYCODE_MOVE_HOME
595             return Qt::Key_Home;
596 
597         case 0x0000007b: // KEYCODE_MOVE_END
598             return Qt::Key_End;
599 
600         case 0x0000007c: // KEYCODE_MOVE_INSERT
601             return Qt::Key_Insert;
602 
603         case 0x0000007d: // KEYCODE_FORWARD
604             return Qt::Key_Forward;
605 
606         case 0x0000007e: // KEYCODE_MEDIA_PLAY
607             return Qt::Key_MediaPlay;
608 
609         case 0x0000007f: // KEYCODE_MEDIA_PAUSE
610             return Qt::Key_MediaPause;
611 
612         case 0x00000080: // KEYCODE_MEDIA_CLOSE
613         case 0x00000081: // KEYCODE_MEDIA_EJECT
614             return Qt::Key_Eject;
615 
616         case 0x00000082: // KEYCODE_MEDIA_RECORD
617             return Qt::Key_MediaRecord;
618 
619         // F1--F12     0x00000083 -- 0x0000008e
620 
621         case 0x0000008f: // KEYCODE_NUM_LOCK
622             return Qt::Key_NumLock;
623 
624         // NUMPAD_0--NUMPAD_9     0x00000090 -- 0x00000099
625 
626         case 0x0000009a: // KEYCODE_NUMPAD_DIVIDE
627             return Qt::KeypadModifier + Qt::Key_Slash;
628 
629         case 0x0000009b: // KEYCODE_NUMPAD_MULTIPLY
630             return Qt::KeypadModifier + Qt::Key_Asterisk;
631 
632         case 0x0000009c: // KEYCODE_NUMPAD_SUBTRACT
633             return Qt::KeypadModifier + Qt::Key_Minus;
634 
635         case 0x0000009d: // KEYCODE_NUMPAD_ADD
636             return Qt::KeypadModifier + Qt::Key_Plus;
637 
638         case 0x0000009e: // KEYCODE_NUMPAD_DOT
639             return Qt::KeypadModifier + Qt::Key_Period;
640 
641         case 0x0000009f: // KEYCODE_NUMPAD_COMMA
642             return Qt::KeypadModifier + Qt::Key_Comma;
643 
644         case 0x000000a0: // KEYCODE_NUMPAD_ENTER
645             return Qt::Key_Enter;
646 
647         case 0x000000a1: // KEYCODE_NUMPAD_EQUALS
648             return Qt::KeypadModifier + Qt::Key_Equal;
649 
650         case 0x000000a2: // KEYCODE_NUMPAD_LEFT_PAREN
651             return Qt::Key_ParenLeft;
652 
653         case 0x000000a3: // KEYCODE_NUMPAD_RIGHT_PAREN
654             return Qt::Key_ParenRight;
655 
656         case 0x000000a4: // KEYCODE_VOLUME_MUTE
657             return Qt::Key_VolumeMute;
658 
659         case 0x000000a5: // KEYCODE_INFO
660             return Qt::Key_Info;
661 
662         case 0x000000a6: // KEYCODE_CHANNEL_UP
663             return Qt::Key_ChannelUp;
664 
665         case 0x000000a7: // KEYCODE_CHANNEL_DOWN
666             return Qt::Key_ChannelDown;
667 
668         case 0x000000a8: // KEYCODE_ZOOM_IN
669             return Qt::Key_ZoomIn;
670 
671         case 0x000000a9: // KEYCODE_ZOOM_OUT
672             return Qt::Key_ZoomOut;
673 
674         case 0x000000aa: // KEYCODE_TV
675         case 0x000000ab: // KEYCODE_WINDOW
676             return 0;
677 
678         case 0x000000ac: // KEYCODE_GUIDE
679             return Qt::Key_Guide;
680 
681         case 0x000000ad: // KEYCODE_DVR
682             return 0;
683 
684         case 0x000000ae: // KEYCODE_BOOKMARK
685             return Qt::Key_AddFavorite;
686 
687         case 0x000000af: // KEYCODE_CAPTIONS
688             return Qt::Key_Subtitle;
689 
690         case 0x000000b0: // KEYCODE_SETTINGS
691             return Qt::Key_Settings;
692 
693         case 0x000000b1: // KEYCODE_TV_POWER
694         case 0x000000b2: // KEYCODE_TV_INPUT
695         case 0x000000b3: // KEYCODE_STB_POWER
696         case 0x000000b4: // KEYCODE_STB_INPUT
697         case 0x000000b5: // KEYCODE_AVR_POWER
698         case 0x000000b6: // KEYCODE_AVR_INPUT
699             return 0;
700 
701         case 0x000000b7: // KEYCODE_PROG_RED
702             return Qt::Key_Red;
703 
704         case 0x000000b8: // KEYCODE_PROG_GREEN
705             return Qt::Key_Green;
706 
707         case 0x000000b9: // KEYCODE_PROG_YELLOW
708             return Qt::Key_Yellow;
709 
710         case 0x000000ba: // KEYCODE_PROG_BLUE
711             return Qt::Key_Blue;
712 
713         // 0x000000bb: // KEYCODE_APP_SWITCH is not sent by the Android O.S.
714 
715         // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb
716 
717         case 0x000000cc: // KEYCODE_LANGUAGE_SWITCH
718         case 0x000000cd: // KEYCODE_MANNER_MODE do we need such a thing?
719         case 0x000000ce: // KEYCODE_3D_MODE
720         case 0x000000cf: // KEYCODE_CONTACTS
721             return 0;
722 
723         case 0x000000d0: // KEYCODE_CALENDAR
724             return Qt::Key_Calendar;
725 
726         case 0x000000d1: // KEYCODE_MUSIC
727             return Qt::Key_Music;
728 
729         case 0x000000d2: // KEYCODE_CALCULATOR
730             return Qt::Key_Calculator;
731 
732         // 0x000000d3 -- 0x000000da some japanese specific keys, someone who understand what is about should check !
733 
734         // 0x000000db: // KEYCODE_ASSIST  not delivered to applications.
735 
736         case 0x000000dc: // KEYCODE_BRIGHTNESS_DOWN
737             return Qt::Key_KeyboardBrightnessDown;
738 
739         case 0x000000dd: // KEYCODE_BRIGHTNESS_UP
740             return Qt::Key_KeyboardBrightnessUp;
741 
742         case 0x000000de: // KEYCODE_MEDIA_AUDIO_TRACK
743             return Qt::Key_AudioCycleTrack;
744 
745         default:
746             qWarning() << "Unhandled key code " << key << '!';
747             return 0;
748         }
749     }
750 
mapAndroidModifiers(jint modifiers)751     static Qt::KeyboardModifiers mapAndroidModifiers(jint modifiers)
752     {
753         Qt::KeyboardModifiers qmodifiers;
754 
755         if (modifiers & 0x00000001) // META_SHIFT_ON
756             qmodifiers |= Qt::ShiftModifier;
757 
758         if (modifiers & 0x00000002) // META_ALT_ON
759             qmodifiers |= Qt::AltModifier;
760 
761         if (modifiers & 0x00000004) // META_SYM_ON
762             qmodifiers |= Qt::MetaModifier;
763 
764         if (modifiers & 0x00001000) // META_CTRL_ON
765             qmodifiers |= Qt::ControlModifier;
766 
767         return qmodifiers;
768     }
769 
770     // maps 0 to the empty string, and anything else to a single-character string
toString(jint unicode)771     static inline QString toString(jint unicode)
772     {
773         return unicode ? QString(QChar(unicode)) : QString();
774     }
775 
keyDown(JNIEnv *,jobject,jint key,jint unicode,jint modifier,jboolean autoRepeat)776     static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat)
777     {
778         QWindowSystemInterface::handleKeyEvent(0,
779                                                QEvent::KeyPress,
780                                                mapAndroidKey(key),
781                                                mapAndroidModifiers(modifier),
782                                                toString(unicode),
783                                                autoRepeat);
784     }
785 
keyUp(JNIEnv *,jobject,jint key,jint unicode,jint modifier,jboolean autoRepeat)786     static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat)
787     {
788         QWindowSystemInterface::handleKeyEvent(0,
789                                                QEvent::KeyRelease,
790                                                mapAndroidKey(key),
791                                                mapAndroidModifiers(modifier),
792                                                toString(unicode),
793                                                autoRepeat);
794     }
795 
keyboardVisibilityChanged(JNIEnv *,jobject,jboolean visibility)796     static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility)
797     {
798         m_softwareKeyboardVisible = visibility;
799         if (!visibility)
800             m_softwareKeyboardRect = QRect();
801 
802         QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
803         if (inputContext && qGuiApp) {
804             inputContext->emitInputPanelVisibleChanged();
805             if (!visibility) {
806                 inputContext->emitKeyboardRectChanged();
807                 QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection);
808             }
809         }
810 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
811         qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
812 #endif
813     }
814 
keyboardGeometryChanged(JNIEnv *,jobject,jint x,jint y,jint w,jint h)815     static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h)
816     {
817         QRect r = QRect(x, y, w, h);
818         if (r == m_softwareKeyboardRect)
819             return;
820         m_softwareKeyboardRect = r;
821         QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
822         if (inputContext && qGuiApp)
823             inputContext->emitKeyboardRectChanged();
824 
825 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
826         qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
827 #endif
828     }
829 
handleLocationChanged(JNIEnv *,jobject,int id,int x,int y)830     static void handleLocationChanged(JNIEnv */*env*/, jobject /*thiz*/, int id, int x, int y)
831     {
832 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
833         qDebug() << "@@@ handleLocationChanged" << id << x << y;
834 #endif
835         QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
836         if (inputContext && qGuiApp)
837             QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection,
838                                       Q_ARG(int, id), Q_ARG(int, x), Q_ARG(int, y));
839 
840     }
841 
842     static JNINativeMethod methods[] = {
843         {"touchBegin","(I)V",(void*)touchBegin},
844         {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
845         {"touchEnd","(II)V",(void*)touchEnd},
846         {"mouseDown", "(III)V", (void *)mouseDown},
847         {"mouseUp", "(III)V", (void *)mouseUp},
848         {"mouseMove", "(III)V", (void *)mouseMove},
849         {"mouseWheel", "(IIIFF)V", (void *)mouseWheel},
850         {"longPress", "(III)V", (void *)longPress},
851         {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported},
852         {"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent},
853         {"keyDown", "(IIIZ)V", (void *)keyDown},
854         {"keyUp", "(IIIZ)V", (void *)keyUp},
855         {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
856         {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged},
857         {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}
858     };
859 
registerNatives(JNIEnv * env)860     bool registerNatives(JNIEnv *env)
861     {
862         jclass appClass = QtAndroid::applicationClass();
863 
864         if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
865             __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
866             return false;
867         }
868 
869         return true;
870     }
871 }
872 
873 QT_END_NAMESPACE
874