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 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 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}
 
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
 

Private Member Functions

void fireReadyTouchShortcut (QTouchEvent *event)
 
void forceDeactivateAllActions ()
 
void forceEndRunningShortcut (const QPointF &localPos)
 
KisTouchShortcutmatchTouchShortcut (QTouchEvent *event)
 
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 154 of file kis_shortcut_matcher.cpp.

155 : m_d(new Private)
156{}

◆ ~KisShortcutMatcher()

KisShortcutMatcher::~KisShortcutMatcher ( )

Definition at line 158 of file kis_shortcut_matcher.cpp.

159{
160 delete m_d;
161}

References m_d.

Member Function Documentation

◆ actionsSuppressed()

bool KisShortcutMatcher::actionsSuppressed ( ) const
inline

Definition at line 136 of file kis_shortcut_matcher.cpp.

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

◆ actionsSuppressedIgnoreFocus()

bool KisShortcutMatcher::actionsSuppressedIgnoreFocus ( ) const
inline

Definition at line 145 of file kis_shortcut_matcher.cpp.

145 {
146 return suppressAllActions;
147 }

◆ addShortcut() [1/4]

void KisShortcutMatcher::addShortcut ( KisNativeGestureShortcut * shortcut)

Definition at line 183 of file kis_shortcut_matcher.cpp.

183 {
184 m_d->nativeGestureShortcuts.append(shortcut);
185}

References m_d.

◆ addShortcut() [2/4]

void KisShortcutMatcher::addShortcut ( KisSingleActionShortcut * shortcut)

Definition at line 168 of file kis_shortcut_matcher.cpp.

169{
170 m_d->singleActionShortcuts.append(shortcut);
171}

References m_d.

◆ addShortcut() [3/4]

void KisShortcutMatcher::addShortcut ( KisStrokeShortcut * shortcut)

Definition at line 173 of file kis_shortcut_matcher.cpp.

174{
175 m_d->strokeShortcuts.append(shortcut);
176}

References m_d.

◆ addShortcut() [4/4]

void KisShortcutMatcher::addShortcut ( KisTouchShortcut * shortcut)

Definition at line 178 of file kis_shortcut_matcher.cpp.

179{
180 m_d->touchShortcuts.append(shortcut);
181}

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 222 of file kis_shortcut_matcher.cpp.

223{
224 Private::RecursionNotifier notifier(this);
225
226
227 bool retval = false;
228
229 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, autorepeated key but can't remember it was pressed"); }
230
231 if (m_d->polledKeys.contains(key)) {
232 m_d->polledKeys.remove(key);
233 }
234
235 if (notifier.isInRecursion()) {
237 } else if (!hasRunningShortcut()) {
238 // Autorepeated key should not be included in the shortcut
239 QSet<Qt::Key> filteredKeys = m_d->keys;
240 filteredKeys.remove(key);
241 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, filteredKeys);
242 }
243
244 return retval;
245}
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 268 of file kis_shortcut_matcher.cpp.

269{
270 Private::RecursionNotifier notifier(this);
271 DEBUG_BUTTON_ACTION("entered", button);
272
273 bool retval = false;
274
275 if (m_d->buttons.contains(button)) { DEBUG_ACTION("Peculiar, button was already pressed."); }
276
277 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
279 retval = tryRunReadyShortcut(button, event);
280 }
281
282 m_d->buttons.insert(button);
283
284 if (notifier.isInRecursion()) {
286 } else if (!hasRunningShortcut()) {
289 }
290
291 return retval;
292}
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 294 of file kis_shortcut_matcher.cpp.

295{
296 Private::RecursionNotifier notifier(this);
297 DEBUG_BUTTON_ACTION("entered", button);
298
299 bool retval = false;
300
301 // here we check for the presence of the **stroke** shortcut only
302 if (m_d->runningShortcut) {
303 KIS_SAFE_ASSERT_RECOVER_NOOP(!notifier.isInRecursion());
304
305 retval = tryEndRunningShortcut(button, event);
306 DEBUG_BUTTON_ACTION("ended", button);
307 }
308
309 if (!m_d->buttons.contains(button)) reset("Peculiar, button released but we can't remember it was pressed");
310 else m_d->buttons.remove(button);
311
312 if (notifier.isInRecursion()) {
314 } else if (!hasRunningShortcut()) {
317 }
318
319 return retval;
320}
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 746 of file kis_shortcut_matcher.cpp.

