Warning, /graphics/krita/3rdparty/ext_qt/0001-Android-Introducing-QtInputEventDispatcher.patch is written in an unsupported language. File is not indexed.
0001 From c64c1710cfd9173842da496446e2eb4dfb6b30c0 Mon Sep 17 00:00:00 2001 0002 From: Sharaf Zaman <shzam@sdf.org> 0003 Date: Thu, 6 Oct 2022 08:14:33 +0000 0004 Subject: [PATCH] Android: Introducing QtInputEventDispatcher 0005 0006 This is a separate thread which receives events from the Android UI 0007 thread and handles the dispatching to Qt's Main Thread. 0008 0009 The reason for this new thread is to prevent some nasty deadlocks 0010 between Android's UI thread and Qt's MainLoopThread (the deadlocks 0011 happened when UI Thread was stuck trying to dispatch an event or flush 0012 Qt's window system queue and while the Qt Main thread was stuck trying 0013 to get a SurfaceView from Android). 0014 0015 In addition to just dispatching this patch also moves the event handling 0016 to cpp (if in case in future we ditch java in favor of native_app_glue 0017 for event handling). Everything is ported almost like the way it was 0018 before, because the previous version of event handling worked correctly 0019 on all devices (I remember, display tablets being the odd ones). 0020 --- 0021 .../qt5/android/QtInputEventDispatcher.java | 119 ++++++++ 0022 .../org/qtproject/qt5/android/QtLayout.java | 12 +- 0023 .../org/qtproject/qt5/android/QtNative.java | 187 +------------ 0024 .../platforms/android/MotionEventWrapper.h | 157 +++++++++++ 0025 .../platforms/android/androidjniinput.cpp | 255 +++++++++++++----- 0026 .../platforms/android/androidjnimain.cpp | 18 ++ 0027 .../platforms/android/androidjnimain.h | 2 + 0028 7 files changed, 503 insertions(+), 247 deletions(-) 0029 create mode 100644 src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java 0030 create mode 100644 src/plugins/platforms/android/MotionEventWrapper.h 0031 0032 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java 0033 new file mode 100644 0034 index 0000000000..15e1c322fe 0035 --- /dev/null 0036 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java 0037 @@ -0,0 +1,119 @@ 0038 +package org.qtproject.qt5.android; 0039 + 0040 +import android.os.Handler; 0041 +import android.os.Looper; 0042 +import android.os.Message; 0043 +import android.util.Log; 0044 +import android.view.InputDevice; 0045 +import android.view.MotionEvent; 0046 + 0047 +public class QtInputEventDispatcher extends Thread { 0048 + 0049 + private static final String TAG = "QtInputEventDispatcher"; 0050 + 0051 + private Handler mEventHandler; 0052 + 0053 + QtInputEventDispatcher() { 0054 + super(TAG); 0055 + } 0056 + 0057 + @Override 0058 + public void run() { 0059 + try { 0060 + Looper.prepare(); 0061 + mEventHandler = 0062 + new Handler( 0063 + Looper.myLooper(), 0064 + new Handler.Callback() { 0065 + @Override 0066 + public boolean handleMessage(Message msg) { 0067 + MotionEvent event = (MotionEvent) msg.obj; 0068 + if (event != null) { 0069 + dispatchMotionEvent(msg.arg1, msg.arg2 == 1, event); 0070 + event.recycle(); 0071 + } 0072 + return true; 0073 + } 0074 + }); 0075 + Looper.loop(); 0076 + } catch (Exception e) { 0077 + Log.e(TAG, "Looper halted, error = " + e); 0078 + e.printStackTrace(); 0079 + } 0080 + } 0081 + 0082 + public void onCommonEvent(MotionEvent event, int id) { 0083 + if (mEventHandler == null) { 0084 + return; 0085 + } 0086 + 0087 + MotionEvent clonedEvent = MotionEvent.obtain(event); 0088 + Message.obtain(mEventHandler, /*what = */ 0, id, /* arg2 = */ 0, clonedEvent) 0089 + .sendToTarget(); 0090 + } 0091 + 0092 + public void onTouchEvent(MotionEvent event, int id) { 0093 + if (mEventHandler == null) { 0094 + return; 0095 + } 0096 + 0097 + MotionEvent clonedEvent = MotionEvent.obtain(event); 0098 + // here we set touch to true 0099 + Message.obtain(mEventHandler, /*what = */ 0, id, /* arg2 = */ 1, clonedEvent) 0100 + .sendToTarget(); 0101 + } 0102 + 0103 + public void onLongPress(final MotionEvent event, final int id) { 0104 + if (mEventHandler == null) { 0105 + return; 0106 + } 0107 + 0108 + Message.obtain( 0109 + mEventHandler, 0110 + new Runnable() { 0111 + @Override 0112 + public void run() { 0113 + longPress(id, (int) event.getX(), (int) event.getY()); 0114 + } 0115 + }) 0116 + .sendToTarget(); 0117 + } 0118 + 0119 + public boolean sendGenericMotionEvent(MotionEvent event, int id) { 0120 + if (!event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 0121 + return false; 0122 + } 0123 + 0124 + if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 0125 + onCommonEvent(event, id); 0126 + return canHandleMouseAction(event); 0127 + } else if ((event.getSource() 0128 + & (InputDevice.SOURCE_STYLUS 0129 + | InputDevice.SOURCE_TOUCHPAD 0130 + | InputDevice.SOURCE_TOUCHSCREEN)) 0131 + != 0) { 0132 + 0133 + onTouchEvent(event, id); 0134 + return true; 0135 + } 0136 + return false; 0137 + } 0138 + 0139 + private static boolean canHandleMouseAction(MotionEvent event) { 0140 + switch (event.getActionMasked()) { 0141 + case MotionEvent.ACTION_UP: 0142 + case MotionEvent.ACTION_DOWN: 0143 + case MotionEvent.ACTION_HOVER_MOVE: 0144 + case MotionEvent.ACTION_MOVE: 0145 + case MotionEvent.ACTION_SCROLL: 0146 + return true; 0147 + default: 0148 + return false; 0149 + } 0150 + } 0151 + 0152 + private static native void dispatchMotionEvent( 0153 + int winId, boolean isTouchEvent, MotionEvent event); 0154 + 0155 + private static native void longPress(int winId, int x, int y); 0156 +} 0157 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java 0158 index 6b067a9cfd..b74cb6bd8f 100644 0159 --- a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java 0160 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java 0161 @@ -53,24 +53,28 @@ public class QtLayout extends ViewGroup 0162 { 0163 private GestureDetector m_gestureDetector; 0164 private Runnable m_startApplicationRunnable; 0165 + private QtInputEventDispatcher inputEventDispatcher; 0166 0167 public QtLayout(Context context, Runnable startRunnable) 0168 { 0169 super(context); 0170 m_startApplicationRunnable = startRunnable; 0171 initializeGestureDetector(context); 0172 + inputEventDispatcher = QtNative.getInputEventDispatcher(); 0173 } 0174 0175 public QtLayout(Context context, AttributeSet attrs) 0176 { 0177 super(context, attrs); 0178 initializeGestureDetector(context); 0179 + inputEventDispatcher = QtNative.getInputEventDispatcher(); 0180 } 0181 0182 public QtLayout(Context context, AttributeSet attrs, int defStyle) 0183 { 0184 super(context, attrs, defStyle); 0185 initializeGestureDetector(context); 0186 + inputEventDispatcher = QtNative.getInputEventDispatcher(); 0187 } 0188 0189 private void initializeGestureDetector(Context context) 0190 @@ -78,7 +82,7 @@ public class QtLayout extends ViewGroup 0191 m_gestureDetector = 0192 new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 0193 public void onLongPress(MotionEvent event) { 0194 - QtNative.longPress(getId(), (int) event.getX(), (int) event.getY()); 0195 + inputEventDispatcher.onLongPress(event, getId()); 0196 } 0197 }); 0198 m_gestureDetector.setIsLongpressEnabled(true); 0199 @@ -278,7 +282,7 @@ public class QtLayout extends ViewGroup 0200 0201 @Override 0202 public boolean onTouchEvent(MotionEvent event) { 0203 - QtNative.sendTouchEvent(event, getId()); 0204 + inputEventDispatcher.onTouchEvent(event, getId()); 0205 m_gestureDetector.onTouchEvent(event); 0206 return true; 0207 } 0208 @@ -286,13 +290,13 @@ public class QtLayout extends ViewGroup 0209 @Override 0210 public boolean onTrackballEvent(MotionEvent event) 0211 { 0212 - QtNative.sendTrackballEvent(event, getId()); 0213 + inputEventDispatcher.onCommonEvent(event, getId()); 0214 return true; 0215 } 0216 0217 @Override 0218 public boolean onGenericMotionEvent(MotionEvent event) 0219 { 0220 - return QtNative.sendGenericMotionEvent(event, getId()); 0221 + return inputEventDispatcher.sendGenericMotionEvent(event, getId()); 0222 } 0223 } 0224 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 0225 index 8e32a83f9f..9c8ecb0d12 100644 0226 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 0227 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 0228 @@ -99,13 +99,13 @@ public class QtNative 0229 private static double m_displayMetricsYDpi = .0; 0230 private static double m_displayMetricsScaledDensity = 1.0; 0231 private static double m_displayMetricsDensity = 1.0; 0232 - private static int m_oldx, m_oldy; 0233 private static final int m_moveThreshold = 0; 0234 private static ClipboardManager m_clipboardManager = null; 0235 private static Method m_checkSelfPermissionMethod = null; 0236 private static Boolean m_tabletEventSupported = null; 0237 private static boolean m_usePrimaryClip = false; 0238 public static QtThread m_qtThread = new QtThread(); 0239 + private static final QtInputEventDispatcher sInputEventDispatcher = new QtInputEventDispatcher(); 0240 private static Method m_addItemMethod = null; 0241 0242 0243 @@ -156,6 +156,10 @@ public class QtNative 0244 } 0245 } 0246 0247 + public static QtInputEventDispatcher getInputEventDispatcher() { 0248 + return sInputEventDispatcher; 0249 + } 0250 + 0251 public static String[] getStringArray(String joinedString) 0252 { 0253 return joinedString.split(","); 0254 @@ -164,6 +168,8 @@ public class QtNative 0255 // this method loads full path libs 0256 public static void loadQtLibraries(final ArrayList<String> libraries) 0257 { 0258 + sInputEventDispatcher.start(); 0259 + Log.i(QtTAG, "InputEventDispatcherStarted"); 0260 m_qtThread.run(new Runnable() { 0261 @Override 0262 public void run() { 0263 @@ -436,169 +442,6 @@ public class QtNative 0264 }); 0265 } 0266 0267 - //@ANDROID-9 0268 - static private int getAction(int index, MotionEvent event) 0269 - { 0270 - int action = event.getActionMasked(); 0271 - if (action == MotionEvent.ACTION_MOVE) { 0272 - int hsz = event.getHistorySize(); 0273 - if (hsz > 0) { 0274 - float x = event.getX(index); 0275 - float y = event.getY(index); 0276 - for (int h = 0; h < hsz; ++h) { 0277 - if ( event.getHistoricalX(index, h) != x || 0278 - event.getHistoricalY(index, h) != y ) 0279 - return 1; 0280 - } 0281 - return 2; 0282 - } 0283 - return 1; 0284 - } 0285 - if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { 0286 - return 0; 0287 - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { 0288 - return 3; 0289 - } 0290 - return 2; 0291 - } 0292 - //@ANDROID-9 0293 - 0294 - static public boolean sendTouchEvent(MotionEvent event, int id) 0295 - { 0296 - int pointerType = 0; 0297 - 0298 - if (m_tabletEventSupported == null) 0299 - m_tabletEventSupported = isTabletEventSupported(); 0300 - 0301 - switch (event.getToolType(0)) { 0302 - case MotionEvent.TOOL_TYPE_STYLUS: 0303 - pointerType = 1; // QTabletEvent::Pen 0304 - break; 0305 - case MotionEvent.TOOL_TYPE_ERASER: 0306 - pointerType = 3; // QTabletEvent::Eraser 0307 - break; 0308 - } 0309 - 0310 - if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { 0311 - return sendMouseEvent(event, id); 0312 - } else if (m_tabletEventSupported && pointerType != 0) { 0313 - final int historySize = event.getHistorySize(); 0314 - for (int h = 0; h < historySize; h++) { 0315 - float tiltRot = event.getHistoricalAxisValue(MotionEvent.AXIS_TILT, h); 0316 - float orientation = event.getHistoricalAxisValue(MotionEvent.AXIS_ORIENTATION, h); 0317 - 0318 - float tiltX = (float) Math.toDegrees(-Math.sin(orientation) * tiltRot); 0319 - float tiltY = (float) Math.toDegrees(Math.cos(orientation) * tiltRot); 0320 - 0321 - tabletEvent(id, event.getDeviceId(), event.getHistoricalEventTime(h), event.getActionMasked(), 0322 - pointerType, event.getButtonState(), event.getHistoricalX(h), 0323 - event.getHistoricalY(h), event.getHistoricalPressure(h), tiltX, tiltY, 0324 - (float)Math.toDegrees(orientation), event.getMetaState()); 0325 - } 0326 - float tiltRot = event.getAxisValue(MotionEvent.AXIS_TILT); 0327 - float orientation = event.getAxisValue(MotionEvent.AXIS_ORIENTATION); 0328 - float tiltX = (float) Math.toDegrees(-Math.sin(orientation) * tiltRot); 0329 - float tiltY = (float) Math.toDegrees(Math.cos(orientation) * tiltRot); 0330 - tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getActionMasked(), pointerType, 0331 - event.getButtonState(), event.getX(), event.getY(), event.getPressure(), tiltX, tiltY, 0332 - (float) Math.toDegrees(orientation), event.getMetaState()); 0333 - return true; 0334 - } else { 0335 - final int historySize = event.getHistorySize(); 0336 - touchBegin(id); 0337 - // batched ones 0338 - for (int h = 0; h < historySize; h++) { 0339 - touchBegin(id); 0340 - for (int i = 0; i < event.getPointerCount(); ++i) { 0341 - touchAdd(id, 0342 - event.getPointerId(i), 0343 - getAction(i, event), 0344 - i == 0, 0345 - (int)event.getHistoricalX(i, h), 0346 - (int)event.getHistoricalY(i, h), 0347 - event.getHistoricalTouchMajor(i, h), 0348 - event.getHistoricalTouchMinor(i, h), 0349 - event.getHistoricalOrientation(i, h), 0350 - event.getHistoricalPressure(i, h)); 0351 - } 0352 - touchEnd(id, event.getAction()); 0353 - } 0354 - touchBegin(id); 0355 - for (int i = 0; i < event.getPointerCount(); ++i) { 0356 - touchAdd(id, 0357 - event.getPointerId(i), 0358 - getAction(i, event), 0359 - i == 0, 0360 - (int)event.getX(i), 0361 - (int)event.getY(i), 0362 - event.getTouchMajor(i), 0363 - event.getTouchMinor(i), 0364 - event.getOrientation(i), 0365 - event.getPressure(i)); 0366 - } 0367 - touchEnd(id, event.getAction()); 0368 - return true; 0369 - } 0370 - } 0371 - 0372 - static public void sendTrackballEvent(MotionEvent event, int id) 0373 - { 0374 - sendMouseEvent(event,id); 0375 - } 0376 - 0377 - static public boolean sendGenericMotionEvent(MotionEvent event, int id) 0378 - { 0379 - if (!event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 0380 - return false; 0381 - } 0382 - 0383 - if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 0384 - return sendMouseEvent(event, id); 0385 - } else if ((event.getSource() & (InputDevice.SOURCE_STYLUS | 0386 - InputDevice.SOURCE_TOUCHPAD | 0387 - InputDevice.SOURCE_TOUCHSCREEN)) != 0) { 0388 - 0389 - return sendTouchEvent(event, id); 0390 - } 0391 - return false; 0392 - } 0393 - 0394 - static public boolean sendMouseEvent(MotionEvent event, int id) 0395 - { 0396 - switch (event.getActionMasked()) { 0397 - case MotionEvent.ACTION_UP: 0398 - mouseUp(id, (int) event.getX(), (int) event.getY(), event.getMetaState()); 0399 - break; 0400 - 0401 - case MotionEvent.ACTION_DOWN: 0402 - mouseDown(id, (int) event.getX(), (int) event.getY(), event.getMetaState(), event.getButtonState()); 0403 - m_oldx = (int) event.getX(); 0404 - m_oldy = (int) event.getY(); 0405 - break; 0406 - case MotionEvent.ACTION_HOVER_MOVE: 0407 - case MotionEvent.ACTION_MOVE: 0408 - if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { 0409 - mouseMove(id, (int) event.getX(), (int) event.getY(), event.getMetaState()); 0410 - } else { 0411 - int dx = (int) (event.getX() - m_oldx); 0412 - int dy = (int) (event.getY() - m_oldy); 0413 - if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { 0414 - mouseMove(id, (int) event.getX(), (int) event.getY(), event.getMetaState()); 0415 - m_oldx = (int) event.getX(); 0416 - m_oldy = (int) event.getY(); 0417 - } 0418 - } 0419 - break; 0420 - case MotionEvent.ACTION_SCROLL: 0421 - mouseWheel(id, (int) event.getX(), (int) event.getY(), 0422 - event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL)); 0423 - break; 0424 - default: 0425 - return false; 0426 - } 0427 - return true; 0428 - } 0429 - 0430 public static Context getContext() { 0431 if (m_activity != null) 0432 return m_activity; 0433 @@ -1074,22 +917,6 @@ public class QtNative 0434 public static native void handleOrientationChanged(int newRotation, int nativeOrientation); 0435 // screen methods 0436 0437 - // pointer methods 0438 - public static native void mouseDown(int winId, int x, int y, int modifier, int actionButton); 0439 - public static native void mouseUp(int winId, int x, int y, int modifiers); 0440 - public static native void mouseMove(int winId, int x, int y, int modifier); 0441 - public static native void mouseWheel(int winId, int x, int y, float hdelta, float vdelta); 0442 - public static native void touchBegin(int winId); 0443 - public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure); 0444 - public static native void touchEnd(int winId, int action); 0445 - public static native void longPress(int winId, int x, int y); 0446 - // pointer methods 0447 - 0448 - // tablet methods 0449 - public static native boolean isTabletEventSupported(); 0450 - public static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure, float tiltX, float tiltY, float rotation, int modifiers); 0451 - // tablet methods 0452 - 0453 // keyboard methods 0454 public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat); 0455 public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat); 0456 diff --git a/src/plugins/platforms/android/MotionEventWrapper.h b/src/plugins/platforms/android/MotionEventWrapper.h 0457 new file mode 100644 0458 index 0000000000..f493d1a2a4 0459 --- /dev/null 0460 +++ b/src/plugins/platforms/android/MotionEventWrapper.h 0461 @@ -0,0 +1,157 @@ 0462 +#ifndef __MOTIONEVENTWRAPPER_H_ 0463 +#define __MOTIONEVENTWRAPPER_H_ 0464 + 0465 +#include <android/input.h> 0466 + 0467 +class MotionEventWrapper 0468 +{ 0469 +public: 0470 + MotionEventWrapper(AInputEvent *inputEvent) 0471 + : m_motionEvent(inputEvent) 0472 + { 0473 + } 0474 + 0475 + inline int32_t getDeviceId() const { return AInputEvent_getDeviceId(m_motionEvent); } 0476 + 0477 + inline int32_t getAction() const { return AMotionEvent_getAction(m_motionEvent); } 0478 + 0479 + inline int32_t getActionMasked() const { return getAction() & AMOTION_EVENT_ACTION_MASK; } 0480 + 0481 + inline int32_t getActionIndex() const 0482 + { 0483 + return (getAction() & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) 0484 + >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; 0485 + } 0486 + 0487 + inline int32_t getToolType(size_t pointerIndex) const 0488 + { 0489 + return AMotionEvent_getToolType(m_motionEvent, pointerIndex); 0490 + } 0491 + 0492 + inline size_t getHistorySize() const { return AMotionEvent_getHistorySize(m_motionEvent); } 0493 + 0494 + inline int64_t getHistoricalEventTime(size_t historicalIndex) const 0495 + { 0496 + return AMotionEvent_getHistoricalEventTime(m_motionEvent, historicalIndex); 0497 + } 0498 + 0499 + inline int64_t getHistoricalEventTimeMs(size_t historicalIndex) const 0500 + { 0501 + return getHistoricalEventTime(historicalIndex) / NS_PER_MS; 0502 + } 0503 + 0504 + inline float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, 0505 + size_t historicalIndex) const 0506 + { 0507 + return AMotionEvent_getHistoricalAxisValue(m_motionEvent, axis, pointerIndex, 0508 + historicalIndex); 0509 + } 0510 + 0511 + inline float getHistoricalX(size_t historicalIndex) const 0512 + { 0513 + return getHistoricalX(0, historicalIndex); 0514 + } 0515 + 0516 + inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const 0517 + { 0518 + return AMotionEvent_getHistoricalX(m_motionEvent, pointerIndex, historicalIndex); 0519 + } 0520 + 0521 + inline float getHistoricalY(size_t historicalIndex) const 0522 + { 0523 + return getHistoricalY(0, historicalIndex); 0524 + } 0525 + 0526 + inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const 0527 + { 0528 + return AMotionEvent_getHistoricalY(m_motionEvent, pointerIndex, historicalIndex); 0529 + } 0530 + 0531 + inline float getHistoricalPressure(size_t historicalIndex) const 0532 + { 0533 + return getHistoricalPressure(0, historicalIndex); 0534 + } 0535 + 0536 + inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const 0537 + { 0538 + return AMotionEvent_getHistoricalPressure(m_motionEvent, pointerIndex, historicalIndex); 0539 + } 0540 + 0541 + float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) 0542 + { 0543 + return AMotionEvent_getHistoricalTouchMajor(m_motionEvent, pointerIndex, historicalIndex); 0544 + } 0545 + 0546 + float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) 0547 + { 0548 + return AMotionEvent_getHistoricalTouchMinor(m_motionEvent, pointerIndex, historicalIndex); 0549 + } 0550 + 0551 + float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) 0552 + { 0553 + return AMotionEvent_getHistoricalOrientation(m_motionEvent, pointerIndex, historicalIndex); 0554 + } 0555 + 0556 + inline int64_t getEventTime() const { return AMotionEvent_getEventTime(m_motionEvent); } 0557 + 0558 + inline int64_t getEventTimeMs() const { return getEventTime() / NS_PER_MS; } 0559 + 0560 + inline float getAxisValue(int32_t axis) const 0561 + { 0562 + return AMotionEvent_getAxisValue(m_motionEvent, axis, 0); 0563 + } 0564 + 0565 + inline float getX(int pointerIndex) const 0566 + { 0567 + return AMotionEvent_getX(m_motionEvent, pointerIndex); 0568 + } 0569 + 0570 + inline float getX() const { return getX(0); } 0571 + 0572 + inline float getY(int pointerIndex) const 0573 + { 0574 + return AMotionEvent_getY(m_motionEvent, pointerIndex); 0575 + } 0576 + 0577 + inline float getY() const { return getY(0); } 0578 + 0579 + inline float getPressure(int pointerIndex) const 0580 + { 0581 + return AMotionEvent_getPressure(m_motionEvent, pointerIndex); 0582 + } 0583 + 0584 + inline float getPressure() const { return getPressure(0); } 0585 + 0586 + inline int32_t getButtonState() const { return AMotionEvent_getButtonState(m_motionEvent); } 0587 + 0588 + inline int32_t getMetaState() const { return AMotionEvent_getMetaState(m_motionEvent); } 0589 + 0590 + size_t getPointerCount() const { return AMotionEvent_getPointerCount(m_motionEvent); } 0591 + 0592 + int32_t getPointerId(size_t pointerIndex) const 0593 + { 0594 + return AMotionEvent_getPointerId(m_motionEvent, pointerIndex); 0595 + } 0596 + 0597 + float getOrientation(size_t pointerIndex) 0598 + { 0599 + return AMotionEvent_getOrientation(m_motionEvent, pointerIndex); 0600 + } 0601 + 0602 + float getTouchMajor(size_t pointerIndex) 0603 + { 0604 + return AMotionEvent_getTouchMajor(m_motionEvent, pointerIndex); 0605 + } 0606 + 0607 + float getTouchMinor(size_t pointerIndex) 0608 + { 0609 + return AMotionEvent_getTouchMinor(m_motionEvent, pointerIndex); 0610 + } 0611 + 0612 +private: 0613 + AInputEvent *m_motionEvent; 0614 + 0615 + const static long NS_PER_MS = 1000000; 0616 +}; 0617 + 0618 +#endif // __MOTIONEVENTWRAPPER_H_ 0619 diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp 0620 index a4bb8ae1a7..5c1d050dba 100644 0621 --- a/src/plugins/platforms/android/androidjniinput.cpp 0622 +++ b/src/plugins/platforms/android/androidjniinput.cpp 0623 @@ -47,6 +47,7 @@ 0624 #include "qandroidplatformintegration.h" 0625 #include "qandroidplatformwindow.h" 0626 #include "qandroidplatformwindowmanager.h" 0627 +#include "MotionEventWrapper.h" 0628 0629 #include <qpa/qwindowsysteminterface.h> 0630 #include <QTouchEvent> 0631 @@ -69,6 +70,8 @@ namespace QtAndroidInput 0632 static QRect m_softwareKeyboardRect; 0633 0634 static QList<QWindowSystemInterface::TouchPoint> m_touchPoints; 0635 + static QHash<int, QPointF> m_lastTouchPointsPos; 0636 + static QPoint m_mouseDownPos; 0637 0638 static QPointer<QWindow> m_mouseGrabber; 0639 static int m_mouseActionButton; 0640 @@ -150,7 +153,8 @@ namespace QtAndroidInput 0641 // other window is clicked. Otherwise Qt goes in an undefined state. I'm not 100% sure 0642 // though. 0643 if (focusWindow && (focusWindow->type() == Qt::Popup || focusWindow->type() == Qt::ToolTip)) { 0644 - focusWindow->hide(); 0645 + QMetaObject::invokeMethod( 0646 + qApp, [focusWindow]() { focusWindow->hide(); }, Qt::BlockingQueuedConnection); 0647 } 0648 0649 QAndroidPlatformWindowManager *wm = dynamic_cast<QAndroidPlatformWindowManager *>(window); 0650 @@ -160,13 +164,13 @@ namespace QtAndroidInput 0651 window = wm->realWindow()->window(); 0652 } 0653 if (window && !QGuiApplicationPrivate::instance()->isWindowBlocked(window)) { 0654 - window->raise(); 0655 + QMetaObject::invokeMethod( 0656 + qApp, [window]() { window->raise(); }, Qt::BlockingQueuedConnection); 0657 QWindowSystemInterface::handleWindowActivated(window, Qt::ActiveWindowFocusReason); 0658 } 0659 } 0660 0661 - static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, 0662 - jint x, jint y, jint modifier, jint actionButton) 0663 + static void mouseDown(float x, float y, jint modifier, jint actionButton) 0664 { 0665 if (m_ignoreMouseEvents) 0666 return; 0667 @@ -189,7 +193,7 @@ namespace QtAndroidInput 0668 mapAndroidModifiers(modifier)); 0669 } 0670 0671 - static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint modifiers) 0672 + static void mouseUp(float x, float y, jint modifiers) 0673 { 0674 QPoint globalPos(x,y); 0675 QWindow *tlw = m_mouseGrabber.data(); 0676 @@ -207,7 +211,7 @@ namespace QtAndroidInput 0677 m_mouseGrabber = 0; 0678 } 0679 0680 - static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint modifier) 0681 + static void mouseMove(float x, float y, jint modifier) 0682 { 0683 if (m_ignoreMouseEvents) 0684 return; 0685 @@ -229,7 +233,7 @@ namespace QtAndroidInput 0686 mapAndroidModifiers(modifier)); 0687 } 0688 0689 - static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta) 0690 + static void mouseWheel(int x, int y, float hdelta, float vdelta) 0691 { 0692 if (m_ignoreMouseEvents) 0693 return; 0694 @@ -290,38 +294,23 @@ namespace QtAndroidInput 0695 Qt::MouseButtons(Qt::NoButton)); 0696 } 0697 0698 - static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/) 0699 + static void touchBegin() 0700 { 0701 m_touchPoints.clear(); 0702 } 0703 0704 - static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean primary, jint x, jint y, 0705 - jfloat major, jfloat minor, jfloat rotation, jfloat pressure) 0706 + static void touchAdd(int id, Qt::TouchPointState state, bool primary, int x, int y, 0707 + float major, float minor, float rotation, float pressure) 0708 { 0709 - Qt::TouchPointState state = Qt::TouchPointStationary; 0710 - switch (action) { 0711 - case 0: 0712 - state = Qt::TouchPointPressed; 0713 - break; 0714 - case 1: 0715 - state = Qt::TouchPointMoved; 0716 - break; 0717 - case 2: 0718 - state = Qt::TouchPointStationary; 0719 - break; 0720 - case 3: 0721 - state = Qt::TouchPointReleased; 0722 - break; 0723 - } 0724 - 0725 const int dw = desktopWidthPixels(); 0726 const int dh = desktopHeightPixels(); 0727 QWindowSystemInterface::TouchPoint touchPoint; 0728 touchPoint.id = id; 0729 touchPoint.pressure = pressure; 0730 touchPoint.rotation = qRadiansToDegrees(rotation); 0731 - touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh)); 0732 + touchPoint.normalPosition = QPointF(double(x) / dw, double(y) / dh); 0733 touchPoint.state = state; 0734 + 0735 touchPoint.area = QRectF(x - double(minor), 0736 y - double(major), 0737 double(minor * 2), 0738 @@ -342,7 +331,7 @@ namespace QtAndroidInput 0739 } 0740 } 0741 0742 - static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint action) 0743 + static void touchEnd(int action) 0744 { 0745 if (m_touchPoints.isEmpty()) 0746 return; 0747 @@ -374,9 +363,13 @@ namespace QtAndroidInput 0748 QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints); 0749 break; 0750 } 0751 + 0752 + if (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) { 0753 + m_lastTouchPointsPos.clear(); 0754 + } 0755 } 0756 0757 - static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/) 0758 + static bool isTabletEventSupported() 0759 { 0760 #if QT_CONFIG(tabletevent) 0761 return true; 0762 @@ -385,9 +378,9 @@ namespace QtAndroidInput 0763 #endif // QT_CONFIG(tabletevent) 0764 } 0765 0766 - static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action, 0767 - jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure, jfloat tiltX, jfloat tiltY, jfloat rotation, 0768 - jint modifiers) 0769 + static void tabletEvent(int deviceId, long time, int action, int pointerType, int buttonState, 0770 + float x, float y, float pressure, float tiltX, float tiltY, 0771 + float rotation, int modifiers) 0772 { 0773 #if QT_CONFIG(tabletevent) 0774 QPointF globalPosF(x, y); 0775 @@ -403,21 +396,6 @@ namespace QtAndroidInput 0776 localPos = platformWindow ? platformWindow->mapFromGlobal(globalPos) : globalPosF; 0777 } 0778 0779 - // Galaxy Note with plain Android: 0780 - // 0 1 0 stylus press 0781 - // 2 1 0 stylus drag 0782 - // 1 1 0 stylus release 0783 - // 0 1 2 stylus press with side-button held 0784 - // 2 1 2 stylus drag with side-button held 0785 - // 1 1 2 stylus release with side-button held 0786 - // Galaxy Note 4 with Samsung firmware: 0787 - // 0 1 0 stylus press 0788 - // 2 1 0 stylus drag 0789 - // 1 1 0 stylus release 0790 - // 211 1 2 stylus press with side-button held 0791 - // 213 1 2 stylus drag with side-button held 0792 - // 212 1 2 stylus release with side-button held 0793 - // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed 0794 Qt::MouseButtons buttons = Qt::NoButton; 0795 switch (action) { 0796 case AMOTION_EVENT_ACTION_UP: 0797 @@ -451,6 +429,155 @@ namespace QtAndroidInput 0798 #endif // QT_CONFIG(tabletevent) 0799 } 0800 0801 + static AInputEvent *getMotionEventFromJava(JNIEnv *env, jobject motionEventJava) 0802 + { 0803 + // From AOSP's AMotionEvent implementation 0804 + return reinterpret_cast<AInputEvent *>( 0805 + env->GetLongField(motionEventJava, QtAndroid::motionEventNativePtr())); 0806 + } 0807 + 0808 + static QTabletEvent::PointerType getPointerType(int toolType) 0809 + { 0810 + if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) { 0811 + return QTabletEvent::Pen; 0812 + } else if (toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { 0813 + return QTabletEvent::Eraser; 0814 + } 0815 + return QTabletEvent::UnknownPointer; 0816 + } 0817 + 0818 + static Qt::TouchPointState getTouchPointStateFromAction(const MotionEventWrapper &event, 0819 + int pointerIndex) 0820 + { 0821 + int actionMasked = event.getActionMasked(); 0822 + int actionIndex = event.getActionIndex(); 0823 + 0824 + if (actionMasked == AMOTION_EVENT_ACTION_DOWN 0825 + || (actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN && pointerIndex == actionIndex)) { 0826 + return Qt::TouchPointPressed; 0827 + } else if (actionMasked == AMOTION_EVENT_ACTION_UP 0828 + || (actionMasked == AMOTION_EVENT_ACTION_POINTER_UP 0829 + && pointerIndex == actionIndex)) { 0830 + return Qt::TouchPointReleased; 0831 + } else { 0832 + const int dw = desktopWidthPixels(); 0833 + const int dh = desktopHeightPixels(); 0834 + 0835 + const int id = event.getPointerId(pointerIndex); 0836 + QPointF lastNormalPosition; 0837 + if (m_lastTouchPointsPos.contains(id)) { 0838 + lastNormalPosition = m_lastTouchPointsPos[id]; 0839 + } 0840 + const QPointF currentNormalPosition = 0841 + QPointF(double(event.getX()) / dw, double(event.getX()) / dh); 0842 + 0843 + m_lastTouchPointsPos[id] = currentNormalPosition; 0844 + 0845 + return (currentNormalPosition == lastNormalPosition) ? Qt::TouchPointStationary 0846 + : Qt::TouchPointMoved; 0847 + } 0848 + } 0849 + 0850 + static void dispatchMotionEvent(JNIEnv *env, jobject /*thiz*/, jint /*winId*/, 0851 + jboolean isTouchEvent, jobject motionEventJava) 0852 + { 0853 + static const bool tabletEventSupported = isTabletEventSupported(); 0854 + 0855 + AInputEvent *motionEvent = getMotionEventFromJava(env, motionEventJava); 0856 + MotionEventWrapper ev(motionEvent); 0857 + if (isTouchEvent) { 0858 + const QTabletEvent::PointerType pointerType = getPointerType(ev.getToolType(0)); 0859 + if (tabletEventSupported && pointerType != QTabletEvent::UnknownPointer) { 0860 + const size_t historySize = ev.getHistorySize(); 0861 + for (size_t historicalIndex = 0; historicalIndex < historySize; ++historicalIndex) { 0862 + const float tiltRot = 0863 + ev.getHistoricalAxisValue(AMOTION_EVENT_AXIS_TILT, 0, historicalIndex); 0864 + const float orientation = ev.getHistoricalAxisValue( 0865 + AMOTION_EVENT_AXIS_ORIENTATION, 0, historicalIndex); 0866 + 0867 + const float tiltX = qRadiansToDegrees(-sin(orientation) * tiltRot); 0868 + const float tiltY = qRadiansToDegrees(cos(orientation) * tiltRot); 0869 + 0870 + const float orientationDegrees = qRadiansToDegrees(orientation); 0871 + 0872 + tabletEvent(ev.getDeviceId(), ev.getHistoricalEventTimeMs(historicalIndex), 0873 + ev.getActionMasked(), pointerType, ev.getButtonState(), 0874 + ev.getHistoricalX(historicalIndex), 0875 + ev.getHistoricalY(historicalIndex), 0876 + ev.getHistoricalPressure(historicalIndex), tiltX, tiltY, 0877 + orientationDegrees, ev.getMetaState()); 0878 + } 0879 + 0880 + const float tiltRot = ev.getAxisValue(AMOTION_EVENT_AXIS_TILT); 0881 + const float orientation = ev.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); 0882 + 0883 + const float tiltX = qRadiansToDegrees(-sin(orientation) * tiltRot); 0884 + const float tiltY = qRadiansToDegrees(cos(orientation) * tiltRot); 0885 + 0886 + const float orientationDegrees = qRadiansToDegrees(orientation); 0887 + 0888 + tabletEvent(ev.getDeviceId(), ev.getEventTimeMs(), ev.getActionMasked(), 0889 + pointerType, ev.getButtonState(), ev.getX(), ev.getY(), 0890 + ev.getPressure(), tiltX, tiltY, orientationDegrees, ev.getMetaState()); 0891 + } else { 0892 + const int historySize = ev.getHistorySize(); 0893 + // batched ones 0894 + for (int historicalIndex = 0; historicalIndex < historySize; historicalIndex++) { 0895 + touchBegin(); 0896 + for (size_t i = 0; i < ev.getPointerCount(); ++i) { 0897 + touchAdd(ev.getPointerId(i), getTouchPointStateFromAction(ev, i), i == 0, 0898 + (int)ev.getHistoricalX(i, historicalIndex), 0899 + (int)ev.getHistoricalY(i, historicalIndex), 0900 + ev.getHistoricalTouchMajor(i, historicalIndex), 0901 + ev.getHistoricalTouchMinor(i, historicalIndex), 0902 + ev.getHistoricalOrientation(i, historicalIndex), 0903 + ev.getHistoricalPressure(i, historicalIndex)); 0904 + } 0905 + touchEnd(ev.getAction()); 0906 + } 0907 + touchBegin(); 0908 + for (size_t i = 0; i < ev.getPointerCount(); ++i) { 0909 + touchAdd(ev.getPointerId(i), getTouchPointStateFromAction(ev, i), i == 0, 0910 + (int)ev.getX(i), (int)ev.getY(i), ev.getTouchMajor(i), 0911 + ev.getTouchMinor(i), ev.getOrientation(i), ev.getPressure(i)); 0912 + } 0913 + touchEnd(ev.getAction()); 0914 + } 0915 + } else { 0916 + switch (ev.getActionMasked()) { 0917 + case AMOTION_EVENT_ACTION_UP: 0918 + mouseUp((int)ev.getX(), (int)ev.getY(), ev.getMetaState()); 0919 + break; 0920 + 0921 + case AMOTION_EVENT_ACTION_DOWN: 0922 + mouseDown((int)ev.getX(), (int)ev.getY(), ev.getMetaState(), ev.getButtonState()); 0923 + m_mouseDownPos.rx() = (int)ev.getX(); 0924 + m_mouseDownPos.ry() = (int)ev.getY(); 0925 + break; 0926 + 0927 + case AMOTION_EVENT_ACTION_HOVER_MOVE: 0928 + case AMOTION_EVENT_ACTION_MOVE: 0929 + if (ev.getToolType(0) == AMOTION_EVENT_TOOL_TYPE_MOUSE) { 0930 + mouseMove((int)ev.getX(), (int)ev.getY(), ev.getMetaState()); 0931 + } else { 0932 + QPoint delta = QPoint(ev.getX(), ev.getY()) - m_mouseDownPos; 0933 + if (fabs(delta.x()) > 5 || fabs(delta.y()) > 5) { 0934 + mouseMove((int)ev.getX(), (int)ev.getY(), ev.getMetaState()); 0935 + m_mouseDownPos.rx() = (int)ev.getX(); 0936 + m_mouseDownPos.ry() = (int)ev.getY(); 0937 + } 0938 + } 0939 + break; 0940 + 0941 + case AMOTION_EVENT_ACTION_SCROLL: 0942 + mouseWheel((int)ev.getX(), (int)ev.getY(), 0943 + ev.getAxisValue(AMOTION_EVENT_AXIS_HSCROLL), 0944 + ev.getAxisValue(AMOTION_EVENT_AXIS_VSCROLL)); 0945 + break; 0946 + } 0947 + } 0948 + } 0949 + 0950 static int mapAndroidKey(int key) 0951 { 0952 // 0--9 0x00000007 -- 0x00000010 0953 @@ -942,35 +1069,37 @@ namespace QtAndroidInput 0954 0955 } 0956 0957 - static JNINativeMethod methods[] = { 0958 - {"touchBegin","(I)V",(void*)touchBegin}, 0959 - {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd}, 0960 - {"touchEnd","(II)V",(void*)touchEnd}, 0961 - {"mouseDown", "(IIIII)V", (void *)mouseDown}, 0962 - {"mouseUp", "(IIII)V", (void *)mouseUp}, 0963 - {"mouseMove", "(IIII)V", (void *)mouseMove}, 0964 - {"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, 0965 - {"longPress", "(III)V", (void *)longPress}, 0966 - {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported}, 0967 - {"tabletEvent", "(IIJIIIFFFFFFI)V", (void *)tabletEvent}, 0968 + const static JNINativeMethod inputDispatcherMethods[] = { 0969 + {"dispatchMotionEvent", "(IZLandroid/view/MotionEvent;)V", (void *)dispatchMotionEvent}, 0970 + {"longPress", "(III)V", (void *)longPress}}; 0971 + 0972 + const static JNINativeMethod qtNativeMethods[] = { 0973 {"keyDown", "(IIIZ)V", (void *)keyDown}, 0974 {"keyUp", "(IIIZ)V", (void *)keyUp}, 0975 {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}, 0976 {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged}, 0977 - {"handleLocationChanged", "(III)V", (void *)handleLocationChanged} 0978 - }; 0979 + {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}}; 0980 0981 bool registerNatives(JNIEnv *env) 0982 { 0983 jclass appClass = QtAndroid::applicationClass(); 0984 + if (env->RegisterNatives(appClass, qtNativeMethods, 0985 + sizeof(qtNativeMethods) / sizeof(qtNativeMethods[0])) 0986 + < 0) { 0987 + __android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed"); 0988 + return false; 0989 + } 0990 0991 - if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { 0992 - __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); 0993 + jclass dispatcherClass = QtAndroid::inputDispatcherClass(); 0994 + if (env->RegisterNatives(dispatcherClass, inputDispatcherMethods, 0995 + sizeof(inputDispatcherMethods) / sizeof(inputDispatcherMethods[0])) 0996 + < 0) { 0997 + __android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed"); 0998 return false; 0999 } 1000 1001 return true; 1002 } 1003 -} 1004 + } // namespace QtAndroidInput 1005 1006 QT_END_NAMESPACE 1007 diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp 1008 index a60b121979..526eb19a3e 100644 1009 --- a/src/plugins/platforms/android/androidjnimain.cpp 1010 +++ b/src/plugins/platforms/android/androidjnimain.cpp 1011 @@ -83,6 +83,8 @@ static jmethodID m_createSurfaceMethodID = nullptr; 1012 static jobject m_serviceObject = nullptr; 1013 static jmethodID m_setSurfaceGeometryMethodID = nullptr; 1014 static jmethodID m_destroySurfaceMethodID = nullptr; 1015 +static jclass m_inputDispatcherClass = nullptr; 1016 +static jfieldID m_motionEventNativePtrField; 1017 1018 static int m_pendingApplicationState = -1; 1019 static QBasicMutex m_platformMutex; 1020 @@ -190,6 +192,16 @@ namespace QtAndroid 1021 return m_applicationClass; 1022 } 1023 1024 + jclass inputDispatcherClass() 1025 + { 1026 + return m_inputDispatcherClass; 1027 + } 1028 + 1029 + jfieldID motionEventNativePtr() 1030 + { 1031 + return m_motionEventNativePtrField; 1032 + } 1033 + 1034 jobject activity() 1035 { 1036 return m_activityObject; 1037 @@ -865,6 +877,12 @@ static int registerNatives(JNIEnv *env) 1038 m_bitmapDrawableClass, 1039 "<init>", 1040 "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V"); 1041 + 1042 + FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtInputEventDispatcher"); 1043 + m_inputDispatcherClass = static_cast<jclass>(env->NewGlobalRef(clazz)); 1044 + 1045 + FIND_AND_CHECK_CLASS("android/view/MotionEvent"); 1046 + GET_AND_CHECK_FIELD(m_motionEventNativePtrField, clazz, "mNativePtr", "J"); 1047 } 1048 1049 return JNI_TRUE; 1050 diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h 1051 index 08f1d50fe3..c04e903ff7 100644 1052 --- a/src/plugins/platforms/android/androidjnimain.h 1053 +++ b/src/plugins/platforms/android/androidjnimain.h 1054 @@ -84,6 +84,8 @@ namespace QtAndroid 1055 JavaVM *javaVM(); 1056 AAssetManager *assetManager(); 1057 jclass applicationClass(); 1058 + jclass inputDispatcherClass(); 1059 + jfieldID motionEventNativePtr(); 1060 jobject activity(); 1061 jobject service(); 1062 1063 -- 1064 2.37.3 1065