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