747{
748 reset("Clearing shortcuts");
749 qDeleteAll(m_d->singleActionShortcuts);
750 m_d->singleActionShortcuts.clear();
751 qDeleteAll(m_d->strokeShortcuts);
752 qDeleteAll(m_d->touchShortcuts);
753 m_d->strokeShortcuts.clear();
754 m_d->candidateShortcuts.clear();
755 m_d->touchShortcuts.clear();
756 m_d->runningShortcut = 0;
757 m_d->readyShortcut = 0;
758}

References m_d, and reset().

◆ debugPressedKeys()

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

Return the internal state of the tracked modifiers.

Definition at line 660 of file kis_shortcut_matcher.cpp.

661{
663 std::copy(m_d->keys.begin(), m_d->keys.end(), std::back_inserter(keys));
664 return keys;
665}

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 354 of file kis_shortcut_matcher.cpp.

355{
356 Private::RecursionNotifier notifier(this);
357
358 m_d->cursorEntered = true;
359
360 if (notifier.isInRecursion()) {
362 } else if (!hasRunningShortcut()) {
365 }
366}

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

◆ fireReadyTouchShortcut()

void KisShortcutMatcher::fireReadyTouchShortcut ( QTouchEvent * event)
private

Definition at line 985 of file kis_shortcut_matcher.cpp.

986{
987 KisTouchShortcut *goodCandidate = matchTouchShortcut(event);
988 if (goodCandidate) {
989 DEBUG_TOUCH_ACTION("starting", event)
990 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
991 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
992
993 goodCandidate->action()->end(event);
994 goodCandidate->action()->deactivate(goodCandidate->shortcutIndex());
995 }
996}
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 962 of file kis_shortcut_matcher.cpp.

963{
964 if (m_d->readyShortcut) {
965 DEBUG_SHORTCUT("Forcefully deactivating action", m_d->readyShortcut);
966 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
967 m_d->readyShortcut = 0;
968 }
969}
#define DEBUG_SHORTCUT(text, shortcut)

References DEBUG_SHORTCUT, and m_d.

◆ forceEndRunningShortcut()

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

Definition at line 937 of file kis_shortcut_matcher.cpp.

938{
939 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->runningShortcut);
940 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
941 // it shouldn't have happened, running and ready shortcuts
942 // at the same time should not be possible
944 }
945
946 // first reset running shortcut to avoid infinite recursion via end()
947 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
948 m_d->runningShortcut = 0;
949
950 if (runningShortcut->action()) {
951 DEBUG_ACTION("Forced ending running shortcut at event");
953 int shortcutIndex = runningShortcut->shortcutIndex();
954
955 QMouseEvent event = runningShortcut->fakeEndEvent(localPos);
956
957 action->end(&event);
958 action->deactivate(shortcutIndex);
959 }
960}
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 620 of file kis_shortcut_matcher.cpp.

621{
622 Q_FOREACH (Qt::Key key, m_d->keys) {
623 if (!keys.contains(key)) {
624 keyReleased(key);
625 }
626 }
627
628 Q_FOREACH (Qt::Key key, keys) {
629 if (!m_d->keys.contains(key)) {
630 keyPressed(key);
631 m_d->polledKeys << key;
632 }
633 }
634
635 Private::RecursionNotifier notifier(this);
636
637 if (notifier.isInRecursion()) {
639 } else if (!hasRunningShortcut()) {
642 }
643
644 DEBUG_ACTION("recoverySyncModifiers");
645}
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 667 of file kis_shortcut_matcher.cpp.

668{
669 return !m_d->polledKeys.empty();
670}

References m_d.

◆ hasRunningShortcut()

bool KisShortcutMatcher::hasRunningShortcut ( ) const

Definition at line 163 of file kis_shortcut_matcher.cpp.

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

References m_d.

◆ KeyboardActionsSuppressed()

bool KisShortcutMatcher::KeyboardActionsSuppressed ( ) const
inline

Definition at line 149 of file kis_shortcut_matcher.cpp.

149 {
151 }

◆ 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 197 of file kis_shortcut_matcher.cpp.

198{
199 Private::RecursionNotifier notifier(this);
200
201 bool retval = false;
202
203 if (m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, records show key was already pressed"); }
204
205 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
206 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, m_d->keys);
207 }
208
209 m_d->keys.insert(key);
210 DEBUG_KEY("Pressed");
211
212 if (notifier.isInRecursion()) {
214 } else if (!hasRunningShortcut()) {
217 }
218
219 return retval;
220}
#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 247 of file kis_shortcut_matcher.cpp.

