Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_input_manager_p.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Michael Abrahams <miabraha@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QMap>
10#include <QApplication>
11#include <QScopedPointer>
12#include <QTimer>
13#include <QtGlobal>
14
15#include <boost/preprocessor/repeat_from_to.hpp>
16
17#include "kis_input_manager.h"
18#include "kis_config.h"
21#include "kis_stroke_shortcut.h"
22#include "kis_touch_shortcut.h"
26
28#include "kis_popup_palette.h"
29#include "config-qt-patches-present.h"
30
31
61static bool isMouseEventType(QEvent::Type t)
62{
63 return (t == QEvent::MouseMove ||
64 t == QEvent::MouseButtonPress ||
65 t == QEvent::MouseButtonRelease ||
66 t == QEvent::MouseButtonDblClick);
67}
68
74
76{
77 Q_UNUSED(target);
78
79 auto debugEvent = [&](int i) {
81 QString pre = QString("[BLOCKED %1:]").arg(i);
82 QMouseEvent *ev = static_cast<QMouseEvent*>(event);
84 }
85 };
86
87 auto debugTabletEvent = [&](int i) {
89 QString pre = QString("[BLOCKED %1:]").arg(i);
90 QTabletEvent *ev = static_cast<QTabletEvent*>(event);
92 }
93 };
94
95 auto debugTouchEvent = [&](int i) {
97 QString pre = QString("[BLOCKED %1:]").arg(i);
98 QTouchEvent *ev = static_cast<QTouchEvent*>(event);
100 }
101 };
102
103 if (peckish && event->type() == QEvent::MouseButtonPress
104 // Drop one mouse press following tabletPress or touchBegin
105 && (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)) {
106 peckish = false;
107 debugEvent(1);
108 return true;
109 }
110
111 if (activateSecondaryButtonsWorkaround) {
112 if (event->type() == QEvent::TabletPress ||
113 event->type() == QEvent::TabletRelease) {
114
115 QTabletEvent *te = static_cast<QTabletEvent*>(event);
116 if (te->button() != Qt::LeftButton) {
117 debugTabletEvent(3);
118 return true;
119 }
120 } else if (event->type() == QEvent::MouseButtonPress ||
121 event->type() == QEvent::MouseButtonRelease ||
122 event->type() == QEvent::MouseButtonDblClick) {
123
124 QMouseEvent *me = static_cast<QMouseEvent*>(event);
125 if (me->button() != Qt::LeftButton) {
126 return false;
127 }
128 }
129 }
130
131 if (isMouseEventType(event->type()) &&
132 (hungry
133 // On Mac, we need mouse events when the tablet is in proximity, but not pressed down
134 // since tablet move events are not generated until after tablet press.
135 #ifndef Q_OS_MAC
136 || (eatSyntheticEvents && static_cast<QMouseEvent*>(event)->source() != Qt::MouseEventNotSynthesized)
137 #endif
138 )) {
139 // Drop mouse events if enabled or event was synthetic & synthetic events are disabled
140 debugEvent(2);
141 return true;
142 }
143
144 if (eatTouchEvents && event->type() == QEvent::TouchBegin) {
145 // Drop touch events. If QEvent::TouchBegin is ignored, we won't
146 // receive further touch events until the next TouchBegin.
147 debugTouchEvent(3);
148 event->ignore();
149 return true;
150 }
151
152 return false; // All clear - let this one through!
153}
154
155
157{
158 if (!hungry && (KisTabletDebugger::instance()->debugEnabled())) {
159 dbgTablet << "Start blocking mouse events";
160 }
161 hungry = true;
162}
163
165{
166 if (hungry && (KisTabletDebugger::instance()->debugEnabled())) {
167 dbgTablet << "Stop blocking mouse events";
168 }
169 hungry = false;
170}
171
173{
174 // Enable on other platforms if getting full-pressure splotches
175 peckish = true;
176}
177
179{
180 eatTouchEvents = true;
181}
182
184{
185 eatTouchEvents = false;
186}
187
192
197
199 : q(qq)
200 , moveEventCompressor(10 /* ms */,
201 KisSignalCompressor::FIRST_ACTIVE,
202 KisSignalCompressor::ADDITIVE_INTERVAL)
204 , popupWidget(nullptr)
205 , touchHoldTimer(new QTimer(qq))
206 , canvasSwitcher(this, qq)
207{
208 KisConfig cfg(true);
209
213
214 if (cfg.trackTabletEventLatency()) {
216 }
217
219 [this] () {
220 return this->canvas ? this->canvas->inputActionGroupsMaskInterface()->inputActionGroupsMask() : AllActionGroup;
221 });
222
228#ifdef Q_OS_MACOS
230#endif
231
236#if defined Q_OS_LINUX && !KRITA_QT_HAS_UNBALANCED_KEY_PRESS_RELEASE_PATCH
238#endif
239
240 if (qEnvironmentVariableIsSet("KRITA_FIX_UNBALANCED_KEY_EVENTS")) {
241 useUnbalancedKeyPressEventWorkaround = qEnvironmentVariableIntValue("KRITA_FIX_UNBALANCED_KEY_EVENTS");
242 }
243
244 touchHoldTimer->setTimerType(Qt::CoarseTimer);
245 touchHoldTimer->setSingleShot(true);
247 connect(touchHoldTimer, &QTimer::timeout, qq, &KisInputManager::slotTouchHoldTriggered);
248}
249
250static const int InputWidgetsThreshold = 2000;
251static const int OtherWidgetsThreshold = 400;
252
254 : QObject(p),
255 d(_d),
256 eatOneMouseStroke(false),
257 focusSwitchThreshold(InputWidgetsThreshold)
258{
259}
260
262{
263 QWidget *widget = qobject_cast<QWidget*>(object);
265
266 thresholdConnections.clear();
267 thresholdConnections.addConnection(&focusSwitchThreshold, SIGNAL(timeout()), widget, SLOT(setFocus()));
268}
269
271{
272 if (!canvas) return;
273
274 QObject *canvasWidget = canvas->canvasWidget();
275
276 if (!canvasResolver.contains(canvasWidget)) {
277 canvasResolver.insert(canvasWidget, canvas);
278 } else {
279 // just a sanity cheek to find out if we are
280 // trying to add two canvases concurrently.
282 }
283
284 if (canvas != d->canvas) {
285 d->q->setupAsEventFilter(canvasWidget);
286 canvasWidget->installEventFilter(this);
287
288 setupFocusThreshold(canvasWidget);
289 focusSwitchThreshold.setEnabled(false);
290
291 d->canvas = canvas;
292 d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
293 }
294}
295
297{
298 QObject *widget = canvas->canvasWidget();
299
300 canvasResolver.remove(widget);
301
302 if (d->eventsReceiver == widget) {
304 }
305
306 widget->removeEventFilter(this);
307
308 if (d->canvas == canvas) {
309 d->canvas = 0;
310 d->toolProxy = 0;
311 }
312}
313
314bool isInputWidget(QWidget *w)
315{
316 if (!w) return false;
317
318
320 types << QLatin1String("QAbstractSlider");
321 types << QLatin1String("QAbstractSpinBox");
322 types << QLatin1String("QLineEdit");
323 types << QLatin1String("QTextEdit");
324 types << QLatin1String("QPlainTextEdit");
325 types << QLatin1String("QComboBox");
326 types << QLatin1String("QKeySequenceEdit");
327
328 Q_FOREACH (const QLatin1String &type, types) {
329 if (w->inherits(type.data())) {
330 return true;
331 }
332 }
333
334 return false;
335}
336
337bool KisInputManager::Private::CanvasSwitcher::eventFilter(QObject* object, QEvent* event )
338{
339 if (canvasResolver.contains(object)) {
340 switch (event->type()) {
341 case QEvent::FocusIn: {
342 QFocusEvent *fevent = static_cast<QFocusEvent*>(event);
343 KisCanvas2 *canvas = canvasResolver.value(object);
344
345 // only relevant canvases from the same main window should be
346 // registered in the switcher
348
349 if (canvas != d->canvas) {
350 eatOneMouseStroke = 2 * (fevent->reason() == Qt::MouseFocusReason);
351 }
352
353 d->canvas = canvas;
354 d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
355
356 d->q->setupAsEventFilter(object);
357
358 object->removeEventFilter(this);
359 object->installEventFilter(this);
360
361 setupFocusThreshold(object);
362 focusSwitchThreshold.setEnabled(false);
363
364 const QPoint globalPos = QCursor::pos();
365 const QPoint localPos = d->canvas->canvasWidget()->mapFromGlobal(globalPos);
366 QWidget *canvasWindow = d->canvas->canvasWidget()->window();
367 const QPoint windowsPos = canvasWindow ? canvasWindow->mapFromGlobal(globalPos) : localPos;
368
369 QEnterEvent event(localPos, windowsPos, globalPos);
370 d->q->eventFilter(object, &event);
371 break;
372 }
373 case QEvent::FocusOut: {
374 focusSwitchThreshold.setEnabled(true);
375 break;
376 }
377 case QEvent::Enter: {
378 break;
379 }
380 case QEvent::Leave: {
381 focusSwitchThreshold.stop();
382 break;
383 }
384 case QEvent::Wheel: {
385 QWidget *widget = static_cast<QWidget*>(object);
386 widget->setFocus();
387 break;
388 }
389 case QEvent::MouseButtonPress:
390 case QEvent::MouseButtonRelease:
391 case QEvent::TabletPress:
392 case QEvent::TabletRelease:
393 focusSwitchThreshold.forceDone();
394
395 if (eatOneMouseStroke) {
396 eatOneMouseStroke--;
397 return true;
398 }
399 break;
400 case QEvent::MouseButtonDblClick:
401 focusSwitchThreshold.forceDone();
402 if (eatOneMouseStroke) {
403 return true;
404 }
405 break;
406 case QEvent::MouseMove:
407 case QEvent::TabletMove: {
408 QWidget *widget = static_cast<QWidget*>(object);
409
410 if (!widget->hasFocus()) {
411 const int delay =
412 isInputWidget(QApplication::focusWidget()) ?
414
415 focusSwitchThreshold.setDelayThreshold(delay);
416 focusSwitchThreshold.start();
417 }
418 }
419 break;
420 default:
421 break;
422 }
423 }
424 return QObject::eventFilter(object, event);
425}
426
430
432{
433 switch (event->type()) {
434 case QEvent::TabletEnterProximity:
435 d->debugEvent<QEvent, false>(event);
436 // Tablet proximity events are unreliable AND fake mouse events do not
437 // necessarily come after tablet events, so this is insufficient.
438 // d->eventEater.eatOneMousePress();
439
440 // Qt sends fake mouse events instead of hover events, so not very useful.
441 // Don't block mouse events on tablet since tablet move events are not generated until
442 // after tablet press.
443#ifndef Q_OS_MACOS
445#endif
446 break;
447 case QEvent::TabletLeaveProximity:
448 d->debugEvent<QEvent, false>(event);
450 break;
451#ifdef Q_OS_WIN
452 case QEvent::KeyPress:
453 case QEvent::KeyRelease:
454 case QEvent::ShortcutOverride:
455 if (d->ignoreHighFunctionKeys) {
456 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
457 int key = keyEvent->key();
458
459 if (key >= Qt::Key_F13 && key <= Qt::Key_F35) {
461 const QString pre = "[BLOCKED HIGH F-KEY]";
463 }
464 return true;
465 }
466 break;
467 }
468#endif /* Q_OS_WIN */
469 default:
470 break;
471 }
472 return QObject::eventFilter(object, event);
473}
474
475#define EXTRA_BUTTON(z, n, _) \
476 if(buttons & Qt::ExtraButton##n) { \
477 buttonSet << Qt::ExtraButton##n; \
478 }
479
481 const QList<Qt::Key> &modifiers,
482 Qt::MouseButtons buttons)
483{
484 KisStrokeShortcut *strokeShortcut =
485 new KisStrokeShortcut(action, index);
486
487 QSet<Qt::MouseButton> buttonSet;
488 if(buttons & Qt::LeftButton) {
489 buttonSet << Qt::LeftButton;
490 }
491 if(buttons & Qt::RightButton) {
492 buttonSet << Qt::RightButton;
493 }
494 if(buttons & Qt::MiddleButton) {
495 buttonSet << Qt::MiddleButton;
496 }
497
498BOOST_PP_REPEAT_FROM_TO(1, 25, EXTRA_BUTTON, _)
499
500 if (!buttonSet.empty()) {
501 strokeShortcut->setButtons(QSet<Qt::Key>(modifiers.cbegin(), modifiers.cend()), buttonSet);
502 matcher.addShortcut(strokeShortcut);
503 }
504 else {
505 delete strokeShortcut;
506 }
507}
508
510 const QList<Qt::Key> &keys)
511{
512 if (keys.size() == 0) return;
513
514 KisSingleActionShortcut *keyShortcut =
515 new KisSingleActionShortcut(action, index);
516
517 //Note: Ordering is important here, Shift + V is different from V + Shift,
518 //which is the reason we use the last key here since most users will enter
519 //shortcuts as "Shift + V". Ideally this should not happen, but this is
520 //the way the shortcut matcher is currently implemented.
521 QList<Qt::Key> allKeys = keys;
522 Qt::Key key = allKeys.takeLast();
523 QSet<Qt::Key> modifiers = QSet<Qt::Key>(allKeys.begin(), allKeys.end());
524 keyShortcut->setKey(modifiers, key);
525 matcher.addShortcut(keyShortcut);
526}
527
529 const QList<Qt::Key> &modifiers,
531{
532 QScopedPointer<KisSingleActionShortcut> keyShortcut(
533 new KisSingleActionShortcut(action, index));
534
536 switch(wheelAction) {
539 break;
542 break;
545 break;
548 break;
551 break;
552 default:
553 return;
554 }
555 keyShortcut->setWheel(QSet<Qt::Key>(modifiers.begin(), modifiers.end()), a);
556 matcher.addShortcut(keyShortcut.take());
557}
558
560{
561 KisTouchShortcut *shortcut = new KisTouchShortcut(action, index, gesture);
562 dbgKrita << "TouchAction:" << action->name();
563 switch(gesture) {
564#ifndef Q_OS_MACOS
567 // Touch painting takes precedence over one-finger touch shortcuts, so
568 // disable this type of shortcut when touch painting is active. Except
569 // touch hold shortcuts, since touching and holding in one spot does
570 // nothing otherwise and is therefore unambiguous.
571 shortcut->setDisableOnTouchPainting(true);
572 Q_FALLTHROUGH();
574 shortcut->setMinimumTouchPoints(1);
575 shortcut->setMaximumTouchPoints(1);
576 break;
579 shortcut->setMinimumTouchPoints(2);
580 shortcut->setMaximumTouchPoints(2);
581 break;
584 shortcut->setMinimumTouchPoints(3);
585 shortcut->setMaximumTouchPoints(3);
586 break;
589 shortcut->setMinimumTouchPoints(4);
590 shortcut->setMaximumTouchPoints(4);
591 break;
594 shortcut->setMinimumTouchPoints(5);
595 shortcut->setMaximumTouchPoints(5);
596#endif
597 default:
598 break;
599 }
600 matcher.addShortcut(shortcut);
601}
602
604{
605 // Qt5 only implements QNativeGestureEvent for macOS
606 Qt::NativeGestureType type;
607 switch (gesture) {
608#ifdef Q_OS_MACOS
609 case KisShortcutConfiguration::PinchGesture:
610 type = Qt::ZoomNativeGesture;
611 break;
612 case KisShortcutConfiguration::PanGesture:
613 type = Qt::PanNativeGesture;
614 break;
615 case KisShortcutConfiguration::RotateGesture:
616 type = Qt::RotateNativeGesture;
617 break;
618 case KisShortcutConfiguration::SmartZoomGesture:
619 type = Qt::SmartZoomNativeGesture;
620 break;
621#endif
622 default:
623 return false;
624 }
625
626 KisNativeGestureShortcut *shortcut = new KisNativeGestureShortcut(action, index, type);
627 matcher.addShortcut(shortcut);
628 return true;
629}
630
632{
634 Q_FOREACH (KisAbstractInputAction *action, actions) {
635 KisToolInvocationAction *toolAction =
636 dynamic_cast<KisToolInvocationAction*>(action);
637
638 if(toolAction) {
639 defaultInputAction = toolAction;
640 }
641 }
642
643 connect(KisInputProfileManager::instance(), SIGNAL(currentProfileChanged()), q, SLOT(profileChanged()));
644 if(KisInputProfileManager::instance()->currentProfile()) {
645 q->profileChanged();
646 }
647}
648
650{
651 bool retval = false;
652
654 event->type() == QEvent::KeyPress ||
655 event->type() == QEvent::KeyRelease) {
656
658 retval = true;
659 }
660
661 return retval && !forwardAllEventsToTool;
662}
663
664#ifdef HAVE_X11
665inline QPointF dividePoints(const QPointF &pt1, const QPointF &pt2) {
666 return QPointF(pt1.x() / pt2.x(), pt1.y() / pt2.y());
667}
668
669inline QPointF multiplyPoints(const QPointF &pt1, const QPointF &pt2) {
670 return QPointF(pt1.x() * pt2.x(), pt1.y() * pt2.y());
671}
672#endif
673
678
680{
696#ifdef Q_OS_WIN32
698 return;
699 }
700#endif
701
703}
704
709
714
719
724
729
734
736{
737 return touchHoldTimer->isActive();
738}
739
740bool KisInputManager::Private::isWithinTouchHoldSlopRange(const QPointF &currentPos) const
741{
742 QPointF d = startingPos - currentPos;
743 qreal distanceSquared = (d.x() * d.x()) + (d.y() * d.y());
744 return distanceSquared <= KisShortcutMatcher::TOUCH_SLOP_SQUARED;
745}
746
748{
749#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
750 QScopedPointer<QEvent> dst;
751 KoPointerEvent::copyQtPointerEvent(touchEvent, dst);
752 bufferedTouchEvents.append(static_cast<QTouchEvent *>(dst.take()));
753#else
754 bufferedTouchEvents.append(touchEvent->clone());
755#endif
756}
757
759{
760 for (QTouchEvent *touchEvent : bufferedTouchEvents) {
761 switch (touchEvent->type()) {
762 case QEvent::TouchBegin:
763 q->handleTouchBegin(touchEvent);
764 break;
765 case QEvent::TouchUpdate:
766 q->handleTouchUpdate(touchEvent);
767 break;
768 default:
769 qWarning("Unhandled buffered touch event type %d", int(touchEvent->type()));
770 break;
771 }
772 delete touchEvent;
773 }
774 bufferedTouchEvents.clear();
775}
776
778{
779 for (QTouchEvent *event : bufferedTouchEvents) {
780 delete event;
781 }
782 bufferedTouchEvents.clear();
783}
784
786{
787 bool retval = false;
788
789 if (event->type() == QTouchEvent::TouchUpdate && touchHasBlockedPressEvents) {
790 matcher.touchUpdateEvent((QTouchEvent *)event);
791 } else if (!matcher.pointerMoved(event) && toolProxy && event->type() != QTouchEvent::TouchUpdate) {
792 toolProxy->forwardHoverEvent(event);
793 }
794 retval = true;
795 event->setAccepted(true);
796
797 return retval;
798}
799
801{
803
804 QVector<Qt::Key> newKeys;
805 Qt::KeyboardModifiers modifiers = mapper.queryStandardModifiers();
806 Q_FOREACH (Qt::Key key, mapper.queryExtendedModifiers()) {
807 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
809 }
810
811 fixShortcutMatcherModifiersState(newKeys, modifiers);
812}
813
815{
817
818 matcher.handlePolledKeys(newKeys);
819
820 for (auto it = danglingKeys.begin(); it != danglingKeys.end();) {
821 if (newKeys.contains(*it)) {
822 newKeys.removeOne(*it);
823 it = danglingKeys.erase(it);
824 } else {
825 ++it;
826 }
827 }
828
829 Q_FOREACH (Qt::Key key, danglingKeys) {
830 QKeyEvent kevent(QEvent::KeyRelease, key, modifiers);
831 processUnhandledEvent(&kevent);
832 }
833
834 Q_FOREACH (Qt::Key key, newKeys) {
835 // just replay the whole sequence
836 {
837 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
838 processUnhandledEvent(&kevent);
839 }
840 {
841 QKeyEvent kevent(QEvent::KeyPress, key, modifiers);
842 processUnhandledEvent(&kevent);
843 }
844 }
845}
846
848{
849 // on OS X, we need to compute the timestamp that compares correctly against the native event timestamp,
850 // which seems to be the msecs since system startup. On Linux with WinTab, we produce the timestamp that
851 // we compare against ourselves in QWindowSystemInterface.
852
853 QElapsedTimer elapsed;
854 elapsed.start();
855 return elapsed.msecsSinceReference();
856}
857
859{
860 dbgTablet << qUtf8Printable(message);
861}
float value(const T *src, size_t ch)
const Params2D p
@ AllActionGroup
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
static bool debugEnabled()
Linethickness.
Abstract base class for input actions.
bool testingAcceptCompressedTabletEvents(bool defaultValue=false) const
int tabletEventsDelay(bool defaultValue=false) const
bool trackTabletEventLatency(bool defaultValue=false) const
bool useRightMiddleTabletButtonWorkaround(bool defaultValue=false) const
bool testingCompressBrushEvents(bool defaultValue=false) const
static Qt::Key workaroundShiftAltMetaHell(const QKeyEvent *keyEvent)
bool eventFilter(QObject *object, QEvent *event) override
bool eventFilter(QObject *object, QEvent *event) override
virtual void print(const QString &message) override
void debugEvent(QEvent *event)
void setMaskSyntheticEvents(bool value)
bool addNativeGestureShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::GestureAction gesture)
bool handleCompressedTabletEvent(QEvent *event)
static constexpr int TOUCH_HOLD_DELAY_MS
void addKeyShortcut(KisAbstractInputAction *action, int index, const QList< Qt::Key > &keys)
void addWheelShortcut(KisAbstractInputAction *action, int index, const QList< Qt::Key > &modifiers, KisShortcutConfiguration::MouseWheelMovement wheelAction)
KisToolInvocationAction * defaultInputAction
QVector< QTouchEvent * > bufferedTouchEvents
bool isWithinTouchHoldSlopRange(const QPointF &currentPos) const
QPointer< KisToolProxy > toolProxy
KisSignalCompressor moveEventCompressor
void addStrokeShortcut(KisAbstractInputAction *action, int index, const QList< Qt::Key > &modifiers, Qt::MouseButtons buttons)
QScopedPointer< QEvent > compressedMoveEvent
void bufferTouchEvent(QTouchEvent *event)
QPointer< KisCanvas2 > canvas
bool processUnhandledEvent(QEvent *event)
KisSharedPtr< TabletLatencyTracker > tabletLatencyTracker
void addTouchShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::GestureAction gesture)
KisPopupWidgetInterface * popupWidget
Central object to manage canvas input.
bool handleTouchBegin(QTouchEvent *touchEvent)
void setupAsEventFilter(QObject *receiver)
bool handleTouchUpdate(QTouchEvent *touchEvent)
bool eventFilter(QObject *object, QEvent *event) override
QList< KisAbstractInputAction * > actions
static KisInputProfileManager * instance()
@ WheelTrackpad
A pan movement on a trackpad.
@ WheelDown
Downwards movement, toward the user.
@ WheelUp
Upwards movement, away from the user.
void addShortcut(KisSingleActionShortcut *shortcut)
void setInputActionGroupsMaskCallback(std::function< KisInputActionGroupsMask()> func)
QVector< Qt::Key > debugPressedKeys() const
bool touchUpdateEvent(QTouchEvent *event)
static constexpr int TOUCH_SLOP_SQUARED
void handlePolledKeys(const QVector< Qt::Key > &keys)
bool pointerMoved(QEvent *event)
void setDelay(std::function< bool()> idleCallback, int idleDelay, int timeout)
@ WheelDown
Mouse wheel moves down.
@ WheelTrackpad
A pan movement on a trackpad.
@ WheelRight
Mouse wheel moves right.
@ WheelLeft
Mouse wheel moves left.
void setKey(const QSet< Qt::Key > &modifiers, Qt::Key key)
void setButtons(const QSet< Qt::Key > &modifiers, const QSet< Qt::MouseButton > &buttons)
QString eventToString(const QMouseEvent &ev, const QString &prefix)
static KisTabletDebugger * instance()
Tool Invocation action of KisAbstractInputAction.
The KisTouchShortcut class only handles touch gestures it does not handle tool invocation i....
void setMaximumTouchPoints(int max)
void setDisableOnTouchPainting(bool disableOnTouchPainting)
void setMinimumTouchPoints(int min)
#define KIS_SAFE_ASSERT_RECOVER_BREAK(cond)
Definition kis_assert.h:127
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define dbgKrita
Definition kis_debug.h:45
#define dbgTablet
Definition kis_debug.h:59
static const int OtherWidgetsThreshold
static const int InputWidgetsThreshold
static bool isMouseEventType(QEvent::Type t)
bool isInputWidget(QWidget *w)
#define EXTRA_BUTTON(z, n, _)
QString buttons(const T &ev)
bool eventFilter(QObject *target, QEvent *event)
#define _(s)
Definition xcftools.h:32