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

Central object to manage canvas input. More...

#include <kis_input_manager.h>

+ Inheritance diagram for KisInputManager:

Classes

class  Private
 

Public Member Functions

void addTrackedCanvas (KisCanvas2 *canvas)
 
void attachPriorityEventFilter (QObject *filter, int priority=0)
 attachPriorityEventFilter
 
KisCanvas2 * canvas () const
 
KisToolInvocationAction * defaultInputAction () const
 
void detachPriorityEventFilter (QObject *filter)
 detachPriorityEventFilter
 
bool eventFilter (QObject *object, QEvent *event) override
 
 KisInputManager (QObject *parent)
 
void registerPopupWidget (KisPopupWidgetInterface *popupWidget)
 
void removeTrackedCanvas (KisCanvas2 *canvas)
 
void setupAsEventFilter (QObject *receiver)
 
void toggleTabletLogger ()
 
QPointer< KisToolProxy > toolProxy () const
 
 ~KisInputManager () override
 

Private Slots

void deregisterPopupWidget ()
 
void profileChanged ()
 
void slotAboutToChangeTool ()
 
void slotCompressedMoveEvent ()
 
void slotConfigChanged ()
 
void slotTextModeChanged ()
 
void slotToolChanged ()
 

Private Member Functions

template<class Event >
bool compressMoveEventCommon (Event *event)
 
bool eventFilterImpl (QEvent *event)
 

Private Attributes

Private *const d
 

Detailed Description

Central object to manage canvas input.

The Input Manager class manages all canvas input. It is created by KisCanvas2 and processes all events related to input sent to the canvas.

The Input Manager keeps track of a set of actions and a set of shortcuts. The actions are pre-defined while the shortcuts are set from configuration.

For each event, it will try to determine if there is a shortcut that matches the input. It will then activate this action and pass all consecutive events on to this action.

See also
KisAbstractInputAction

Definition at line 38 of file kis_input_manager.h.

Constructor & Destructor Documentation

◆ KisInputManager()

KisInputManager::KisInputManager ( QObject * parent)

Constructor.

Definition at line 58 of file kis_input_manager.cpp.

59 : QObject(parent), d(new Private(this))
60{
61 d->setupActions();
62
63 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
65
66 connect(KoToolManager::instance(), SIGNAL(aboutToChangeTool(KoCanvasController*)), SLOT(slotAboutToChangeTool()));
67 connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*)), SLOT(slotToolChanged()));
68 connect(KoToolManager::instance(), SIGNAL(textModeChanged(bool)), SLOT(slotTextModeChanged()));
69 connect(&d->moveEventCompressor, SIGNAL(timeout()), SLOT(slotCompressedMoveEvent()));
70
71
72 QApplication::instance()->
73 installEventFilter(new Private::ProximityNotifier(d, this));
74
75 // on macos global Monitor listen to keypresses when krita is not in focus
76 // and local monitor listen presses when krita is in focus.
77#ifdef Q_OS_MACOS
78 KisExtendedModifiersMapper::setLocalMonitor(true, &d->matcher);
79#endif
80}
static KisConfigNotifier * instance()
KisSignalCompressor moveEventCompressor
static KoToolManager * instance()
Return the toolmanager singleton.

References d, KoToolManager::instance(), KisConfigNotifier::instance(), KisInputManager::Private::matcher, KisInputManager::Private::moveEventCompressor, KisInputManager::Private::setupActions(), slotAboutToChangeTool(), slotCompressedMoveEvent(), slotConfigChanged(), slotTextModeChanged(), and slotToolChanged().

◆ ~KisInputManager()

KisInputManager::~KisInputManager ( )
override

Destructor.

Definition at line 82 of file kis_input_manager.cpp.

83{
84#ifdef Q_OS_MACOS
85 KisExtendedModifiersMapper::setLocalMonitor(false);
86#endif
87 delete d;
88}

References d.

Member Function Documentation

◆ addTrackedCanvas()

void KisInputManager::addTrackedCanvas ( KisCanvas2 * canvas)

◆ attachPriorityEventFilter()

void KisInputManager::attachPriorityEventFilter ( QObject * filter,
int priority = 0 )

attachPriorityEventFilter

Parameters
filter
priority

Definition at line 137 of file kis_input_manager.cpp.

138{
139 Private::PriorityList::iterator begin = d->priorityEventFilter.begin();
140 Private::PriorityList::iterator it = begin;
141 Private::PriorityList::iterator end = d->priorityEventFilter.end();
142
143 it = std::find_if(begin, end,
144 kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
145
146 if (it != end) return;
147
148 it = std::find_if(begin, end,
149 kismpl::mem_greater(&Private::PriorityPair::first, priority));
150
151 d->priorityEventFilter.insert(it, qMakePair(priority, filter));
153}
auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value)
mem_equal_to is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:233
auto mem_greater(MemTypeNoRef Class::*ptr, MemType &&value)
mem_greater is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:341