248{
249 Private::RecursionNotifier notifier(this);
250
251 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, key released but can't remember it was pressed"); }
252 else m_d->keys.remove(key);
253
254 m_d->polledKeys.remove(key);
255
256 DEBUG_KEY("Released");
257
258 if (notifier.isInRecursion()) {
260 } else if (!hasRunningShortcut()) {
263 }
264
265 return false;
266}

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 368 of file kis_shortcut_matcher.cpp.

369{
370 Private::RecursionNotifier notifier(this);
371
372 m_d->cursorEntered = false;
373
374 if (notifier.isInRecursion()) {
376 } else if (!hasRunningShortcut()) {
379 }
380}

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 672 of file kis_shortcut_matcher.cpp.

673{
674 Private::RecursionNotifier notifier(this);
675
676 DEBUG_ACTION("lostFocusEvent");
677
678 if (m_d->runningShortcut) {
679 forceEndRunningShortcut(localPos);
680 }
681
683
691}
void forceEndRunningShortcut(const QPointF &localPos)

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

◆ matchTouchShortcut()

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

Definition at line 998 of file kis_shortcut_matcher.cpp.

999{
1000 KisTouchShortcut *goodCandidate = nullptr;
1001 Q_FOREACH (KisTouchShortcut *shortcut, m_d->touchShortcuts) {
1002 // if the type of the action is drag, check if we match with drag type and if the type is tap, check if we match
1003 // with tap type.
1004 if (shortcut->isAvailable(m_d->actionGroupMask())
1005 && ((shortcut->matchDragType(event) && m_d->isTouchDragDetected)
1006 || (shortcut->matchTapType(event) && !m_d->isTouchDragDetected))
1007 && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1008
1009 goodCandidate = shortcut;
1010 }
1011 }
1012 return goodCandidate;
1013}
bool isAvailable(KisInputActionGroupsMask mask) const
bool matchDragType(QTouchEvent *event)
bool matchTapType(QTouchEvent *event)
int priority() const override

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

◆ nativeGestureBeginEvent()

bool KisShortcutMatcher::nativeGestureBeginEvent ( QNativeGestureEvent * event)

Definition at line 541 of file kis_shortcut_matcher.cpp.

542{
543 Q_UNUSED(event);
544
545 Private::RecursionNotifier notifier(this);
546
547 return !notifier.isInRecursion();
548}

◆ nativeGestureEndEvent()

bool KisShortcutMatcher::nativeGestureEndEvent ( QNativeGestureEvent * event)

Definition at line 564 of file kis_shortcut_matcher.cpp.

565{
566 Private::RecursionNotifier notifier(this);
567
568 if ( m_d->nativeGestureShortcut && !m_d->nativeGestureShortcut->match( event ) ) {
570 }
571
572 if (notifier.isInRecursion()) {
574 } else if (!hasRunningShortcut()) {
577 }
578
579 return true;
580}
bool tryEndNativeGestureShortcut(QNativeGestureEvent *event)

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

◆ nativeGestureEvent()

bool KisShortcutMatcher::nativeGestureEvent ( QNativeGestureEvent * event)

Definition at line 550 of file kis_shortcut_matcher.cpp.

551{
552 bool retval = false;
553 if (!hasRunningShortcut()) {
554 retval = tryRunNativeGestureShortcut( event );
555 }
556 else if (m_d->nativeGestureShortcut) {
557 m_d->nativeGestureShortcut->action()->inputEvent( event );
558 retval = true;
559 }
560
561 return retval;
562}
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 335 of file kis_shortcut_matcher.cpp.

336{
337 Private::RecursionNotifier notifier(this);
338
339 if (notifier.isInRecursion()) {
340 return false;
341 }
342
343 bool retval = false;
344
345 if (m_d->runningShortcut) {
346 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->touchShortcut && !m_d->nativeGestureShortcut, false);
347 m_d->runningShortcut->action()->inputEvent(event);
348 retval = true;
349 }
350
351 return retval;
352}
#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 802 of file kis_shortcut_matcher.cpp.

