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

#include <kis_shortcut_matcher.h>

+ Inheritance diagram for KisShortcutMatcher:

Classes

struct  RecursionGuard
 
struct  RecursionNotifier
 

Public Member Functions

bool actionsSuppressed () const
 
bool actionsSuppressedIgnoreFocus () const
 
void addShortcut (KisNativeGestureShortcut *shortcut)
 
void addShortcut (KisSingleActionShortcut *shortcut)
 
void addShortcut (KisStrokeShortcut *shortcut)
 
void addShortcut (KisTouchShortcut *shortcut)
 
bool autoRepeatedKeyPressed (Qt::Key key)
 
bool buttonPressed (Qt::MouseButton button, QEvent *event)
 
bool buttonReleased (Qt::MouseButton button, QEvent *event)
 
void clearShortcuts ()
 
QVector< Qt::Key > debugPressedKeys () const
 
void enterEvent ()
 
void handlePolledKeys (const QVector< Qt::Key > &keys)
 
bool hasPolledKeys ()
 
bool hasRunningShortcut () const
 
bool hasTouchHoldShortcut () const
 
bool KeyboardActionsSuppressed () const
 
bool keyPressed (Qt::Key key)
 
bool keyReleased (Qt::Key key)
 
 KisShortcutMatcher ()
 
void leaveEvent ()
 
void lostFocusEvent (const QPointF &localPos)
 
bool nativeGestureBeginEvent (QNativeGestureEvent *event)
 
bool nativeGestureEndEvent (QNativeGestureEvent *event)
 
bool nativeGestureEvent (QNativeGestureEvent *event)
 
bool pointerMoved (QEvent *event)
 
 Private ()
 
void reinitialize ()
 
void reinitializeButtons ()
 
bool sanityCheckModifiersCorrectness (Qt::KeyboardModifiers modifiers) const
 
void setInputActionGroupsMaskCallback (std::function< KisInputActionGroupsMask()> func)
 
bool supportsHiResInputEvents ()
 
void suppressAllActions (bool value)
 
void suppressAllKeyboardActions (bool value)
 
void suppressConflictingKeyActions (const QVector< QKeySequence > &shortcuts)
 
void toolHasBeenActivated ()
 
bool touchBeginEvent (QTouchEvent *event)
 
void touchCancelEvent (QTouchEvent *event, const QPointF &localPos)
 
bool touchEndEvent (QTouchEvent *event)
 
bool touchHoldBeginEvent (QTouchEvent *event)
 
bool touchUpdateEvent (QTouchEvent *event)
 
bool wheelEvent (KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
 
 ~KisShortcutMatcher ()
 
 ~Private ()
 

Public Attributes

std::function< KisInputActionGroupsMask()> actionGroupMask
 
QScopedPointer< QEvent > bestCandidateTouchEvent
 
int brokenByRecursion = 0
 
QSet< Qt::MouseButton > buttons
 
QList< KisStrokeShortcut * > candidateShortcuts
 
bool cursorEntered
 
bool isTouchDragDetected {false}
 
bool isTouchHeld {false}
 
QSet< Qt::Key > keys
 
QList< QTouchEvent::TouchPoint > lastTouchPoints
 
int matchingIteration {0}
 
int maxTouchPoints {0}
 
KisNativeGestureShortcutnativeGestureShortcut
 
QList< KisNativeGestureShortcut * > nativeGestureShortcuts
 
QSet< Qt::Key > polledKeys
 
KisStrokeShortcutreadyShortcut
 
int recursiveCounter = 0
 
KisStrokeShortcutrunningShortcut
 
QList< KisSingleActionShortcut * > singleActionShortcuts
 
QList< KisStrokeShortcut * > strokeShortcuts
 
bool suppressAllActions
 
bool suppressAllKeyboardActions
 
QSet< KisSingleActionShortcut * > suppressedSingleActionShortcuts
 
KisTouchShortcuttouchShortcut
 
QList< KisTouchShortcut * > touchShortcuts
 

Static Public Attributes

static constexpr int TOUCH_SLOP_SQUARED = 16 * 16
 

Private Member Functions

void fireReadyTouchShortcut (QTouchEvent *event)
 
void forceDeactivateAllActions ()
 
void forceEndRunningShortcut (const QPointF &localPos)
 
KisTouchShortcutmatchTouchShortcut (QTouchEvent *event)
 
bool matchTouchShortcutBasedOnState (QTouchEvent *event, KisTouchShortcut *shortcut)
 
void prepareReadyShortcuts ()
 
void reset ()
 
void reset (QString msg)
 
void setMaxTouchPointEvent (QTouchEvent *event)
 
void tryActivateReadyShortcut ()
 
bool tryEndNativeGestureShortcut (QNativeGestureEvent *event)
 
bool tryEndRunningShortcut (Qt::MouseButton button, QEvent *event)
 
bool tryEndTouchShortcut (QTouchEvent *event)
 
bool tryRunNativeGestureShortcut (QNativeGestureEvent *event)
 
bool tryRunReadyShortcut (Qt::MouseButton button, QEvent *event)
 
template<typename T , typename U >
bool tryRunSingleActionShortcutImpl (T param, U *event, const QSet< Qt::Key > &keysState, bool keyboard=true)
 
bool tryRunTouchShortcut (QTouchEvent *event)
 
bool tryRunWheelShortcut (KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
 
- Private Member Functions inherited from Private
 Private (KisCanvas2 *c)
 

Private Attributes

Private *const m_d
 
- Private Attributes inherited from Private
KisCanvas2canvas
 
int displayedFrame
 
int intendedFrame
 

Friends

class KisInputManagerTest
 

Detailed Description

The class that manages connections between shortcuts and actions.

It processes input events and generates state transitions for the actions basing on the data, represented by the shortcuts.

The class works with two types of actions: long running (represented by KisStrokeShortcuts) and "atomic" (KisSingleActionShortcut). The former one involves some long interaction with the user by means of a mouse cursor or a tablet, the latter one simple action like "Zoom 100%" or "Reset Rotation".

The single action shortcuts are handled quite easily. The matcher listens to the events coming, manages two lists of the pressed keys and buttons and when their content corresponds to some single action shortcut it just runs this shortcut once.

The strategy for handling the stroke shortcuts is a bit more complex. Each such action may be in one of the three states:

Idle <-> Ready <-> Running

In "Idle" state the action is completely inactive and has no access to the user

When the action is in "Ready" state, it means that all the modifiers for the action are already pressed and we are only waiting for a user to press the mouse button and start a stroke. In this state the action can show the user its Cursor to notify the user what is going to happen next.

In the "Running" state, the action has full access to the user input and is considered to perform all the work it was created for.

To implement such state transitions for the actions, KisShortcutMatcher first forms a list of the actions which can be moved to a ready state (m_d->readyShortcuts), then chooses the one with the highest priority to be the only shortcut in the "Ready" state and activates it (m_d->readyShortcut). Then when the user presses the mouse button, the matcher looks through the list of ready shortcuts, chooses which will be running now, deactivates (if needed) currently activated action and starts the chosen one.

See also
KisSingleActionShortcut
KisStrokeShortcut

Definition at line 46 of file kis_shortcut_matcher.cpp.

Constructor & Destructor Documentation

◆ ~Private()

KisShortcutMatcher::~Private ( )
inline

Definition at line 60 of file kis_shortcut_matcher.cpp.

61 {
62 qDeleteAll(singleActionShortcuts);
63 qDeleteAll(strokeShortcuts);
64 qDeleteAll(touchShortcuts);
65 }
QList< KisStrokeShortcut * > strokeShortcuts
QList< KisSingleActionShortcut * > singleActionShortcuts
QList< KisTouchShortcut * > touchShortcuts

◆ KisShortcutMatcher()

KisShortcutMatcher::KisShortcutMatcher ( )

Definition at line 155 of file kis_shortcut_matcher.cpp.

156 : m_d(new Private)
157{}

◆ ~KisShortcutMatcher()

KisShortcutMatcher::~KisShortcutMatcher ( )

Definition at line 159 of file kis_shortcut_matcher.cpp.

160{
161 delete m_d;
162}

References m_d.

Member Function Documentation

◆ actionsSuppressed()

bool KisShortcutMatcher::actionsSuppressed ( ) const
inline

Definition at line 137 of file kis_shortcut_matcher.cpp.

137 {
138#ifndef Q_OS_ANDROID
140#else
141 // when S-pen is not pointing the canvas, actions on canvas are disabled, till it points back to canvas.
142 return false;
143#endif
144 }

◆ actionsSuppressedIgnoreFocus()

bool KisShortcutMatcher::actionsSuppressedIgnoreFocus ( ) const
inline

Definition at line 146 of file kis_shortcut_matcher.cpp.

146 {
147 return suppressAllActions;
148 }

◆ addShortcut() [1/4]

void KisShortcutMatcher::addShortcut ( KisNativeGestureShortcut * shortcut)

Definition at line 194 of file kis_shortcut_matcher.cpp.

194 {
195 m_d->nativeGestureShortcuts.append(shortcut);
196}

References m_d.

◆ addShortcut() [2/4]

void KisShortcutMatcher::addShortcut ( KisSingleActionShortcut * shortcut)

Definition at line 179 of file kis_shortcut_matcher.cpp.

180{
181 m_d->singleActionShortcuts.append(shortcut);
182}

References m_d.

◆ addShortcut() [3/4]

void KisShortcutMatcher::addShortcut ( KisStrokeShortcut * shortcut)

Definition at line 184 of file kis_shortcut_matcher.cpp.

185{
186 m_d->strokeShortcuts.append(shortcut);
187}

References m_d.

◆ addShortcut() [4/4]

void KisShortcutMatcher::addShortcut ( KisTouchShortcut * shortcut)

Definition at line 189 of file kis_shortcut_matcher.cpp.

190{
191 m_d->touchShortcuts.append(shortcut);
192}

References m_d.

◆ autoRepeatedKeyPressed()

bool KisShortcutMatcher::autoRepeatedKeyPressed ( Qt::Key key)

Handles a key press event that has been generated by the autorepeat.

Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 233 of file kis_shortcut_matcher.cpp.

234{
235 Private::RecursionNotifier notifier(this);
236
237
238 bool retval = false;
239
240 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, autorepeated key but can't remember it was pressed"); }
241
242 if (m_d->polledKeys.contains(key)) {
243 m_d->polledKeys.remove(key);
244 }
245
246 if (notifier.isInRecursion()) {
248 } else if (!hasRunningShortcut()) {
249 // Autorepeated key should not be included in the shortcut
250 QSet<Qt::Key> filteredKeys = m_d->keys;
251 filteredKeys.remove(key);
252 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, filteredKeys);
253 }
254
255 return retval;
256}
bool tryRunSingleActionShortcutImpl(T param, U *event, const QSet< Qt::Key > &keysState, bool keyboard=true)
#define DEBUG_ACTION(action)
WGConfigNotifier * notifier()
Definition WGConfig.cpp:190

References DEBUG_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), m_d, and tryRunSingleActionShortcutImpl().

