Paste P141

Synthesize mouse events with Windows API
ActivePublic

Authored by alvinhochun on Dec 4 2017, 7:16 PM.
diff --git a/libs/ui/input/wintab/kis_tablet_support_win8.cpp b/libs/ui/input/wintab/kis_tablet_support_win8.cpp
index 53bb88a43d..69367c43c0 100644
--- a/libs/ui/input/wintab/kis_tablet_support_win8.cpp
+++ b/libs/ui/input/wintab/kis_tablet_support_win8.cpp
@@ -38,6 +38,8 @@
#include <QWidget>
#include <QWindow>
+#include <private/qguiapplication_p.h>
+
#include <utility>
#include <kis_debug.h>
@@ -624,7 +626,77 @@ bool sendProximityTabletEvent(const QEvent::Type eventType, const POINTER_PEN_IN
return ev.isAccepted();
}
-bool sendPositionalTabletEvent(QWidget *target, const QEvent::Type eventType, const POINTER_PEN_INFO &penInfo, const PointerDeviceItem &device, const PenPointerItem &penPointerItem)
+bool synthesizeMouseEvent(const QWidget *target, const QTabletEvent &ev, const POINTER_PEN_INFO &penInfo)
+{
+ BOOL result = SetCursorPos(penInfo.pointerInfo.ptPixelLocationRaw.x, penInfo.pointerInfo.ptPixelLocationRaw.y);
+ if (!result) {
+ qDebug() << "SetCursorPos failed, err" << GetLastError();
+ // return true;
+ }
+ QPointF localPosF = ev.posF();
+ QWindow *window = target->windowHandle();
+ if (!window) {
+ QWidget *nativeParent = target->nativeParentWidget();
+ if (!nativeParent) {
+ warnTablet << "KisTabletSupportWin8::synthesizeMouseEvent target->nativeParentWidget is null!";
+ return false;
+ }
+ window = nativeParent->windowHandle();
+ const QPoint globalPos = ev.globalPosF().toPoint();
+ const QPoint localPos = nativeParent->mapFromGlobal(globalPos);
+ const QPointF delta = ev.globalPosF() - globalPos;
+ localPosF = localPos + delta;
+ }
+ QWindowSystemInterfacePrivate::MouseEvent fake(window, ev.timestamp(), localPosF,
+ ev.globalPosF(),ev.buttons(), ev.modifiers(), Qt::MouseEventSynthesizedByQt);
+ fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
+ QGuiApplicationPrivate::processMouseEvent(&fake);
+ // DWORD inputDataFlags = 0;
+ // switch (ev.type()) {
+ // case QEvent::TabletPress:
+ // switch (ev.button()) {
+ // case Qt::LeftButton:
+ // inputDataFlags = MOUSEEVENTF_LEFTDOWN;
+ // break;
+ // case Qt::RightButton:
+ // inputDataFlags = MOUSEEVENTF_RIGHTDOWN;
+ // break;
+ // default:
+ // return true;
+ // }
+ // break;
+ // case QEvent::TabletRelease:
+ // switch (ev.button()) {
+ // case Qt::LeftButton:
+ // inputDataFlags = MOUSEEVENTF_LEFTUP;
+ // break;
+ // case Qt::RightButton:
+ // inputDataFlags = MOUSEEVENTF_RIGHTUP;
+ // break;
+ // default:
+ // return true;
+ // }
+ // break;
+ // case QEvent::TabletMove:
+ // default:
+ // inputDataFlags = MOUSEEVENTF_MOVE;
+ // break;
+ // }
+ // INPUT inputData = {};
+ // inputData.type = INPUT_MOUSE;
+ // inputData.mi.dx = penInfo.pointerInfo.ptPixelLocationRaw.x;
+ // inputData.mi.dy = penInfo.pointerInfo.ptPixelLocationRaw.y;
+ // inputData.mi.dwFlags = inputDataFlags | MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE_NOCOALESCE;
+ // //inputData.mi.dwExtraInfo =
+ // UINT result2 = SendInput(1, &inputData, sizeof(inputData));
+ // if (result2 != 1) {
+ // qDebug() << "SendInput failed, err" << GetLastError();
+ // return true;
+ // }
+ return true;
+}
+
+bool sendPositionalTabletEvent(QWidget *target, const QEvent::Type eventType, const POINTER_PEN_INFO &penInfo, const PointerDeviceItem &device, const PenPointerItem &penPointerItem, const bool shouldSynthesizeMouseEvent = true)
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(
eventType == QEvent::TabletMove || eventType == QEvent::TabletPress || eventType == QEvent::TabletRelease,
@@ -634,7 +706,10 @@ bool sendPositionalTabletEvent(QWidget *target, const QEvent::Type eventType, co
ev.setAccepted(false);
ev.setTimestamp(penInfo.pointerInfo.dwTime);
QCoreApplication::sendEvent(target, &ev);
- return ev.isAccepted();
+ if (!shouldSynthesizeMouseEvent) {
+ return true;
+ }
+ return synthesizeMouseEvent(target, ev, penInfo);
}
bool handlePenEnterMsg(const POINTER_PEN_INFO &penInfo)
@@ -698,7 +773,7 @@ bool handlePenLeaveMsg(const POINTER_PEN_INFO &penInfo)
return false;
}
-bool handleSinglePenUpdate(PenPointerItem &penPointerItem, const POINTER_PEN_INFO &penInfo, const PointerDeviceItem &device)
+bool handleSinglePenUpdate(PenPointerItem &penPointerItem, const POINTER_PEN_INFO &penInfo, const PointerDeviceItem &device, const bool shouldSynthesizeMouseEvent)
{
QWidget *targetWidget;
if (penPointerItem.isCaptured()) {
@@ -745,7 +820,7 @@ bool handleSinglePenUpdate(PenPointerItem &penPointerItem, const POINTER_PEN_INF
// penPointerItem.activeWidget = targetWidget;
}
- bool handled = sendPositionalTabletEvent(targetWidget, QEvent::TabletMove, penInfo, device, penPointerItem);
+ bool handled = sendPositionalTabletEvent(targetWidget, QEvent::TabletMove, penInfo, device, penPointerItem, shouldSynthesizeMouseEvent);
if (!handled) {
// dbgTablet << "Target widget doesn't want pen events";
}
@@ -783,12 +858,13 @@ bool handlePenUpdateMsg(const POINTER_PEN_INFO &penInfo)
// The returned array is in reverse chronological order
const auto rbegin = penInfoArray.rbegin();
const auto rend = penInfoArray.rend();
+ const auto rlast = rend - 1; // Only synthesize mouse event for the last one
for (auto it = rbegin; it != rend; ++it) {
- handled |= handleSinglePenUpdate(*currentPointerIt, *it, *devIt); // Bitwise OR doesn't short circuit
+ handled |= handleSinglePenUpdate(*currentPointerIt, *it, *devIt, it == rlast); // Bitwise OR doesn't short circuit
}
return handled;
} else {
- return handleSinglePenUpdate(*currentPointerIt, penInfo, *devIt);
+ return handleSinglePenUpdate(*currentPointerIt, penInfo, *devIt, true);
}
}
@@ -979,9 +1055,7 @@ bool handlePointerMsg(const MSG &msg)
case WM_POINTERLEAVE:
return handlePenLeaveMsg(penInfo);
case WM_POINTERUPDATE:
- // HACK: Force further processing to force Windows to generate mouse move events
- handlePenUpdateMsg(penInfo);
- return false;
+ return handlePenUpdateMsg(penInfo);
case WM_POINTERCAPTURECHANGED:
// TODO: Should this event be handled?
dbgTablet << "FIXME: WM_POINTERCAPTURECHANGED isn't handled";