7#include <QtGui/qtguiglobal.h>
14#include <qpa/qplatformwindow.h>
15#include <qpa/qwindowsysteminterface.h>
16#include <QtGui/private/qpointingdevice_p.h>
20#include <QGuiApplication>
26Q_LOGGING_CATEGORY(lcQpaInputMethods,
"qt.qpa.input.methods");
46 void updateSelection(
int selStart,
int selEnd,
int candidatesStart,
int candidatesEnd)
48 qCDebug(lcQpaInputMethods) <<
">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
50 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
"updateSelection", selStart, selEnd,
51 candidatesStart, candidatesEnd);
57 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
58 "showSoftwareKeyboard", QtAndroidPrivate::activity(),
59 left, top, width, height, inputHints,
61 qCDebug(lcQpaInputMethods) <<
"@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
67 reg->callInterface<QtJniTypes::QtInputInterface>(
"resetSoftwareKeyboard");
68 qCDebug(lcQpaInputMethods) <<
"@@@ RESETSOFTWAREKEYBOARD";
74 reg->callInterface<QtJniTypes::QtInputInterface>(
"hideSoftwareKeyboard");
75 qCDebug(lcQpaInputMethods) <<
"@@@ HIDESOFTWAREKEYBOARD";
81 return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>(
82 "isSoftwareKeyboardVisible");
87 return m_softwareKeyboardRect;
93 return reg->callInterface<QtJniTypes::QtInputInterface, jint>(
"getSelectionHandleWidth");
99 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
100 "updateHandles", mode, editMenuPos.x(), editMenuPos.y(),
101 editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
118 const auto buttons =
static_cast<AndroidMouseButtons>(j_buttons);
119 Qt::MouseButtons mouseButtons;
121 mouseButtons.setFlag(Qt::LeftButton);
124 mouseButtons.setFlag(Qt::RightButton);
127 mouseButtons.setFlag(Qt::MiddleButton);
130 mouseButtons.setFlag(Qt::BackButton);
133 mouseButtons.setFlag(Qt::ForwardButton);
136 mouseButtons.setFlag(Qt::LeftButton);
139 mouseButtons.setFlag(Qt::RightButton);
142 if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
143 qWarning() <<
"Unhandled button value:" << buttons <<
"Falling back to Qt::LeftButton";
144 mouseButtons = Qt::LeftButton;
151 Qt::KeyboardModifiers qmodifiers;
153 if (modifiers & 0x00000001)
154 qmodifiers |= Qt::ShiftModifier;
156 if (modifiers & 0x00000002)
157 qmodifiers |= Qt::AltModifier;
159 if (modifiers & 0x00000004)
160 qmodifiers |= Qt::MetaModifier;
162 if (modifiers & 0x00001000)
163 qmodifiers |= Qt::ControlModifier;
165 if (modifiers & 0x00010000)
166 qmodifiers |= Qt::MetaModifier;
172 jint mouseButtonState, jint metaState, QEvent::Type type)
174 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
175 const bool mouseReleased = type == QEvent::MouseButtonRelease && qtButtons == Qt::NoButton;
176 const Qt::MouseButtons eventButtons = mouseReleased ? m_lastSeenButtons : qtButtons;
179 static_assert (
sizeof(eventButtons) <=
sizeof(uint),
"Qt::MouseButtons size changed. Adapt code.");
181 if (eventButtons == Qt::NoButton)
184 const Qt::KeyboardModifiers modifiers = mapAndroidModifiers(metaState);
185 for (uint buttonInt = 0x1;
static_cast<uint>(eventButtons) >= buttonInt; buttonInt <<= 1) {
186 const auto button =
static_cast<Qt::MouseButton>(buttonInt);
187 if (eventButtons.testFlag(button)) {
188 QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
189 qtButtons, button, type, modifiers);
195 jint mouseButtonState, jint metaState)
200 const QPoint localPos(x,y);
201 QWindow *window = windowFromId(winId);
203 const QPoint globalPos = window && window->handle() ?
204 window->handle()->mapToGlobal(localPos) : localPos;
205 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, metaState,
206 QEvent::MouseButtonPress);
210 jint mouseButtonState, jint metaState)
212 const QPoint localPos(x,y);
213 QWindow *window = m_mouseGrabber.data();
215 window = windowFromId(winId);
217 const QPoint globalPos = window && window->handle() ?
218 window->handle()->mapToGlobal(localPos) : localPos;
220 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, metaState,
221 QEvent::MouseButtonRelease);
227 jint mouseButtonState, jint metaState)
232 const QPoint localPos(x,y);
233 QWindow *window = m_mouseGrabber.data();
235 window = windowFromId(winId);
236 const QPoint globalPos = window && window->handle() ?
237 window->handle()->mapToGlobal(localPos) : localPos;
238 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
240 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
241 qtButtons, Qt::NoButton, QEvent::MouseMove,
242 mapAndroidModifiers(metaState));
246 jfloat hdelta, jfloat vdelta, jint metaState)
251 const QPoint localPos(x,y);
252 QWindow *window = m_mouseGrabber.data();
254 window = windowFromId(winId);
255 const QPoint globalPos = window && window->handle() ?
256 window->handle()->mapToGlobal(localPos) : localPos;
257 const QPoint angleDelta(hdelta * 120, vdelta * 120);
259 QWindowSystemInterface::handleWheelEvent(window,
264 mapAndroidModifiers(metaState));
272 const QPoint localPos(x,y);
273 QWindow *window = windowFromId(winId);
274 const QPoint globalPos = window && window->handle() ?
275 window->handle()->mapToGlobal(localPos) : localPos;
277 if (inputContext && qGuiApp)
278 QMetaObject::invokeMethod(inputContext,
"longPress", Q_ARG(
int, globalPos.x()), Q_ARG(
int, globalPos.y()));
281 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue(
"QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
282 if (!rightMouseFromLongPress)
288 if (!m_mouseGrabber) {
289 const Qt::KeyboardModifiers modifiers = mapAndroidModifiers(metaState);
290 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
291 Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
292 QEvent::MouseButtonPress, modifiers);
293 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
294 Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
295 QEvent::MouseButtonRelease, modifiers);
305 jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
307 QEventPoint::State state = QEventPoint::State::Stationary;
310 state = QEventPoint::State::Pressed;
313 state = QEventPoint::State::Updated;
316 state = QEventPoint::State::Stationary;
319 state = QEventPoint::State::Released;
326 qCWarning(lcQpaInputMethods,
"Touch event received for non-existing window %d", winId);
330 QPointF mappedTouchPoint;
331 if (window->handle())
332 mappedTouchPoint = window->handle()->mapToGlobalF(QPointF(x, y));
334 mappedTouchPoint = window->mapToGlobal(QPointF(x, y));
336 QWindowSystemInterface::TouchPoint touchPoint;
338 touchPoint.id = id + 1;
339 touchPoint.pressure = pressure;
340 touchPoint.rotation = qRadiansToDegrees(rotation);
341 touchPoint.state = state;
342 touchPoint.area = QRectF(mappedTouchPoint.x() -
double(minor * 0.5f),
343 mappedTouchPoint.y() -
double(major * 0.5f),
348 if (state == QEventPoint::State::Pressed) {
350 if (inputContext && qGuiApp)
351 QMetaObject::invokeMethod(inputContext,
"touchDown", Q_ARG(
int, mappedTouchPoint.x()), Q_ARG(
int, mappedTouchPoint.y()));
358 if (!platformIntegration)
361 QPointingDevice *touchDevice = platformIntegration->touchDevice();
363 touchDevice =
new QPointingDevice(
"Android touchscreen", 1,
364 QInputDevice::DeviceType::TouchScreen,
365 QPointingDevice::PointerType::Finger,
366 QPointingDevice::Capability::Position
367 | QPointingDevice::Capability::Area
368 | QPointingDevice::Capability::Pressure,
370 QWindowSystemInterface::registerInputDevice(touchDevice);
371 platformIntegration->setTouchDevice(touchDevice);
374 QPointingDevicePrivate::get(touchDevice)->setAvailableVirtualGeometry(
375 platformIntegration->screen()->availableGeometry());
387 const QPointingDevice *touchDevice = getTouchDevice();
394 QWindowSystemInterface::handleTouchEvent(window, touchDevice,
395 m_touchPoints, mapAndroidModifiers(metaState));
404 const QPointingDevice *touchDevice = getTouchDevice();
411 QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice,
412 mapAndroidModifiers(metaState));
417#if QT_CONFIG(tabletevent)
425 jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure, jint metaState)
427#if QT_CONFIG(tabletevent)
428 const QPointF localPos(x, y);
429 QWindow *window = windowFromId(winId);
430 const QPointF globalPosF = window && window->handle() ?
431 window->handle()->mapFromGlobalF(localPos) : localPos;
448 Qt::MouseButtons buttons = Qt::NoButton;
453 buttons = Qt::NoButton;
456 if (buttonState == 0)
457 buttons = Qt::LeftButton;
459 buttons = Qt::MouseButtons(buttonState);
463 qCDebug(lcQpaInputMethods) << action << pointerType << buttonState <<
'@' << x << y <<
"pressure" << pressure <<
": buttons" << buttons;
465 QWindowSystemInterface::handleTabletEvent(window, ulong(time),
466 localPos, globalPosF,
int(QInputDevice::DeviceType::Stylus), pointerType,
467 buttons, pressure, 0, 0, 0., 0., 0, deviceId, mapAndroidModifiers(metaState));
474 if (key >= 0x00000007 && key <= 0x00000010)
475 return QKeyCombination::fromCombined(Qt::Key_0 + key - 0x00000007);
478 if (key >= 0x0000001d && key <= 0x00000036)
479 return QKeyCombination::fromCombined(Qt::Key_A + key - 0x0000001d);
482 if (key >= 0x00000083 && key <= 0x0000008e)
483 return QKeyCombination::fromCombined(Qt::Key_F1 + key - 0x00000083);
486 if (key >= 0x00000090 && key <= 0x00000099)
487 return QKeyCombination::fromCombined(Qt::KeypadModifier | Qt::Key_0 + key - 0x00000090);
493 return Qt::Key_unknown;
499 return Qt::Key_Right;
510 return Qt::Key_Hangup;
515 return Qt::Key_Asterisk;
518 return Qt::Key_NumberSign;
530 return Qt::Key_Right;
533 return Qt::Key_Enter;
536 return Qt::Key_VolumeUp;
539 return Qt::Key_VolumeDown;
542 return Qt::Key_PowerOff;
545 return Qt::Key_Camera;
548 return Qt::Key_Clear;
553 return Qt::Key_Comma;
556 return Qt::Key_Period;
564 return Qt::Key_Shift;
570 return Qt::Key_Space;
576 return Qt::Key_Explorer;
579 return Qt::Key_LaunchMail;
582 return Qt::Key_Return;
585 return Qt::Key_Backspace;
588 return Qt::Key_QuoteLeft;
591 return Qt::Key_Minus;
594 return Qt::Key_Equal;
597 return Qt::Key_BracketLeft;
600 return Qt::Key_BracketRight;
603 return Qt::Key_Backslash;
606 return Qt::Key_Semicolon;
609 return Qt::Key_Apostrophe;
612 return Qt::Key_Slash;
621 return QKeyCombination::fromCombined(0);
624 return Qt::Key_CameraFocus;
633 return QKeyCombination::fromCombined(0);
636 return Qt::Key_Search;
639 return Qt::Key_MediaTogglePlayPause;
642 return Qt::Key_MediaStop;
645 return Qt::Key_MediaNext;
648 return Qt::Key_MediaPrevious;
651 return Qt::Key_AudioRewind;
654 return Qt::Key_AudioForward;
657 return Qt::Key_MicMute;
660 return Qt::Key_PageUp;
663 return Qt::Key_PageDown;
666 return QKeyCombination::fromCombined(0);
683 return QKeyCombination::fromCombined(0);
686 return Qt::Key_Escape;
689 return Qt::Key_Delete;
693 return Qt::Key_Control;
696 return Qt::Key_CapsLock;
699 return Qt::Key_ScrollLock;
706 return QKeyCombination::fromCombined(0);
709 return Qt::Key_Print;
712 return Qt::Key_Pause;
721 return Qt::Key_Insert;
724 return Qt::Key_Forward;
727 return Qt::Key_MediaPlay;
730 return Qt::Key_MediaPause;
734 return Qt::Key_Eject;
737 return Qt::Key_MediaRecord;
742 return Qt::Key_NumLock;
747 return Qt::KeypadModifier | Qt::Key_Slash;
750 return Qt::KeypadModifier | Qt::Key_Asterisk;
753 return Qt::KeypadModifier | Qt::Key_Minus;
756 return Qt::KeypadModifier | Qt::Key_Plus;
759 return Qt::KeypadModifier | Qt::Key_Period;
762 return Qt::KeypadModifier | Qt::Key_Comma;
765 return Qt::Key_Enter;
768 return Qt::KeypadModifier | Qt::Key_Equal;
771 return Qt::Key_ParenLeft;
774 return Qt::Key_ParenRight;
777 return Qt::Key_VolumeMute;
783 return Qt::Key_ChannelUp;
786 return Qt::Key_ChannelDown;
789 return Qt::Key_ZoomIn;
792 return Qt::Key_ZoomOut;
796 return QKeyCombination::fromCombined(0);
799 return Qt::Key_Guide;
802 return QKeyCombination::fromCombined(0);
805 return Qt::Key_AddFavorite;
808 return Qt::Key_Subtitle;
811 return Qt::Key_Settings;
819 return QKeyCombination::fromCombined(0);
825 return Qt::Key_Green;
828 return Qt::Key_Yellow;
841 return QKeyCombination::fromCombined(0);
844 return Qt::Key_Calendar;
847 return Qt::Key_Music;
850 return Qt::Key_Calculator;
857 return Qt::Key_KeyboardBrightnessDown;
860 return Qt::Key_KeyboardBrightnessUp;
863 return Qt::Key_AudioCycleTrack;
866 qWarning() <<
"Unhandled key code " << key <<
'!';
867 return QKeyCombination::fromCombined(0);
874 return unicode ? QString(QChar(unicode)) : QString();
891 qWarning(
"Failed to deliver Android key event on the GUI thread");
896 static void keyDown(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
898 const int qtKeyCombination = mapAndroidKey(key).toCombined();
899 const auto qtModifiers = mapAndroidModifiers(modifier);
900 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
901 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
902 const auto text = toString(unicode);
904 bool accepted =
false;
905 if (isBackKey || isMenuKey) {
907 qtModifiers, text, autoRepeat);
909 QWindowSystemInterface::handleKeyEvent(
910 nullptr, QEvent::KeyPress, qtKeyCombination, qtModifiers, text, autoRepeat);
917 auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
918 iface->runOnAndroidMainThread([iface]() {
919 if (!iface->isActivityContext())
921 iface->context().callMethod<jboolean>(
"moveTaskToBack",
true);
925 static void keyUp(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
927 const int qtKeyCombination = mapAndroidKey(key).toCombined();
928 const auto qtModifiers = mapAndroidModifiers(modifier);
929 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
930 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
931 const auto text = toString(unicode);
933 if (!isBackKey && !isMenuKey) {
934 QWindowSystemInterface::handleKeyEvent(
935 nullptr, QEvent::KeyRelease, qtKeyCombination, qtModifiers, text, autoRepeat);
940 qtModifiers, text, autoRepeat);
954 if (inputContext && qGuiApp) {
955 inputContext->emitInputPanelVisibleChanged();
957 inputContext->emitKeyboardRectChanged();
958 QMetaObject::invokeMethod(inputContext,
"hideSelectionHandles", Qt::QueuedConnection);
961 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
966 QRect r = QRect(x, y, w, h);
967 if (r == m_softwareKeyboardRect)
971 if (inputContext && qGuiApp)
972 inputContext->emitKeyboardRectChanged();
974 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
979 qCDebug(lcQpaInputMethods) <<
"@@@ handleLocationChanged" << id << x << y;
982 if (inputContext && qGuiApp)
983 QMetaObject::invokeMethod(inputContext,
"handleLocationChanged", Qt::QueuedConnection,
984 Q_ARG(
int, id), Q_ARG(
int, x), Q_ARG(
int, y));
990 {
"touchBegin",
"(I)V",(
void*)touchBegin},
991 {
"touchAdd",
"(IIIZIIFFFF)V",(
void*)touchAdd},
992 {
"touchEnd",
"(III)V",(
void*)touchEnd},
993 {
"touchCancel",
"(II)V", (
void *)touchCancel},
994 {
"mouseDown",
"(IIIII)V", (
void *)mouseDown},
995 {
"mouseUp",
"(IIIII)V", (
void *)mouseUp},
996 {
"mouseMove",
"(IIIII)V", (
void *)mouseMove},
997 {
"mouseWheel",
"(IIIFFI)V", (
void *)mouseWheel},
998 {
"longPress",
"(IIII)V", (
void *)longPress},
999 {
"isTabletEventSupported",
"()Z", (
void *)isTabletEventSupported},
1000 {
"tabletEvent",
"(IIJIIIFFFI)V", (
void *)tabletEvent},
1001 {
"keyDown",
"(IIIZ)V", (
void *)keyDown},
1002 {
"keyUp",
"(IIIZ)V", (
void *)keyUp},
1003 {
"keyboardVisibilityChanged",
"(Z)V", (
void *)keyboardVisibilityChanged},
1004 {
"keyboardGeometryChanged",
"(IIII)V", (
void *)keyboardGeometryChanged},
1005 {
"handleLocationChanged",
"(III)V", (
void *)handleLocationChanged},
1010 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtInputDelegate>::className(),
1012 __android_log_print(ANDROID_LOG_FATAL,
"Qt",
"RegisterNatives failed");
static QAndroidInputContext * androidInputContext()
\inmodule QtCore\reentrant
Combined button and popup list for selecting options.
QBasicMutex * platformInterfaceMutex()
QAndroidPlatformIntegration * androidPlatformIntegration()
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")