References d, kismpl::mem_equal_to(), kismpl::mem_greater(), KisInputManager::Private::priorityEventFilter, and KisInputManager::Private::priorityEventFilterSeqNo.

◆ canvas()

KisCanvas2 * KisInputManager::canvas ( ) const

Return the canvas this input manager is associated with.

Definition at line 805 of file kis_input_manager.cpp.

806{
807 return d->canvas;
808}
QPointer< KisCanvas2 > canvas

References KisInputManager::Private::canvas, and d.

◆ compressMoveEventCommon()

template<class Event >
bool KisInputManager::compressMoveEventCommon ( Event * event)
private

We construct a copy of this event object, so we must ensure it has a correct type.

Compress the events if the tool doesn't need high resolution input

On Linux Qt eats the rest of unneeded events if we ignore the first of the chunk of tablet events. So generally we should never activate this feature. Only for testing purposes!

Definition at line 233 of file kis_input_manager.cpp.

234{
239 static_assert(std::is_same<Event, QMouseEvent>::value ||
240 std::is_same<Event, QTabletEvent>::value,
241 "event should be a mouse or a tablet event");
242
243
244 bool retval = false;
245
249 if ((event->type() == QEvent::MouseMove ||
250 event->type() == QEvent::TabletMove) &&
253#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
254 KoPointerEvent::copyQtPointerEvent(event, d->compressedMoveEvent);
255#else
256 d->compressedMoveEvent.reset(event->clone());
257#endif
259
267 event->setAccepted(true);
268 }
269
270 retval = true;
271 } else {
273 retval = d->handleCompressedTabletEvent(event);
274 }
275
276 return retval;
277}
bool handleCompressedTabletEvent(QEvent *event)
QScopedPointer< QEvent > compressedMoveEvent

References KisInputManager::Private::compressedMoveEvent, d, KisInputManager::Private::handleCompressedTabletEvent(), KisInputManager::Private::matcher, KisInputManager::Private::moveEventCompressor, slotCompressedMoveEvent(), KisSignalCompressor::start(), KisShortcutMatcher::supportsHiResInputEvents(), KisInputManager::Private::testingAcceptCompressedTabletEvents, and KisInputManager::Private::testingCompressBrushEvents.

◆ defaultInputAction()

KisToolInvocationAction * KisInputManager::defaultInputAction ( ) const

The built-in action that forwards primary strokes to the active tool.

Definition at line 815 of file kis_input_manager.cpp.

816{
817 return d->defaultInputAction;
818}
KisToolInvocationAction * defaultInputAction

References d, and KisInputManager::Private::defaultInputAction.

◆ deregisterPopupWidget

void KisInputManager::deregisterPopupWidget ( )
privateslot

Definition at line 110 of file kis_input_manager.cpp.

111{
112 if (d->popupWidget->onScreen()) {
114 }
115
116 // FUNKY!
117 auto popupObject = dynamic_cast<QObject*>(d->popupWidget);
118 KIS_ASSERT(popupObject);
119 disconnect(popupObject, nullptr, this, nullptr); // Disconnect all.
120
121 d->popupWidget = nullptr;
122}
KisPopupWidgetInterface * popupWidget
virtual void dismiss()=0
Called when you want to dismiss a popup widget.
virtual bool onScreen()=0
Returns whether the widget is active (on screen) or not.
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References d, KisPopupWidgetInterface::dismiss(), KIS_ASSERT, KisPopupWidgetInterface::onScreen(), and KisInputManager::Private::popupWidget.

◆ detachPriorityEventFilter()

void KisInputManager::detachPriorityEventFilter ( QObject * filter)

detachPriorityEventFilter

Parameters
filter

Definition at line 155 of file kis_input_manager.cpp.

