Krita Source Code Documentation
Loading...
Searching...
No Matches
KisInputEventsEater Class Reference

#include <KisInputEventsEater.h>

Public Types

enum  EventBlockingReason {
  NotBlocked = 0x0 , BlockedByTabletProximity = 0x01 , BlockedByTabletHover = 0x02 , BlockedByTabletPress = 0x04 ,
  BlockedByTouchPress = 0x08 , BlockedByNextPressSuppression = 0x10 , BlockedByButtonsWorkaround = 0x20 , BlockedBySynthetic = 0x40
}
 

Public Member Functions

void eatOneMousePress ()
 
bool eventFilter (QObject *target, QEvent *event)
 
 KisInputEventsEater ()
 
void notifyTabletEnterProximity ()
 
void notifyTabletLeaveProximity ()
 

Static Public Member Functions

template<class Event >
static void debugEvent (QEvent *event, EventBlockingReasons reasons=NotBlocked)
 

Private Member Functions

void debugEaterStateTransition (const QLatin1String &stateName, bool newValue, QEvent::Type eventType, const QLatin1String &comment=QLatin1String())
 

Private Attributes

bool activateSecondaryButtonsWorkaround {false}
 
bool eatOneMousePressEvent {false}
 
bool tabletIsHovering {false}
 
bool tabletIsInProximity {false}
 
bool tabletIsPressed {false}
 
bool touchIsActive {false}
 

Detailed Description

Definition at line 24 of file KisInputEventsEater.h.

Member Enumeration Documentation

◆ EventBlockingReason

Enumerator
NotBlocked 
BlockedByTabletProximity 
BlockedByTabletHover 
BlockedByTabletPress 
BlockedByTouchPress 
BlockedByNextPressSuppression 
BlockedByButtonsWorkaround 
BlockedBySynthetic 

Definition at line 27 of file KisInputEventsEater.h.

Constructor & Destructor Documentation

◆ KisInputEventsEater()

KisInputEventsEater::KisInputEventsEater ( )

Definition at line 75 of file KisInputEventsEater.cpp.

76{
77 KisConfig cfg(true);
78 activateSecondaryButtonsWorkaround = cfg.useRightMiddleTabletButtonWorkaround();
79}

References activateSecondaryButtonsWorkaround, and KisConfig::useRightMiddleTabletButtonWorkaround().

Member Function Documentation

◆ debugEaterStateTransition()

void KisInputEventsEater::debugEaterStateTransition ( const QLatin1String & stateName,
bool newValue,
QEvent::Type eventType,
const QLatin1String & comment = QLatin1String() )
private

Definition at line 81 of file KisInputEventsEater.cpp.

82{
83 if (comment.isEmpty()) {
84 dbgInputEater.noquote().nospace() << stateName << " <- " << newValue << " by " << eventType;
85 } else {
86 dbgInputEater.noquote().nospace() << stateName << " <- " << newValue << " by " << eventType << " (" << comment << ")";
87 }
88}
#define dbgInputEater
Definition kis_debug.h:67

References dbgInputEater.

◆ debugEvent()

template<class Event >
static void KisInputEventsEater::debugEvent ( QEvent * event,
EventBlockingReasons reasons = NotBlocked )
inlinestatic

Definition at line 50 of file KisInputEventsEater.h.

51 {
53 return;
54
55 QString reasonsString;
56
57 if (reasons.testFlag(BlockedByTabletProximity)) {
58 reasonsString += "Prx";
59 }
60
61 if (reasons.testFlag(BlockedByTabletHover)) {
62 reasonsString += "Hov";
63 }
64
65 if (reasons.testFlag(BlockedByTabletPress)) {
66 reasonsString += "Prs";
67 }
68
69 if (reasons.testFlag(BlockedByNextPressSuppression)) {
70 reasonsString += "Nxt";
71 }
72
73 if (reasons.testFlag(BlockedByTouchPress)) {
74 reasonsString += "Tch";
75 }
76
77 if (reasons.testFlag(BlockedBySynthetic)) {
78 reasonsString += "Syn";
79 }
80
81 QString msg1 = QString("[%1] ").arg(reasonsString, 15);
82 Event *specificEvent = static_cast<Event *>(event);
83 dbgTablet << KisTabletDebugger::instance()->eventToString(*specificEvent, msg1);
84 }
static bool debugEnabled()
Linethickness.
QString eventToString(const QMouseEvent &ev, const QString &prefix)
static KisTabletDebugger * instance()
#define dbgTablet
Definition kis_debug.h:62