803{
804 m_d->candidateShortcuts.clear();
805 if (m_d->actionsSuppressed()) return;
806
807 // Allow letting the modifiers to be matched so key_shift + middle mouse move can be matched, but key_v + mouse drag can not.
808 bool containsOnlyModifiers = !m_d->keys.isEmpty();
809 Q_FOREACH(const Qt::Key k, m_d->keys) {
810 if (k != Qt::Key_Shift && k != Qt::Key_Control && k != Qt::Key_Alt && k != Qt::Key_Meta) {
811 containsOnlyModifiers = false;
812 break;
813 }
814 }
815 if (m_d->KeyboardActionsSuppressed()
816 && !containsOnlyModifiers && !m_d->keys.isEmpty()
817 && m_d->buttons.isEmpty()) {
818 return;
819 }
820
821 Q_FOREACH (KisStrokeShortcut *s, m_d->strokeShortcuts) {
822 if (s->matchReady(m_d->keys, m_d->buttons)) {
823 m_d->candidateShortcuts.append(s);
824 }
825 }
826}
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 590 of file kis_shortcut_matcher.cpp.

591{
592 Private::RecursionNotifier notifier(this);
593
594
595 reset("reinitialize");
596
597 if (notifier.isInRecursion()) {
599 } else if (!hasRunningShortcut()) {
602 }
603}

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 605 of file kis_shortcut_matcher.cpp.

606{
607 Private::RecursionNotifier notifier(this);
608
609 m_d->buttons.clear();
610 DEBUG_ACTION("reinitializing buttons");
611
612 if (notifier.isInRecursion()) {
614 } else if (!hasRunningShortcut()) {
617 }
618}

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

◆ reset() [1/2]

void KisShortcutMatcher::reset ( )
private

Definition at line 707 of file kis_shortcut_matcher.cpp.

708{
709 m_d->keys.clear();
710 m_d->buttons.clear();
711 DEBUG_ACTION("reset!");
712}

References DEBUG_ACTION, and m_d.

◆ reset() [2/2]

void KisShortcutMatcher::reset ( QString msg)
private

Definition at line 715 of file kis_shortcut_matcher.cpp.

716{
717 m_d->keys.clear();
718 m_d->buttons.clear();
719 Q_UNUSED(msg);
720 DEBUG_ACTION(msg);
721}

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 647 of file kis_shortcut_matcher.cpp.

648{
649 auto checkKey = [this, modifiers] (Qt::Key key, Qt::KeyboardModifier modifier) {
650 return m_d->keys.contains(key) == bool(modifiers & modifier);
651 };
652
653 return checkKey(Qt::Key_Shift, Qt::ShiftModifier) &&
654 checkKey(Qt::Key_Control, Qt::ControlModifier) &&
655 checkKey(Qt::Key_Alt, Qt::AltModifier) &&
656 checkKey(Qt::Key_Meta, Qt::MetaModifier);
657
658}

References m_d.

◆ setInputActionGroupsMaskCallback()

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

Definition at line 760 of file kis_shortcut_matcher.cpp.

761{
762 m_d->actionGroupMask = func;
763}

References m_d.

◆ setMaxTouchPointEvent()

void KisShortcutMatcher::setMaxTouchPointEvent ( QTouchEvent * event)
private

Definition at line 971 of file kis_shortcut_matcher.cpp.

972{
973 int touchPointCount = event->touchPoints().size();
974 if (touchPointCount > m_d->maxTouchPoints) {
975 m_d->maxTouchPoints = touchPointCount;
976#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
977 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateTouchEvent);
978#else
979 m_d->bestCandidateTouchEvent.reset(event->clone());
980#endif
981
982 }
983}

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 187 of file kis_shortcut_matcher.cpp.

188{
189 return (m_d->runningShortcut && m_d->runningShortcut->action()
190 && m_d->runningShortcut->action()->supportsHiResInputEvents(m_d->runningShortcut->shortcutIndex()))
191 || (m_d->touchShortcut && m_d->touchShortcut->action()
192 && m_d->touchShortcut->action()->supportsHiResInputEvents(m_d->touchShortcut->shortcutIndex()))
193 || (m_d->nativeGestureShortcut && m_d->nativeGestureShortcut->action()
194 && m_d->nativeGestureShortcut->action()->supportsHiResInputEvents(m_d->nativeGestureShortcut->shortcutIndex()));
195}

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 728 of file kis_shortcut_matcher.cpp.