156{
157 Private::PriorityList::iterator it = d->priorityEventFilter.begin();
158 Private::PriorityList::iterator end = d->priorityEventFilter.end();
159
160 it = std::find_if(it, end,
161 kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
162
163 if (it != end) {
164 d->priorityEventFilter.erase(it);
165 }
166}

References d, kismpl::mem_equal_to(), and KisInputManager::Private::priorityEventFilter.

◆ eventFilter()

bool KisInputManager::eventFilter ( QObject * object,
QEvent * event )
override

Event filter method. Overridden from QObject.

If the filter removed itself from the filters list or added something there, just exit the loop

Definition at line 185 of file kis_input_manager.cpp.

186{
187 if (object != d->eventsReceiver) return false;
188
189 if (d->eventEater.eventFilter(object, event)) return false;
190
191 if (!d->matcher.hasRunningShortcut()) {
192
193 int savedPriorityEventFilterSeqNo = d->priorityEventFilterSeqNo;
194
195 for (auto it = d->priorityEventFilter.begin(); it != d->priorityEventFilter.end(); /*noop*/) {
196 const QPointer<QObject> &filter = it->second;
197
198 if (filter.isNull()) {
199 it = d->priorityEventFilter.erase(it);
200
202 savedPriorityEventFilterSeqNo++;
203 continue;
204 }
205
206 if (filter->eventFilter(object, event)) return true;
207
212 if (d->priorityEventFilterSeqNo != savedPriorityEventFilterSeqNo) {
213 return true;
214 }
215
216 ++it;
217 }
218
219 // KoToolProxy needs to pre-process some events to ensure the
220 // global shortcuts (not the input manager's ones) are not
221 // executed, in particular, this line will accept events when the
222 // tool is in text editing, preventing shortcut triggering
223 if (d->toolProxy) {
224 d->toolProxy->processEvent(event);
225 }
226 }
227
228 // Continue with the actual switch statement...
229 return eventFilterImpl(event);
230}
bool eventFilter(QObject *target, QEvent *event)
KisInputEventsEater eventEater
QPointer< KisToolProxy > toolProxy
bool eventFilterImpl(QEvent *event)

References d, KisInputManager::Private::eventEater, KisInputEventsEater::eventFilter(), eventFilterImpl(), KisInputManager::Private::eventsReceiver, KisShortcutMatcher::hasRunningShortcut(), KisInputManager::Private::matcher, KisInputManager::Private::priorityEventFilter, KisInputManager::Private::priorityEventFilterSeqNo, and KisInputManager::Private::toolProxy.

◆ eventFilterImpl()

bool KisInputManager::eventFilterImpl ( QEvent * event)
private

When Krita (as an application) has no input focus, we cannot handle key events. But at the same time, when the user hovers Krita canvas, we should still show him the correct cursor.

So here we just add a simple workaround to resync shortcut matcher's state at least against the basic modifiers, like Shift, Control and Alt.

On Windows, when the user presses some global window manager shortcuts, e.g. Alt+Space (to show window title menu), events for these key presses and releases are not delivered (see bug 424319). This code is a workaround for this problem. It checks consistency of standard modifiers and resets shortcut's matcher state in case of a trouble.

Re-check the native platform key API against keys we are unsure about, and fix them in case they now show as released.

The other part of the fix is placed in the handler of ShortcutOverride, because it needs a custom set of the presset keys.

See a comment in the handler of KeyRelease event for shouldSynchronizeOnNextKeyPress explanation

There is also a case when Krita gets focus via Win+1 key, then the polled key '1' gets into the matcher, but OS does not deliver any signals for it (see bug 451424)

On some systems Qt fails to generate a correct sequence of events when the user releases a modifier key while some other key is pressed.

In such cases Qt doesn't understand that the key has changed its name in the meantime and sends incorrect key-release event for it (or an auto- repeated key-release/key-press pair).

Example (on en-US keyboard):

1) Press Shift (Key_Shift-press is delivered) 2) Press '2' (Key_At-press is delivered) 3) Release Shift (Key_Shift-release is delivered) 4) Release '2' (Key_2-release is delivered, which is unbalanced)

The same issue happens with non-latin keyboards, where Qt does auto-key-replace routines when Control modifier is pressed.

https://bugs.kde.org/show_bug.cgi?id=454256 https://bugreports.qt.io/browse/QTBUG-103868

Wayland sends us a duplicated ScrollBegin event (one for every axis), so we cannot rely just on status of the running stroke and should use hasTouchpadScrollShortcuts() instead.

When wheelEvent->phase() is not Qt::NoScrollPhase, the delta can be easily null, so we should ignore these events.

We don't try to pass unhandled events to the tool proxy (via toolProxy->forwardHoverEvent(event)) because of the following reasons:

On Windows and Linux touch evetns are generated for touch screens only. And touch screens have no "hover" state.

On MacOS touch events are also generated for the Apple's trackpad. Though, for single-finger movements, these touch events are usually unbalanced, i.e. they don't have a corresponding TouchBegin event.

We could theoretically pass these events to the tool on MacOS only, but it seems like the system-generated mouse events are more precise and granular. That is why we just allow these mouse events in EventEater when we detect they are coming from a touchpad/trackpad outside of TouchBegin/TouchEnd guards.

Definition at line 298 of file kis_input_manager.cpp.

