From eb17fca4f8f07d2badf8ffe56a526b71524340e1 Mon Sep 17 00:00:00 2001 From: askmeaboutloom Date: Sun, 24 Nov 2024 00:51:58 +0100 Subject: [PATCH] Ignore spontaneous tablet events in canvas instead Rather than doing it with an event filter, because that apparently doesn't work properly and still lets spontaneous events through. They're now ignored in the canvas controller/canvas view instead. --- ChangeLog | 1 + src/desktop/scene/canvasview.cpp | 34 +++++++++++----- src/desktop/tabletinput.cpp | 57 ++++----------------------- src/desktop/tabletinput.h | 10 +++++ src/desktop/view/canvascontroller.cpp | 42 ++++++++++++++------ 5 files changed, 74 insertions(+), 70 deletions(-) diff --git a/ChangeLog b/ChangeLog index baffb175d5..0c4cee3c25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ Unreleased Version 2.2.2-pre * Fix: Don't carry over HUD button presses to dock UI in small screen mode. Thanks Meru for reporting. * Feature: Make list action buttons in settings dialog clearer, adding an edit button for canvas shortcuts. Thanks Maffi for suggesting. * Fix: Work around broken transparency when copying images between canvases on Wayland. Thanks Absolute Goober for reporting. + * Fix: Properly ignore system tablet events when using KisTablet drivers on Windows. Thanks Doc for reporting. 2024-11-06 Version 2.2.2-beta.4 * Fix: Solve rendering glitches with selection outlines that happen on some systems. Thanks xxxx for reporting. diff --git a/src/desktop/scene/canvasview.cpp b/src/desktop/scene/canvasview.cpp index 3b6d7c4492..52e3d4d3a2 100644 --- a/src/desktop/scene/canvasview.cpp +++ b/src/desktop/scene/canvasview.cpp @@ -2006,16 +2006,21 @@ bool CanvasView::viewportEvent(QEvent *event) QTabletEvent *tabev = static_cast(event); const auto tabPos = compat::tabPosF(*tabev); Qt::KeyboardModifiers modifiers = getTabletModifiers(tabev); + bool spontaneous = tabev->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_press spontaneous=%d x=%f y=%f pressure=%f xtilt=%d " "ytilt=%d rotation=%f buttons=0x%x modifiers=0x%x pendown=%d " - "touching=%d effectivemodifiers=0x%u", - tabev->spontaneous(), tabPos.x(), tabPos.y(), tabev->pressure(), + "touching=%d effectivemodifiers=0x%u ignore=%d", + spontaneous, tabPos.x(), tabPos.y(), tabev->pressure(), compat::cast_6(tabev->xTilt()), compat::cast_6(tabev->yTilt()), qDegreesToRadians(tabev->rotation()), unsigned(tabev->buttons()), unsigned(tabev->modifiers()), m_pendown, m_touch->isTouching(), - unsigned(modifiers)); + unsigned(modifiers), int(ignore)); + if(ignore) { + return true; + } Qt::MouseButton button; bool eraserOverride; @@ -2057,16 +2062,21 @@ bool CanvasView::viewportEvent(QEvent *event) const auto tabPos = compat::tabPosF(*tabev); Qt::KeyboardModifiers modifiers = getTabletModifiers(tabev); Qt::MouseButtons buttons = tabev->buttons(); + bool spontaneous = tabev->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_move spontaneous=%d x=%f y=%f pressure=%f xtilt=%d " "ytilt=%d rotation=%f buttons=0x%x modifiers=0x%x pendown=%d " - "touching=%d effectivemodifiers=0x%u", - tabev->spontaneous(), tabPos.x(), tabPos.y(), tabev->pressure(), + "touching=%d effectivemodifiers=0x%u ignore=%d", + int(spontaneous), tabPos.x(), tabPos.y(), tabev->pressure(), compat::cast_6(tabev->xTilt()), compat::cast_6(tabev->yTilt()), qDegreesToRadians(tabev->rotation()), unsigned(buttons), unsigned(tabev->modifiers()), m_pendown, m_touch->isTouching(), - unsigned(modifiers)); + unsigned(modifiers), int(ignore)); + if(ignore) { + return true; + } if(!tabletinput::passPenEvents()) { tabev->accept(); @@ -2091,12 +2101,18 @@ bool CanvasView::viewportEvent(QEvent *event) QTabletEvent *tabev = static_cast(event); const auto tabPos = compat::tabPosF(*tabev); Qt::KeyboardModifiers modifiers = getTabletModifiers(tabev); + bool spontaneous = tabev->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_release spontaneous=%d x=%f y=%f buttons=0x%x pendown=%d " - "touching=%d effectivemodifiers=0x%u", - tabev->spontaneous(), tabPos.x(), tabPos.y(), + "touching=%d effectivemodifiers=0x%u ignore=%d", + int(spontaneous), tabPos.x(), tabPos.y(), unsigned(tabev->buttons()), m_pendown, m_touch->isTouching(), - unsigned(modifiers)); + unsigned(modifiers), int(ignore)); + if(ignore) { + return true; + } + updateCursorPos(tabPos.toPoint()); if(!tabletinput::passPenEvents()) { tabev->accept(); diff --git a/src/desktop/tabletinput.cpp b/src/desktop/tabletinput.cpp index 89fc0e1d9c..95c9f8a94f 100644 --- a/src/desktop/tabletinput.cpp +++ b/src/desktop/tabletinput.cpp @@ -20,45 +20,12 @@ static Mode currentMode = Mode::Uninitialized; #ifdef Q_OS_WIN -class SpontaneousTabletEventFilter final : public QObject { -public: - explicit SpontaneousTabletEventFilter(QObject *parent) - : QObject{parent} - { - } - -protected: - bool eventFilter(QObject *watched, QEvent *event) override final - { - switch(event->type()) { - case QEvent::TabletEnterProximity: - case QEvent::TabletLeaveProximity: - case QEvent::TabletMove: - case QEvent::TabletPress: - case QEvent::TabletRelease: - // KisTablet uses QApplication::sendEvent, which means its events - // are never set to be spontaneous. We use that to filter out Qt's - // own tablet events, which in turn are always spontaneous. - if(event->spontaneous()) { - return false; - } - [[fallthrough]]; - default: - return QObject::eventFilter(watched, event); - } - } -}; - static KisTabletSupportWin8 *kisTabletSupportWin8; -static SpontaneousTabletEventFilter *spontaneousTabletEventFilter; +static bool shouldPassPenEvents = true; static void resetKisTablet(DrawpileApp &app) { - if(spontaneousTabletEventFilter) { - app.removeEventFilter(spontaneousTabletEventFilter); - delete spontaneousTabletEventFilter; - spontaneousTabletEventFilter = nullptr; - } + shouldPassPenEvents = true; if(kisTabletSupportWin8) { app.removeNativeEventFilter(kisTabletSupportWin8); delete kisTabletSupportWin8; @@ -67,17 +34,11 @@ static void resetKisTablet(DrawpileApp &app) KisTabletSupportWin::quit(); } -static void installSpontaneousTabletEventFilter(DrawpileApp &app) -{ - spontaneousTabletEventFilter = new SpontaneousTabletEventFilter{&app}; - app.installEventFilter(spontaneousTabletEventFilter); -} - static void enableKisTabletWinink(DrawpileApp &app) { kisTabletSupportWin8 = new KisTabletSupportWin8; if(kisTabletSupportWin8->init()) { - installSpontaneousTabletEventFilter(app); + shouldPassPenEvents = false; app.installNativeEventFilter(kisTabletSupportWin8); currentMode = Mode::KisTabletWinink; } else { @@ -87,10 +48,10 @@ static void enableKisTabletWinink(DrawpileApp &app) } } -static void enableKisTabletWintab(DrawpileApp &app, bool relativePenModeHack) +static void enableKisTabletWintab(bool relativePenModeHack) { if(KisTabletSupportWin::init()) { - installSpontaneousTabletEventFilter(app); + shouldPassPenEvents = false; KisTabletSupportWin::enableRelativePenModeHack(relativePenModeHack); if(relativePenModeHack) { currentMode = Mode::KisTabletWintabRelativePenHack; @@ -148,10 +109,10 @@ void init(DrawpileApp &app) enableKisTabletWinink(app); break; case Mode::KisTabletWintab: - enableKisTabletWintab(app, false); + enableKisTabletWintab(false); break; case Mode::KisTabletWintabRelativePenHack: - enableKisTabletWintab(app, true); + enableKisTabletWintab(true); break; # if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) case Mode::Qt5: @@ -201,9 +162,7 @@ const char *current() #ifdef Q_OS_WIN bool passPenEvents() { - // The spontaneous event filter is installed if and only if a KisTablet - // input mode is currently active. - return !spontaneousTabletEventFilter; + return shouldPassPenEvents; } #endif diff --git a/src/desktop/tabletinput.h b/src/desktop/tabletinput.h index 27644d47a0..26cc0b63de 100644 --- a/src/desktop/tabletinput.h +++ b/src/desktop/tabletinput.h @@ -53,11 +53,21 @@ const char *current(); // meaning we don't double up on them and the view acts properly. #ifdef Q_OS_WIN bool passPenEvents(); + +inline bool ignoreSpontaneous() +{ + return !passPenEvents(); +} #else constexpr bool passPenEvents() { return true; } + +constexpr bool ignoreSpontaneous() +{ + return false; +} #endif } diff --git a/src/desktop/view/canvascontroller.cpp b/src/desktop/view/canvascontroller.cpp index 97c425e07e..ae06305b81 100644 --- a/src/desktop/view/canvascontroller.cpp +++ b/src/desktop/view/canvascontroller.cpp @@ -4,6 +4,7 @@ extern "C" { } #include "desktop/main.h" #include "desktop/scene/toggleitem.h" +#include "desktop/tabletinput.h" #include "desktop/utils/qtguicompat.h" #include "desktop/utils/touchhandler.h" #include "desktop/view/canvascontroller.h" @@ -668,13 +669,19 @@ void CanvasController::handleTabletMove(QTabletEvent *event) qreal yTilt = event->yTilt(); Qt::KeyboardModifiers modifiers = getTabletModifiers(event); Qt::MouseButtons buttons = event->buttons(); + bool spontaneous = event->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_move spontaneous=%d x=%f y=%f pressure=%f xtilt=%f " "ytilt=%f rotation=%f buttons=0x%x modifiers=0x%x penstate=%d " - "touching=%d effectivemodifiers=0x%u", - int(event->spontaneous()), posf.x(), posf.y(), pressure, xTilt, - yTilt, rotation, unsigned(buttons), unsigned(event->modifiers()), - int(m_penState), int(m_touch->isTouching()), unsigned(modifiers)); + "touching=%d effectivemodifiers=0x%u ignore=%d", + int(spontaneous), posf.x(), posf.y(), pressure, xTilt, yTilt, + rotation, unsigned(buttons), unsigned(event->modifiers()), + int(m_penState), int(m_touch->isTouching()), unsigned(modifiers), + int(ignore)); + if(ignore) { + return; + } // Under Windows Ink, some tablets report bogus zero-pressure inputs. // We accept them so that they don't result in synthesized mouse events, @@ -704,13 +711,19 @@ void CanvasController::handleTabletPress(QTabletEvent *event) qreal xTilt = event->xTilt(); qreal yTilt = event->yTilt(); Qt::KeyboardModifiers modifiers = getTabletModifiers(event); + bool spontaneous = event->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_press spontaneous=%d x=%f y=%f pressure=%f xtilt=%f " "ytilt=%f rotation=%f buttons=0x%x modifiers=0x%x penstate=%d " - "touching=%d effectivemodifiers=0x%u", - int(event->spontaneous()), posf.x(), posf.y(), pressure, xTilt, - yTilt, rotation, unsigned(buttons), unsigned(event->modifiers()), - int(m_penState), int(m_touch->isTouching()), unsigned(modifiers)); + "touching=%d effectivemodifiers=0x%u ignore=%d", + int(spontaneous), posf.x(), posf.y(), pressure, xTilt, yTilt, + rotation, unsigned(buttons), unsigned(event->modifiers()), + int(m_penState), int(m_touch->isTouching()), unsigned(modifiers), + int(ignore)); + if(ignore) { + return; + } Qt::MouseButton button; bool eraserOverride; @@ -744,12 +757,17 @@ void CanvasController::handleTabletRelease(QTabletEvent *event) QPointF posf = tabletPosF(event); Qt::KeyboardModifiers modifiers = getTabletModifiers(event); + bool spontaneous = event->spontaneous(); + bool ignore = spontaneous && tabletinput::ignoreSpontaneous(); DP_EVENT_LOG( "tablet_release spontaneous=%d x=%f y=%f buttons=0x%x penstate=%d " - "touching=%d effectivemodifiers=0x%u", - int(event->spontaneous()), posf.x(), posf.y(), - unsigned(event->buttons()), int(m_penState), - int(m_touch->isTouching()), unsigned(modifiers)); + "touching=%d effectivemodifiers=0x%u ignore=%d", + int(spontaneous), posf.x(), posf.y(), unsigned(event->buttons()), + int(m_penState), int(m_touch->isTouching()), unsigned(modifiers), + int(ignore)); + if(ignore) { + return; + } penReleaseEvent( QDateTime::currentMSecsSinceEpoch(), posf, event->button(),