729{
730 m_d->suppressedSingleActionShortcuts.clear();
731
732 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
733 Q_FOREACH (const QKeySequence &seq, shortcuts) {
734 if (s->conflictsWith(seq)) {
735 m_d->suppressedSingleActionShortcuts.insert(s);
736 }
737 }
738 }
739}
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 693 of file kis_shortcut_matcher.cpp.

694{
695 Private::RecursionNotifier notifier(this);
696
697 DEBUG_ACTION("toolHasBeenActivated");
698
699 if (notifier.isInRecursion()) {
701 } else if (!hasRunningShortcut()) {
704 }
705}

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

◆ touchBeginEvent()

bool KisShortcutMatcher::touchBeginEvent ( QTouchEvent * event)

Definition at line 382 of file kis_shortcut_matcher.cpp.

383{
384 DEBUG_TOUCH_ACTION("entered", event)
385
386 Private::RecursionNotifier notifier(this);
387
388 m_d->lastTouchPoints = event->touchPoints();
389
390 // reset state
391 m_d->maxTouchPoints = event->touchPoints().size();
392 m_d->matchingIteration = 1;
393 m_d->isTouchDragDetected = false;
394#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
395 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateTouchEvent);
396#else
397 m_d->bestCandidateTouchEvent.reset(event->clone());
398#endif
399
400 return !notifier.isInRecursion();
401}

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 499 of file kis_shortcut_matcher.cpp.

500{
501 Private::RecursionNotifier notifier(this);
502
503 m_d->maxTouchPoints = 0;
504
505 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->runningShortcut || !m_d->touchShortcut);
506
507 // end the stroke types
508 if (m_d->touchShortcut) {
509 KisTouchShortcut *touchShortcut = m_d->touchShortcut;
510 m_d->touchShortcut = 0;
511 QScopedPointer<QEvent> dstEvent;
512#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
513 KoPointerEvent::copyQtPointerEvent(event, dstEvent);
514#else
515 dstEvent.reset(event->clone());
516#endif
517
518 // HACK: Because TouchEvents in KoPointerEvent need to contain at least one touchpoint
519 QTouchEvent* touchEvent = dynamic_cast<QTouchEvent *>(dstEvent.data());
520 KIS_ASSERT(touchEvent);
521#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
522 touchEvent->setTouchPoints(m_d->lastTouchPoints);
523#else
524 dstEvent.reset(new QTouchEvent(event->type(),
525 event->pointingDevice(),
526 event->modifiers(),
527 m_d->lastTouchPoints));
528#endif
529 touchShortcut->action()->end(dstEvent.data());
531 }
532
533 if (notifier.isInRecursion()) {
535 } else if (!hasRunningShortcut()) {
538 }
539}
#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 475 of file kis_shortcut_matcher.cpp.

476{
477 Private::RecursionNotifier notifier(this);
478
479 m_d->maxTouchPoints = 0;
480
481 if (!m_d->isTouchDragDetected && m_d->bestCandidateTouchEvent && !hasRunningShortcut()) {
482 fireReadyTouchShortcut(static_cast<QTouchEvent *>(m_d->bestCandidateTouchEvent.data()));
483 }
484
485 DEBUG_TOUCH_ACTION("ending", event)
486 // we should try and end the shortcut too (it might be that there is none? (sketch))
487 const bool retval = tryEndTouchShortcut(event);
488
489 if (notifier.isInRecursion()) {
491 } else if (!hasRunningShortcut()) {
494 }
495
496 return retval;
497}
bool tryEndTouchShortcut(QTouchEvent *event)
void fireReadyTouchShortcut(QTouchEvent *event)

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

◆ touchUpdateEvent()

bool KisShortcutMatcher::touchUpdateEvent ( QTouchEvent * event)

Definition at line 403 of file kis_shortcut_matcher.cpp.

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

References DEBUG_TOUCH_ACTION, fireReadyTouchShortcut(), hasRunningShortcut(), m_d, matchTouchShortcut(), setMaxTouchPointEvent(), 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 873 of file kis_shortcut_matcher.cpp.