299{
300 bool retval = false;
301
302 // Try closing any open popup widget and
303 // consume input if possible.
304 if (d->popupWidget) {
305 QEvent::Type type = event->type();
306
307 if (type == QEvent::MouseButtonPress
308 || type == QEvent::MouseButtonDblClick
309 || type == QEvent::TabletPress
310 || type == QEvent::TouchBegin
311 || type == QEvent::NativeGesture) {
312 bool wasVisible = d->popupWidget->onScreen();
314
315 if (wasVisible) {
316 d->popupWasActive = true;
317 event->setAccepted(true);
318 return true; // Event consumed.
319 }
320 }
321 }
322
323 if (shouldResetWheelDelta(event)) {
325 }
326
327 if (event->type() == QEvent::MouseMove ||
328 event->type() == QEvent::MouseButtonPress ||
329 event->type() == QEvent::MouseButtonRelease ||
330 event->type() == QEvent::TabletMove ||
331 event->type() == QEvent::TabletPress ||
332 event->type() == QEvent::TabletRelease ||
333 event->type() == QEvent::Wheel) {
334
344 QWidget *receivingWidget = dynamic_cast<QWidget*>(d->eventsReceiver);
345 if (receivingWidget && !receivingWidget->hasFocus()) {
347 } else {
355 QInputEvent *inputEvent = static_cast<QInputEvent*>(event);
356 if (event->type() != QEvent::ShortcutOverride &&
357 !d->matcher.sanityCheckModifiersCorrectness(inputEvent->modifiers())) {
358
360 } else if (d->matcher.hasPolledKeys()) {
369 }
370 }
371 }
372
373 switch (event->type()) {
374 case QEvent::MouseButtonPress:
375 case QEvent::MouseButtonDblClick: {
376 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
377
378 if (d->popupWidget) {
379 retval = true;
380 } else {
381 //Make sure the input actions know we are active.
383 retval = d->matcher.buttonPressed(mouseEvent->button(), mouseEvent);
384 }
385 //Reset signal compressor to prevent processing events before press late
387 event->setAccepted(retval);
388 break;
389 }
390 case QEvent::MouseButtonRelease: {
391 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
392 retval = d->matcher.buttonReleased(mouseEvent->button(), mouseEvent);
393 event->setAccepted(retval);
394 break;
395 }
396 case QEvent::ShortcutOverride: {
397 KisInputEventsEater::debugEvent<QKeyEvent>(event);
398 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
399
401
410 QVector<Qt::Key> guessedKeys;
412 Qt::KeyboardModifiers modifiers = mapper.queryStandardModifiers();
413 Q_FOREACH (Qt::Key key, mapper.queryExtendedModifiers()) {
414 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
416 }
417
418 if (!d->matcher.debugPressedKeys().contains(key)) {
419 guessedKeys.removeOne(key);
420 }
421
422 d->fixShortcutMatcherModifiersState(guessedKeys, modifiers);
424 }
425
426 if (!keyEvent->isAutoRepeat()) {
427 retval = d->matcher.keyPressed(key);
428 } else {
429 retval = d->matcher.autoRepeatedKeyPressed(key);
430 }
431
432 // In case we matched a shortcut we should accept the event to
433 // notify Qt that it shouldn't try to trigger its partially matched
434 // shortcuts.
435 if (retval) {
436 keyEvent->setAccepted(true);
437 }
438
439 break;
440 }
441 case QEvent::KeyRelease: {
442 KisInputEventsEater::debugEvent<QKeyEvent>(event);
443 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
444
445 if (!keyEvent->isAutoRepeat()) {
447 retval = d->matcher.keyReleased(key);
448
476 !d->matcher.debugPressedKeys().isEmpty() &&
477 (key == Qt::Key_Shift || key == Qt::Key_Alt ||
478 key == Qt::Key_Control || key == Qt::Key_Meta)) {
479
481 }
482 }
483 break;
484 }
485 case QEvent::MouseMove: {
486 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
487 retval = compressMoveEventCommon(mouseEvent);
488
489 break;
490 }
491 case QEvent::Wheel: {
492 KisInputEventsEater::debugEvent<QWheelEvent>(event);
493 QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
494
495 if (wheelEvent->phase() != Qt::NoScrollPhase && d->matcher.hasTouchpadScrollShortcuts()) {
503 if (wheelEvent->phase() == Qt::ScrollBegin) {
505 } else if (wheelEvent->phase() == Qt::ScrollEnd) {
506 d->matcher.touchpadScrollEndEvent(wheelEvent);
507 } else {
508 d->matcher.touchpadScrollEvent(wheelEvent);
509 }
510
511 break;
512 }
513
514 d->accumulatedScrollDelta += wheelEvent->angleDelta();
515
520 if (wheelEvent->angleDelta().isNull()) {
521 retval = true;
522 break;
523 }
524
525 bool wasScrolled = false;
526
527 {
529
530 if (wheelEvent->angleDelta().y() < 0) {
532 } else if (wheelEvent->angleDelta().y() > 0) {
534 }
535
536 while (qAbs(d->accumulatedScrollDelta.y()) >= QWheelEvent::DefaultDeltasPerStep) {
537 // Make sure the input actions know we are active.
539 retval = d->matcher.wheelEvent(yAction, wheelEvent);
541 KisAlgebra2D::signPZ(d->accumulatedScrollDelta.y()) * QWheelEvent::DefaultDeltasPerStep;
542 wasScrolled = true;
543 }
544 }
545
546 {
548
549 if (wheelEvent->angleDelta().x() < 0) {
551 } else if (wheelEvent->angleDelta().x() > 0) {
553 }
554
555 while (qAbs(d->accumulatedScrollDelta.x()) >= QWheelEvent::DefaultDeltasPerStep) {
556 // Make sure the input actions know we are active.
558 retval = d->matcher.wheelEvent(xAction, wheelEvent);
560 KisAlgebra2D::signPZ(d->accumulatedScrollDelta.x()) * QWheelEvent::DefaultDeltasPerStep;
561 wasScrolled = true;
562 }
563 }
564
565 retval = !wasScrolled;
566 break;
567 }
568#ifndef Q_OS_ANDROID
569 case QEvent::Enter:
570 KisInputEventsEater::debugEvent<QEvent>(event);
571 //Make sure the input actions know we are active.
574 break;
575 case QEvent::Leave:
576 KisInputEventsEater::debugEvent<QEvent>(event);
578 break;
579#endif
580 case QEvent::FocusIn:
581 KisInputEventsEater::debugEvent<QEvent>(event);
583
586 break;
587
588 case QEvent::FocusOut: {
589 KisInputEventsEater::debugEvent<QEvent>(event);
591
592 QPointF currentLocalPos =
593 canvas()->canvasWidget()->mapFromGlobal(QCursor::pos());
594
595 d->matcher.lostFocusEvent(currentLocalPos);
596
597 break;
598 }
599 case QEvent::TabletPress: {
600 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
601
602 {
603 //Make sure the input actions know we are active.
605 retval = d->matcher.buttonPressed(tabletEvent->button(), tabletEvent);
606 }
607
608 event->setAccepted(true);
609 retval = true;
610
611 //Reset signal compressor to prevent processing events before press late
613
614#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
615 // remove this hack when this patch is integrated:
616 // https://codereview.qt-project.org/#/c/255384/
617 event->setAccepted(false);
619#elif defined Q_OS_WIN32
625#endif
626
627 break;
628 }
629 case QEvent::TabletMove: {
630 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
631 retval = compressMoveEventCommon(tabletEvent);
632
633 if (d->tabletLatencyTracker) {
634 d->tabletLatencyTracker->push(tabletEvent->timestamp());
635 }
636
637#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
638 // remove this hack when this patch is integrated:
639 // https://codereview.qt-project.org/#/c/255384/
640 event->setAccepted(false);
641#endif
642
643 break;
644 }
645 case QEvent::TabletRelease: {
646 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
647 retval = d->matcher.buttonReleased(tabletEvent->button(), tabletEvent);
648 retval = true;
649 event->setAccepted(true);
650
651#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
652 // remove this hack when this patch is integrated:
653 // https://codereview.qt-project.org/#/c/255384/
654 event->setAccepted(false);
655#endif
656
657 break;
658 }
659
660 case QEvent::TouchBegin:
661 {
662 // The popup was dismissed in previous TouchBegin->TouchEnd sequence. We now have a new TouchBegin.
663 d->popupWasActive = false;
664 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
666
667 retval = d->matcher.touchBeginEvent(touchEvent);
668
670 // we accept touch events unconditionally to disable
671 // system-wide gesture on the canvas
672 event->accept();
673 break;
674 }
675
676 case QEvent::TouchUpdate:
677 {
678 if (d->popupWasActive) {
679 event->setAccepted(true);
680 return true;
681 }
682 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
683
684#ifdef Q_OS_MAC
686 const int totalPointCount = KisTouchShortcut::countTouchPoints(touchEvent, KisTouchShortcut::allTouchStates());
687
688 if (pressedCount < 2 && totalPointCount > pressedCount) {
689 d->matcher.touchEndEvent(touchEvent);
690 retval = true;
691 } else {
692#endif
694 d->matcher.touchUpdateEvent(touchEvent);
716 retval = true;
717
718#ifdef Q_OS_MACOS
719 }
720#endif
721
722 // we accept touch events unconditionally to disable
723 // system-wide gesture on the canvas
724 event->accept();
725 break;
726 }
727
728 case QEvent::TouchEnd:
729 {
730 if (d->popupWasActive) {
731 event->setAccepted(true);
732 return true;
733 }
734 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
735
736 retval = d->matcher.touchEndEvent(touchEvent);
737
738 // we accept touch events unconditionally to disable
739 // system-wide gesture on the canvas
740 event->accept();
741 break;
742 }
743 case QEvent::TouchCancel:
744 {
745 if (d->popupWasActive) {
746 event->setAccepted(true);
747 return true;
748 }
749 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
750 d->matcher.touchCancelEvent(touchEvent);
751
752 retval = true;
753
754 // we accept tablet events unconditionally to disable
755 // system-wide gesture on the canvas
756 event->accept();
757 break;
758 }
759
760 case QEvent::NativeGesture:
761 {
762 QNativeGestureEvent *gevent = static_cast<QNativeGestureEvent*>(event);
763 switch (gevent->gestureType()) {
764 case Qt::BeginNativeGesture:
765 {
767 retval = d->matcher.nativeGestureBeginEvent(gevent);
768 event->accept();
769 break;
770 }
771 case Qt::EndNativeGesture:
772 {
773 retval = d->matcher.nativeGestureEndEvent(gevent);
774 event->accept();
775 break;
776 }
777 default:
778 {
780 retval = d->matcher.nativeGestureEvent(gevent);
781 event->accept();
782 break;
783 }
784 }
785 retval = true;
786 event->accept();
787 break;
788 }
789
790 default:
791 break;
792 }
793
794 return !retval ? d->processUnhandledEvent(event) : true;
795}
static void setInputManager(KisInputManager *manager)
KisAbstractCanvasWidget * canvasWidget
static Qt::Key workaroundShiftAltMetaHell(const QKeyEvent *keyEvent)
bool processUnhandledEvent(QEvent *event)
KisSharedPtr< TabletLatencyTracker > tabletLatencyTracker
bool compressMoveEventCommon(Event *event)
void lostFocusEvent(const QPointF &localPos)
bool autoRepeatedKeyPressed(Qt::Key key)
bool buttonReleased(Qt::MouseButton button, QEvent *event)
bool touchpadScrollEndEvent(QWheelEvent *event)
bool hasTouchpadScrollShortcuts() const
bool nativeGestureEndEvent(QNativeGestureEvent *event)
bool keyPressed(Qt::Key key)
bool touchBeginEvent(QTouchEvent *event)
bool touchpadScrollBeginEvent(QWheelEvent *event)
bool touchpadScrollEvent(QWheelEvent *event)
void touchCancelEvent(QTouchEvent *event)
QVector< Qt::Key > debugPressedKeys() const
bool touchEndEvent(QTouchEvent *event)
bool touchUpdateEvent(QTouchEvent *event)
bool nativeGestureEvent(QNativeGestureEvent *event)
bool buttonPressed(Qt::MouseButton button, QEvent *event)
bool sanityCheckModifiersCorrectness(Qt::KeyboardModifiers modifiers) const
bool nativeGestureBeginEvent(QNativeGestureEvent *event)
bool keyReleased(Qt::Key key)
bool wheelEvent(KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
@ WheelDown
Mouse wheel moves down.
@ WheelRight
Mouse wheel moves right.
@ WheelLeft
Mouse wheel moves left.
static Qt::TouchPointStates pressedOnlyTouchStates()
static int countTouchPoints(const QTouchEvent *event, Qt::TouchPointStates allowedStates)
static Qt::TouchPointStates allTouchStates()
bool shouldResetWheelDelta(QEvent *event)

References KisInputManager::Private::accumulatedScrollDelta, KisTouchShortcut::allTouchStates(), KisShortcutMatcher::autoRepeatedKeyPressed(), KisShortcutMatcher::buttonPressed(), KisShortcutMatcher::buttonReleased(), canvas(), KisCanvas2::canvasWidget, compressMoveEventCommon(), KisTouchShortcut::countTouchPoints(), d, KisShortcutMatcher::debugPressedKeys(), deregisterPopupWidget(), KisInputEventsEater::eatOneMousePress(), KisShortcutMatcher::enterEvent(), KisInputManager::Private::eventEater, KisInputManager::Private::eventsReceiver, KisInputManager::Private::fixShortcutMatcherModifiersState(), KisShortcutMatcher::hasPolledKeys(), KisShortcutMatcher::hasTouchpadScrollShortcuts(), KisShortcutMatcher::keyPressed(), KisShortcutMatcher::keyReleased(), KisShortcutMatcher::leaveEvent(), KisShortcutMatcher::lostFocusEvent(), KisInputManager::Private::matcher, KisShortcutMatcher::nativeGestureBeginEvent(), KisShortcutMatcher::nativeGestureEndEvent(), KisShortcutMatcher::nativeGestureEvent(), KisPopupWidgetInterface::onScreen(), KisInputManager::Private::popupWasActive, KisInputManager::Private::popupWidget, KisTouchShortcut::pressedOnlyTouchStates(), KisInputManager::Private::processUnhandledEvent(), KisExtendedModifiersMapper::queryExtendedModifiers(), KisExtendedModifiersMapper::queryStandardModifiers(), KisShortcutMatcher::reinitializeButtons(), KisInputManager::Private::resetCompressor(), KisShortcutMatcher::sanityCheckModifiersCorrectness(), KisAbstractInputAction::setInputManager(), shouldResetWheelDelta(), KisInputManager::Private::shouldSynchronizeOnNextKeyPress, KisAlgebra2D::signPZ(), KisInputManager::Private::tabletLatencyTracker, KisShortcutMatcher::touchBeginEvent(), KisShortcutMatcher::touchCancelEvent(), KisShortcutMatcher::touchEndEvent(), KisShortcutMatcher::touchpadScrollBeginEvent(), KisShortcutMatcher::touchpadScrollEndEvent(), KisShortcutMatcher::touchpadScrollEvent(), KisShortcutMatcher::touchUpdateEvent(), KisInputManager::Private::useUnbalancedKeyPressEventWorkaround, KisSingleActionShortcut::WheelDown, KisShortcutMatcher::wheelEvent(), KisSingleActionShortcut::WheelLeft, KisSingleActionShortcut::WheelRight, KisSingleActionShortcut::WheelUp, and KisExtendedModifiersMapper::workaroundShiftAltMetaHell().

◆ profileChanged

void KisInputManager::profileChanged ( )
privateslot

Definition at line 871 of file kis_input_manager.cpp.

872{
874
876 if (profile) {
877 const QList<KisShortcutConfiguration*> shortcuts = profile->allShortcuts();
878
879 for (KisShortcutConfiguration * const shortcut : shortcuts) {
880 dbgUI << "Adding shortcut" << shortcut->keys() << "for action" << shortcut->action()->name();
881 switch(shortcut->type()) {
883 d->addKeyShortcut(shortcut->action(), shortcut->mode(), shortcut->keys());
884 break;
886 d->addStrokeShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->buttons());
887 break;
889 d->addWheelShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->wheel());
890 break;
892 d->addTouchShortcut(shortcut->action(), shortcut->mode(), shortcut->touchGesture());
893 break;
895 d->addNativeGestureShortcut(shortcut->action(), shortcut->mode(), shortcut->nativeGesture());
896 break;
897 default:
898 break;
899 }
900 }
901
902 {
903 KisAbstractInputAction *action = profile->actionForId("Tool Invocation");
904 if (action) {
905 // Touch painting shortcuts
908 }
909 }
910 }
911 else {
912 warnUI << "No Input Profile Found: canvas interaction will be impossible";
913 }
914}
Abstract base class for input actions.
void addTouchShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::TouchGestureAction gesture, bool isTouchPainting=false)
bool addNativeGestureShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::NativeGestureAction gesture)
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)
void addStrokeShortcut(KisAbstractInputAction *action, int index, const QList< Qt::Key > &modifiers, Qt::MouseButtons buttons)
static KisInputProfileManager * instance()
A container class for sets of shortcuts associated with an action.
QList< KisShortcutConfiguration * > allShortcuts() const
KisAbstractInputAction * actionForId(const QString &id) const
A class encapsulating all settings for a single shortcut.
@ MouseButtonType
A mouse button, possibly with key modifiers.
@ MouseWheelType
Mouse wheel movement, possibly with key modifiers.
@ KeyCombinationType
A list of keys that should be pressed.
#define dbgUI
Definition kis_debug.h:56
#define warnUI
Definition kis_debug.h:101