References dbgTablet, debugEnabled(), KisTabletDebugger::eventToString(), and KisTabletDebugger::instance().

◆ eatOneMousePress()

void KisInputEventsEater::eatOneMousePress ( )

Definition at line 350 of file KisInputEventsEater.cpp.

351{
352 // Enable on other platforms if getting full-pressure splotches
354}

References eatOneMousePressEvent.

◆ eventFilter()

bool KisInputEventsEater::eventFilter ( QObject * target,
QEvent * event )

Tablet events have higher priority over the touch events, so, if a touch has been started before the tablet stroke, then TouchUpdate events will no cause the EventEater to perform state transitions to the tablet state (on Windows, the streams of touch and tablet event come in parallel independently).

Please note that the actual cancellation of the already started touch action is performed inside KisShortcutMatcher, not in the event eater. Here we just allow all the TouchUpdate events pass firther and block synthesized mouse events only.

Definition at line 89 of file KisInputEventsEater.cpp.

90{
91 using namespace Qt::StringLiterals;
92
93 Q_UNUSED(target);
94
95 {
96 // handle `newTabletIsHovering` and `tabletIsPressed` state transitions
97
98 if (isTabletEventType(event->type())) {
99
100 QTabletEvent *ev = static_cast<QTabletEvent*>(event);
101 const bool newTabletIsHovering = ev->buttons() == Qt::NoButton;
102 const bool newTabletIsPressed = !newTabletIsHovering;
103
104 if (newTabletIsHovering != tabletIsHovering) {
105 tabletIsHovering = newTabletIsHovering;
106 debugEaterStateTransition("tabletIsHovering"_L1, newTabletIsHovering, event->type());
107 }
108
109 if (newTabletIsPressed != tabletIsPressed) {
110 tabletIsPressed = newTabletIsPressed;
111 debugEaterStateTransition("tabletIsPressed"_L1, newTabletIsPressed, event->type());
112 }
113
114#ifdef KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND
115 if (!tabletIsInProximity && !missingTabletProximityEventsWorkaround) {
116 warnInputEater << "WARNING: received a tablet event while the tablet is not in proximity! Activating a workaround...";
117 missingTabletProximityEventsWorkaround = MissingTabletProximityEnterWorkaround();
118 } else if (tabletIsInProximity && missingTabletProximityEventsWorkaround) {
119 warnInputEater << "WARNING: received a delayed tablet proximity event, disabling the workaround...";
120 missingTabletProximityEventsWorkaround = std::nullopt;
121 } else if (missingTabletProximityEventsWorkaround) {
122 missingTabletProximityEventsWorkaround->notifyTabletEventArrived();
123 }
124#endif /* KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND */
125 }
126
127#ifdef KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND
128 if (missingTabletProximityEventsWorkaround && !tabletIsPressed && isMouseEventType(event->type())) {
129 missingTabletProximityEventsWorkaround->notifyMouseEventArrived();
130 if (missingTabletProximityEventsWorkaround->shouldForgetAboutTabletInProximity()) {
131 if (tabletIsHovering) {
132 tabletIsHovering = false;
133 debugEaterStateTransition("tabletIsHovering"_L1, false, event->type(), "missing proximity workaround"_L1);
134 }
135 missingTabletProximityEventsWorkaround = std::nullopt;
136 }
137 }
138#endif /* KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND */
139
140 if (event->type() == QEvent::FocusOut ||
141 event->type() == QEvent::Leave ||
153 (event->type() == QEvent::TouchBegin && !tabletIsInProximity)) {
154
155 if (tabletIsHovering) {
156 tabletIsHovering = false;
157 debugEaterStateTransition("tabletIsHovering"_L1, false, event->type());
158 }
159 if (tabletIsPressed) {
160 tabletIsPressed = false;
161 debugEaterStateTransition("tabletIsPressed"_L1, false, event->type());
162 }
163
164#ifdef KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND
165 missingTabletProximityEventsWorkaround = std::nullopt;
166#endif /* KRITA_ENABLE_MISSING_PROXIMITY_ENTER_WORKAROUND */
167 }
168
169 // also proximity-leave in a corresponding function...
170 }
171
172 {
173 // handle `touchIsActive` state transitions
174
175 bool assumeTouchStarted = event->type() == QEvent::TouchBegin;
176
177 if (!assumeTouchStarted && event->type() == QEvent::TouchUpdate) {
178 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
179
180#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
181 using DeviceType = QInputDevice::DeviceType;
182#else
183 using DeviceType = QTouchDevice::DeviceType;
184#endif
185
186 if (touchEvent->device()->type() == DeviceType::TouchPad) {
187#ifdef Q_OS_MACOS
202 // noop, keep assumeTouchStarted false
203#else
204 dbgInputEater << "Received a TouchUpdate for a touchpad device on a non-MacOS system!";
205#endif
206 } else {
207 assumeTouchStarted = true;
208 }
209 }
210
211 if (assumeTouchStarted) {
212 if (!touchIsActive) {
213 touchIsActive = true;
214 debugEaterStateTransition("touchIsActive"_L1, true, event->type());
215 }
216 }
217
218 if (event->type() == QEvent::TouchEnd ||
219 event->type() == QEvent::TouchCancel) {
220 if (touchIsActive) {
221 touchIsActive = false;
222 debugEaterStateTransition("touchIsActive"_L1, false, event->type());
223 }
224 }
225 }
226
227 if (eatOneMousePressEvent && event->type() == QEvent::MouseButtonPress
228 // Drop one mouse press following tabletPress or touchBegin
229 && (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)) {
230 eatOneMousePressEvent = false;
231 debugEvent<QMouseEvent>(event, BlockedByNextPressSuppression);
232 return true;
233 }
234
236 if (event->type() == QEvent::TabletPress ||
237 event->type() == QEvent::TabletRelease) {
238
239 QTabletEvent *te = static_cast<QTabletEvent*>(event);
240 if (te->button() != Qt::LeftButton) {
241 debugEvent<QTabletEvent>(te, BlockedByButtonsWorkaround);
242 return true;
243 }
244 } else if (event->type() == QEvent::MouseButtonPress ||
245 event->type() == QEvent::MouseButtonRelease ||
246 event->type() == QEvent::MouseButtonDblClick) {
247
248 QMouseEvent *me = static_cast<QMouseEvent*>(event);
249 if (me->button() != Qt::LeftButton) {
250 return false;
251 }
252 }
253 }
254
255 const bool shouldEatMouseEvents =
256 // On MacOS Qt sends fake mouse events instead of hover events,
257 // so we should not block mouse events when the tablet just hovers
258 // the canvas. The real TabletMove events will arrive only when
259 // the user touches the surface of the tablet, i.e. after a TabletPress.
260#ifndef Q_OS_MACOS
263#endif
266
267 if (isMouseEventType(event->type()) &&
268 (shouldEatMouseEvents
269 // On Mac, we need mouse events when the tablet is in proximity, but not pressed down
270 // since tablet move events are not generated until after tablet press.
271 #ifndef Q_OS_MAC
272 || (static_cast<QMouseEvent*>(event)->source() != Qt::MouseEventNotSynthesized)
273 #endif
274 )) {
275
276 EventBlockingReasons reasons = NotBlocked;
277#ifndef Q_OS_MACOS
279 reasons.setFlag(BlockedByTabletHover, tabletIsHovering);
280 reasons.setFlag(BlockedBySynthetic, static_cast<QMouseEvent*>(event)->source() != Qt::MouseEventNotSynthesized);
281#endif
282 reasons.setFlag(BlockedByTabletPress, tabletIsPressed);
283 reasons.setFlag(BlockedByTouchPress, touchIsActive);
284
285 debugEvent<QMouseEvent>(event, reasons);
286
287 // Drop mouse events if enabled or event was synthetic & synthetic events are disabled
288 return true;
289 }
290
291 if (event->type() == QEvent::TouchBegin &&
293
294 EventBlockingReasons reasons = NotBlocked;
296 reasons.setFlag(BlockedByTabletHover, tabletIsHovering);
297 reasons.setFlag(BlockedByTabletPress, tabletIsPressed);
298
299 debugEvent<QTouchEvent>(event, reasons);
300
301 if (touchIsActive) {
302 // don't forget to reset the touch active state, since we are
303 // not going to receive the res of the events
304 touchIsActive = false;
305 debugEaterStateTransition("touchIsActive"_L1, false, event->type(), "cancelled by tablet"_L1);
306 }
307
308 // Drop touch-begin event. It will prevent KisShortcutMatcher to
309 // start any touch action, while letting it complete any existing
310 // actions. We explicitly accept the event to make sure OS will
311 // not trigger any global gestures (works on WinInk only).
312 event->accept();
313 return true;
314 }
315
316 if (isMouseEventType(event->type())) {
317 debugEvent<QMouseEvent>(event, NotBlocked);
318 } else if (isTabletEventType(event->type())) {
319 debugEvent<QTabletEvent>(event, NotBlocked);
320 } else if (isTouchEventType(event->type())) {
321 debugEvent<QTouchEvent>(event, NotBlocked);
322 } else if (isNativeGestureEventType(event->type())) {
323 debugEvent<QNativeGestureEvent>(event, NotBlocked);
324 }
325
326 return false; // All clear - let this one through!
327}
static bool isTouchEventType(QEvent::Type t)
static bool isMouseEventType(QEvent::Type t)
static bool isNativeGestureEventType(QEvent::Type t)
static bool isTabletEventType(QEvent::Type t)
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
void debugEaterStateTransition(const QLatin1String &stateName, bool newValue, QEvent::Type eventType, const QLatin1String &comment=QLatin1String())
#define warnInputEater
Definition kis_debug.h:110

