6#include <QtGui/qtguiglobal.h>
12#include <qpa/qplatformwindow.h>
13#include <qpa/qwindowsysteminterface.h>
17#include <QGuiApplication>
22Q_LOGGING_CATEGORY(lcQpaInputMethods,
"qt.qpa.input.methods");
40 void updateSelection(
int selStart,
int selEnd,
int candidatesStart,
int candidatesEnd)
42 qCDebug(lcQpaInputMethods) <<
">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
44 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
"updateSelection", selStart, selEnd,
45 candidatesStart, candidatesEnd);
51 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
52 "showSoftwareKeyboard", QtAndroidPrivate::activity(),
53 left, top, width, height, inputHints,
55 qCDebug(lcQpaInputMethods) <<
"@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
61 reg->callInterface<QtJniTypes::QtInputInterface>(
"resetSoftwareKeyboard");
62 qCDebug(lcQpaInputMethods) <<
"@@@ RESETSOFTWAREKEYBOARD";
68 reg->callInterface<QtJniTypes::QtInputInterface>(
"hideSoftwareKeyboard");
69 qCDebug(lcQpaInputMethods) <<
"@@@ HIDESOFTWAREKEYBOARD";
75 return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>(
76 "isSoftwareKeyboardVisible");
81 return m_softwareKeyboardRect;
87 return reg->callInterface<QtJniTypes::QtInputInterface, jint>(
"getSelectionHandleWidth");
93 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
94 "updateHandles", mode, editMenuPos.x(), editMenuPos.y(),
95 editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
112 const auto buttons =
static_cast<AndroidMouseButtons>(j_buttons);
113 Qt::MouseButtons mouseButtons;
114 if (buttons.testFlag(BUTTON_PRIMARY))
115 mouseButtons.setFlag(Qt::LeftButton);
117 if (buttons.testFlag(BUTTON_SECONDARY))
118 mouseButtons.setFlag(Qt::RightButton);
120 if (buttons.testFlag(BUTTON_TERTIARY))
121 mouseButtons.setFlag(Qt::MiddleButton);
123 if (buttons.testFlag(BUTTON_BACK))
124 mouseButtons.setFlag(Qt::BackButton);
126 if (buttons.testFlag(BUTTON_FORWARD))
127 mouseButtons.setFlag(Qt::ForwardButton);
129 if (buttons.testFlag(BUTTON_STYLUS_PRIMARY))
130 mouseButtons.setFlag(Qt::LeftButton);
132 if (buttons.testFlag(BUTTON_STYLUS_SECONDARY))
133 mouseButtons.setFlag(Qt::RightButton);
136 if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
137 qWarning() <<
"Unhandled button value:" << buttons <<
"Falling back to Qt::LeftButton";
138 mouseButtons = Qt::LeftButton;
144 jint mouseButtonState, QEvent::Type type)
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;
151 static_assert (
sizeof(eventButtons) <=
sizeof(uint),
"Qt::MouseButtons size changed. Adapt code.");
153 if (eventButtons == Qt::NoButton) {
154 QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, qtButtons, Qt::NoButton, type);
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);
166 static void mouseDown(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
171 const QPoint localPos(x,y);
172 QWindow *window = windowFromId(winId);
174 const QPoint globalPos = window && window->handle() ?
175 window->handle()->mapToGlobal(localPos) : localPos;
176 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonPress);
179 static void mouseUp(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
181 const QPoint localPos(x,y);
182 QWindow *window = m_mouseGrabber.data();
184 window = windowFromId(winId);
186 const QPoint globalPos = window && window->handle() ?
187 window->handle()->mapToGlobal(localPos) : localPos;
189 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonRelease);
194 static void mouseMove(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
199 const QPoint localPos(x,y);
200 QWindow *window = m_mouseGrabber.data();
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);
208 static void mouseWheel(JNIEnv *,
jobject , jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta)
213 const QPoint localPos(x,y);
214 QWindow *window = m_mouseGrabber.data();
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);
221 QWindowSystemInterface::handleWheelEvent(window,
232 const QPoint globalPos(x,y);
233 QWindow *window = windowFromId(winId);
234 const QPoint localPos = window && window->handle() ?
235 window->handle()->mapFromGlobal(globalPos) : globalPos;
237 if (inputContext && qGuiApp)
238 QMetaObject::invokeMethod(inputContext,
"longPress", Q_ARG(
int, globalPos.x()), Q_ARG(
int, globalPos.y()));
241 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue(
"QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
242 if (!rightMouseFromLongPress)
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);
264 jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
266 QEventPoint::State state = QEventPoint::State::Stationary;
269 state = QEventPoint::State::Pressed;
272 state = QEventPoint::State::Updated;
275 state = QEventPoint::State::Stationary;
278 state = QEventPoint::State::Released;
285 availableSize = platformIntegration
->screen()->availableGeometry().size();
291 qCWarning(lcQpaInputMethods,
"Touch event received for non-existing window %d", winId);
295 QPointF mappedTouchPoint;
296 if (window->handle())
297 mappedTouchPoint = window->handle()->mapToGlobalF(QPointF(x, y));
299 mappedTouchPoint = window->mapToGlobal(QPointF(x, y));
301 QWindowSystemInterface::TouchPoint touchPoint;
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),
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()));
325 if (!platformIntegration)
328 QPointingDevice *touchDevice = platformIntegration->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,
338 QWindowSystemInterface::registerInputDevice(touchDevice);
339 platformIntegration->setTouchDevice(touchDevice);
351 const QPointingDevice *touchDevice = getTouchDevice();
358 QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
367 const QPointingDevice *touchDevice = getTouchDevice();
374 QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice);
379#if QT_CONFIG(tabletevent)
387 jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
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;
410 Qt::MouseButtons buttons = Qt::NoButton;
415 buttons = Qt::NoButton;
418 if (buttonState == 0)
419 buttons = Qt::LeftButton;
421 buttons = Qt::MouseButtons(buttonState);
425 qCDebug(lcQpaInputMethods) << action << pointerType << buttonState <<
'@' << x << y <<
"pressure" << pressure <<
": buttons" << buttons;
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);
436 if (key >= 0x00000007 && key <= 0x00000010)
437 return QKeyCombination::fromCombined(Qt::Key_0 + key - 0x00000007);
440 if (key >= 0x0000001d && key <= 0x00000036)
441 return QKeyCombination::fromCombined(Qt::Key_A + key - 0x0000001d);
444 if (key >= 0x00000083 && key <= 0x0000008e)
445 return QKeyCombination::fromCombined(Qt::Key_F1 + key - 0x00000083);
448 if (key >= 0x00000090 && key <= 0x00000099)
449 return QKeyCombination::fromCombined(Qt::KeypadModifier | Qt::Key_0 + key - 0x00000090);
455 return Qt::Key_unknown;
461 return Qt::Key_Right;
472 return Qt::Key_Hangup;
477 return Qt::Key_Asterisk;
480 return Qt::Key_NumberSign;
492 return Qt::Key_Right;
495 return Qt::Key_Enter;
498 return Qt::Key_VolumeUp;
501 return Qt::Key_VolumeDown;
504 return Qt::Key_PowerOff;
507 return Qt::Key_Camera;
510 return Qt::Key_Clear;
515 return Qt::Key_Comma;
518 return Qt::Key_Period;
526 return Qt::Key_Shift;
532 return Qt::Key_Space;
538 return Qt::Key_Explorer;
541 return Qt::Key_LaunchMail;
544 return Qt::Key_Return;
547 return Qt::Key_Backspace;
550 return Qt::Key_QuoteLeft;
553 return Qt::Key_Minus;
556 return Qt::Key_Equal;
559 return Qt::Key_BracketLeft;
562 return Qt::Key_BracketRight;
565 return Qt::Key_Backslash;
568 return Qt::Key_Semicolon;
571 return Qt::Key_Apostrophe;
574 return Qt::Key_Slash;
583 return QKeyCombination::fromCombined(0);
586 return Qt::Key_CameraFocus;
595 return QKeyCombination::fromCombined(0);
598 return Qt::Key_Search;
601 return Qt::Key_MediaTogglePlayPause;
604 return Qt::Key_MediaStop;
607 return Qt::Key_MediaNext;
610 return Qt::Key_MediaPrevious;
613 return Qt::Key_AudioRewind;
616 return Qt::Key_AudioForward;
619 return Qt::Key_MicMute;
622 return Qt::Key_PageUp;
625 return Qt::Key_PageDown;
628 return QKeyCombination::fromCombined(0);
645 return QKeyCombination::fromCombined(0);
648 return Qt::Key_Escape;
651 return Qt::Key_Delete;
655 return Qt::Key_Control;
658 return Qt::Key_CapsLock;
661 return Qt::Key_ScrollLock;
668 return QKeyCombination::fromCombined(0);
671 return Qt::Key_Print;
674 return Qt::Key_Pause;
683 return Qt::Key_Insert;
686 return Qt::Key_Forward;
689 return Qt::Key_MediaPlay;
692 return Qt::Key_MediaPause;
696 return Qt::Key_Eject;
699 return Qt::Key_MediaRecord;
704 return Qt::Key_NumLock;
709 return Qt::KeypadModifier | Qt::Key_Slash;
712 return Qt::KeypadModifier | Qt::Key_Asterisk;
715 return Qt::KeypadModifier | Qt::Key_Minus;
718 return Qt::KeypadModifier | Qt::Key_Plus;
721 return Qt::KeypadModifier | Qt::Key_Period;
724 return Qt::KeypadModifier | Qt::Key_Comma;
727 return Qt::Key_Enter;
730 return Qt::KeypadModifier | Qt::Key_Equal;
733 return Qt::Key_ParenLeft;
736 return Qt::Key_ParenRight;
739 return Qt::Key_VolumeMute;
745 return Qt::Key_ChannelUp;
748 return Qt::Key_ChannelDown;
751 return Qt::Key_ZoomIn;
754 return Qt::Key_ZoomOut;
758 return QKeyCombination::fromCombined(0);
761 return Qt::Key_Guide;
764 return QKeyCombination::fromCombined(0);
767 return Qt::Key_AddFavorite;
770 return Qt::Key_Subtitle;
773 return Qt::Key_Settings;
781 return QKeyCombination::fromCombined(0);
787 return Qt::Key_Green;
790 return Qt::Key_Yellow;
803 return QKeyCombination::fromCombined(0);
806 return Qt::Key_Calendar;
809 return Qt::Key_Music;
812 return Qt::Key_Calculator;
819 return Qt::Key_KeyboardBrightnessDown;
822 return Qt::Key_KeyboardBrightnessUp;
825 return Qt::Key_AudioCycleTrack;
828 qWarning() <<
"Unhandled key code " << key <<
'!';
829 return QKeyCombination::fromCombined(0);
835 Qt::KeyboardModifiers qmodifiers;
837 if (modifiers & 0x00000001)
838 qmodifiers |= Qt::ShiftModifier;
840 if (modifiers & 0x00000002)
841 qmodifiers |= Qt::AltModifier;
843 if (modifiers & 0x00000004)
844 qmodifiers |= Qt::MetaModifier;
846 if (modifiers & 0x00001000)
847 qmodifiers |= Qt::ControlModifier;
855 return unicode ? QString(QChar(unicode)) : QString();
858 static void keyDown(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
860 QWindowSystemInterface::handleKeyEvent(0,
862 mapAndroidKey(key).toCombined(),
863 mapAndroidModifiers(modifier),
868 static void keyUp(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
870 QWindowSystemInterface::handleKeyEvent(0,
872 mapAndroidKey(key).toCombined(),
873 mapAndroidModifiers(modifier),
884 if (inputContext && qGuiApp) {
885 inputContext->emitInputPanelVisibleChanged();
887 inputContext->emitKeyboardRectChanged();
888 QMetaObject::invokeMethod(inputContext,
"hideSelectionHandles", Qt::QueuedConnection);
891 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
896 QRect r = QRect(x, y, w, h);
897 if (r == m_softwareKeyboardRect)
901 if (inputContext && qGuiApp)
902 inputContext->emitKeyboardRectChanged();
904 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
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));
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},
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");
static QAndroidInputContext * androidInputContext()
\inmodule QtCore\reentrant
QBasicMutex * platformInterfaceMutex()
QAndroidPlatformIntegration * androidPlatformIntegration()
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")