References KisInputProfile::actionForId(), KisToolInvocationAction::ActivateShortcut, KisInputManager::Private::addKeyShortcut(), KisInputManager::Private::addNativeGestureShortcut(), KisInputManager::Private::addStrokeShortcut(), KisInputManager::Private::addTouchShortcut(), KisInputManager::Private::addWheelShortcut(), KisInputProfile::allShortcuts(), KisShortcutMatcher::clearShortcuts(), KisInputProfileManager::currentProfile, d, dbgUI, KisInputProfileManager::instance(), KisShortcutConfiguration::KeyCombinationType, KisInputManager::Private::matcher, KisShortcutConfiguration::MouseButtonType, KisShortcutConfiguration::MouseWheelType, KisShortcutConfiguration::NativeGestureType, KisShortcutConfiguration::OneFingerDrag, KisShortcutConfiguration::OneFingerTap, KisShortcutConfiguration::TouchGestureType, and warnUI.

◆ registerPopupWidget()

void KisInputManager::registerPopupWidget ( KisPopupWidgetInterface * popupWidget)

Definition at line 100 of file kis_input_manager.cpp.

101{
102 d->popupWidget = popupWidget;
103
104 // FUNKY!
105 auto popupObject = dynamic_cast<QObject*>(d->popupWidget);
106 KIS_ASSERT(popupObject);
107 connect(popupObject, SIGNAL(finished()), this, SLOT(deregisterPopupWidget()));
108}

References d, deregisterPopupWidget(), KIS_ASSERT, and KisInputManager::Private::popupWidget.

◆ removeTrackedCanvas()

void KisInputManager::removeTrackedCanvas ( KisCanvas2 * canvas)

◆ setupAsEventFilter()

void KisInputManager::setupAsEventFilter ( QObject * receiver)

Installs the input manager as an event filter for receiver. Please note that KisInputManager is supposed to handle events for a single receiver only. This is defined by the fact that it resends some of the events back through the Qt's queue to the receiver. That is why the input manager will assert when it gets an event with wrong destination.

Definition at line 168 of file kis_input_manager.cpp.

169{
170 if (d->eventsReceiver) {
171 d->eventsReceiver->removeEventFilter(this);
172 }
173
174 d->eventsReceiver = receiver;
175
176 if (d->eventsReceiver) {
177 d->eventsReceiver->installEventFilter(this);
178 }
179}

References d, and KisInputManager::Private::eventsReceiver.

◆ slotAboutToChangeTool

void KisInputManager::slotAboutToChangeTool ( )
privateslot

Definition at line 820 of file kis_input_manager.cpp.

821{
822 QPointF currentLocalPos;
823 if (canvas() && canvas()->canvasWidget()) {
824 currentLocalPos = canvas()->canvasWidget()->mapFromGlobal(QCursor::pos());
825 }
826 // once more, don't forget the global state whenever matcher may trigger a KisAbstractInputAction
828
829 d->matcher.lostFocusEvent(currentLocalPos);
830}

