diff --git a/ChangeLog b/ChangeLog index baffb175d..0c4cee3c2 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 3b6d7c449..52e3d4d3a 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 89fc0e1d9..95c9f8a94 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 27644d47a..26cc0b63d 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 97c425e07..ae06305b8 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(),