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>
25Q_LOGGING_CATEGORY(lcQpaInputMethods,
"qt.qpa.input.methods");
45 void updateSelection(
int selStart,
int selEnd,
int candidatesStart,
int candidatesEnd)
47 qCDebug(lcQpaInputMethods) <<
">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
49 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
"updateSelection", selStart, selEnd,
50 candidatesStart, candidatesEnd);
56 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
57 "showSoftwareKeyboard", QtAndroidPrivate::activity(),
58 left, top, width, height, inputHints,
60 qCDebug(lcQpaInputMethods) <<
"@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
66 reg->callInterface<QtJniTypes::QtInputInterface>(
"resetSoftwareKeyboard");
67 qCDebug(lcQpaInputMethods) <<
"@@@ RESETSOFTWAREKEYBOARD";
73 reg->callInterface<QtJniTypes::QtInputInterface>(
"hideSoftwareKeyboard");
74 qCDebug(lcQpaInputMethods) <<
"@@@ HIDESOFTWAREKEYBOARD";
80 return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>(
81 "isSoftwareKeyboardVisible");
86 return m_softwareKeyboardRect;
92 return reg->callInterface<QtJniTypes::QtInputInterface, jint>(
"getSelectionHandleWidth");
98 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
99 "updateHandles", mode, editMenuPos.x(), editMenuPos.y(),
100 editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
117 const auto buttons =
static_cast<AndroidMouseButtons>(j_buttons);
118 Qt::MouseButtons mouseButtons;
120 mouseButtons.setFlag(Qt::LeftButton);
123 mouseButtons.setFlag(Qt::RightButton);
126 mouseButtons.setFlag(Qt::MiddleButton);
129 mouseButtons.setFlag(Qt::BackButton);
132 mouseButtons.setFlag(Qt::ForwardButton);
135 mouseButtons.setFlag(Qt::LeftButton);
138 mouseButtons.setFlag(Qt::RightButton);
141 if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
142 qWarning() <<
"Unhandled button value:" << buttons <<
"Falling back to Qt::LeftButton";
143 mouseButtons = Qt::LeftButton;
150 Qt::KeyboardModifiers qmodifiers;
152 if (modifiers & 0x00000001)
153 qmodifiers |= Qt::ShiftModifier;
155 if (modifiers & 0x00000002)
156 qmodifiers |= Qt::AltModifier;
158 if (modifiers & 0x00000004)
159 qmodifiers |= Qt::MetaModifier;
161 if (modifiers & 0x00001000)
162 qmodifiers |= Qt::ControlModifier;
164 if (modifiers & 0x00010000)
165 qmodifiers |= Qt::MetaModifier;
171 jint mouseButtonState, jint metaState, QEvent::Type type)
173 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
174 const bool mouseReleased = type == QEvent::MouseButtonRelease && qtButtons == Qt::NoButton;
175 const Qt::MouseButtons eventButtons = mouseReleased ? m_lastSeenButtons : qtButtons;
178 static_assert (
sizeof(eventButtons) <=
sizeof(uint),
"Qt::MouseButtons size changed. Adapt code.");
180 if (eventButtons == Qt::NoButton)
183 const Qt::KeyboardModifiers modifiers = mapAndroidModifiers(metaState);
184 for (uint buttonInt = 0x1;
static_cast<uint>(eventButtons) >= buttonInt; buttonInt <<= 1) {
185 const auto button =
static_cast<Qt::MouseButton>(buttonInt);
186 if (eventButtons.testFlag(button)) {
187 QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
188 qtButtons, button, type, modifiers);
194 jint mouseButtonState, jint metaState)
199 const QPoint localPos(x,y);
200 QWindow *window = windowFromId(winId);
202 const QPoint globalPos = window && window->handle() ?
203 window->handle()->mapToGlobal(localPos) : localPos;
204 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, metaState,
205 QEvent::MouseButtonPress);
209 jint mouseButtonState, jint metaState)
211 const QPoint localPos(x,y);
212 QWindow *window = m_mouseGrabber.data();
214 window = windowFromId(winId);
216 const QPoint globalPos = window && window->handle() ?
217 window->handle()->mapToGlobal(localPos) : localPos;
219 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, metaState,
220 QEvent::MouseButtonRelease);
226 jint mouseButtonState, jint metaState)
231 const QPoint localPos(x,y);
232 QWindow *window = m_mouseGrabber.data();
234 window = windowFromId(winId);
235 const QPoint globalPos = window && window->handle() ?
236 window->handle()->mapToGlobal(localPos) : localPos;
237 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
239 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
240 qtButtons, Qt::NoButton, QEvent::MouseMove,
241 mapAndroidModifiers(metaState));
245 jfloat hdelta, jfloat vdelta, jint metaState)
250 const QPoint localPos(x,y);
251 QWindow *window = m_mouseGrabber.data();
253 window = windowFromId(winId);
254 const QPoint globalPos = window && window->handle() ?
255 window->handle()->mapToGlobal(localPos) : localPos;
256 const QPoint angleDelta(hdelta * 120, vdelta * 120);
258 QWindowSystemInterface::handleWheelEvent(window,
263 mapAndroidModifiers(metaState));
271 const QPoint localPos(x,y);
272 QWindow *window = windowFromId(winId);
273 const QPoint globalPos = window && window->handle() ?
274 window->handle()->mapToGlobal(localPos) : localPos;
276 if (inputContext && qGuiApp)
277 QMetaObject::invokeMethod(inputContext,
"longPress", Q_ARG(
int, globalPos.x()), Q_ARG(
int, globalPos.y()));
280 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue(
"QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
281 if (!rightMouseFromLongPress)
287 if (!m_mouseGrabber) {
288 const Qt::KeyboardModifiers modifiers = mapAndroidModifiers(metaState);
289 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
290 Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
291 QEvent::MouseButtonPress, modifiers);
292 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
293 Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
294 QEvent::MouseButtonRelease, modifiers);
304 jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
306 QEventPoint::State state = QEventPoint::State::Stationary;
309 state = QEventPoint::State::Pressed;
312 state = QEventPoint::State::Updated;
315 state = QEventPoint::State::Stationary;
318 state = QEventPoint::State::Released;
325 qCWarning(lcQpaInputMethods,
"Touch event received for non-existing window %d", winId);
329 QPointF mappedTouchPoint;
330 if (window->handle())
331 mappedTouchPoint = window->handle()->mapToGlobalF(QPointF(x, y));
333 mappedTouchPoint = window->mapToGlobal(QPointF(x, y));
335 QWindowSystemInterface::TouchPoint touchPoint;
337 touchPoint.id = id + 1;
338 touchPoint.pressure = pressure;
339 touchPoint.rotation = qRadiansToDegrees(rotation);
340 touchPoint.state = state;
341 touchPoint.area = QRectF(mappedTouchPoint.x() -
double(minor * 0.5f),
342 mappedTouchPoint.y() -
double(major * 0.5f),
347 if (state == QEventPoint::State::Pressed) {
349 if (inputContext && qGuiApp)
350 QMetaObject::invokeMethod(inputContext,
"touchDown", Q_ARG(
int, mappedTouchPoint.x()), Q_ARG(
int, mappedTouchPoint.y()));
357 if (!platformIntegration)
360 QPointingDevice *touchDevice = platformIntegration->touchDevice();
362 touchDevice =
new QPointingDevice(
"Android touchscreen", 1,
363 QInputDevice::DeviceType::TouchScreen,
364 QPointingDevice::PointerType::Finger,
365 QPointingDevice::Capability::Position
366 | QPointingDevice::Capability::Area
367 | QPointingDevice::Capability::Pressure,
369 QWindowSystemInterface::registerInputDevice(touchDevice);
370 platformIntegration->setTouchDevice(touchDevice);
373 QPointingDevicePrivate::get(touchDevice)->setAvailableVirtualGeometry(
374 platformIntegration->screen()->availableGeometry());
386 const QPointingDevice *touchDevice = getTouchDevice();
393 QWindowSystemInterface::handleTouchEvent(window, touchDevice,
394 m_touchPoints, mapAndroidModifiers(metaState));
403 const QPointingDevice *touchDevice = getTouchDevice();
410 QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice,
411 mapAndroidModifiers(metaState));
416#if QT_CONFIG(tabletevent)
424 jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure, jint metaState)
426#if QT_CONFIG(tabletevent)
427 const QPointF localPos(x, y);
428 QWindow *window = windowFromId(winId);
429 const QPointF globalPosF = window && window->handle() ?
430 window->handle()->mapFromGlobalF(localPos) : localPos;
447 Qt::MouseButtons buttons = Qt::NoButton;
452 buttons = Qt::NoButton;
455 if (buttonState == 0)
456 buttons = Qt::LeftButton;
458 buttons = Qt::MouseButtons(buttonState);
462 qCDebug(lcQpaInputMethods) << action << pointerType << buttonState <<
'@' << x << y <<
"pressure" << pressure <<
": buttons" << buttons;
464 QWindowSystemInterface::handleTabletEvent(window, ulong(time),
465 localPos, globalPosF,
int(QInputDevice::DeviceType::Stylus), pointerType,
466 buttons, pressure, 0, 0, 0., 0., 0, deviceId, mapAndroidModifiers(metaState));
473 if (key >= 0x00000007 && key <= 0x00000010)
474 return QKeyCombination::fromCombined(Qt::Key_0 + key - 0x00000007);
477 if (key >= 0x0000001d && key <= 0x00000036)
478 return QKeyCombination::fromCombined(Qt::Key_A + key - 0x0000001d);
481 if (key >= 0x00000083 && key <= 0x0000008e)
482 return QKeyCombination::fromCombined(Qt::Key_F1 + key - 0x00000083);
485 if (key >= 0x00000090 && key <= 0x00000099)
486 return QKeyCombination::fromCombined(Qt::KeypadModifier | Qt::Key_0 + key - 0x00000090);
492 return Qt::Key_unknown;
498 return Qt::Key_Right;
509 return Qt::Key_Hangup;
514 return Qt::Key_Asterisk;
517 return Qt::Key_NumberSign;
529 return Qt::Key_Right;
532 return Qt::Key_Enter;
535 return Qt::Key_VolumeUp;
538 return Qt::Key_VolumeDown;
541 return Qt::Key_PowerOff;
544 return Qt::Key_Camera;
547 return Qt::Key_Clear;
552 return Qt::Key_Comma;
555 return Qt::Key_Period;
563 return Qt::Key_Shift;
569 return Qt::Key_Space;
575 return Qt::Key_Explorer;
578 return Qt::Key_LaunchMail;
581 return Qt::Key_Return;
584 return Qt::Key_Backspace;
587 return Qt::Key_QuoteLeft;
590 return Qt::Key_Minus;
593 return Qt::Key_Equal;
596 return Qt::Key_BracketLeft;
599 return Qt::Key_BracketRight;
602 return Qt::Key_Backslash;
605 return Qt::Key_Semicolon;
608 return Qt::Key_Apostrophe;
611 return Qt::Key_Slash;
620 return QKeyCombination::fromCombined(0);
623 return Qt::Key_CameraFocus;
632 return QKeyCombination::fromCombined(0);
635 return Qt::Key_Search;
638 return Qt::Key_MediaTogglePlayPause;
641 return Qt::Key_MediaStop;
644 return Qt::Key_MediaNext;
647 return Qt::Key_MediaPrevious;
650 return Qt::Key_AudioRewind;
653 return Qt::Key_AudioForward;
656 return Qt::Key_MicMute;
659 return Qt::Key_PageUp;
662 return Qt::Key_PageDown;
665 return QKeyCombination::fromCombined(0);
682 return QKeyCombination::fromCombined(0);
685 return Qt::Key_Escape;
688 return Qt::Key_Delete;
692 return Qt::Key_Control;
695 return Qt::Key_CapsLock;
698 return Qt::Key_ScrollLock;
705 return QKeyCombination::fromCombined(0);
708 return Qt::Key_Print;
711 return Qt::Key_Pause;
720 return Qt::Key_Insert;
723 return Qt::Key_Forward;
726 return Qt::Key_MediaPlay;
729 return Qt::Key_MediaPause;
733 return Qt::Key_Eject;
736 return Qt::Key_MediaRecord;
741 return Qt::Key_NumLock;
746 return Qt::KeypadModifier | Qt::Key_Slash;
749 return Qt::KeypadModifier | Qt::Key_Asterisk;
752 return Qt::KeypadModifier | Qt::Key_Minus;
755 return Qt::KeypadModifier | Qt::Key_Plus;
758 return Qt::KeypadModifier | Qt::Key_Period;
761 return Qt::KeypadModifier | Qt::Key_Comma;
764 return Qt::Key_Enter;
767 return Qt::KeypadModifier | Qt::Key_Equal;
770 return Qt::Key_ParenLeft;
773 return Qt::Key_ParenRight;
776 return Qt::Key_VolumeMute;
782 return Qt::Key_ChannelUp;
785 return Qt::Key_ChannelDown;
788 return Qt::Key_ZoomIn;
791 return Qt::Key_ZoomOut;
795 return QKeyCombination::fromCombined(0);
798 return Qt::Key_Guide;
801 return QKeyCombination::fromCombined(0);
804 return Qt::Key_AddFavorite;
807 return Qt::Key_Subtitle;
810 return Qt::Key_Settings;
818 return QKeyCombination::fromCombined(0);
824 return Qt::Key_Green;
827 return Qt::Key_Yellow;
840 return QKeyCombination::fromCombined(0);
843 return Qt::Key_Calendar;
846 return Qt::Key_Music;
849 return Qt::Key_Calculator;
856 return Qt::Key_KeyboardBrightnessDown;
859 return Qt::Key_KeyboardBrightnessUp;
862 return Qt::Key_AudioCycleTrack;
865 qWarning() <<
"Unhandled key code " << key <<
'!';
866 return QKeyCombination::fromCombined(0);
873 return unicode ? QString(QChar(unicode)) : QString();
876 static void keyDown(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
878 const int qtKeyCombination = mapAndroidKey(key).toCombined();
879 const auto qtModifiers = mapAndroidModifiers(modifier);
880 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
881 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
882 const auto text = toString(unicode);
884 bool accepted =
false;
885 if (isBackKey || isMenuKey) {
886 accepted = QWindowSystemInterface::handleKeyEvent<
887 QWindowSystemInterface::SynchronousDelivery>(
888 nullptr, QEvent::KeyPress, qtKeyCombination, qtModifiers, text, autoRepeat);
890 QWindowSystemInterface::handleKeyEvent(
891 nullptr, QEvent::KeyPress, qtKeyCombination, qtModifiers, text, autoRepeat);
898 auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
899 iface->runOnAndroidMainThread([iface]() {
900 if (!iface->isActivityContext())
902 iface->context().callMethod<jboolean>(
"moveTaskToBack",
true);
906 static void keyUp(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
908 const int qtKeyCombination = mapAndroidKey(key).toCombined();
909 const auto qtModifiers = mapAndroidModifiers(modifier);
910 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
911 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
912 const auto text = toString(unicode);
914 if (!isBackKey && !isMenuKey) {
915 QWindowSystemInterface::handleKeyEvent(
916 nullptr, QEvent::KeyRelease, qtKeyCombination, qtModifiers, text, autoRepeat);
920 const bool accepted =
921 QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
922 nullptr, QEvent::KeyRelease, qtKeyCombination, qtModifiers, text, autoRepeat);
936 if (inputContext && qGuiApp) {
937 inputContext->emitInputPanelVisibleChanged();
939 inputContext->emitKeyboardRectChanged();
940 QMetaObject::invokeMethod(inputContext,
"hideSelectionHandles", Qt::QueuedConnection);
943 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
948 QRect r = QRect(x, y, w, h);
949 if (r == m_softwareKeyboardRect)
953 if (inputContext && qGuiApp)
954 inputContext->emitKeyboardRectChanged();
956 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
961 qCDebug(lcQpaInputMethods) <<
"@@@ handleLocationChanged" << id << x << y;
963 if (inputContext && qGuiApp)
964 QMetaObject::invokeMethod(inputContext,
"handleLocationChanged", Qt::BlockingQueuedConnection,
965 Q_ARG(
int, id), Q_ARG(
int, x), Q_ARG(
int, y));
971 {
"touchBegin",
"(I)V",(
void*)touchBegin},
972 {
"touchAdd",
"(IIIZIIFFFF)V",(
void*)touchAdd},
973 {
"touchEnd",
"(III)V",(
void*)touchEnd},
974 {
"touchCancel",
"(II)V", (
void *)touchCancel},
975 {
"mouseDown",
"(IIIII)V", (
void *)mouseDown},
976 {
"mouseUp",
"(IIIII)V", (
void *)mouseUp},
977 {
"mouseMove",
"(IIIII)V", (
void *)mouseMove},
978 {
"mouseWheel",
"(IIIFFI)V", (
void *)mouseWheel},
979 {
"longPress",
"(IIII)V", (
void *)longPress},
980 {
"isTabletEventSupported",
"()Z", (
void *)isTabletEventSupported},
981 {
"tabletEvent",
"(IIJIIIFFFI)V", (
void *)tabletEvent},
982 {
"keyDown",
"(IIIZ)V", (
void *)keyDown},
983 {
"keyUp",
"(IIIZ)V", (
void *)keyUp},
984 {
"keyboardVisibilityChanged",
"(Z)V", (
void *)keyboardVisibilityChanged},
985 {
"keyboardGeometryChanged",
"(IIII)V", (
void *)keyboardGeometryChanged},
986 {
"handleLocationChanged",
"(III)V", (
void *)handleLocationChanged},
991 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtInputDelegate>::className(),
993 __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")