References canvas(), KisCanvas2::canvasWidget, d, KisShortcutMatcher::lostFocusEvent(), KisInputManager::Private::matcher, and KisAbstractInputAction::setInputManager().

◆ slotCompressedMoveEvent

void KisInputManager::slotCompressedMoveEvent ( )
privateslot

Definition at line 797 of file kis_input_manager.cpp.

798{
799 if (d->compressedMoveEvent) {
801 d->compressedMoveEvent.reset();
802 }
803}
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)

References KisInputManager::Private::compressedMoveEvent, d, KisInputManager::Private::handleCompressedTabletEvent(), and void().

◆ slotConfigChanged

void KisInputManager::slotConfigChanged ( )
privateslot

Definition at line 124 of file kis_input_manager.cpp.

125{
126#ifdef Q_OS_WIN
127 d->ignoreHighFunctionKeys = KisConfig(true).ignoreHighFunctionKeys();
129#endif
130}
bool ignoreHighFunctionKeys(bool defaultValue=false) const

References d, KisInputManager::Private::fixShortcutMatcherModifiersState(), and KisConfig::ignoreHighFunctionKeys().

◆ slotTextModeChanged

void KisInputManager::slotTextModeChanged ( )
privateslot

Definition at line 855 of file kis_input_manager.cpp.