874{
875 KisStrokeShortcut *goodCandidate = 0;
876
877 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
878 if (!goodCandidate || s->priority() > goodCandidate->priority()) {
879 goodCandidate = s;
880 }
881 }
882
883 if (goodCandidate) {
884 if (m_d->readyShortcut && m_d->readyShortcut != goodCandidate) {
885 DEBUG_SHORTCUT("Deactivated previous shortcut action", m_d->readyShortcut);
886 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
887 m_d->readyShortcut = 0;
888 }
889
890 if (!m_d->readyShortcut) {
891 DEBUG_SHORTCUT("Preparing new ready action", goodCandidate);
892
900 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
901 m_d->readyShortcut = goodCandidate;
902 }
903 } else if (m_d->readyShortcut) {
904 DEBUG_SHORTCUT("Deactivating action", m_d->readyShortcut);
905 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
906 m_d->readyShortcut = 0;
907 }
908}
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 1105 of file kis_shortcut_matcher.cpp.

1106{
1107 Private::RecursionNotifier notifier(this);
1108
1109 if (m_d->nativeGestureShortcut) {
1110 // first reset running shortcut to avoid infinite recursion via end()
1111 KisNativeGestureShortcut *nativeGestureShortcut = m_d->nativeGestureShortcut;
1112
1113 nativeGestureShortcut->action()->end(event);
1114 nativeGestureShortcut->action()->deactivate(m_d->nativeGestureShortcut->shortcutIndex());
1115
1116 m_d->nativeGestureShortcut = 0; // empty it out now that we are done with it
1117
1118 return true;
1119 }
1120
1121 if (notifier.isInRecursion()) {
1123 } else if (!hasRunningShortcut()) {
1126 }
1127
1128 return false;
1129}

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 910 of file kis_shortcut_matcher.cpp.

911{
912 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->runningShortcut, true);
913 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
914 // it shouldn't have happened, running and ready shortcuts
915 // at the same time should not be possible
917 }
918
919 if (m_d->runningShortcut && m_d->runningShortcut->matchBegin(button)) {
920
921 // first reset running shortcut to avoid infinite recursion via end()
922 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
923 m_d->runningShortcut = 0;
924
925 if (runningShortcut->action()) {
926 DEBUG_EVENT_ACTION("Ending running shortcut at event", event);
928 int shortcutIndex = runningShortcut->shortcutIndex();
929 action->end(event);
930 action->deactivate(shortcutIndex);
931 }
932 }
933
934 return !m_d->runningShortcut;
935}
#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 1049 of file kis_shortcut_matcher.cpp.

1050{
1051 if (m_d->touchShortcut) {
1052 // first reset running shortcut to avoid infinite recursion via end()
1053 KisTouchShortcut *touchShortcut = m_d->touchShortcut;
1054
1055 DEBUG_SHORTCUT("ending", touchShortcut)
1056 touchShortcut->action()->end(event);
1057 touchShortcut->action()->deactivate(m_d->touchShortcut->shortcutIndex());
1058
1059 m_d->touchShortcut = 0; // empty it out now that we are done with it
1060
1061 return true;
1062 }
1063
1064 return false;
1065}

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

◆ tryRunNativeGestureShortcut()

bool KisShortcutMatcher::tryRunNativeGestureShortcut ( QNativeGestureEvent * event)
private

Definition at line 1067 of file kis_shortcut_matcher.cpp.

1068{
1069 KisNativeGestureShortcut *goodCandidate = 0;
1070
1071 if (m_d->actionsSuppressed())
1072 return false;
1073
1074 Q_FOREACH (KisNativeGestureShortcut* shortcut, m_d->nativeGestureShortcuts) {
1075 if (shortcut->match(event) && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1076 goodCandidate = shortcut;
1077 }
1078 }
1079
1080 if (goodCandidate) {
1081 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1082
1083 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1084 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1086
1087 m_d->nativeGestureShortcut = goodCandidate;
1088
1089 Private::RecursionGuard guard(this);
1090 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1091 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1092
1093 // the tool might have opened some dialog, which could break our event loop
1094 if (guard.brokenByRecursion()) {
1095 goodCandidate->action()->end(event);
1096 m_d->nativeGestureShortcut = 0;
1097
1099 }
1100 }
1101
1102 return m_d->nativeGestureShortcut;
1103}
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 828 of file kis_shortcut_matcher.cpp.

