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#include <memory>
32
33
63static bool isMouseEventType(QEvent::Type t)
64{
65 return (t == QEvent::MouseMove ||
66 t == QEvent::MouseButtonPress ||
67 t == QEvent::MouseButtonRelease ||
68 t == QEvent::MouseButtonDblClick);
69}
70
76
78{
79 Q_UNUSED(target);
80
81 auto debugEvent = [&](int i) {
83 QString pre = QString("[BLOCKED %1:]").arg(i);
84 QMouseEvent *ev = static_cast<QMouseEvent*>(event);
86 }
87 };
88
89 auto debugTabletEvent = [&](int i) {
91 QString pre = QString("[BLOCKED %1:]").arg(i);
92 QTabletEvent *ev = static_cast<QTabletEvent*>(event);
94 }
95 };
96
97 auto debugTouchEvent = [&](int i) {
99 QString pre = QString("[BLOCKED %1:]").arg(i);
100 QTouchEvent *ev = static_cast<QTouchEvent*>(event);
102 }
103 };
104
105 if (peckish && event->type() == QEvent::MouseButtonPress
106 // Drop one mouse press following tabletPress or touchBegin
107 && (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)) {
108 peckish = false;
109 debugEvent(1);
110 return true;
111 }
112
113 if (activateSecondaryButtonsWorkaround) {
114 if (event->type() == QEvent::TabletPress ||
115 event->type() == QEvent::TabletRelease) {
116
117 QTabletEvent *te = static_cast<QTabletEvent*>(event);
118 if (te->button() != Qt::LeftButton) {
119 debugTabletEvent(3);
120 return true;
121 }
122 } else if (event->type() == QEvent::MouseButtonPress ||
123 event->type() == QEvent::MouseButtonRelease ||
124 event->type() == QEvent::MouseButtonDblClick) {
125
126 QMouseEvent *me = static_cast<QMouseEvent*>(event);
127 if (me->button() != Qt::LeftButton) {
128 return false;
129 }
130 }
131 }
132
133 if (isMouseEventType(event->type()) &&
134 (hungry
135 // On Mac, we need mouse events when the tablet is in proximity, but not pressed down
136 // since tablet move events are not generated until after tablet press.
137 #ifndef Q_OS_MAC
138 || (eatSyntheticEvents && static_cast<QMouseEvent*>(event)->source() != Qt::MouseEventNotSynthesized)
139 #endif
140 )) {
141 // Drop mouse events if enabled or event was synthetic & synthetic events are disabled
142 debugEvent(2);
143 return true;
144 }
145
146 if (eatTouchEvents && event->type() == QEvent::TouchBegin) {
147 // Drop touch events. If QEvent::TouchBegin is ignored, we won't
148 // receive further touch events until the next TouchBegin.
149 debugTouchEvent(3);
150 event->ignore();
151 return true;
152 }
153
154 return false; // All clear - let this one through!
155}
156
157
159{
160 if (!hungry && (KisTabletDebugger::instance()->debugEnabled())) {
161 dbgTablet << "Start blocking mouse events";
162 }
163 hungry = true;
164}
165
167{
168 if (hungry && (KisTabletDebugger::instance()->debugEnabled())) {
169 dbgTablet << "Stop blocking mouse events";
170 }
171 hungry = false;
172}
173
175{
176 // Enable on other platforms if getting full-pressure splotches
177 peckish = true;
178}
179
181{
182 eatTouchEvents = true;
183}
184
186{
187 eatTouchEvents = false;
188}
189
194
199
201 : q(qq)
202 , moveEventCompressor(10 /* ms */,
203 KisSignalCompressor::FIRST_ACTIVE,
204 KisSignalCompressor::ADDITIVE_INTERVAL)
206 , popupWidget(nullptr)
207 , touchHoldTimer(new QTimer(qq))
208 , canvasSwitcher(this, qq)
209{
210 KisConfig cfg(true);
211
215
216 if (cfg.trackTabletEventLatency()) {
218 }
219
221 [this] () {
222 return this->canvas ? this->canvas->inputActionGroupsMaskInterface()->inputActionGroupsMask() : AllActionGroup;
223 });
224
230#ifdef Q_OS_MACOS
232#endif
233
238#if defined Q_OS_LINUX && !KRITA_QT_HAS_UNBALANCED_KEY_PRESS_RELEASE_PATCH
240#endif
241
242 if (qEnvironmentVariableIsSet("KRITA_FIX_UNBALANCED_KEY_EVENTS")) {
243 useUnbalancedKeyPressEventWorkaround = qEnvironmentVariableIntValue("KRITA_FIX_UNBALANCED_KEY_EVENTS");
244 }
245
246 touchHoldTimer->setTimerType(Qt::CoarseTimer);
247 touchHoldTimer->setSingleShot(true);
249 connect(touchHoldTimer, &QTimer::timeout, qq, &KisInputManager::slotTouchHoldTriggered);
250}
251
252static const int InputWidgetsThreshold = 2000;
253static const int OtherWidgetsThreshold = 400;
254
256 : QObject(p),
257 d(_d),
258 eatOneMouseStroke(false),
259 focusSwitchThreshold(InputWidgetsThreshold)
260{
261}
262
264{
265 QWidget *widget = qobject_cast<QWidget*>(object);
267
268 thresholdConnections.clear();
269 thresholdConnections.addConnection(&focusSwitchThreshold, SIGNAL(timeout()), widget, SLOT(setFocus()));
270}
271
273{
274 if (!canvas) return;
275
276 QObject *canvasWidget = canvas->canvasWidget();
277
278 if (!canvasResolver.contains(canvasWidget)) {
279 canvasResolver.insert(canvasWidget, canvas);
280 } else {
281 // just a sanity cheek to find out if we are
282 // trying to add two canvases concurrently.
284 }
285
286 if (canvas != d->canvas) {
287 d->q->setupAsEventFilter(canvasWidget);
288 canvasWidget->installEventFilter(this);
289
290 setupFocusThreshold(canvasWidget);
291 focusSwitchThreshold.setEnabled(false);
292
293 d->canvas = canvas;
294 d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
295 }
296}
297
299{
300 QObject *widget = canvas->canvasWidget();
301
302 canvasResolver.remove(widget);
303
304 if (d->eventsReceiver == widget) {
306 }
307
308 widget->removeEventFilter(this);
309
310 if (d->canvas == canvas) {
311 d->canvas = 0;
312 d->toolProxy = 0;
313 }
314}
315
316bool isInputWidget(QWidget *w)
317{
318 if (!w) return false;
319
320
322 types << QLatin1String("QAbstractSlider");
323 types << QLatin1String("QAbstractSpinBox");
324 types << QLatin1String("QLineEdit");
325 types << QLatin1String("QTextEdit");
326 types << QLatin1String("QPlainTextEdit");
327 types << QLatin1String("QComboBox");
328 types << QLatin1String("QKeySequenceEdit");
329
330 Q_FOREACH (const QLatin1String &type, types) {
331 if (w->inherits(type.data())) {
332 return true;
333 }
334 }
335
336 return false;
337}
338
339bool KisInputManager::Private::CanvasSwitcher::eventFilter(QObject* object, QEvent* event )
340{
341 if (canvasResolver.contains(object)) {
342 switch (event->type()) {
343 case QEvent::FocusIn: {
344 QFocusEvent *fevent = static_cast<QFocusEvent*>(event);
345 KisCanvas2 *canvas = canvasResolver.value(object);
346
347 // only relevant canvases from the same main window should be
348 // registered in the switcher
350
351 if (canvas != d->canvas) {
352 eatOneMouseStroke = 2 * (fevent->reason() == Qt::MouseFocusReason);
353 }
354
355 d->canvas = canvas;
356 d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
357
358 d->q->setupAsEventFilter(object);
359
360 object->removeEventFilter(this);
361 object->installEventFilter(this);
362
363 setupFocusThreshold(object);
364 focusSwitchThreshold.setEnabled(false);
365
366 const QPoint globalPos = QCursor::pos();
367 const QPoint localPos = d->canvas->canvasWidget()->mapFromGlobal(globalPos);
368 QWidget *canvasWindow = d->canvas->canvasWidget()->window();
369 const QPoint windowsPos = canvasWindow ? canvasWindow->mapFromGlobal(globalPos) : localPos;
370
371 QEnterEvent event(localPos, windowsPos, globalPos);
372 d->q->eventFilter(object, &event);
373 break;
374 }
375 case QEvent::FocusOut: {
376 focusSwitchThreshold.setEnabled(true);
377 break;
378 }
379 case QEvent::Enter: {
380 break;
381 }
382 case QEvent::Leave: {
383 focusSwitchThreshold.stop();
384 break;
385 }
386 case QEvent::Wheel: {
387 QWidget *widget = static_cast<QWidget*>(object);
388 widget->setFocus();
389 break;
390 }
391 case QEvent::MouseButtonPress:
392 case QEvent::MouseButtonRelease:
393 case QEvent::TabletPress:
394 case QEvent::TabletRelease:
395 focusSwitchThreshold.forceDone();
396
397 if (eatOneMouseStroke) {
398 eatOneMouseStroke--;
399 return true;
400 }
401 break;
402 case QEvent::MouseButtonDblClick:
403 focusSwitchThreshold.forceDone();
404 if (eatOneMouseStroke) {
405 return true;
406 }
407 break;
408 case QEvent::MouseMove:
409 case QEvent::TabletMove: {
410 QWidget *widget = static_cast<QWidget*>(object);
411
412 if (!widget->hasFocus()) {
413 const int delay =
414 isInputWidget(QApplication::focusWidget()) ?
416
417 focusSwitchThreshold.setDelayThreshold(delay);
418 focusSwitchThreshold.start();
419 }
420 }
421 break;
422 default:
423 break;
424 }
425 }
426 return QObject::eventFilter(object, event);
427}
428
432
434{
435 switch (event->type()) {
436 case QEvent::TabletEnterProximity:
437 d->debugEvent<QEvent, false>(event);
438 // Tablet proximity events are unreliable AND fake mouse events do not
439 // necessarily come after tablet events, so this is insufficient.
440 // d->eventEater.eatOneMousePress();
441
442 // Qt sends fake mouse events instead of hover events, so not very useful.
443 // Don't block mouse events on tablet since tablet move events are not generated until
444 // after tablet press.
445#ifndef Q_OS_MACOS
447#endif
448 break;
449 case QEvent::TabletLeaveProximity:
450 d->debugEvent<QEvent, false>(event);
452 break;
453#ifdef Q_OS_WIN
454 case QEvent::KeyPress:
455 case QEvent::KeyRelease:
456 case QEvent::ShortcutOverride:
457 if (d->ignoreHighFunctionKeys) {
458 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
459 int key = keyEvent->key();
460
461 if (key >= Qt::Key_F13 && key <= Qt::Key_F35) {
463 const QString pre = "[BLOCKED HIGH F-KEY]";
465 }
466 return true;
467 }
468 break;
469 }
470#endif /* Q_OS_WIN */
471 default:
472 break;
473 }
474 return QObject::eventFilter(object, event);
475}
476
477#define EXTRA_BUTTON(z, n, _) \
478 if(buttons & Qt::ExtraButton##n) { \
479 buttonSet << Qt::ExtraButton##n; \
480 }
481
483 const QList<Qt::Key> &modifiers,
484 Qt::MouseButtons buttons)
485{
486 KisStrokeShortcut *strokeShortcut =
487 new KisStrokeShortcut(action, index);
488
489 QSet<Qt::MouseButton> buttonSet;
490 if(buttons & Qt::LeftButton) {
491 buttonSet << Qt::LeftButton;
492 }
493 if(buttons & Qt::RightButton) {
494 buttonSet << Qt::RightButton;
495 }
496 if(buttons & Qt::MiddleButton) {
497 buttonSet << Qt::MiddleButton;
498 }
499
500BOOST_PP_REPEAT_FROM_TO(1, 25, EXTRA_BUTTON, _)
501
502 if (!buttonSet.empty()) {
503 strokeShortcut->setButtons(QSet<Qt::Key>(modifiers.cbegin(), modifiers.cend()), buttonSet);
504 matcher.addShortcut(strokeShortcut);
505 }
506 else {
507 delete strokeShortcut;
508 }
509}
510
512 const QList<Qt::Key> &keys)
513{
514 if (keys.size() == 0) return;
515
516 KisSingleActionShortcut *keyShortcut =
517 new KisSingleActionShortcut(action, index);
518
519 //Note: Ordering is important here, Shift + V is different from V + Shift,
520 //which is the reason we use the last key here since most users will enter
521 //shortcuts as "Shift + V". Ideally this should not happen, but this is
522 //the way the shortcut matcher is currently implemented.
523 QList<Qt::Key> allKeys = keys;
524 Qt::Key key = allKeys.takeLast();
525 QSet<Qt::Key> modifiers = QSet<Qt::Key>(allKeys.begin(), allKeys.end());
526 keyShortcut->setKey(modifiers, key);
527 matcher.addShortcut(keyShortcut);
528}
529
531 const QList<Qt::Key> &modifiers,
533{
534 std::unique_ptr<KisSingleActionShortcut> keyShortcut(
535 new KisSingleActionShortcut(action, index));
536
538 switch(wheelAction) {
541 break;
544 break;
547 break;
550 break;
553 break;
554 default:
555 return;
556 }
557 keyShortcut->setWheel(QSet<Qt::Key>(modifiers.begin(), modifiers.end()), a);
558 matcher.addShortcut(keyShortcut.release());
559}
560
562{
563 KisTouchShortcut *shortcut = new KisTouchShortcut(action, index, gesture);
564 dbgKrita << "TouchAction:" << action->name();
565 switch(gesture) {
566#ifndef Q_OS_MACOS
569 // Touch painting takes precedence over one-finger touch shortcuts, so
570 // disable this type of shortcut when touch painting is active. Except
571 // touch hold shortcuts, since touching and holding in one spot does
572 // nothing otherwise and is therefore unambiguous.
573 shortcut->setDisableOnTouchPainting(true);
574 Q_FALLTHROUGH();
576 shortcut->setMinimumTouchPoints(1);
577 shortcut->setMaximumTouchPoints(1);
578 break;
581 shortcut->setMinimumTouchPoints(2);
582 shortcut->setMaximumTouchPoints(2);
583 break;
586 shortcut->setMinimumTouchPoints(3);
587 shortcut->setMaximumTouchPoints(3);
588 break;
591 shortcut->setMinimumTouchPoints(4);
592 shortcut->setMaximumTouchPoints(4);
593 break;
596 shortcut->setMinimumTouchPoints(5);
597 shortcut->setMaximumTouchPoints(5);
598#endif
599 default:
600 break;
601 }
602 matcher.addShortcut(shortcut);
603}
604
606{
607 // Qt5 only implements QNativeGestureEvent for macOS
608 Qt::NativeGestureType type;
609 switch (gesture) {
610#ifdef Q_OS_MACOS
611 case KisShortcutConfiguration::PinchGesture:
612 type = Qt::ZoomNativeGesture;
613 break;
614 case KisShortcutConfiguration::PanGesture:
615 type = Qt::PanNativeGesture;
616 break;
617 case KisShortcutConfiguration::RotateGesture:
618 type = Qt::RotateNativeGesture;
619 break;
620 case KisShortcutConfiguration::SmartZoomGesture:
621 type = Qt::SmartZoomNativeGesture;
622 break;
623#endif
624 default:
625 return false;
626 }
627
628 KisNativeGestureShortcut *shortcut = new KisNativeGestureShortcut(action, index, type);
629 matcher.addShortcut(shortcut);
630 return true;
631}
632
634{
636 Q_FOREACH (KisAbstractInputAction *action, actions) {
637 KisToolInvocationAction *toolAction =
638 dynamic_cast<KisToolInvocationAction*>(action);
639
640 if(toolAction) {
641 defaultInputAction = toolAction;
642 }
643 }
644
645 connect(KisInputProfileManager::instance(), SIGNAL(currentProfileChanged()), q, SLOT(profileChanged()));
646 if(KisInputProfileManager::instance()->currentProfile()) {
647 q->profileChanged();
648 }
649}
650
652{
653 bool retval = false;
654
656 event->type() == QEvent::KeyPress ||
657 event->type() == QEvent::KeyRelease) {
658
660 retval = true;
661 }
662
663 return retval && !forwardAllEventsToTool;
664}
665
666#ifdef HAVE_X11
667inline QPointF dividePoints(const QPointF &pt1, const QPointF &pt2) {
668 return QPointF(pt1.x() / pt2.x(), pt1.y() / pt2.y());
669}
670
671inline QPointF multiplyPoints(const QPointF &pt1, const QPointF &pt2) {
672 return QPointF(pt1.x() * pt2.x(), pt1.y() * pt2.y());
673}
674#endif
675
680
682{
698#ifdef Q_OS_WIN32
700 return;
701 }
702#endif
703
705}
706
711
716
721
726
731
736
738{
739 return touchHoldTimer->isActive();
740}
741
742bool KisInputManager::Private::isWithinTouchHoldSlopRange(const QPointF &currentPos) const
743{
744 QPointF d = startingPos - currentPos;
745 qreal distanceSquared = (d.x() * d.x()) + (d.y() * d.y());
746 return distanceSquared <= KisShortcutMatcher::TOUCH_SLOP_SQUARED;
747}
748
750{
751#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
752 QScopedPointer<QEvent> dst;
753 KoPointerEvent::copyQtPointerEvent(touchEvent, dst);
754 bufferedTouchEvents.append(static_cast<QTouchEvent *>(dst.take()));
755#else
756 bufferedTouchEvents.append(touchEvent->clone());
757#endif
758}
759
761{
762 for (QTouchEvent *touchEvent : bufferedTouchEvents) {
763 switch (touchEvent->type()) {
764 case QEvent::TouchBegin:
765 q->handleTouchBegin(touchEvent);
766 break;
767 case QEvent::TouchUpdate:
768 q->handleTouchUpdate(touchEvent);
769 break;
770 default:
771 qWarning("Unhandled buffered touch event type %d", int(touchEvent->type()));
772 break;
773 }
774 delete touchEvent;
775 }
776 bufferedTouchEvents.clear();
777}
778
780{
781 for (QTouchEvent *event : bufferedTouchEvents) {
782 delete event;
783 }
784 bufferedTouchEvents.clear();
785}
786
788{
789 bool retval = false;
790
791 if (event->type() == QTouchEvent::TouchUpdate && touchHasBlockedPressEvents) {
792 matcher.touchUpdateEvent((QTouchEvent *)event);
793 } else if (!matcher.pointerMoved(event) && toolProxy && event->type() != QTouchEvent::TouchUpdate) {
794 toolProxy->forwardHoverEvent(event);
795 }
796 retval = true;
797 event->setAccepted(true);
798
799 return retval;
800}
801
803{
805
806 QVector<Qt::Key> newKeys;
807 Qt::KeyboardModifiers modifiers = mapper.queryStandardModifiers();
808 Q_FOREACH (Qt::Key key, mapper.queryExtendedModifiers()) {
809 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
811 }
812
813 fixShortcutMatcherModifiersState(newKeys, modifiers);
814}
815
817{
819
820 matcher.handlePolledKeys(newKeys);
821
822 for (auto it = danglingKeys.begin(); it != danglingKeys.end();) {
823 if (newKeys.contains(*it)) {
824 newKeys.removeOne(*it);
825 it = danglingKeys.erase(it);
826 } else {
827 ++it;
828 }
829 }
830
831 Q_FOREACH (Qt::Key key, danglingKeys) {
832 QKeyEvent kevent(QEvent::KeyRelease, key, modifiers);
833 processUnhandledEvent(&kevent);
834 }
835
836 Q_FOREACH (Qt::Key key, newKeys) {
837 // just replay the whole sequence
838 {
839 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
840 processUnhandledEvent(&kevent);
841 }
842 {
843 QKeyEvent kevent(QEvent::KeyPress, key, modifiers);
844 processUnhandledEvent(&kevent);
845 }
846 }
847}
848
850{
851 // on OS X, we need to compute the timestamp that compares correctly against the native event timestamp,
852 // which seems to be the msecs since system startup. On Linux with WinTab, we produce the timestamp that
853 // we compare against ourselves in QWindowSystemInterface.
854
855 QElapsedTimer elapsed;
856 elapsed.start();
857 return elapsed.msecsSinceReference();
858}
859
861{
862 dbgTablet << qUtf8Printable(message);
863}
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