856{
857 if (!d->canvas) return;
858 KoToolManager *toolManager = KoToolManager::instance();
859 KoToolBase *tool = toolManager->toolById(canvas(), toolManager->activeToolId());
860 if (tool) {
861 if (tool->isInTextMode()) {
864 } else {
865 d->forwardAllEventsToTool = false;
867 }
868 }
869}
bool isInTextMode() const
KoToolBase * toolById(KoCanvasBase *canvas, const QString &id) const
QString activeToolId() const
Returns the toolId of the currently active tool.

References KoToolManager::activeToolId(), canvas(), KisInputManager::Private::canvas, d, KisInputManager::Private::forwardAllEventsToTool, KoToolManager::instance(), KoToolBase::isInTextMode(), KisInputManager::Private::matcher, KisShortcutMatcher::suppressAllKeyboardActions, and KoToolManager::toolById().

◆ slotToolChanged

void KisInputManager::slotToolChanged ( )
privateslot

Definition at line 832 of file kis_input_manager.cpp.

833{
834 if (!d->canvas) return;
835 KoToolManager *toolManager = KoToolManager::instance();
836 KoToolBase *tool = toolManager->toolById(canvas(), toolManager->activeToolId());
837 if (tool) {
838 // once more, don't forget the global state whenever matcher may trigger a KisAbstractInputAction
840
842 if (tool->isInTextMode()) {
845 } else {
846 d->forwardAllEventsToTool = false;
848 }
849
850 d->matcher.suppressConflictingKeyActions(toolProxy()->toolPriorityShortcuts());
852 }
853}
void setMaskSyntheticEvents(bool value)
QPointer< KisToolProxy > toolProxy() const
void suppressConflictingKeyActions(const QVector< QKeySequence > &shortcuts)
bool maskSyntheticEvents() const

References KoToolManager::activeToolId(), canvas(), KisInputManager::Private::canvas, d, KisInputManager::Private::forwardAllEventsToTool, KoToolManager::instance(), KoToolBase::isInTextMode(), KoToolBase::maskSyntheticEvents(), KisInputManager::Private::matcher, KisAbstractInputAction::setInputManager(), KisInputManager::Private::setMaskSyntheticEvents(), KisShortcutMatcher::suppressAllKeyboardActions, KisShortcutMatcher::suppressConflictingKeyActions(), KoToolManager::toolById(), KisShortcutMatcher::toolHasBeenActivated(), and toolProxy().

◆ toggleTabletLogger()

void KisInputManager::toggleTabletLogger ( )

◆ toolProxy()

QPointer< KisToolProxy > KisInputManager::toolProxy ( ) const

The tool proxy of the current application.

Definition at line 810 of file kis_input_manager.cpp.

811{
812 return d->toolProxy;
813}

References d, and KisInputManager::Private::toolProxy.

Member Data Documentation

◆ d

Private* const KisInputManager::d
private

Definition at line 119 of file kis_input_manager.h.


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