◆ buttonPressed()

bool KisShortcutMatcher::buttonPressed ( Qt::MouseButton button,
QEvent * event )

Handles button presses from a tablet or mouse.

Parameters
eventthe event that caused this call. Must be of type QTabletEvent or QMouseEvent.
Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 279 of file kis_shortcut_matcher.cpp.

280{
281 Private::RecursionNotifier notifier(this);
282 DEBUG_BUTTON_ACTION("entered", button);
283
284 bool retval = false;
285
286 if (m_d->buttons.contains(button)) { DEBUG_ACTION("Peculiar, button was already pressed."); }
287
288 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
290 retval = tryRunReadyShortcut(button, event);
291 }
292
293 m_d->buttons.insert(button);
294
295 if (notifier.isInRecursion()) {
297 } else if (!hasRunningShortcut()) {
300 }
301
302 return retval;
303}
bool tryRunReadyShortcut(Qt::MouseButton button, QEvent *event)
#define DEBUG_BUTTON_ACTION(text, button)
QString button(const QWheelEvent &ev)

References button(), DEBUG_ACTION, DEBUG_BUTTON_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), tryActivateReadyShortcut(), and tryRunReadyShortcut().

◆ buttonReleased()

bool KisShortcutMatcher::buttonReleased ( Qt::MouseButton button,
QEvent * event )

Handles the mouse button release event

Parameters
eventthe event that caused this call. Must be of type QTabletEvent or QMouseEvent.
Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 305 of file kis_shortcut_matcher.cpp.

306{
307 Private::RecursionNotifier notifier(this);
308 DEBUG_BUTTON_ACTION("entered", button);
309
310 bool retval = false;
311
312 // here we check for the presence of the **stroke** shortcut only
313 if (m_d->runningShortcut) {
314 KIS_SAFE_ASSERT_RECOVER_NOOP(!notifier.isInRecursion());
315
316 retval = tryEndRunningShortcut(button, event);
317 DEBUG_BUTTON_ACTION("ended", button);
318 }
319
320 if (!m_d->buttons.contains(button)) reset("Peculiar, button released but we can't remember it was pressed");
321 else m_d->buttons.remove(button);
322
323 if (notifier.isInRecursion()) {
325 } else if (!hasRunningShortcut()) {
328 }
329
330 return retval;
331}
bool tryEndRunningShortcut(Qt::MouseButton button, QEvent *event)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References button(), DEBUG_BUTTON_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, prepareReadyShortcuts(), reset(), tryActivateReadyShortcut(), and tryEndRunningShortcut().

◆ clearShortcuts()

void KisShortcutMatcher::clearShortcuts ( )

Remove all shortcuts that have been registered.

Definition at line 787 of file kis_shortcut_matcher.cpp.

788{
789 reset("Clearing shortcuts");
790 qDeleteAll(m_d->singleActionShortcuts);
791 m_d->singleActionShortcuts.clear();
792 qDeleteAll(m_d->strokeShortcuts);
793 qDeleteAll(m_d->touchShortcuts);
794 m_d->strokeShortcuts.clear();
795 m_d->candidateShortcuts.clear();
796 m_d->touchShortcuts.clear();
797 m_d->runningShortcut = 0;
798 m_d->readyShortcut = 0;
799}

References m_d, and reset().

◆ debugPressedKeys()

QVector< Qt::Key > KisShortcutMatcher::debugPressedKeys ( ) const

Return the internal state of the tracked modifiers.

Definition at line 701 of file kis_shortcut_matcher.cpp.

702{
704 std::copy(m_d->keys.begin(), m_d->keys.end(), std::back_inserter(keys));
705 return keys;
706}

References keys, and m_d.

◆ enterEvent()

void KisShortcutMatcher::enterEvent ( )

Handle cursor's Enter event. We never eat it because it might be used by someone else

Definition at line 365 of file kis_shortcut_matcher.cpp.

366{
367 Private::RecursionNotifier notifier(this);
368
369 m_d->cursorEntered = true;
370
371 if (notifier.isInRecursion()) {
373 } else if (!hasRunningShortcut()) {
376 }
377}

References forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ fireReadyTouchShortcut()

void KisShortcutMatcher::fireReadyTouchShortcut ( QTouchEvent * event)
private

Definition at line 1026 of file kis_shortcut_matcher.cpp.

1027{
1028 KisTouchShortcut *goodCandidate = matchTouchShortcut(event);
1029 if (goodCandidate) {
1030 DEBUG_TOUCH_ACTION("starting", event)
1031 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1032 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1033
1034 goodCandidate->action()->end(event);
1035 goodCandidate->action()->deactivate(goodCandidate->shortcutIndex());
1036 }
1037}
virtual void activate(int shortcut)
virtual void deactivate(int shortcut)
virtual void end(QEvent *event)
virtual void begin(int shortcut, QEvent *event)
KisAbstractInputAction * action
KisTouchShortcut * matchTouchShortcut(QTouchEvent *event)
The KisTouchShortcut class only handles touch gestures it does not handle tool invocation i....
#define DEBUG_TOUCH_ACTION(text, event)

References KisAbstractShortcut::action, KisAbstractInputAction::activate(), KisAbstractInputAction::begin(), KisAbstractInputAction::deactivate(), DEBUG_TOUCH_ACTION, KisAbstractInputAction::end(), matchTouchShortcut(), and KisAbstractShortcut::shortcutIndex.

◆ forceDeactivateAllActions()

void KisShortcutMatcher::forceDeactivateAllActions ( )
private

Definition at line 1003 of file kis_shortcut_matcher.cpp.

1004{
1005 if (m_d->readyShortcut) {
1006 DEBUG_SHORTCUT("Forcefully deactivating action", m_d->readyShortcut);
1007 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
1008 m_d->readyShortcut = 0;
1009 }
1010}
#define DEBUG_SHORTCUT(text, shortcut)

References DEBUG_SHORTCUT, and m_d.

◆ forceEndRunningShortcut()

void KisShortcutMatcher::forceEndRunningShortcut ( const QPointF & localPos)
private

Definition at line 978 of file kis_shortcut_matcher.cpp.

979{
980 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->runningShortcut);
981 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
982 // it shouldn't have happened, running and ready shortcuts
983 // at the same time should not be possible
985 }
986
987 // first reset running shortcut to avoid infinite recursion via end()
988 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
989 m_d->runningShortcut = 0;
990
991 if (runningShortcut->action()) {
992 DEBUG_ACTION("Forced ending running shortcut at event");
994 int shortcutIndex = runningShortcut->shortcutIndex();
995
996 QMouseEvent event = runningShortcut->fakeEndEvent(localPos);
997
998 action->end(&event);
999 action->deactivate(shortcutIndex);
1000 }
1001}
Abstract base class for input actions.
KisStrokeShortcut * runningShortcut
QMouseEvent fakeEndEvent(const QPointF &localPos) const
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), DEBUG_ACTION, KisAbstractInputAction::end(), KisStrokeShortcut::fakeEndEvent(), forceDeactivateAllActions(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, runningShortcut, and KisAbstractShortcut::shortcutIndex.

◆ handlePolledKeys()

void KisShortcutMatcher::handlePolledKeys ( const QVector< Qt::Key > & keys)

Resets the internal state of the matcher, tries to resync it to the state passed via argument and activates the prepared action if possible.

This synchronization happens when the user hovers Krita windows, without having keyboard focus set to it (therefore matcher cannot get key press and release events), and is also used for various other fixes.

Definition at line 661 of file kis_shortcut_matcher.cpp.

662{
663 Q_FOREACH (Qt::Key key, m_d->keys) {
664 if (!keys.contains(key)) {
665 keyReleased(key);
666 }
667 }
668
669 Q_FOREACH (Qt::Key key, keys) {
670 if (!m_d->keys.contains(key)) {
671 keyPressed(key);
672 m_d->polledKeys << key;
673 }
674 }
675
676 Private::RecursionNotifier notifier(this);
677
678 if (notifier.isInRecursion()) {
680 } else if (!hasRunningShortcut()) {
683 }
684
685 DEBUG_ACTION("recoverySyncModifiers");
686}
bool keyPressed(Qt::Key key)
bool keyReleased(Qt::Key key)

References DEBUG_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), keyPressed(), keyReleased(), keys, m_d, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ hasPolledKeys()

bool KisShortcutMatcher::hasPolledKeys ( )

Check if polled keys are present, which signals that we need to call KisInputManager::Private::fixShortcutMatcherModifiersState.

Definition at line 708 of file kis_shortcut_matcher.cpp.

709{
710 return !m_d->polledKeys.empty();
711}

References m_d.

◆ hasRunningShortcut()

bool KisShortcutMatcher::hasRunningShortcut ( ) const

Definition at line 164 of file kis_shortcut_matcher.cpp.

165{
166 return m_d->runningShortcut || m_d->touchShortcut || m_d->nativeGestureShortcut;
167}

References m_d.

◆ hasTouchHoldShortcut()

bool KisShortcutMatcher::hasTouchHoldShortcut ( ) const

Definition at line 169 of file kis_shortcut_matcher.cpp.

170{
171 for (const KisTouchShortcut *shortcut : m_d->touchShortcuts) {
172 if (shortcut->isHoldType() && shortcut->isAvailable(m_d->actionGroupMask())) {
173 return true;
174 }
175 }
176 return false;
177}

References m_d.

◆ KeyboardActionsSuppressed()

bool KisShortcutMatcher::KeyboardActionsSuppressed ( ) const
inline

Definition at line 150 of file kis_shortcut_matcher.cpp.

150 {
152 }

◆ keyPressed()

bool KisShortcutMatcher::keyPressed ( Qt::Key key)

Handles a key press event. No autorepeat events should be passed to this method.

Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 208 of file kis_shortcut_matcher.cpp.

209{
210 Private::RecursionNotifier notifier(this);
211
212 bool retval = false;
213
214 if (m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, records show key was already pressed"); }
215
216 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
217 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, m_d->keys);
218 }
219
220 m_d->keys.insert(key);
221 DEBUG_KEY("Pressed");
222
223 if (notifier.isInRecursion()) {
225 } else if (!hasRunningShortcut()) {
228 }
229
230 return retval;
231}
#define DEBUG_KEY(text)

References DEBUG_ACTION, DEBUG_KEY, forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), tryActivateReadyShortcut(), and tryRunSingleActionShortcutImpl().

◆ keyReleased()

bool KisShortcutMatcher::keyReleased ( Qt::Key key)

Handles a key release event. No autorepeat events should be passed to this method.

Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 258 of file kis_shortcut_matcher.cpp.

259{
260 Private::RecursionNotifier notifier(this);
261
262 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, key released but can't remember it was pressed"); }
263 else m_d->keys.remove(key);
264
265 m_d->polledKeys.remove(key);
266
267 DEBUG_KEY("Released");
268
269 if (notifier.isInRecursion()) {
271 } else if (!hasRunningShortcut()) {
274 }
275
276 return false;
277}

References DEBUG_ACTION, DEBUG_KEY, forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ leaveEvent()

void KisShortcutMatcher::leaveEvent ( )

Handle cursor's Leave event. We never eat it because it might be used by someone else

Definition at line 379 of file kis_shortcut_matcher.cpp.

380{
381 Private::RecursionNotifier notifier(this);
382
383 m_d->cursorEntered = false;
384
385 if (notifier.isInRecursion()) {
387 } else if (!hasRunningShortcut()) {
390 }
391}

References forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ lostFocusEvent()

void KisShortcutMatcher::lostFocusEvent ( const QPointF & localPos)

Krita lost focus, it means that all the running actions should be ended forcefully.

TODO: it might be that we should also deactivate touch and native gestures on focus-out events. After testing on Windows it seems like it works fine without any explicit stopping the touch strokes. They just continue in the unfocused application (given that Krita does not get overlapped by another window)

Definition at line 713 of file kis_shortcut_matcher.cpp.

714{
715 Private::RecursionNotifier notifier(this);
716
717 DEBUG_ACTION("lostFocusEvent");
718
719 if (m_d->runningShortcut) {
720 forceEndRunningShortcut(localPos);
721 }
722
724
732}
void forceEndRunningShortcut(const QPointF &localPos)

References DEBUG_ACTION, forceDeactivateAllActions(), forceEndRunningShortcut(), and m_d.

◆ matchTouchShortcut()

KisTouchShortcut * KisShortcutMatcher::matchTouchShortcut ( QTouchEvent * event)
private

Definition at line 1039 of file kis_shortcut_matcher.cpp.

1040{
1041 KisTouchShortcut *goodCandidate = nullptr;
1042 Q_FOREACH (KisTouchShortcut *shortcut, m_d->touchShortcuts) {
1043 if (shortcut->isAvailable(m_d->actionGroupMask())
1044 && matchTouchShortcutBasedOnState(event, shortcut)
1045 && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1046
1047 goodCandidate = shortcut;
1048 }
1049 }
1050 return goodCandidate;
1051}
bool isAvailable(KisInputActionGroupsMask mask) const
bool matchTouchShortcutBasedOnState(QTouchEvent *event, KisTouchShortcut *shortcut)
int priority() const override

References KisAbstractShortcut::isAvailable(), m_d, matchTouchShortcutBasedOnState(), and KisTouchShortcut::priority().

◆ matchTouchShortcutBasedOnState()

bool KisShortcutMatcher::matchTouchShortcutBasedOnState ( QTouchEvent * event,
KisTouchShortcut * shortcut )
private

Definition at line 1053 of file kis_shortcut_matcher.cpp.

1054{
1055 if (m_d->isTouchHeld) {
1056 return shortcut->matchHoldType(event);
1057 } else if (m_d->isTouchDragDetected) {
1058 return shortcut->matchDragType(event);
1059 } else {
1060 return shortcut->matchTapType(event);
1061 }
1062}
bool matchDragType(QTouchEvent *event)
bool matchTapType(QTouchEvent *event)
bool matchHoldType(QTouchEvent *event)

References m_d, KisTouchShortcut::matchDragType(), KisTouchShortcut::matchHoldType(), and KisTouchShortcut::matchTapType().

◆ nativeGestureBeginEvent()

bool KisShortcutMatcher::nativeGestureBeginEvent ( QNativeGestureEvent * event)

Definition at line 582 of file kis_shortcut_matcher.cpp.

583{
584 Q_UNUSED(event);
585
586 Private::RecursionNotifier notifier(this);
587
588 return !notifier.isInRecursion();
589}

◆ nativeGestureEndEvent()

bool KisShortcutMatcher::nativeGestureEndEvent ( QNativeGestureEvent * event)

Definition at line 605 of file kis_shortcut_matcher.cpp.

606{
607 Private::RecursionNotifier notifier(this);
608
609 if ( m_d->nativeGestureShortcut && !m_d->nativeGestureShortcut->match( event ) ) {
611 }
612
613 if (notifier.isInRecursion()) {
615 } else if (!hasRunningShortcut()) {
618 }
619
620 return true;
621}
bool tryEndNativeGestureShortcut(QNativeGestureEvent *event)

References forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), tryActivateReadyShortcut(), and tryEndNativeGestureShortcut().

◆ nativeGestureEvent()

bool KisShortcutMatcher::nativeGestureEvent ( QNativeGestureEvent * event)

Definition at line 591 of file kis_shortcut_matcher.cpp.

592{
593 bool retval = false;
594 if (!hasRunningShortcut()) {
595 retval = tryRunNativeGestureShortcut( event );
596 }
597 else if (m_d->nativeGestureShortcut) {
598 m_d->nativeGestureShortcut->action()->inputEvent( event );
599 retval = true;
600 }
601
602 return retval;
603}
bool tryRunNativeGestureShortcut(QNativeGestureEvent *event)

References hasRunningShortcut(), m_d, and tryRunNativeGestureShortcut().

◆ pointerMoved()

bool KisShortcutMatcher::pointerMoved ( QEvent * event)

Handles tablet and mouse move events.

Parameters
eventthe event that caused this call
Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 346 of file kis_shortcut_matcher.cpp.

347{
348 Private::RecursionNotifier notifier(this);
349
350 if (notifier.isInRecursion()) {
351 return false;
352 }
353
354 bool retval = false;
355
356 if (m_d->runningShortcut) {
357 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->touchShortcut && !m_d->nativeGestureShortcut, false);
358 m_d->runningShortcut->action()->inputEvent(event);
359 retval = true;
360 }
361
362 return retval;
363}
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and m_d.

◆ prepareReadyShortcuts()

void KisShortcutMatcher::prepareReadyShortcuts ( )
private

Definition at line 843 of file kis_shortcut_matcher.cpp.

844{
845 m_d->candidateShortcuts.clear();
846 if (m_d->actionsSuppressed()) return;
847
848 // Allow letting the modifiers to be matched so key_shift + middle mouse move can be matched, but key_v + mouse drag can not.
849 bool containsOnlyModifiers = !m_d->keys.isEmpty();
850 Q_FOREACH(const Qt::Key k, m_d->keys) {
851 if (k != Qt::Key_Shift && k != Qt::Key_Control && k != Qt::Key_Alt && k != Qt::Key_Meta) {
852 containsOnlyModifiers = false;
853 break;
854 }
855 }
856 if (m_d->KeyboardActionsSuppressed()
857 && !containsOnlyModifiers && !m_d->keys.isEmpty()
858 && m_d->buttons.isEmpty()) {
859 return;
860 }
861
862 Q_FOREACH (KisStrokeShortcut *s, m_d->strokeShortcuts) {
863 if (s->matchReady(m_d->keys, m_d->buttons)) {
864 m_d->candidateShortcuts.append(s);
865 }
866 }
867}
bool matchReady(const QSet< Qt::Key > &modifiers, const QSet< Qt::MouseButton > &buttons)

References m_d, and KisStrokeShortcut::matchReady().

◆ Private()

KisShortcutMatcher::Private ( )
inline

Definition at line 49 of file kis_shortcut_matcher.cpp.

51 , readyShortcut(0)
52 , touchShortcut(0)
54 , actionGroupMask([] () { return AllActionGroup; })
55 , suppressAllActions(false)
57 , cursorEntered(false)
58 {}
@ AllActionGroup
KisTouchShortcut * touchShortcut
KisStrokeShortcut * readyShortcut
std::function< KisInputActionGroupsMask()> actionGroupMask
KisNativeGestureShortcut * nativeGestureShortcut

References AllActionGroup.

◆ reinitialize()

void KisShortcutMatcher::reinitialize ( )

Resets the internal state of the matcher and activates the prepared action if possible.

This should be done when the window has lost the focus for some time, so that several events could be lost

Definition at line 631 of file kis_shortcut_matcher.cpp.

632{
633 Private::RecursionNotifier notifier(this);
634
635
636 reset("reinitialize");
637
638 if (notifier.isInRecursion()) {
640 } else if (!hasRunningShortcut()) {
643 }
644}

References forceDeactivateAllActions(), hasRunningShortcut(), prepareReadyShortcuts(), reset(), and tryActivateReadyShortcut().

◆ reinitializeButtons()

void KisShortcutMatcher::reinitializeButtons ( )

Resets the internal state of the buttons inside matcher and activates the prepared action if possible.

This should be done when the window has lost the focus for some time, so that several events could be lost

Definition at line 646 of file kis_shortcut_matcher.cpp.

647{
648 Private::RecursionNotifier notifier(this);
649
650 m_d->buttons.clear();
651 DEBUG_ACTION("reinitializing buttons");
652
653 if (notifier.isInRecursion()) {
655 } else if (!hasRunningShortcut()) {
658 }
659}

References DEBUG_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ reset() [1/2]

void KisShortcutMatcher::reset ( )
private

Definition at line 748 of file kis_shortcut_matcher.cpp.

749{
750 m_d->keys.clear();
751 m_d->buttons.clear();
752 DEBUG_ACTION("reset!");
753}

References DEBUG_ACTION, and m_d.

◆ reset() [2/2]

void KisShortcutMatcher::reset ( QString msg)
private

Definition at line 756 of file kis_shortcut_matcher.cpp.

757{
758 m_d->keys.clear();
759 m_d->buttons.clear();
760 Q_UNUSED(msg);
761 DEBUG_ACTION(msg);
762}

References DEBUG_ACTION, and m_d.

◆ sanityCheckModifiersCorrectness()

bool KisShortcutMatcher::sanityCheckModifiersCorrectness ( Qt::KeyboardModifiers modifiers) const

Sanity check correctness of the internal state of the matcher by comparing it to the standard modifiers that we get with every input event. Right now this sanity check is used on Windows only.

Definition at line 688 of file kis_shortcut_matcher.cpp.

689{
690 auto checkKey = [this, modifiers] (Qt::Key key, Qt::KeyboardModifier modifier) {
691 return m_d->keys.contains(key) == bool(modifiers & modifier);
692 };
693
694 return checkKey(Qt::Key_Shift, Qt::ShiftModifier) &&
695 checkKey(Qt::Key_Control, Qt::ControlModifier) &&
696 checkKey(Qt::Key_Alt, Qt::AltModifier) &&
697 checkKey(Qt::Key_Meta, Qt::MetaModifier);
698
699}

References m_d.

◆ setInputActionGroupsMaskCallback()

void KisShortcutMatcher::setInputActionGroupsMaskCallback ( std::function< KisInputActionGroupsMask()> func)

Definition at line 801 of file kis_shortcut_matcher.cpp.

802{
803 m_d->actionGroupMask = func;
804}

References m_d.

◆ setMaxTouchPointEvent()

void KisShortcutMatcher::setMaxTouchPointEvent ( QTouchEvent * event)
private

Definition at line 1012 of file kis_shortcut_matcher.cpp.

1013{
1014 int touchPointCount = event->touchPoints().size();
1015 if (touchPointCount > m_d->maxTouchPoints) {
1016 m_d->maxTouchPoints = touchPointCount;
1017#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1018 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateTouchEvent);
1019#else
1020 m_d->bestCandidateTouchEvent.reset(event->clone());
1021#endif
1022
1023 }
1024}

References m_d.

◆ supportsHiResInputEvents()

bool KisShortcutMatcher::supportsHiResInputEvents ( )

Returns true if the currently running shortcut supports processing hi resolution flow of events from the tablet device. In most of the cases (except of the painting itself) too many events make the execution of the action too slow, so the action can decide whether it needs it.

Definition at line 198 of file kis_shortcut_matcher.cpp.

199{
200 return (m_d->runningShortcut && m_d->runningShortcut->action()
201 && m_d->runningShortcut->action()->supportsHiResInputEvents(m_d->runningShortcut->shortcutIndex()))
202 || (m_d->touchShortcut && m_d->touchShortcut->action()
203 && m_d->touchShortcut->action()->supportsHiResInputEvents(m_d->touchShortcut->shortcutIndex()))
204 || (m_d->nativeGestureShortcut && m_d->nativeGestureShortcut->action()
205 && m_d->nativeGestureShortcut->action()->supportsHiResInputEvents(m_d->nativeGestureShortcut->shortcutIndex()));
206}

References m_d.

◆ suppressAllActions()

void KisShortcutMatcher::suppressAllActions ( bool value)

Disables the start of any actions.

WARNING: the actions that has been started before this call will not be ended. They will be ended in their usual way, when the mouse button will be released.

◆ suppressAllKeyboardActions()

void KisShortcutMatcher::suppressAllKeyboardActions ( bool value)

Disable keyboard actions.

This will disable all actions that consist of only keyboard keys being pressed without mouse or stylus buttons being pressed.

This is turned on when the tool is in text mode.

◆ suppressConflictingKeyActions()

void KisShortcutMatcher::suppressConflictingKeyActions ( const QVector< QKeySequence > & shortcuts)

Disable one-time actions whose shortcuts conflict with the listed shortcuts

Definition at line 769 of file kis_shortcut_matcher.cpp.

770{
771 m_d->suppressedSingleActionShortcuts.clear();
772
773 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
774 Q_FOREACH (const QKeySequence &seq, shortcuts) {
775 if (s->conflictsWith(seq)) {
776 m_d->suppressedSingleActionShortcuts.insert(s);
777 }
778 }
779 }
780}
bool conflictsWith(const QKeySequence &seq)

References KisSingleActionShortcut::conflictsWith(), and m_d.

◆ toolHasBeenActivated()

void KisShortcutMatcher::toolHasBeenActivated ( )

Is called when a new tool has been activated. The method activates any tool's action if possible with the currently active modifiers.

Definition at line 734 of file kis_shortcut_matcher.cpp.

735{
736 Private::RecursionNotifier notifier(this);
737
738 DEBUG_ACTION("toolHasBeenActivated");
739
740 if (notifier.isInRecursion()) {
742 } else if (!hasRunningShortcut()) {
745 }
746}

References DEBUG_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ touchBeginEvent()

bool KisShortcutMatcher::touchBeginEvent ( QTouchEvent * event)

Definition at line 393 of file kis_shortcut_matcher.cpp.

394{
395 DEBUG_TOUCH_ACTION("entered", event)
396
397 Private::RecursionNotifier notifier(this);
398
399 m_d->lastTouchPoints = event->touchPoints();
400
401 // reset state
402 m_d->maxTouchPoints = event->touchPoints().size();
403 m_d->matchingIteration = 1;
404 m_d->isTouchDragDetected = false;
405 m_d->isTouchHeld = false;
406#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
407 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateTouchEvent);
408#else
409 m_d->bestCandidateTouchEvent.reset(event->clone());
410#endif
411
412 return !notifier.isInRecursion();
413}

References DEBUG_TOUCH_ACTION, and m_d.

◆ touchCancelEvent()

void KisShortcutMatcher::touchCancelEvent ( QTouchEvent * event,
const QPointF & localPos )

We received TouchCancel event, it means this event sequence has ended right here i.e without a valid TouchEnd, so we should immediately stop all running actions.

Definition at line 517 of file kis_shortcut_matcher.cpp.

518{
519 Private::RecursionNotifier notifier(this);
520
521 m_d->maxTouchPoints = 0;
522 m_d->isTouchHeld = false;
523
524 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->runningShortcut || !m_d->touchShortcut);
525
526 // end the stroke types
527 if (m_d->touchShortcut) {
528 KisTouchShortcut *touchShortcut = m_d->touchShortcut;
529 m_d->touchShortcut = 0;
530 QScopedPointer<QEvent> dstEvent;
531#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
532 KoPointerEvent::copyQtPointerEvent(event, dstEvent);
533#else
534 dstEvent.reset(event->clone());
535#endif
536
537 // HACK: Because TouchEvents in KoPointerEvent need to contain at least one touchpoint
538 QTouchEvent* touchEvent = dynamic_cast<QTouchEvent *>(dstEvent.data());
539 KIS_ASSERT(touchEvent);
540#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
541 touchEvent->setTouchPoints(m_d->lastTouchPoints);
542#else
543 dstEvent.reset(new QTouchEvent(event->type(),
544 event->pointingDevice(),
545 event->modifiers(),
546 m_d->lastTouchPoints));
547#endif
548 touchShortcut->action()->end(dstEvent.data());
550 }
551
552 if (notifier.isInRecursion()) {
554 } else if (!hasRunningShortcut()) {
557 }
558}
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), KisAbstractInputAction::end(), forceDeactivateAllActions(), hasRunningShortcut(), KIS_ASSERT, KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, prepareReadyShortcuts(), KisAbstractShortcut::shortcutIndex, touchShortcut, and tryActivateReadyShortcut().

◆ touchEndEvent()

bool KisShortcutMatcher::touchEndEvent ( QTouchEvent * event)

Definition at line 492 of file kis_shortcut_matcher.cpp.

493{
494 Private::RecursionNotifier notifier(this);
495
496 m_d->maxTouchPoints = 0;
497 m_d->isTouchHeld = false;
498
499 if (!m_d->isTouchDragDetected && m_d->bestCandidateTouchEvent && !hasRunningShortcut()) {
500 fireReadyTouchShortcut(static_cast<QTouchEvent *>(m_d->bestCandidateTouchEvent.data()));
501 }
502
503 DEBUG_TOUCH_ACTION("ending", event)
504 // we should try and end the shortcut too (it might be that there is none? (sketch))
505 const bool retval = tryEndTouchShortcut(event);
506
507 if (notifier.isInRecursion()) {
509 } else if (!hasRunningShortcut()) {
512 }
513
514 return retval;
515}
bool tryEndTouchShortcut(QTouchEvent *event)
void fireReadyTouchShortcut(QTouchEvent *event)

References DEBUG_TOUCH_ACTION, fireReadyTouchShortcut(), forceDeactivateAllActions(), hasRunningShortcut(), m_d, prepareReadyShortcuts(), tryActivateReadyShortcut(), and tryEndTouchShortcut().

◆ touchHoldBeginEvent()

bool KisShortcutMatcher::touchHoldBeginEvent ( QTouchEvent * event)

Effectively a long-press touch event, generated by KisInputManager when the user touches and holds a spot with one finger. Replaces touchBeginEvent, but other events keep streaming in as normal.

Definition at line 560 of file kis_shortcut_matcher.cpp.

561{
562 DEBUG_TOUCH_ACTION("hold", event)
563
564 // Can happen when multiple shortcut sources interact.
565 if (m_d->runningShortcut) {
566 return false;
567 }
568
569 m_d->isTouchHeld = true; // Must be set first, used in tryRunTouchShortcut.
570 if (tryRunTouchShortcut(event)) {
571 DEBUG_ACTION("touch shortcut found");
572 return true;
573 } else {
574 // Shouldn't really happen, since KisInputManager checks whether a touch
575 // hold shortcut exists beforehand. We'll just handle this though.
576 DEBUG_ACTION("touch shortcut not found");
577 m_d->isTouchHeld = false;
578 return touchBeginEvent(event);
579 }
580}
bool tryRunTouchShortcut(QTouchEvent *event)
bool touchBeginEvent(QTouchEvent *event)

References DEBUG_ACTION, DEBUG_TOUCH_ACTION, m_d, touchBeginEvent(), and tryRunTouchShortcut().

◆ touchUpdateEvent()

bool KisShortcutMatcher::touchUpdateEvent ( QTouchEvent * event)

Definition at line 415 of file kis_shortcut_matcher.cpp.

416{
417 DEBUG_TOUCH_ACTION("entered", event)
418
419 if (m_d->isTouchHeld) {
420 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->touchShortcut, false);
421 m_d->touchShortcut->action()->inputEvent(event);
422 return true;
423 }
424
425 bool retval = false;
426
427 const int touchPointCount = event->touchPoints().size();
428 // check whether the touchpoints are relatively stationary or have been moved for dragging.
429 for (int i = 0; i < event->touchPoints().size() && !m_d->isTouchDragDetected; ++i) {
430 const QTouchEvent::TouchPoint &touchPoint = event->touchPoints().at(i);
431 const QPointF delta = touchPoint.pos() - touchPoint.startPos();
432 const qreal deltaSquared = delta.x() * delta.x() + delta.y() * delta.y();
433 // if the drag is detected, until the next TouchBegin even, we'll be assuming the gesture to be of dragging
434 // type.
435 m_d->isTouchDragDetected = deltaSquared > TOUCH_SLOP_SQUARED;
436 }
437
438 // for a first few events we don't process the events right away. But analyze and keep track of the event with most
439 // touchpoints. This is done to prevent conditions where in three-finger-tap, two-finger-tap be preceded due to
440 // latency
441 const int numIterations = 10;
442 if (m_d->matchingIteration <= numIterations && !m_d->isTouchDragDetected) {
443 m_d->matchingIteration++;
445 DEBUG_TOUCH_ACTION("return best", event)
446 return matchTouchShortcut((QTouchEvent *)m_d->bestCandidateTouchEvent.data());
447 }
448
449 if (m_d->isTouchDragDetected) {
450 if (m_d->touchShortcut && !m_d->touchShortcut->matchDragType(event)) {
451 DEBUG_TOUCH_ACTION("ending", event)
452 // we should end the event as an event with more touchpoints was received
453 retval = tryEndTouchShortcut(event);
454 }
455 if (!hasRunningShortcut() && touchPointCount >= m_d->maxTouchPoints) {
456 m_d->maxTouchPoints = touchPointCount;
457 DEBUG_TOUCH_ACTION("starting", event);
458 retval = tryRunTouchShortcut(event);
459 } else if (m_d->touchShortcut) {
460 // The typical assumption when we get here is that the shortcut has been matched, for which we use
461 // the events with TouchPointPressed state. But there may be instances where shortcut is never
462 // un-matched (meaning: never being tryEndTouchShortcut called on it) even when the finger is
463 // released, and when the next contact is made, the shortcut proceeds assuming continuity -- which
464 // is a false assumption.
465 // So, if we see a TouchPointPressed, we should know that somewhere previously finger was lifted
466 // and we should let the action know this.
467 if (event->touchPointStates() & Qt::TouchPointPressed) {
468 m_d->touchShortcut->action()->begin(m_d->touchShortcut->shortcutIndex(), event);
469 } else if (event->touchPointStates() & Qt::TouchPointReleased) {
470 m_d->touchShortcut->action()->end(event);
471 } else {
472 m_d->touchShortcut->action()->inputEvent(event);
473 }
474 retval = true;
475 }
476 } else {
477 // triggered if a new finger was added, which might result in shortcut not matching the action
478 if ((event->touchPointStates() & Qt::TouchPointReleased) == Qt::TouchPointReleased && !hasRunningShortcut()) {
479 // we should end the event as an event with more touchpoints was received
480 if (m_d->maxTouchPoints <= touchPointCount) {
481 m_d->maxTouchPoints = touchPointCount;
482 DEBUG_TOUCH_ACTION("firing", event);
484 m_d->bestCandidateTouchEvent.reset();
485 }
486 }
487 }
488
489 return retval;
490}
static constexpr int TOUCH_SLOP_SQUARED
void setMaxTouchPointEvent(QTouchEvent *event)
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References DEBUG_TOUCH_ACTION, fireReadyTouchShortcut(), hasRunningShortcut(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, matchTouchShortcut(), setMaxTouchPointEvent(), TOUCH_SLOP_SQUARED, tryEndTouchShortcut(), and tryRunTouchShortcut().

◆ tryActivateReadyShortcut()

void KisShortcutMatcher::tryActivateReadyShortcut ( )
private

It is important that we first activate the action, and only after that assign it to m_d->readyShortcut. It makes is possible to activate another tool in KisToolInvocationAction and survive the call to forceDeactivateAllActions() from lostFocusEvent(), which would enter infinite loop otherwise.

Definition at line 914 of file kis_shortcut_matcher.cpp.

915{
916 KisStrokeShortcut *goodCandidate = 0;
917
918 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
919 if (!goodCandidate || s->priority() > goodCandidate->priority()) {
920 goodCandidate = s;
921 }
922 }
923
924 if (goodCandidate) {
925 if (m_d->readyShortcut && m_d->readyShortcut != goodCandidate) {
926 DEBUG_SHORTCUT("Deactivated previous shortcut action", m_d->readyShortcut);
927 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
928 m_d->readyShortcut = 0;
929 }
930
931 if (!m_d->readyShortcut) {
932 DEBUG_SHORTCUT("Preparing new ready action", goodCandidate);
933
941 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
942 m_d->readyShortcut = goodCandidate;
943 }
944 } else if (m_d->readyShortcut) {
945 DEBUG_SHORTCUT("Deactivating action", m_d->readyShortcut);
946 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
947 m_d->readyShortcut = 0;
948 }
949}
int priority() const override

References KisAbstractShortcut::action, KisAbstractInputAction::activate(), DEBUG_SHORTCUT, m_d, KisStrokeShortcut::priority(), and KisAbstractShortcut::shortcutIndex.

◆ tryEndNativeGestureShortcut()

bool KisShortcutMatcher::tryEndNativeGestureShortcut ( QNativeGestureEvent * event)
private

Definition at line 1154 of file kis_shortcut_matcher.cpp.

1155{
1156 Private::RecursionNotifier notifier(this);
1157
1158 if (m_d->nativeGestureShortcut) {
1159 // first reset running shortcut to avoid infinite recursion via end()
1160 KisNativeGestureShortcut *nativeGestureShortcut = m_d->nativeGestureShortcut;
1161
1162 nativeGestureShortcut->action()->end(event);
1163 nativeGestureShortcut->action()->deactivate(m_d->nativeGestureShortcut->shortcutIndex());
1164
1165 m_d->nativeGestureShortcut = 0; // empty it out now that we are done with it
1166
1167 return true;
1168 }
1169
1170 if (notifier.isInRecursion()) {
1172 } else if (!hasRunningShortcut()) {
1175 }
1176
1177 return false;
1178}

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), KisAbstractInputAction::end(), forceDeactivateAllActions(), hasRunningShortcut(), m_d, nativeGestureShortcut, prepareReadyShortcuts(), and tryActivateReadyShortcut().

◆ tryEndRunningShortcut()

bool KisShortcutMatcher::tryEndRunningShortcut ( Qt::MouseButton button,
QEvent * event )
private

Definition at line 951 of file kis_shortcut_matcher.cpp.

952{
953 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->runningShortcut, true);
954 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
955 // it shouldn't have happened, running and ready shortcuts
956 // at the same time should not be possible
958 }
959
960 if (m_d->runningShortcut && m_d->runningShortcut->matchBegin(button)) {
961
962 // first reset running shortcut to avoid infinite recursion via end()
963 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
964 m_d->runningShortcut = 0;
965
966 if (runningShortcut->action()) {
967 DEBUG_EVENT_ACTION("Ending running shortcut at event", event);
969 int shortcutIndex = runningShortcut->shortcutIndex();
970 action->end(event);
971 action->deactivate(shortcutIndex);
972 }
973 }
974
975 return !m_d->runningShortcut;
976}
#define DEBUG_EVENT_ACTION(text, event)

References KisAbstractShortcut::action, button(), KisAbstractInputAction::deactivate(), DEBUG_EVENT_ACTION, KisAbstractInputAction::end(), forceDeactivateAllActions(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, runningShortcut, and KisAbstractShortcut::shortcutIndex.

◆ tryEndTouchShortcut()

bool KisShortcutMatcher::tryEndTouchShortcut ( QTouchEvent * event)
private

Definition at line 1098 of file kis_shortcut_matcher.cpp.

1099{
1100 if (m_d->touchShortcut) {
1101 // first reset running shortcut to avoid infinite recursion via end()
1102 KisTouchShortcut *touchShortcut = m_d->touchShortcut;
1103
1104 DEBUG_SHORTCUT("ending", touchShortcut)
1105 touchShortcut->action()->end(event);
1106 touchShortcut->action()->deactivate(m_d->touchShortcut->shortcutIndex());
1107
1108 m_d->touchShortcut = 0; // empty it out now that we are done with it
1109
1110 return true;
1111 }
1112
1113 return false;
1114}

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), DEBUG_SHORTCUT, KisAbstractInputAction::end(), m_d, and touchShortcut.

◆ tryRunNativeGestureShortcut()

bool KisShortcutMatcher::tryRunNativeGestureShortcut ( QNativeGestureEvent * event)
private

Definition at line 1116 of file kis_shortcut_matcher.cpp.

1117{
1118 KisNativeGestureShortcut *goodCandidate = 0;
1119
1120 if (m_d->actionsSuppressed())
1121 return false;
1122
1123 Q_FOREACH (KisNativeGestureShortcut* shortcut, m_d->nativeGestureShortcuts) {
1124 if (shortcut->match(event) && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1125 goodCandidate = shortcut;
1126 }
1127 }
1128
1129 if (goodCandidate) {
1130 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1131
1132 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1133 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1135
1136 m_d->nativeGestureShortcut = goodCandidate;
1137
1138 Private::RecursionGuard guard(this);
1139 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1140 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1141
1142 // the tool might have opened some dialog, which could break our event loop
1143 if (guard.brokenByRecursion()) {
1144 goodCandidate->action()->end(event);
1145 m_d->nativeGestureShortcut = 0;
1146
1148 }
1149 }
1150
1151 return m_d->nativeGestureShortcut;
1152}
bool match(QNativeGestureEvent *event)

References KisAbstractShortcut::action, KisAbstractInputAction::activate(), KisAbstractInputAction::begin(), KisAbstractInputAction::end(), forceDeactivateAllActions(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, KisNativeGestureShortcut::match(), KisNativeGestureShortcut::priority(), and KisAbstractShortcut::shortcutIndex.

◆ tryRunReadyShortcut()

bool KisShortcutMatcher::tryRunReadyShortcut ( Qt::MouseButton button,
QEvent * event )
private

Definition at line 869 of file kis_shortcut_matcher.cpp.

870{
871 KisStrokeShortcut *goodCandidate = 0;
872
873 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
874 if (s->isAvailable(m_d->actionGroupMask()) &&
875 s->matchBegin(button) &&
876 (!goodCandidate || s->priority() > goodCandidate->priority())) {
877
878 goodCandidate = s;
879 }
880 }
881
882 if (goodCandidate) {
883 if (m_d->readyShortcut) {
884 if (m_d->readyShortcut != goodCandidate) {
885 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
886 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
887 }
888 m_d->readyShortcut = 0;
889 } else {
890 DEBUG_EVENT_ACTION("Matched *new* shortcut for event", event);
891 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
892 }
893
894 DEBUG_SHORTCUT("Starting new action", goodCandidate);
895
896 {
897 m_d->runningShortcut = goodCandidate;
898 Private::RecursionGuard guard(this);
899 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
900
901 // the tool might have opened some dialog, which could break our event loop
902 if (guard.brokenByRecursion()) {
903 goodCandidate->action()->end(event);
904 m_d->runningShortcut = 0;
905
907 }
908 }
909 }
910
911 return m_d->runningShortcut;
912}
bool matchBegin(Qt::MouseButton button)

References KisAbstractShortcut::action, KisAbstractInputAction::activate(), KisAbstractInputAction::begin(), button(), DEBUG_EVENT_ACTION, DEBUG_SHORTCUT, KisAbstractInputAction::end(), forceDeactivateAllActions(), KisAbstractShortcut::isAvailable(), m_d, KisStrokeShortcut::matchBegin(), KisStrokeShortcut::priority(), and KisAbstractShortcut::shortcutIndex.

◆ tryRunSingleActionShortcutImpl()

template<typename T , typename U >
bool KisShortcutMatcher::tryRunSingleActionShortcutImpl ( T param,
U * event,
const QSet< Qt::Key > & keysState,
bool keyboard = true )
private

Definition at line 813 of file kis_shortcut_matcher.cpp.

814{
815 if (m_d->actionsSuppressedIgnoreFocus() || (keyboard && m_d->KeyboardActionsSuppressed())) {
816 DEBUG_EVENT_ACTION("Event suppressed", event)
817 return false;
818 }
819
820 KisSingleActionShortcut *goodCandidate = 0;
821
822 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
823 if (!m_d->suppressedSingleActionShortcuts.contains(s) &&
824 s->isAvailable(m_d->actionGroupMask()) &&
825 s->match(keysState, param) &&
826 (!goodCandidate || s->priority() > goodCandidate->priority())) {
827
828 goodCandidate = s;
829 }
830 }
831
832 if (goodCandidate) {
833 DEBUG_EVENT_ACTION("Beginning action for event", event);
834 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
835 goodCandidate->action()->end(0);
836 } else {
837 DEBUG_EVENT_ACTION("Could not match a candidate for event", event)
838 }
839
840 return goodCandidate;
841}
bool match(const QSet< Qt::Key > &modifiers, Qt::Key key)

References KisAbstractShortcut::action, KisAbstractInputAction::begin(), DEBUG_EVENT_ACTION, KisAbstractInputAction::end(), KisAbstractShortcut::isAvailable(), m_d, KisSingleActionShortcut::match(), KisSingleActionShortcut::priority(), and KisAbstractShortcut::shortcutIndex.

◆ tryRunTouchShortcut()

bool KisShortcutMatcher::tryRunTouchShortcut ( QTouchEvent * event)
private

Definition at line 1064 of file kis_shortcut_matcher.cpp.

1065{
1066 KisTouchShortcut *goodCandidate = matchTouchShortcut(event);
1067
1068 if (m_d->actionsSuppressed())
1069 return false;
1070
1071 if (goodCandidate) {
1072 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1073
1074 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1075 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1077
1078 m_d->touchShortcut = goodCandidate;
1079
1080 Private::RecursionGuard guard(this);
1081 DEBUG_SHORTCUT("Running a touch shortcut", goodCandidate)
1082
1083 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1084 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1085
1086 // the tool might have opened some dialog, which could break our event loop
1087 if (guard.brokenByRecursion()) {
1088 goodCandidate->action()->end(event);
1089 m_d->touchShortcut = 0;
1090
1092 }
1093 }
1094
1095 return m_d->touchShortcut;
1096}

References KisAbstractShortcut::action, KisAbstractInputAction::activate(), KisAbstractInputAction::begin(), DEBUG_SHORTCUT, KisAbstractInputAction::end(), forceDeactivateAllActions(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, matchTouchShortcut(), and KisAbstractShortcut::shortcutIndex.

◆ tryRunWheelShortcut()

bool KisShortcutMatcher::tryRunWheelShortcut ( KisSingleActionShortcut::WheelAction wheelAction,
QWheelEvent * event )
private

Definition at line 806 of file kis_shortcut_matcher.cpp.

807{
808 return tryRunSingleActionShortcutImpl(wheelAction, event, m_d->keys, false);
809}

References m_d, and tryRunSingleActionShortcutImpl().

◆ wheelEvent()

bool KisShortcutMatcher::wheelEvent ( KisSingleActionShortcut::WheelAction wheelAction,
QWheelEvent * event )

Handles the mouse wheel event

Returns
whether the event has been handled successfully and should be eaten by the events filter

Definition at line 333 of file kis_shortcut_matcher.cpp.

334{
335 Private::RecursionNotifier notifier(this);
336
337
338 if (hasRunningShortcut() || notifier.isInRecursion()) {
339 DEBUG_ACTION("Wheel event canceled.");
340 return false;
341 }
342
343 return tryRunWheelShortcut(wheelAction, event);
344}
bool tryRunWheelShortcut(KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)

References DEBUG_ACTION, hasRunningShortcut(), and tryRunWheelShortcut().

Friends And Related Symbol Documentation

◆ KisInputManagerTest

friend class KisInputManagerTest
friend

Definition at line 291 of file kis_shortcut_matcher.h.

Member Data Documentation

◆ actionGroupMask

std::function<KisInputActionGroupsMask()> KisShortcutMatcher::actionGroupMask

Definition at line 92 of file kis_shortcut_matcher.cpp.

◆ bestCandidateTouchEvent

QScopedPointer<QEvent> KisShortcutMatcher::bestCandidateTouchEvent

Definition at line 90 of file kis_shortcut_matcher.cpp.

◆ brokenByRecursion

int KisShortcutMatcher::brokenByRecursion = 0

Definition at line 98 of file kis_shortcut_matcher.cpp.

◆ buttons

QSet<Qt::MouseButton> KisShortcutMatcher::buttons

Definition at line 74 of file kis_shortcut_matcher.cpp.

◆ candidateShortcuts

QList<KisStrokeShortcut*> KisShortcutMatcher::candidateShortcuts

Definition at line 80 of file kis_shortcut_matcher.cpp.

◆ cursorEntered

bool KisShortcutMatcher::cursorEntered

Definition at line 95 of file kis_shortcut_matcher.cpp.

◆ isTouchDragDetected

bool KisShortcutMatcher::isTouchDragDetected {false}

Definition at line 88 of file kis_shortcut_matcher.cpp.

88{false};

◆ isTouchHeld

bool KisShortcutMatcher::isTouchHeld {false}

Definition at line 89 of file kis_shortcut_matcher.cpp.

89{false};

◆ keys

QSet<Qt::Key> KisShortcutMatcher::keys

Definition at line 73 of file kis_shortcut_matcher.cpp.

◆ lastTouchPoints

QList<QTouchEvent::TouchPoint> KisShortcutMatcher::lastTouchPoints

Definition at line 84 of file kis_shortcut_matcher.cpp.

◆ m_d

Private* const KisShortcutMatcher::m_d
private

Definition at line 319 of file kis_shortcut_matcher.h.

◆ matchingIteration

int KisShortcutMatcher::matchingIteration {0}

Definition at line 87 of file kis_shortcut_matcher.cpp.

87{0};

◆ maxTouchPoints

int KisShortcutMatcher::maxTouchPoints {0}

Definition at line 86 of file kis_shortcut_matcher.cpp.

86{0};

◆ nativeGestureShortcut

KisNativeGestureShortcut* KisShortcutMatcher::nativeGestureShortcut

Definition at line 83 of file kis_shortcut_matcher.cpp.

◆ nativeGestureShortcuts

QList<KisNativeGestureShortcut*> KisShortcutMatcher::nativeGestureShortcuts

Definition at line 71 of file kis_shortcut_matcher.cpp.

◆ polledKeys

QSet<Qt::Key> KisShortcutMatcher::polledKeys

Definition at line 76 of file kis_shortcut_matcher.cpp.

◆ readyShortcut

KisStrokeShortcut* KisShortcutMatcher::readyShortcut

Definition at line 79 of file kis_shortcut_matcher.cpp.

◆ recursiveCounter

int KisShortcutMatcher::recursiveCounter = 0

Definition at line 97 of file kis_shortcut_matcher.cpp.

◆ runningShortcut

KisStrokeShortcut* KisShortcutMatcher::runningShortcut

Definition at line 78 of file kis_shortcut_matcher.cpp.

◆ singleActionShortcuts

QList<KisSingleActionShortcut*> KisShortcutMatcher::singleActionShortcuts

Definition at line 67 of file kis_shortcut_matcher.cpp.

◆ strokeShortcuts

QList<KisStrokeShortcut*> KisShortcutMatcher::strokeShortcuts

Definition at line 69 of file kis_shortcut_matcher.cpp.

◆ suppressAllActions

void KisShortcutMatcher::suppressAllActions

Definition at line 93 of file kis_shortcut_matcher.cpp.

◆ suppressAllKeyboardActions

void KisShortcutMatcher::suppressAllKeyboardActions

Definition at line 94 of file kis_shortcut_matcher.cpp.

◆ suppressedSingleActionShortcuts

QSet<KisSingleActionShortcut*> KisShortcutMatcher::suppressedSingleActionShortcuts

Definition at line 68 of file kis_shortcut_matcher.cpp.

◆ TOUCH_SLOP_SQUARED

constexpr int KisShortcutMatcher::TOUCH_SLOP_SQUARED = 16 * 16
staticconstexpr

Definition at line 77 of file kis_shortcut_matcher.h.

◆ touchShortcut

KisTouchShortcut* KisShortcutMatcher::touchShortcut

Definition at line 82 of file kis_shortcut_matcher.cpp.

◆ touchShortcuts

QList<KisTouchShortcut*> KisShortcutMatcher::touchShortcuts

Definition at line 70 of file kis_shortcut_matcher.cpp.


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