References activateSecondaryButtonsWorkaround, BlockedByButtonsWorkaround, BlockedByNextPressSuppression, BlockedBySynthetic, BlockedByTabletHover, BlockedByTabletPress, BlockedByTabletProximity, BlockedByTouchPress, dbgInputEater, debugEaterStateTransition(), eatOneMousePressEvent, isMouseEventType(), isNativeGestureEventType(), isTabletEventType(), isTouchEventType(), NotBlocked, source(), tabletIsHovering, tabletIsInProximity, tabletIsPressed, target(), touchIsActive, and warnInputEater.

◆ notifyTabletEnterProximity()

void KisInputEventsEater::notifyTabletEnterProximity ( )

Definition at line 329 of file KisInputEventsEater.cpp.

330{
331 using namespace Qt::StringLiterals;
332
333 tabletIsInProximity = true;
334 debugEaterStateTransition("tabletIsInProximity"_L1, true, QEvent::TabletEnterProximity);
335}

References debugEaterStateTransition(), and tabletIsInProximity.

◆ notifyTabletLeaveProximity()

void KisInputEventsEater::notifyTabletLeaveProximity ( )

Definition at line 337 of file KisInputEventsEater.cpp.

338{
339 using namespace Qt::StringLiterals;
340
341 tabletIsInProximity = false;
342 debugEaterStateTransition("tabletIsInProximity"_L1, false, QEvent::TabletLeaveProximity);
343
344 if (tabletIsHovering) {
345 tabletIsHovering = false;
346 debugEaterStateTransition("tabletIsHovering"_L1, false, QEvent::TabletLeaveProximity);
347 }
348}

References debugEaterStateTransition(), tabletIsHovering, and tabletIsInProximity.

Member Data Documentation

◆ activateSecondaryButtonsWorkaround

bool KisInputEventsEater::activateSecondaryButtonsWorkaround {false}
private

Definition at line 89 of file KisInputEventsEater.h.

89{false}; // Use mouse events for right- and middle-clicks

◆ eatOneMousePressEvent

bool KisInputEventsEater::eatOneMousePressEvent {false}
private

Definition at line 88 of file KisInputEventsEater.h.

88{false}; // Eat a single mouse press event

◆ tabletIsHovering

bool KisInputEventsEater::tabletIsHovering {false}
private

Definition at line 92 of file KisInputEventsEater.h.

92{false};

◆ tabletIsInProximity

bool KisInputEventsEater::tabletIsInProximity {false}
private

Definition at line 91 of file KisInputEventsEater.h.

91{false};

◆ tabletIsPressed

bool KisInputEventsEater::tabletIsPressed {false}
private

Definition at line 93 of file KisInputEventsEater.h.

93{false};

◆ touchIsActive

bool KisInputEventsEater::touchIsActive {false}
private

Definition at line 94 of file KisInputEventsEater.h.

94{false};

The documentation for this class was generated from the following files: