Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_input_manager.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
3 * SPDX-FileCopyrightText: 2012 Arjen Hiemstra <ahiemstra@heimr.nl>
4 * SPDX-FileCopyrightText: 2015 Michael Abrahams <miabraha@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kis_input_manager.h"
10
11#include <kis_debug.h>
12#include <QQueue>
13#include <klocalizedstring.h>
14#include <QApplication>
15#include <QTouchEvent>
16#include <QWidget>
17
18#include <KoToolManager.h>
19#include <KoPointerEvent.h>
20
21#include "kis_tool_proxy.h"
22
23#include <kis_config.h>
24#include <kis_config_notifier.h>
25#include <kis_canvas2.h>
26#include <KisViewManager.h>
27#include <kis_image.h>
30
33#include "kis_pan_action.h"
36#include "kis_zoom_action.h"
39
41#include "kis_stroke_shortcut.h"
43#include "kis_touch_shortcut.h"
44
45#include "kis_input_profile.h"
48
51
53#include "kis_input_manager_p.h"
54#include "kis_algebra_2d.h"
55#include "config-qt-patches-present.h"
56
57
58template <typename T>
60 return reinterpret_cast<quintptr>(value.data());
61}
62
64 : QObject(parent), d(new Private(this))
65{
66 d->setupActions();
67
68 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
70
71 connect(KoToolManager::instance(), SIGNAL(aboutToChangeTool(KoCanvasController*)), SLOT(slotAboutToChangeTool()));
72 connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*)), SLOT(slotToolChanged()));
73 connect(KoToolManager::instance(), SIGNAL(textModeChanged(bool)), SLOT(slotTextModeChanged()));
74 connect(&d->moveEventCompressor, SIGNAL(timeout()), SLOT(slotCompressedMoveEvent()));
75
76
77 QApplication::instance()->
78 installEventFilter(new Private::ProximityNotifier(d, this));
79
80 // on macos global Monitor listen to keypresses when krita is not in focus
81 // and local monitor listen presses when krita is in focus.
82#ifdef Q_OS_MACOS
83 KisExtendedModifiersMapper::setLocalMonitor(true, &d->matcher);
84#endif
85}
86
88{
89#ifdef Q_OS_MACOS
90 KisExtendedModifiersMapper::setLocalMonitor(false);
91#endif
92 delete d;
93}
94
99
104
106{
107 d->popupWidget = popupWidget;
108
109 // FUNKY!
110 auto popupObject = dynamic_cast<QObject*>(d->popupWidget);
111 KIS_ASSERT(popupObject);
112 connect(popupObject, SIGNAL(finished()), this, SLOT(deregisterPopupWidget()));
113}
114
116{
117 if (d->popupWidget->onScreen()) {
119 }
120
121 // FUNKY!
122 auto popupObject = dynamic_cast<QObject*>(d->popupWidget);
123 KIS_ASSERT(popupObject);
124 disconnect(popupObject, nullptr, this, nullptr); // Disconnect all.
125
126 d->popupWidget = nullptr;
127}
128
130{
131#ifdef Q_OS_WIN
132 d->ignoreHighFunctionKeys = KisConfig(true).ignoreHighFunctionKeys();
134#endif
135}
136
137
142
143void KisInputManager::attachPriorityEventFilter(QObject *filter, int priority)
144{
145 Private::PriorityList::iterator begin = d->priorityEventFilter.begin();
146 Private::PriorityList::iterator it = begin;
147 Private::PriorityList::iterator end = d->priorityEventFilter.end();
148
149 it = std::find_if(begin, end,
150 kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
151
152 if (it != end) return;
153
154 it = std::find_if(begin, end,
155 kismpl::mem_greater(&Private::PriorityPair::first, priority));
156
157 d->priorityEventFilter.insert(it, qMakePair(priority, filter));
159}
160
162{
163 Private::PriorityList::iterator it = d->priorityEventFilter.begin();
164 Private::PriorityList::iterator end = d->priorityEventFilter.end();
165
166 it = std::find_if(it, end,
167 kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
168
169 if (it != end) {
170 d->priorityEventFilter.erase(it);
171 }
172}
173
175{
176 if (d->eventsReceiver) {
177 d->eventsReceiver->removeEventFilter(this);
178 }
179
180 d->eventsReceiver = receiver;
181
182 if (d->eventsReceiver) {
183 d->eventsReceiver->installEventFilter(this);
184 }
185}
186
187#if defined (__clang__)
188#pragma GCC diagnostic ignored "-Wswitch"
189#endif
190
191bool KisInputManager::eventFilter(QObject* object, QEvent* event)
192{
193 if (object != d->eventsReceiver) return false;
194
195 if (d->eventEater.eventFilter(object, event)) return false;
196
197 if (!d->matcher.hasRunningShortcut()) {
198
199 int savedPriorityEventFilterSeqNo = d->priorityEventFilterSeqNo;
200
201 for (auto it = d->priorityEventFilter.begin(); it != d->priorityEventFilter.end(); /*noop*/) {
202 const QPointer<QObject> &filter = it->second;
203
204 if (filter.isNull()) {
205 it = d->priorityEventFilter.erase(it);
206
208 savedPriorityEventFilterSeqNo++;
209 continue;
210 }
211
212 if (filter->eventFilter(object, event)) return true;
213
218 if (d->priorityEventFilterSeqNo != savedPriorityEventFilterSeqNo) {
219 return true;
220 }
221
222 ++it;
223 }
224
225 // KoToolProxy needs to pre-process some events to ensure the
226 // global shortcuts (not the input manager's ones) are not
227 // executed, in particular, this line will accept events when the
228 // tool is in text editing, preventing shortcut triggering
229 if (d->toolProxy) {
230 d->toolProxy->processEvent(event);
231 }
232 }
233
234 // Continue with the actual switch statement...
235 return eventFilterImpl(event);
236}
237
238template <class Event>
240{
245 static_assert(std::is_same<Event, QMouseEvent>::value ||
246 std::is_same<Event, QTabletEvent>::value ||
247 std::is_same<Event, QTouchEvent>::value,
248 "event should be a mouse or a tablet event");
249
250
251 bool retval = false;
252
256 if ((event->type() == QEvent::MouseMove ||
257 event->type() == QEvent::TabletMove ||
258 event->type() == QEvent::TouchUpdate) &&
261#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
262 KoPointerEvent::copyQtPointerEvent(event, d->compressedMoveEvent);
263#else
264 d->compressedMoveEvent.reset(event->clone());
265#endif
267
275 event->setAccepted(true);
276 }
277
278 retval = true;
279 } else {
281 retval = d->handleCompressedTabletEvent(event);
282 }
283
284 return retval;
285}
286
287bool shouldResetWheelDelta(QEvent * event)
288{
289 return
290 event->type() == QEvent::FocusIn ||
291 event->type() == QEvent::FocusOut ||
292 event->type() == QEvent::MouseButtonPress ||
293 event->type() == QEvent::MouseButtonRelease ||
294 event->type() == QEvent::MouseButtonDblClick ||
295 event->type() == QEvent::TabletPress ||
296 event->type() == QEvent::TabletRelease ||
297 event->type() == QEvent::Enter ||
298 event->type() == QEvent::Leave ||
299 event->type() == QEvent::TouchBegin ||
300 event->type() == QEvent::TouchEnd ||
301 event->type() == QEvent::TouchCancel ||
302 event->type() == QEvent::NativeGesture;
303
304}
305
307{
308 bool retval = false;
309
310 // Try closing any open popup widget and
311 // consume input if possible.
312 if (d->popupWidget) {
313 QEvent::Type type = event->type();
314
315 if (type == QEvent::MouseButtonPress
316 || type == QEvent::MouseButtonDblClick
317 || type == QEvent::TabletPress
318 || type == QEvent::TouchBegin
319 || type == QEvent::NativeGesture) {
320 bool wasVisible = d->popupWidget->onScreen();
322
323 if (wasVisible) {
324 d->popupWasActive = true;
325 event->setAccepted(true);
326 return true; // Event consumed.
327 }
328 }
329 }
330
331 if (shouldResetWheelDelta(event)) {
333 }
334
335 if (event->type() == QEvent::MouseMove ||
336 event->type() == QEvent::MouseButtonPress ||
337 event->type() == QEvent::MouseButtonRelease ||
338 event->type() == QEvent::TabletMove ||
339 event->type() == QEvent::TabletPress ||
340 event->type() == QEvent::TabletRelease ||
341 event->type() == QEvent::Wheel) {
342
352 QWidget *receivingWidget = dynamic_cast<QWidget*>(d->eventsReceiver);
353 if (receivingWidget && !receivingWidget->hasFocus()) {
355 } else {
363 QInputEvent *inputEvent = static_cast<QInputEvent*>(event);
364 if (event->type() != QEvent::ShortcutOverride &&
365 !d->matcher.sanityCheckModifiersCorrectness(inputEvent->modifiers())) {
366
368 } else if (d->matcher.hasPolledKeys()) {
377 }
378 }
379 }
380
381 switch (event->type()) {
382 case QEvent::MouseButtonPress:
383 case QEvent::MouseButtonDblClick: {
384 d->debugEvent<QMouseEvent, true>(event);
385 if (d->touchHasBlockedPressEvents) break;
386
387 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
388
389 if (d->popupWidget) {
390 retval = true;
391 } else {
392 //Make sure the input actions know we are active.
394 retval = d->matcher.buttonPressed(mouseEvent->button(), mouseEvent);
395 }
396 //Reset signal compressor to prevent processing events before press late
398 event->setAccepted(retval);
399 break;
400 }
401 case QEvent::MouseButtonRelease: {
402 d->debugEvent<QMouseEvent, true>(event);
403 if (d->touchHasBlockedPressEvents) break;
404
405 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
406 retval = d->matcher.buttonReleased(mouseEvent->button(), mouseEvent);
407 event->setAccepted(retval);
408 break;
409 }
410 case QEvent::ShortcutOverride: {
411 d->debugEvent<QKeyEvent, false>(event);
412 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
413
415
424 QVector<Qt::Key> guessedKeys;
426 Qt::KeyboardModifiers modifiers = mapper.queryStandardModifiers();
427 Q_FOREACH (Qt::Key key, mapper.queryExtendedModifiers()) {
428 QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
430 }
431
432 if (!d->matcher.debugPressedKeys().contains(key)) {
433 guessedKeys.removeOne(key);
434 }
435
436 d->fixShortcutMatcherModifiersState(guessedKeys, modifiers);
438 }
439
440 if (!keyEvent->isAutoRepeat()) {
441 retval = d->matcher.keyPressed(key);
442 } else {
443 retval = d->matcher.autoRepeatedKeyPressed(key);
444 }
445
446 // In case we matched a shortcut we should accept the event to
447 // notify Qt that it shouldn't try to trigger its partially matched
448 // shortcuts.
449 if (retval) {
450 keyEvent->setAccepted(true);
451 }
452
453 break;
454 }
455 case QEvent::KeyRelease: {
456 d->debugEvent<QKeyEvent, false>(event);
457 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
458
459 if (!keyEvent->isAutoRepeat()) {
461 retval = d->matcher.keyReleased(key);
462
490 !d->matcher.debugPressedKeys().isEmpty() &&
491 (key == Qt::Key_Shift || key == Qt::Key_Alt ||
492 key == Qt::Key_Control || key == Qt::Key_Meta)) {
493
495 }
496 }
497 break;
498 }
499 case QEvent::MouseMove: {
500 d->debugEvent<QMouseEvent, true>(event);
501
502 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
503 retval = compressMoveEventCommon(mouseEvent);
504
505 break;
506 }
507 case QEvent::Wheel: {
508 d->debugEvent<QWheelEvent, false>(event);
509 QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
510
511#ifdef Q_OS_MACOS
512 // Some QT wheel events are actually touch pad pan events. From the QT docs:
513 // "Wheel events are generated for both mouse wheels and trackpad scroll gestures."
514
515 // We differentiate between touchpad events and real mouse wheels by inspecting the
516 // event source.
517
518 if (wheelEvent->source() == Qt::MouseEventSource::MouseEventSynthesizedBySystem) {
521 break;
522 }
523#endif
524
525 d->accumulatedScrollDelta += wheelEvent->angleDelta().y();
527
532#ifdef Q_OS_MACOS
533 if (wheelEvent->angleDelta().isNull()) {
534 retval = true;
535 break;
536 }
537#endif
538
539 if (wheelEvent->angleDelta().x() < 0) {
541 } else if (wheelEvent->angleDelta().x() >0) {
543 }
544
545 if (wheelEvent->angleDelta().y() < 0) {
547 } else if (wheelEvent->angleDelta().y() > 0) {
549 }
550
551 bool wasScrolled = false;
552
553 while (qAbs(d->accumulatedScrollDelta) >= QWheelEvent::DefaultDeltasPerStep) {
554 //Make sure the input actions know we are active.
556 retval = d->matcher.wheelEvent(action, wheelEvent);
559 QWheelEvent::DefaultDeltasPerStep;
560 wasScrolled = true;
561 }
562
563 if (wasScrolled) {
565 }
566
567 retval = !wasScrolled;
568 break;
569 }
570#ifndef Q_OS_ANDROID
571 case QEvent::Enter:
572 d->debugEvent<QEvent, false>(event);
573 //Make sure the input actions know we are active.
575 if (!d->containsPointer) {
576 d->containsPointer = true;
577
580 }
582 break;
583 case QEvent::Leave:
584 d->debugEvent<QEvent, false>(event);
585 d->containsPointer = false;
593
595 break;
596#endif
597 case QEvent::FocusIn:
598 d->debugEvent<QEvent, false>(event);
600
603
605 break;
606
607 case QEvent::FocusOut: {
608 d->debugEvent<QEvent, false>(event);
610
611 QPointF currentLocalPos =
612 canvas()->canvasWidget()->mapFromGlobal(QCursor::pos());
613
614 d->matcher.lostFocusEvent(currentLocalPos);
615
616 break;
617 }
618 case QEvent::TabletPress: {
619 d->debugEvent<QTabletEvent, false>(event);
620 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
621
622 {
623 //Make sure the input actions know we are active.
625 retval = d->matcher.buttonPressed(tabletEvent->button(), tabletEvent);
626 if (!d->containsPointer) {
627 d->containsPointer = true;
629 }
630 }
631
632 event->setAccepted(true);
633 retval = true;
636 //Reset signal compressor to prevent processing events before press late
638
639
640#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
641 // remove this hack when this patch is integrated:
642 // https://codereview.qt-project.org/#/c/255384/
643 event->setAccepted(false);
645#elif defined Q_OS_WIN32
651#endif
652
653 break;
654 }
655 case QEvent::TabletMove: {
656 d->debugEvent<QTabletEvent, false>(event);
657
658 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
659 retval = compressMoveEventCommon(tabletEvent);
660
661 if (d->tabletLatencyTracker) {
662 d->tabletLatencyTracker->push(tabletEvent->timestamp());
663 }
664
673
674#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
675 // remove this hack when this patch is integrated:
676 // https://codereview.qt-project.org/#/c/255384/
677 event->setAccepted(false);
678#endif
679
680 break;
681 }
682 case QEvent::TabletRelease: {
683#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID)
685#endif
687 d->debugEvent<QTabletEvent, false>(event);
688
689 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
690 retval = d->matcher.buttonReleased(tabletEvent->button(), tabletEvent);
691 retval = true;
692 event->setAccepted(true);
693
694#if defined Q_OS_LINUX && !KRITA_QT_HAS_ENTER_LEAVE_PATCH
695 // remove this hack when this patch is integrated:
696 // https://codereview.qt-project.org/#/c/255384/
697 event->setAccepted(false);
698#endif
699
700 break;
701 }
702
703 case QEvent::TouchBegin:
704 {
705 d->debugEvent<QTouchEvent, false>(event);
706 // The popup was dismissed in previous TouchBegin->TouchEnd sequence. We now have a new TouchBegin.
707 d->popupWasActive = false;
708 if (startTouch(retval)) {
709 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
711 d->previousPos = touchEvent->touchPoints().at(0).pos();
712 // we don't want to lose this event
713#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
714 KoPointerEvent::copyQtPointerEvent(touchEvent, d->originatingTouchBeginEvent);
715#else
716 d->originatingTouchBeginEvent.reset(touchEvent->clone());
717#endif
718 retval = d->matcher.touchBeginEvent(touchEvent);
720 d->touchStrokeStarted = false;
721 }
723 event->accept();
724 }
725 break;
726 }
727
728 case QEvent::TouchUpdate:
729 {
730 if (d->popupWasActive) {
731 event->setAccepted(true);
732 return true;
733 }
734 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
735 d->debugEvent<QTouchEvent, false>(event);
736
737#ifdef Q_OS_MAC
738 int count = 0;
739 Q_FOREACH (const QTouchEvent::TouchPoint &point, touchEvent->touchPoints()) {
740 if (point.state() != Qt::TouchPointReleased) {
741 count++;
742 }
743 }
744
745 if (count < 2 && touchEvent->touchPoints().length() > count) {
747 retval = d->matcher.touchEndEvent(touchEvent);
748 } else {
749#endif
750 QPointF currentPos = touchEvent->touchPoints().at(0).pos();
751 if (d->touchStrokeStarted || (!KisConfig(true).disableTouchOnCanvas()
753 && touchEvent->touchPoints().count() == 1
754 && touchEvent->touchPointStates() != Qt::TouchPointStationary
755 && (qAbs(currentPos.x() - d->previousPos.x()) > 1 // stop wobbliness which Qt sends us
756 || qAbs(currentPos.y() - d->previousPos.y()) > 1)))
757 {
758 d->previousPos = currentPos;
759 if (!d->touchStrokeStarted) {
760 // we start it here not in TouchBegin, because Qt::TouchPointStationary doesn't work with hpdi devices.
761 retval = d->matcher.buttonPressed(Qt::LeftButton, d->originatingTouchBeginEvent.data());
762 d->touchStrokeStarted = retval;
763 } else {
764 // if it is a full-fledged stroke, then ignore (currentPos.x - previousPos.x)
765 retval = compressMoveEventCommon(touchEvent);
767 }
768 } else {
771 retval = compressMoveEventCommon(touchEvent);
772 } else {
773 retval = d->matcher.touchUpdateEvent(touchEvent);
775 }
776 }
777#ifdef Q_OS_MACOS
778 }
779#endif
780 // if the event isn't handled, Qt starts to send MouseEvents
781 if (!KisConfig(true).disableTouchOnCanvas())
782 retval = true;
783
784 event->accept();
785 break;
786 }
787
788 case QEvent::TouchEnd:
789 {
790 if (d->popupWasActive) {
791 event->setAccepted(true);
792 return true;
793 }
794 d->debugEvent<QTouchEvent, false>(event);
795 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
796 retval = d->matcher.touchEndEvent(touchEvent);
797 if (d->touchStrokeStarted) {
798 retval = d->matcher.buttonReleased(Qt::LeftButton, touchEvent);
799 d->previousPos = {0, 0};
800 d->touchStrokeStarted = false; // stroke ended
802 && touchEvent->touchPoints().count() == 1) {
803 // If no stroke has been started while touch painting is enabled,
804 // the user tapped with one finger, but didn't make any motion that
805 // caused us to start a stroke. We produce a press and release in
806 // response so that the tool responds to their input.
807 d->matcher.buttonPressed(Qt::LeftButton, d->originatingTouchBeginEvent.data());
808 d->matcher.buttonReleased(Qt::LeftButton, touchEvent);
809 }
810
811 endTouch();
813
814 // if the event isn't handled, Qt starts to send MouseEvents
815 if (!KisConfig(true).disableTouchOnCanvas())
816 retval = true;
817
818 event->accept();
819 break;
820 }
821 case QEvent::TouchCancel:
822 {
823 if (d->popupWasActive) {
824 event->setAccepted(true);
825 return true;
826 }
827 d->debugEvent<QTouchEvent, false>(event);
828 endTouch();
830 QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
831 d->matcher.touchCancelEvent(touchEvent, d->previousPos);
832 // reset state
833 d->previousPos = {0, 0};
834 d->touchStrokeStarted = false;
835 retval = true;
836 event->accept();
837 break;
838 }
839
840 case QEvent::NativeGesture:
841 {
842 QNativeGestureEvent *gevent = static_cast<QNativeGestureEvent*>(event);
843 switch (gevent->gestureType()) {
844 case Qt::BeginNativeGesture:
845 {
846 if (startTouch(retval)) {
848 retval = d->matcher.nativeGestureBeginEvent(gevent);
849 event->accept();
850 }
851 break;
852 }
853 case Qt::EndNativeGesture:
854 {
855 endTouch();
856 retval = d->matcher.nativeGestureEndEvent(gevent);
857 event->accept();
858 break;
859 }
860 default:
861 {
863 retval = d->matcher.nativeGestureEvent(gevent);
864 event->accept();
865 break;
866 }
867 }
868 break;
869 }
870
871 default:
872 break;
873 }
874
875 return !retval ? d->processUnhandledEvent(event) : true;
876}
877
879{
880 Q_UNUSED(retval);
881
882 // Touch rejection: if touch is disabled on canvas, no need to block mouse press events
883 if (KisConfig(true).disableTouchOnCanvas()) {
885 }
886
887 return true;
888}
889
894
896{
897 if (d->compressedMoveEvent) {
898 // d->touchHasBlockedPressEvents = false;
899
901 d->compressedMoveEvent.reset();
902 //dbgInput << "Compressed move event received.";
903 } else {
904 //dbgInput << "Unexpected empty move event";
905 }
906}
907
909{
910 return d->canvas;
911}
912
917
919{
920 QPointF currentLocalPos;
921 if (canvas() && canvas()->canvasWidget()) {
922 currentLocalPos = canvas()->canvasWidget()->mapFromGlobal(QCursor::pos());
923 }
924 // once more, don't forget the global state whenever matcher may trigger a KisAbstractInputAction
926
927 d->matcher.lostFocusEvent(currentLocalPos);
928}
929
931{
932 if (!d->canvas) return;
933 KoToolManager *toolManager = KoToolManager::instance();
934 KoToolBase *tool = toolManager->toolById(canvas(), toolManager->activeToolId());
935 if (tool) {
936 // once more, don't forget the global state whenever matcher may trigger a KisAbstractInputAction
938
940 if (tool->isInTextMode()) {
943 } else {
944 d->forwardAllEventsToTool = false;
946 }
947
948 d->matcher.suppressConflictingKeyActions(toolProxy()->toolPriorityShortcuts());
950 }
951}
952
954{
955 if (!d->canvas) return;
956 KoToolManager *toolManager = KoToolManager::instance();
957 KoToolBase *tool = toolManager->toolById(canvas(), toolManager->activeToolId());
958 if (tool) {
959 if (tool->isInTextMode()) {
962 } else {
963 d->forwardAllEventsToTool = false;
965 }
966 }
967}
968
969
971{
973
975 if (profile) {
976 const QList<KisShortcutConfiguration*> shortcuts = profile->allShortcuts();
977
978 for (KisShortcutConfiguration * const shortcut : shortcuts) {
979 dbgUI << "Adding shortcut" << shortcut->keys() << "for action" << shortcut->action()->name();
980 switch(shortcut->type()) {
982 d->addKeyShortcut(shortcut->action(), shortcut->mode(), shortcut->keys());
983 break;
985 d->addStrokeShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->buttons());
986 break;
988 d->addWheelShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->wheel());
989 break;
991 if (!d->addNativeGestureShortcut(shortcut->action(), shortcut->mode(), shortcut->gesture())) {
992 d->addTouchShortcut(shortcut->action(), shortcut->mode(), shortcut->gesture());
993 }
994 break;
995 default:
996 break;
997 }
998 }
999 }
1000 else {
1001 dbgInput << "No Input Profile Found: canvas interaction will be impossible";
1002 }
1003}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
unsigned int uint
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
static void setInputManager(KisInputManager *manager)
KisAbstractCanvasWidget * canvasWidget
static KisConfigNotifier * instance()
bool disableTouchOnCanvas() const
bool ignoreHighFunctionKeys(bool defaultValue=false) const
static Qt::Key workaroundShiftAltMetaHell(const QKeyEvent *keyEvent)
void debugEvent(QEvent *event)
void setMaskSyntheticEvents(bool value)
bool addNativeGestureShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::GestureAction gesture)
bool handleCompressedTabletEvent(QEvent *event)
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)
QScopedPointer< QEvent > originatingTouchBeginEvent
QPointer< KisToolProxy > toolProxy
KisSignalCompressor moveEventCompressor
void addStrokeShortcut(KisAbstractInputAction *action, int index, const QList< Qt::Key > &modifiers, Qt::MouseButtons buttons)
QScopedPointer< QEvent > compressedMoveEvent
QPointer< KisCanvas2 > canvas
bool processUnhandledEvent(QEvent *event)
KisSharedPtr< TabletLatencyTracker > tabletLatencyTracker
void addTouchShortcut(KisAbstractInputAction *action, int index, KisShortcutConfiguration::GestureAction gesture)
KisPopupWidgetInterface * popupWidget
KisCanvas2 * canvas() const
bool compressMoveEventCommon(Event *event)
~KisInputManager() override
void detachPriorityEventFilter(QObject *filter)
detachPriorityEventFilter
void setupAsEventFilter(QObject *receiver)
QPointer< KisToolProxy > toolProxy() const
void removeTrackedCanvas(KisCanvas2 *canvas)
void addTrackedCanvas(KisCanvas2 *canvas)
KisInputManager(QObject *parent)
void attachPriorityEventFilter(QObject *filter, int priority=0)
attachPriorityEventFilter
bool eventFilter(QObject *object, QEvent *event) override
bool startTouch(bool &retval)
void registerPopupWidget(KisPopupWidgetInterface *popupWidget)
bool eventFilterImpl(QEvent *event)
static KisInputProfileManager * instance()
A container class for sets of shortcuts associated with an action.
QList< KisShortcutConfiguration * > allShortcuts() const
The PopupWidgetInterface abstract class defines the basic interface that will be used by all popup wi...
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.
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.
void lostFocusEvent(const QPointF &localPos)
bool autoRepeatedKeyPressed(Qt::Key key)
bool buttonReleased(Qt::MouseButton button, QEvent *event)
bool nativeGestureEndEvent(QNativeGestureEvent *event)
bool keyPressed(Qt::Key key)
bool touchBeginEvent(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)
void suppressConflictingKeyActions(const QVector< QKeySequence > &shortcuts)
bool keyReleased(Qt::Key key)
void touchCancelEvent(QTouchEvent *event, const QPointF &localPos)
bool wheelEvent(KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
@ WheelDown
Mouse wheel moves down.
@ WheelTrackpad
A pan movement on a trackpad.
@ WheelRight
Mouse wheel moves right.
@ WheelLeft
Mouse wheel moves left.
static KisTabletDebugger * instance()
bool maskSyntheticEvents() const
bool isInTextMode() const
KoToolBase * toolById(KoCanvasBase *canvas, const QString &id) const
QString activeToolId() const
Returns the toolId of the currently active tool.
static KoToolManager * instance()
Return the toolmanager singleton.
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define dbgUI
Definition kis_debug.h:52
#define dbgInput
Definition kis_debug.h:57
bool shouldResetWheelDelta(QEvent *event)
uint qHash(QPointer< T > value)
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
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
bool eventFilter(QObject *target, QEvent *event)