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