7#include <QtGui/qtguiglobal.h>
14#include <qpa/qplatformwindow.h>
15#include <qpa/qwindowsysteminterface.h>
19#include <QGuiApplication>
24Q_LOGGING_CATEGORY(lcQpaInputMethods,
"qt.qpa.input.methods");
44 void updateSelection(
int selStart,
int selEnd,
int candidatesStart,
int candidatesEnd)
46 qCDebug(lcQpaInputMethods) <<
">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
48 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
"updateSelection", selStart, selEnd,
49 candidatesStart, candidatesEnd);
55 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
56 "showSoftwareKeyboard", QtAndroidPrivate::activity(),
57 left, top, width, height, inputHints,
59 qCDebug(lcQpaInputMethods) <<
"@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
65 reg->callInterface<QtJniTypes::QtInputInterface>(
"resetSoftwareKeyboard");
66 qCDebug(lcQpaInputMethods) <<
"@@@ RESETSOFTWAREKEYBOARD";
72 reg->callInterface<QtJniTypes::QtInputInterface>(
"hideSoftwareKeyboard");
73 qCDebug(lcQpaInputMethods) <<
"@@@ HIDESOFTWAREKEYBOARD";
79 return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>(
80 "isSoftwareKeyboardVisible");
85 return m_softwareKeyboardRect;
91 return reg->callInterface<QtJniTypes::QtInputInterface, jint>(
"getSelectionHandleWidth");
97 reg->callInterface<QtJniTypes::QtInputInterface,
void>(
98 "updateHandles", mode, editMenuPos.x(), editMenuPos.y(),
99 editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
116 const auto buttons =
static_cast<AndroidMouseButtons>(j_buttons);
117 Qt::MouseButtons mouseButtons;
119 mouseButtons.setFlag(Qt::LeftButton);
122 mouseButtons.setFlag(Qt::RightButton);
125 mouseButtons.setFlag(Qt::MiddleButton);
128 mouseButtons.setFlag(Qt::BackButton);
131 mouseButtons.setFlag(Qt::ForwardButton);
134 mouseButtons.setFlag(Qt::LeftButton);
137 mouseButtons.setFlag(Qt::RightButton);
140 if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
141 qWarning() <<
"Unhandled button value:" << buttons <<
"Falling back to Qt::LeftButton";
142 mouseButtons = Qt::LeftButton;
148 jint mouseButtonState, QEvent::Type type)
150 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
151 const bool mouseReleased = type == QEvent::MouseButtonRelease && qtButtons == Qt::NoButton;
152 const Qt::MouseButtons eventButtons = mouseReleased ? m_lastSeenButtons : qtButtons;
155 static_assert (
sizeof(eventButtons) <=
sizeof(uint),
"Qt::MouseButtons size changed. Adapt code.");
157 if (eventButtons == Qt::NoButton)
160 for (uint buttonInt = 0x1;
static_cast<uint>(eventButtons) >= buttonInt; buttonInt <<= 1) {
161 const auto button =
static_cast<Qt::MouseButton>(buttonInt);
162 if (eventButtons.testFlag(button)) {
163 QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
164 qtButtons, button, type);
169 static void mouseDown(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
174 const QPoint localPos(x,y);
175 QWindow *window = windowFromId(winId);
177 const QPoint globalPos = window && window->handle() ?
178 window->handle()->mapToGlobal(localPos) : localPos;
179 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonPress);
182 static void mouseUp(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
184 const QPoint localPos(x,y);
185 QWindow *window = m_mouseGrabber.data();
187 window = windowFromId(winId);
189 const QPoint globalPos = window && window->handle() ?
190 window->handle()->mapToGlobal(localPos) : localPos;
192 sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonRelease);
197 static void mouseMove(JNIEnv *,
jobject , jint winId, jint x, jint y, jint mouseButtonState)
202 const QPoint localPos(x,y);
203 QWindow *window = m_mouseGrabber.data();
205 window = windowFromId(winId);
206 const QPoint globalPos = window && window->handle() ?
207 window->handle()->mapToGlobal(localPos) : localPos;
208 const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
210 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
211 qtButtons, Qt::NoButton, QEvent::MouseMove);
214 static void mouseWheel(JNIEnv *,
jobject , jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta)
219 const QPoint localPos(x,y);
220 QWindow *window = m_mouseGrabber.data();
222 window = windowFromId(winId);
223 const QPoint globalPos = window && window->handle() ?
224 window->handle()->mapToGlobal(localPos) : localPos;
225 const QPoint angleDelta(hdelta * 120, vdelta * 120);
227 QWindowSystemInterface::handleWheelEvent(window,
238 const QPoint localPos(x,y);
239 QWindow *window = windowFromId(winId);
240 const QPoint globalPos = window && window->handle() ?
241 window->handle()->mapToGlobal(localPos) : localPos;
243 if (inputContext && qGuiApp)
244 QMetaObject::invokeMethod(inputContext,
"longPress", Q_ARG(
int, globalPos.x()), Q_ARG(
int, globalPos.y()));
247 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue(
"QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
248 if (!rightMouseFromLongPress)
254 if (!m_mouseGrabber) {
255 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
256 Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
257 QEvent::MouseButtonPress);
258 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
259 Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
260 QEvent::MouseButtonRelease);
270 jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
272 QEventPoint::State state = QEventPoint::State::Stationary;
275 state = QEventPoint::State::Pressed;
278 state = QEventPoint::State::Updated;
281 state = QEventPoint::State::Stationary;
284 state = QEventPoint::State::Released;
291 availableSize = platformIntegration
->screen()->availableGeometry().size();
297 qCWarning(lcQpaInputMethods,
"Touch event received for non-existing window %d", winId);
301 QPointF mappedTouchPoint;
302 if (window->handle())
303 mappedTouchPoint = window->handle()->mapToGlobalF(QPointF(x, y));
305 mappedTouchPoint = window->mapToGlobal(QPointF(x, y));
307 QWindowSystemInterface::TouchPoint touchPoint;
309 touchPoint.id = id + 1;
310 touchPoint.pressure = pressure;
311 touchPoint.rotation = qRadiansToDegrees(rotation);
312 touchPoint.normalPosition = QPointF((mappedTouchPoint.x() / availableSize.width()),
313 (mappedTouchPoint.y() / availableSize.height()));
314 touchPoint.state = state;
315 touchPoint.area = QRectF(mappedTouchPoint.x() -
double(minor * 0.5f),
316 mappedTouchPoint.y() -
double(major * 0.5f),
321 if (state == QEventPoint::State::Pressed) {
323 if (inputContext && qGuiApp)
324 QMetaObject::invokeMethod(inputContext,
"touchDown", Q_ARG(
int, mappedTouchPoint.x()), Q_ARG(
int, mappedTouchPoint.y()));
331 if (!platformIntegration)
334 QPointingDevice *touchDevice = platformIntegration->touchDevice();
336 touchDevice =
new QPointingDevice(
"Android touchscreen", 1,
337 QInputDevice::DeviceType::TouchScreen,
338 QPointingDevice::PointerType::Finger,
339 QPointingDevice::Capability::Position
340 | QPointingDevice::Capability::Area
341 | QPointingDevice::Capability::Pressure
342 | QPointingDevice::Capability::NormalizedPosition,
344 QWindowSystemInterface::registerInputDevice(touchDevice);
345 platformIntegration->setTouchDevice(touchDevice);
357 const QPointingDevice *touchDevice = getTouchDevice();
364 QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
373 const QPointingDevice *touchDevice = getTouchDevice();
380 QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice);
385#if QT_CONFIG(tabletevent)
393 jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
395#if QT_CONFIG(tabletevent)
396 const QPointF localPos(x, y);
397 QWindow *window = windowFromId(winId);
398 const QPointF globalPosF = window && window->handle() ?
399 window->handle()->mapFromGlobalF(localPos) : localPos;
416 Qt::MouseButtons buttons = Qt::NoButton;
421 buttons = Qt::NoButton;
424 if (buttonState == 0)
425 buttons = Qt::LeftButton;
427 buttons = Qt::MouseButtons(buttonState);
431 qCDebug(lcQpaInputMethods) << action << pointerType << buttonState <<
'@' << x << y <<
"pressure" << pressure <<
": buttons" << buttons;
433 QWindowSystemInterface::handleTabletEvent(window, ulong(time),
434 localPos, globalPosF,
int(QInputDevice::DeviceType::Stylus), pointerType,
435 buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier);
442 if (key >= 0x00000007 && key <= 0x00000010)
443 return QKeyCombination::fromCombined(Qt::Key_0 + key - 0x00000007);
446 if (key >= 0x0000001d && key <= 0x00000036)
447 return QKeyCombination::fromCombined(Qt::Key_A + key - 0x0000001d);
450 if (key >= 0x00000083 && key <= 0x0000008e)
451 return QKeyCombination::fromCombined(Qt::Key_F1 + key - 0x00000083);
454 if (key >= 0x00000090 && key <= 0x00000099)
455 return QKeyCombination::fromCombined(Qt::KeypadModifier | Qt::Key_0 + key - 0x00000090);
461 return Qt::Key_unknown;
467 return Qt::Key_Right;
478 return Qt::Key_Hangup;
483 return Qt::Key_Asterisk;
486 return Qt::Key_NumberSign;
498 return Qt::Key_Right;
501 return Qt::Key_Enter;
504 return Qt::Key_VolumeUp;
507 return Qt::Key_VolumeDown;
510 return Qt::Key_PowerOff;
513 return Qt::Key_Camera;
516 return Qt::Key_Clear;
521 return Qt::Key_Comma;
524 return Qt::Key_Period;
532 return Qt::Key_Shift;
538 return Qt::Key_Space;
544 return Qt::Key_Explorer;
547 return Qt::Key_LaunchMail;
550 return Qt::Key_Return;
553 return Qt::Key_Backspace;
556 return Qt::Key_QuoteLeft;
559 return Qt::Key_Minus;
562 return Qt::Key_Equal;
565 return Qt::Key_BracketLeft;
568 return Qt::Key_BracketRight;
571 return Qt::Key_Backslash;
574 return Qt::Key_Semicolon;
577 return Qt::Key_Apostrophe;
580 return Qt::Key_Slash;
589 return QKeyCombination::fromCombined(0);
592 return Qt::Key_CameraFocus;
601 return QKeyCombination::fromCombined(0);
604 return Qt::Key_Search;
607 return Qt::Key_MediaTogglePlayPause;
610 return Qt::Key_MediaStop;
613 return Qt::Key_MediaNext;
616 return Qt::Key_MediaPrevious;
619 return Qt::Key_AudioRewind;
622 return Qt::Key_AudioForward;
625 return Qt::Key_MicMute;
628 return Qt::Key_PageUp;
631 return Qt::Key_PageDown;
634 return QKeyCombination::fromCombined(0);
651 return QKeyCombination::fromCombined(0);
654 return Qt::Key_Escape;
657 return Qt::Key_Delete;
661 return Qt::Key_Control;
664 return Qt::Key_CapsLock;
667 return Qt::Key_ScrollLock;
674 return QKeyCombination::fromCombined(0);
677 return Qt::Key_Print;
680 return Qt::Key_Pause;
689 return Qt::Key_Insert;
692 return Qt::Key_Forward;
695 return Qt::Key_MediaPlay;
698 return Qt::Key_MediaPause;
702 return Qt::Key_Eject;
705 return Qt::Key_MediaRecord;
710 return Qt::Key_NumLock;
715 return Qt::KeypadModifier | Qt::Key_Slash;
718 return Qt::KeypadModifier | Qt::Key_Asterisk;
721 return Qt::KeypadModifier | Qt::Key_Minus;
724 return Qt::KeypadModifier | Qt::Key_Plus;
727 return Qt::KeypadModifier | Qt::Key_Period;
730 return Qt::KeypadModifier | Qt::Key_Comma;
733 return Qt::Key_Enter;
736 return Qt::KeypadModifier | Qt::Key_Equal;
739 return Qt::Key_ParenLeft;
742 return Qt::Key_ParenRight;
745 return Qt::Key_VolumeMute;
751 return Qt::Key_ChannelUp;
754 return Qt::Key_ChannelDown;
757 return Qt::Key_ZoomIn;
760 return Qt::Key_ZoomOut;
764 return QKeyCombination::fromCombined(0);
767 return Qt::Key_Guide;
770 return QKeyCombination::fromCombined(0);
773 return Qt::Key_AddFavorite;
776 return Qt::Key_Subtitle;
779 return Qt::Key_Settings;
787 return QKeyCombination::fromCombined(0);
793 return Qt::Key_Green;
796 return Qt::Key_Yellow;
809 return QKeyCombination::fromCombined(0);
812 return Qt::Key_Calendar;
815 return Qt::Key_Music;
818 return Qt::Key_Calculator;
825 return Qt::Key_KeyboardBrightnessDown;
828 return Qt::Key_KeyboardBrightnessUp;
831 return Qt::Key_AudioCycleTrack;
834 qWarning() <<
"Unhandled key code " << key <<
'!';
835 return QKeyCombination::fromCombined(0);
841 Qt::KeyboardModifiers qmodifiers;
843 if (modifiers & 0x00000001)
844 qmodifiers |= Qt::ShiftModifier;
846 if (modifiers & 0x00000002)
847 qmodifiers |= Qt::AltModifier;
849 if (modifiers & 0x00000004)
850 qmodifiers |= Qt::MetaModifier;
852 if (modifiers & 0x00001000)
853 qmodifiers |= Qt::ControlModifier;
861 return unicode ? QString(QChar(unicode)) : QString();
864 static void keyDown(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
866 const int qtKeyCombination = mapAndroidKey(key).toCombined();
867 const auto qtModifiers = mapAndroidModifiers(modifier);
868 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
869 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
870 const auto text = toString(unicode);
872 bool accepted =
false;
873 if (isBackKey || isMenuKey) {
874 accepted = QWindowSystemInterface::handleKeyEvent<
875 QWindowSystemInterface::SynchronousDelivery>(
876 nullptr, QEvent::KeyPress, qtKeyCombination, qtModifiers, text, autoRepeat);
878 QWindowSystemInterface::handleKeyEvent(
879 nullptr, QEvent::KeyPress, qtKeyCombination, qtModifiers, text, autoRepeat);
886 auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
887 iface->runOnAndroidMainThread([iface]() {
888 if (!iface->isActivityContext())
890 iface->context().callMethod<jboolean>(
"moveTaskToBack",
true);
894 static void keyUp(JNIEnv *,
jobject , jint key, jint unicode, jint modifier, jboolean autoRepeat)
896 const int qtKeyCombination = mapAndroidKey(key).toCombined();
897 const auto qtModifiers = mapAndroidModifiers(modifier);
898 const auto isBackKey = qtKeyCombination == Qt::Key_Back;
899 const auto isMenuKey = qtKeyCombination == Qt::Key_Menu;
900 const auto text = toString(unicode);
902 if (!isBackKey && !isMenuKey) {
903 QWindowSystemInterface::handleKeyEvent(
904 nullptr, QEvent::KeyRelease, qtKeyCombination, qtModifiers, text, autoRepeat);
908 const bool accepted =
909 QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
910 nullptr, QEvent::KeyRelease, qtKeyCombination, qtModifiers, text, autoRepeat);
924 if (inputContext && qGuiApp) {
925 inputContext->emitInputPanelVisibleChanged();
927 inputContext->emitKeyboardRectChanged();
928 QMetaObject::invokeMethod(inputContext,
"hideSelectionHandles", Qt::QueuedConnection);
931 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
936 QRect r = QRect(x, y, w, h);
937 if (r == m_softwareKeyboardRect)
941 if (inputContext && qGuiApp)
942 inputContext->emitKeyboardRectChanged();
944 qCDebug(lcQpaInputMethods) <<
"@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
949 qCDebug(lcQpaInputMethods) <<
"@@@ handleLocationChanged" << id << x << y;
951 if (inputContext && qGuiApp)
952 QMetaObject::invokeMethod(inputContext,
"handleLocationChanged", Qt::BlockingQueuedConnection,
953 Q_ARG(
int, id), Q_ARG(
int, x), Q_ARG(
int, y));
959 {
"touchBegin",
"(I)V",(
void*)touchBegin},
960 {
"touchAdd",
"(IIIZIIFFFF)V",(
void*)touchAdd},
961 {
"touchEnd",
"(II)V",(
void*)touchEnd},
962 {
"touchCancel",
"(I)V", (
void *)touchCancel},
963 {
"mouseDown",
"(IIII)V", (
void *)mouseDown},
964 {
"mouseUp",
"(IIII)V", (
void *)mouseUp},
965 {
"mouseMove",
"(IIII)V", (
void *)mouseMove},
966 {
"mouseWheel",
"(IIIFF)V", (
void *)mouseWheel},
967 {
"longPress",
"(III)V", (
void *)longPress},
968 {
"isTabletEventSupported",
"()Z", (
void *)isTabletEventSupported},
969 {
"tabletEvent",
"(IIJIIIFFF)V", (
void *)tabletEvent},
970 {
"keyDown",
"(IIIZ)V", (
void *)keyDown},
971 {
"keyUp",
"(IIIZ)V", (
void *)keyUp},
972 {
"keyboardVisibilityChanged",
"(Z)V", (
void *)keyboardVisibilityChanged},
973 {
"keyboardGeometryChanged",
"(IIII)V", (
void *)keyboardGeometryChanged},
974 {
"handleLocationChanged",
"(III)V", (
void *)handleLocationChanged},
979 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtInputDelegate>::className(),
981 __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")