829{
830 KisStrokeShortcut *goodCandidate = 0;
831
832 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
833 if (s->isAvailable(m_d->actionGroupMask()) &&
834 s->matchBegin(button) &&
835 (!goodCandidate || s->priority() > goodCandidate->priority())) {
836
837 goodCandidate = s;
838 }
839 }
840
841 if (goodCandidate) {
842 if (m_d->readyShortcut) {
843 if (m_d->readyShortcut != goodCandidate) {
844 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
845 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
846 }
847 m_d->readyShortcut = 0;
848 } else {
849 DEBUG_EVENT_ACTION("Matched *new* shortcut for event", event);
850 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
851 }
852
853 DEBUG_SHORTCUT("Starting new action", goodCandidate);
854
855 {
856 m_d->runningShortcut = goodCandidate;
857 Private::RecursionGuard guard(this);
858 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
859
860 // the tool might have opened some dialog, which could break our event loop
861 if (guard.brokenByRecursion()) {
862 goodCandidate->action()->end(event);
863 m_d->runningShortcut = 0;
864
866 }
867 }
868 }
869
870 return m_d->runningShortcut;
871}
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 772 of file kis_shortcut_matcher.cpp.

773{
774 if (m_d->actionsSuppressedIgnoreFocus() || (keyboard && m_d->KeyboardActionsSuppressed())) {
775 DEBUG_EVENT_ACTION("Event suppressed", event)
776 return false;
777 }
778
779 KisSingleActionShortcut *goodCandidate = 0;
780
781 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
782 if (!m_d->suppressedSingleActionShortcuts.contains(s) &&
783 s->isAvailable(m_d->actionGroupMask()) &&
784 s->match(keysState, param) &&
785 (!goodCandidate || s->priority() > goodCandidate->priority())) {
786
787 goodCandidate = s;
788 }
789 }
790
791 if (goodCandidate) {
792 DEBUG_EVENT_ACTION("Beginning action for event", event);
793 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
794 goodCandidate->action()->end(0);
795 } else {
796 DEBUG_EVENT_ACTION("Could not match a candidate for event", event)
797 }
798
799 return goodCandidate;
800}
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 1015 of file kis_shortcut_matcher.cpp.

1016{
1017 KisTouchShortcut *goodCandidate = matchTouchShortcut(event);
1018
1019 if (m_d->actionsSuppressed())
1020 return false;
1021
1022 if (goodCandidate) {
1023 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1024
1025 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1026 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1028
1029 m_d->touchShortcut = goodCandidate;
1030
1031 Private::RecursionGuard guard(this);
1032 DEBUG_SHORTCUT("Running a touch shortcut", goodCandidate)
1033
1034 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1035 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1036
1037 // the tool might have opened some dialog, which could break our event loop
1038 if (guard.brokenByRecursion()) {
1039 goodCandidate->action()->end(event);
1040 m_d->touchShortcut = 0;
1041
1043 }
1044 }
1045
1046 return m_d->touchShortcut;
1047}

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 765 of file kis_shortcut_matcher.cpp.

766{
767 return tryRunSingleActionShortcutImpl(wheelAction, event, m_d->keys, false);
768}

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 322 of file kis_shortcut_matcher.cpp.

323{
324 Private::RecursionNotifier notifier(this);
325
326
327 if (hasRunningShortcut() || notifier.isInRecursion()) {
328 DEBUG_ACTION("Wheel event canceled.");
329 return false;
330 }
331
332 return tryRunWheelShortcut(wheelAction, event);
333}
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 281 of file kis_shortcut_matcher.h.

Member Data Documentation

◆ actionGroupMask

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

Definition at line 91 of file kis_shortcut_matcher.cpp.

◆ bestCandidateTouchEvent

QScopedPointer<QEvent> KisShortcutMatcher::bestCandidateTouchEvent

Definition at line 89 of file kis_shortcut_matcher.cpp.

◆ brokenByRecursion

int KisShortcutMatcher::brokenByRecursion = 0

Definition at line 97 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 94 of file kis_shortcut_matcher.cpp.

◆ isTouchDragDetected

bool KisShortcutMatcher::isTouchDragDetected {false}

Definition at line 88 of file kis_shortcut_matcher.cpp.

88{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 308 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 96 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 92 of file kis_shortcut_matcher.cpp.

◆ suppressAllKeyboardActions

void KisShortcutMatcher::suppressAllKeyboardActions

Definition at line 93 of file kis_shortcut_matcher.cpp.

◆ suppressedSingleActionShortcuts

QSet<KisSingleActionShortcut*> KisShortcutMatcher::suppressedSingleActionShortcuts

Definition at line 68 of file kis_shortcut_matcher.cpp.

◆ 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: