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

#include <kis_shortcut_matcher.h>

+ Inheritance diagram for KisShortcutMatcher:

Classes

struct  IgnoreMultiFingerCancelWorkaround
 
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 (KisTouchpadScrollShortcut *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 hasTouchpadScrollShortcuts () const
 
bool ignoreMultiFingerCancelWorkaroundEnalbed () 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 setIgnoreMultiFingerCancelWorkaroundEnalbed (bool value)
 
void setInputActionGroupsMaskCallback (std::function< KisInputActionGroupsMask()> func)
 
void setTouchHoldDelay (int value)
 
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)
 
bool touchEndEvent (QTouchEvent *event)
 
int touchHoldDelay () const
 
bool touchpadScrollBeginEvent (QWheelEvent *event)
 
bool touchpadScrollEndEvent (QWheelEvent *event)
 
bool touchpadScrollEvent (QWheelEvent *event)
 
bool touchUpdateEvent (QTouchEvent *event)
 
bool wheelEvent (KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
 
 ~KisShortcutMatcher ()
 
 ~Private ()
 

Public Attributes

std::function< KisInputActionGroupsMask()> actionGroupMask
 
QScopedPointer< QEvent > bestCandidateForTapTouchEvent
 
int brokenByRecursion = 0
 
QSet< Qt::MouseButton > buttons
 
QList< KisStrokeShortcut * > candidateShortcuts
 
bool cursorEntered
 
std::optional< IgnoreMultiFingerCancelWorkaround > ignoreMultiFingerCancelWorkaround
 
bool isTouchDragDetected {false}
 
bool isTouchHeld {false}
 
QSet< Qt::Key > keys
 
QScopedPointer< QTouchEvent > lastProcessedTouchEvent
 
int matchingIteration {0}
 
int maxTouchPoints {0}
 
KisNativeGestureShortcut * nativeGestureShortcut
 
QList< KisNativeGestureShortcut * > nativeGestureShortcuts
 
QSet< Qt::Key > polledKeys
 
KisStrokeShortcut * readyShortcut
 
int recursiveCounter = 0
 
KisStrokeShortcut * runningShortcut
 
QList< KisSingleActionShortcut * > singleActionShortcuts
 
QList< KisStrokeShortcut * > strokeShortcuts
 
bool suppressAllActions
 
bool suppressAllKeyboardActions
 
QSet< KisSingleActionShortcut * > suppressedSingleActionShortcuts
 
bool touchActionTracked {false}
 
int touchHoldDelayMs {400}
 
std::optional< KisTouchHoldEventsPostponer > touchHoldEventPostponer
 
KisTouchpadScrollShortcut * touchpadScrollShortcut
 
QList< KisTouchpadScrollShortcut * > touchpadScrollShortcuts
 
KisTouchShortcut * touchShortcut
 
QList< KisTouchShortcut * > touchShortcuts
 

Static Public Attributes

static constexpr qreal TOUCH_SLOP = 16
 
static constexpr int TOUCH_SLOP_SQUARED = 16 * 16
 

Private Types

enum class  TouchShortcutMode { Drag = 0 , Tap , Hold }
 

Private Member Functions

void forceDeactivateAllActions ()
 
void forceEndRunningShortcut (const QPointF &localPos)
 
KisTouchShortcut * matchTouchShortcut (QTouchEvent *event, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
 
bool matchTouchShortcutBasedOnState (QTouchEvent *event, KisTouchShortcut *shortcut, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
 
void prepareReadyShortcuts ()
 
void reset ()
 
void reset (QString msg)
 
void setMaxTouchPointEvent (QTouchEvent *event)
 
void slotTouchHoldCompleted ()
 
bool touchUpdateEventImpl (QTouchEvent *event)
 
void tryActivateReadyShortcut ()
 
void tryCancelAllCurrentTouchActionsImpl ()
 
template<typename EventType , typename ShortcutType >
bool tryEndGestureBasedShortcutImpl (EventType *event, ShortcutType **resultShortcutPtr)
 
bool tryEndNativeGestureShortcut (QNativeGestureEvent *event)
 
bool tryEndRunningShortcut (Qt::MouseButton button, QEvent *event)
 
bool tryEndTouchpadScrollShortcut (QWheelEvent *event)
 
bool tryEndTouchShortcut (QTouchEvent *event)
 
bool tryFireTapTouchShortcut (QTouchEvent *event, Qt::TouchPointStates allowedStates)
 
template<typename EventType , typename ShortcutType >
bool tryRunGestureBasedShortcutImpl (EventType *event, ShortcutType **resultShortcutPtr, const QList< ShortcutType * > allTypedShortcuts)
 
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 tryRunTouchpadScrollShortcut (QWheelEvent *event)
 
bool tryRunTouchShortcut (QTouchEvent *event, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
 
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
KisCanvas2 * canvas
 
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 89 of file kis_shortcut_matcher.cpp.

Member Enumeration Documentation

◆ TouchShortcutMode

enum class KisShortcutMatcher::TouchShortcutMode
strongprivate
Enumerator
Drag 
Tap 
Hold 

Definition at line 320 of file kis_shortcut_matcher.h.

Constructor & Destructor Documentation

◆ ~Private()

KisShortcutMatcher::~Private ( )
inline

Definition at line 104 of file kis_shortcut_matcher.cpp.

105 {
106 qDeleteAll(singleActionShortcuts);
107 qDeleteAll(strokeShortcuts);
108 qDeleteAll(touchShortcuts);
109 }
QList< KisStrokeShortcut * > strokeShortcuts
QList< KisSingleActionShortcut * > singleActionShortcuts
QList< KisTouchShortcut * > touchShortcuts

◆ KisShortcutMatcher()

KisShortcutMatcher::KisShortcutMatcher ( )

Definition at line 218 of file kis_shortcut_matcher.cpp.

219 : m_d(new Private)
220{}

◆ ~KisShortcutMatcher()

KisShortcutMatcher::~KisShortcutMatcher ( )

Definition at line 222 of file kis_shortcut_matcher.cpp.

223{
224 delete m_d;
225}

References m_d.

Member Function Documentation

◆ actionsSuppressed()

bool KisShortcutMatcher::actionsSuppressed ( ) const
inline

Definition at line 200 of file kis_shortcut_matcher.cpp.

200 {
201#ifndef Q_OS_ANDROID
203#else
204 // when S-pen is not pointing the canvas, actions on canvas are disabled, till it points back to canvas.
205 return suppressAllActions;
206#endif
207 }

◆ actionsSuppressedIgnoreFocus()

bool KisShortcutMatcher::actionsSuppressedIgnoreFocus ( ) const
inline

Definition at line 209 of file kis_shortcut_matcher.cpp.

209 {
210 return suppressAllActions;
211 }

◆ addShortcut() [1/5]

void KisShortcutMatcher::addShortcut ( KisNativeGestureShortcut * shortcut)

Definition at line 257 of file kis_shortcut_matcher.cpp.

258{
259 m_d->nativeGestureShortcuts.append(shortcut);
260}

References m_d.

◆ addShortcut() [2/5]

void KisShortcutMatcher::addShortcut ( KisSingleActionShortcut * shortcut)

Definition at line 242 of file kis_shortcut_matcher.cpp.

243{
244 m_d->singleActionShortcuts.append(shortcut);
245}

References m_d.

◆ addShortcut() [3/5]

void KisShortcutMatcher::addShortcut ( KisStrokeShortcut * shortcut)

Definition at line 247 of file kis_shortcut_matcher.cpp.

248{
249 m_d->strokeShortcuts.append(shortcut);
250}

References m_d.

◆ addShortcut() [4/5]

void KisShortcutMatcher::addShortcut ( KisTouchpadScrollShortcut * shortcut)

Definition at line 262 of file kis_shortcut_matcher.cpp.

263{
264 m_d->touchpadScrollShortcuts.append(shortcut);
265}

References m_d.

◆ addShortcut() [5/5]

void KisShortcutMatcher::addShortcut ( KisTouchShortcut * shortcut)

Definition at line 252 of file kis_shortcut_matcher.cpp.

253{
254 m_d->touchShortcuts.append(shortcut);
255}

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

305{
306 Private::RecursionNotifier notifier(this);
307
308
309 bool retval = false;
310
311 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, autorepeated key but can't remember it was pressed"); }
312
313 if (m_d->polledKeys.contains(key)) {
314 m_d->polledKeys.remove(key);
315 }
316
317 if (notifier.isInRecursion()) {
319 } else if (!hasRunningShortcut()) {
320 // Autorepeated key should not be included in the shortcut
321 QSet<Qt::Key> filteredKeys = m_d->keys;
322 filteredKeys.remove(key);
323 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, filteredKeys);
324 }
325
326 return retval;
327}
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 350 of file kis_shortcut_matcher.cpp.

351{
352 Private::RecursionNotifier notifier(this);
353 DEBUG_BUTTON_ACTION("entered", button);
354
355 // the tablet actions have the priority over any existing
356 // touch action, so we should cancel them first
358
359 bool retval = false;
360
361 if (m_d->buttons.contains(button)) { DEBUG_ACTION("Peculiar, button was already pressed."); }
362
363 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
365 retval = tryRunReadyShortcut(button, event);
366 }
367
368 m_d->buttons.insert(button);
369
370 if (notifier.isInRecursion()) {
372 } else if (!hasRunningShortcut()) {
375 }
376
377 return retval;
378}
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(), tryCancelAllCurrentTouchActionsImpl(), 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 380 of file kis_shortcut_matcher.cpp.

381{
382 Private::RecursionNotifier notifier(this);
383 DEBUG_BUTTON_ACTION("entered", button);
384
385 bool retval = false;
386
387 // here we check for the presence of the **stroke** shortcut only
388 if (m_d->runningShortcut) {
389 KIS_SAFE_ASSERT_RECOVER_NOOP(!notifier.isInRecursion());
390
391 retval = tryEndRunningShortcut(button, event);
392 DEBUG_BUTTON_ACTION("ended", button);
393 }
394
395 if (!m_d->buttons.contains(button)) reset("Peculiar, button released but we can't remember it was pressed");
396 else m_d->buttons.remove(button);
397
398 if (notifier.isInRecursion()) {
400 } else if (!hasRunningShortcut()) {
403 }
404
405 return retval;
406}
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 1101 of file kis_shortcut_matcher.cpp.

1102{
1103 reset("Clearing shortcuts");
1104
1105 qDeleteAll(m_d->singleActionShortcuts);
1106 m_d->singleActionShortcuts.clear();
1107 m_d->suppressedSingleActionShortcuts.clear();
1108
1109 qDeleteAll(m_d->strokeShortcuts);
1110 m_d->strokeShortcuts.clear();
1111
1112 qDeleteAll(m_d->touchShortcuts);
1113 m_d->touchShortcuts.clear();
1114
1115 qDeleteAll(m_d->nativeGestureShortcuts);
1116 m_d->nativeGestureShortcuts.clear();
1117
1118 qDeleteAll(m_d->touchpadScrollShortcuts);
1119 m_d->touchpadScrollShortcuts.clear();
1120
1121 m_d->candidateShortcuts.clear();
1122 m_d->runningShortcut = 0;
1123 m_d->readyShortcut = 0;
1124 m_d->touchShortcut = 0;
1125 m_d->nativeGestureShortcut = 0;
1126 m_d->touchpadScrollShortcut = 0;
1127}

References m_d, and reset().

◆ debugPressedKeys()

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

Return the internal state of the tracked modifiers.

Definition at line 1015 of file kis_shortcut_matcher.cpp.

1016{
1018 std::copy(m_d->keys.begin(), m_d->keys.end(), std::back_inserter(keys));
1019 return keys;
1020}

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

441{
442 Private::RecursionNotifier notifier(this);
443
444 m_d->cursorEntered = true;
445
446 if (notifier.isInRecursion()) {
448 } else if (!hasRunningShortcut()) {
451 }
452}

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

◆ forceDeactivateAllActions()

void KisShortcutMatcher::forceDeactivateAllActions ( )
private

Definition at line 1359 of file kis_shortcut_matcher.cpp.

1360{
1361 if (m_d->readyShortcut) {
1362 DEBUG_SHORTCUT("Forcefully deactivating action", m_d->readyShortcut);
1363 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
1364 m_d->readyShortcut = 0;
1365 }
1366}
#define DEBUG_SHORTCUT(text, shortcut)

References DEBUG_SHORTCUT, and m_d.

◆ forceEndRunningShortcut()

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

Definition at line 1334 of file kis_shortcut_matcher.cpp.

1335{
1336 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->runningShortcut);
1337 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
1338 // it shouldn't have happened, running and ready shortcuts
1339 // at the same time should not be possible
1341 }
1342
1343 // first reset running shortcut to avoid infinite recursion via end()
1344 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
1345 m_d->runningShortcut = 0;
1346
1347 if (runningShortcut->action()) {
1348 DEBUG_ACTION("Forced ending running shortcut at event");
1350 int shortcutIndex = runningShortcut->shortcutIndex();
1351
1352 QMouseEvent event = runningShortcut->fakeEndEvent(localPos);
1353
1354 action->end(&event);
1355 action->deactivate(shortcutIndex);
1356 }
1357}
Abstract base class for input actions.
virtual void deactivate(int shortcut)
virtual void end(QEvent *event)
KisAbstractInputAction * action
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 975 of file kis_shortcut_matcher.cpp.

976{
977 Q_FOREACH (Qt::Key key, m_d->keys) {
978 if (!keys.contains(key)) {
979 keyReleased(key);
980 }
981 }
982
983 Q_FOREACH (Qt::Key key, keys) {
984 if (!m_d->keys.contains(key)) {
985 keyPressed(key);
986 m_d->polledKeys << key;
987 }
988 }
989
990 Private::RecursionNotifier notifier(this);
991
992 if (notifier.isInRecursion()) {
994 } else if (!hasRunningShortcut()) {
997 }
998
999 DEBUG_ACTION("recoverySyncModifiers");
1000}
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 1022 of file kis_shortcut_matcher.cpp.

1023{
1024 return !m_d->polledKeys.empty();
1025}

References m_d.

◆ hasRunningShortcut()

bool KisShortcutMatcher::hasRunningShortcut ( ) const

Definition at line 227 of file kis_shortcut_matcher.cpp.

228{
229 return m_d->runningShortcut || m_d->touchShortcut || m_d->nativeGestureShortcut || m_d->touchpadScrollShortcut;
230}

References m_d.

◆ hasTouchHoldShortcut()

bool KisShortcutMatcher::hasTouchHoldShortcut ( ) const

Definition at line 232 of file kis_shortcut_matcher.cpp.

233{
234 for (const KisTouchShortcut *shortcut : m_d->touchShortcuts) {
235 if (shortcut->isHoldType() && shortcut->isAvailable(m_d->actionGroupMask())) {
236 return true;
237 }
238 }
239 return false;
240}
The KisTouchShortcut class only handles touch gestures it does not handle tool invocation i....

References m_d.

◆ hasTouchpadScrollShortcuts()

bool KisShortcutMatcher::hasTouchpadScrollShortcuts ( ) const

Definition at line 874 of file kis_shortcut_matcher.cpp.

875{
876 return !m_d->touchpadScrollShortcuts.isEmpty();
877}

References m_d.

◆ ignoreMultiFingerCancelWorkaroundEnalbed()

bool KisShortcutMatcher::ignoreMultiFingerCancelWorkaroundEnalbed ( ) const
See also
setIgnoreMultiFingerCancelWorkaroundEnalbed()

Definition at line 1612 of file kis_shortcut_matcher.cpp.

1613{
1614 return m_d->ignoreMultiFingerCancelWorkaround.has_value();
1615}

References m_d.

◆ KeyboardActionsSuppressed()

bool KisShortcutMatcher::KeyboardActionsSuppressed ( ) const
inline

Definition at line 213 of file kis_shortcut_matcher.cpp.

213 {
215 }

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

280{
281 Private::RecursionNotifier notifier(this);
282
283 bool retval = false;
284
285 if (m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, records show key was already pressed"); }
286
287 if (!hasRunningShortcut() && !notifier.isInRecursion()) {
288 retval = tryRunSingleActionShortcutImpl(key, (QEvent*)0, m_d->keys);
289 }
290
291 m_d->keys.insert(key);
292 DEBUG_KEY("Pressed");
293
294 if (notifier.isInRecursion()) {
296 } else if (!hasRunningShortcut()) {
299 }
300
301 return retval;
302}
#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 329 of file kis_shortcut_matcher.cpp.

330{
331 Private::RecursionNotifier notifier(this);
332
333 if (!m_d->keys.contains(key)) { DEBUG_ACTION("Peculiar, key released but can't remember it was pressed"); }
334 else m_d->keys.remove(key);
335
336 m_d->polledKeys.remove(key);
337
338 DEBUG_KEY("Released");
339
340 if (notifier.isInRecursion()) {
342 } else if (!hasRunningShortcut()) {
345 }
346
347 return false;
348}

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

455{
456 Private::RecursionNotifier notifier(this);
457
458 m_d->cursorEntered = false;
459
460 if (notifier.isInRecursion()) {
462 } else if (!hasRunningShortcut()) {
465 }
466}

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

1028{
1029 Private::RecursionNotifier notifier(this);
1030
1031 DEBUG_ACTION("lostFocusEvent");
1032
1033 if (m_d->runningShortcut) {
1034 forceEndRunningShortcut(localPos);
1035 }
1036
1038
1046}
void forceEndRunningShortcut(const QPointF &localPos)

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

◆ matchTouchShortcut()

KisTouchShortcut * KisShortcutMatcher::matchTouchShortcut ( QTouchEvent * event,
Qt::TouchPointStates allowedStates,
TouchShortcutMode mode )
private

Definition at line 1411 of file kis_shortcut_matcher.cpp.

1412{
1413 KisTouchShortcut *goodCandidate = nullptr;
1414 Q_FOREACH (KisTouchShortcut *shortcut, m_d->touchShortcuts) {
1415 if (shortcut->isAvailable(m_d->actionGroupMask())
1416 && matchTouchShortcutBasedOnState(event, shortcut, allowedStates, mode)
1417 && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1418
1419 goodCandidate = shortcut;
1420 }
1421 }
1422 return goodCandidate;
1423}
bool matchTouchShortcutBasedOnState(QTouchEvent *event, KisTouchShortcut *shortcut, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
bool isAvailable(KisInputActionGroupsMask mask) const override
int priority() const override

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

◆ matchTouchShortcutBasedOnState()

bool KisShortcutMatcher::matchTouchShortcutBasedOnState ( QTouchEvent * event,
KisTouchShortcut * shortcut,
Qt::TouchPointStates allowedStates,
TouchShortcutMode mode )
private

Definition at line 1425 of file kis_shortcut_matcher.cpp.

1426{
1427 switch (mode) {
1429 return shortcut->matchHoldType(event, allowedStates);
1430 break;
1432 return shortcut->matchDragType(event, allowedStates);
1433 break;
1435 return shortcut->matchTapType(event, allowedStates);
1436 break;
1437 }
1438
1439#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1440 return false;
1441#else
1442 Q_UNREACHABLE_RETURN(false);
1443#endif
1444}
bool matchTapType(const QTouchEvent *event, Qt::TouchPointStates allowedStates)
bool matchDragType(const QTouchEvent *event, Qt::TouchPointStates allowedStates)
bool matchHoldType(const QTouchEvent *event, Qt::TouchPointStates allowedStates)

References Drag, Hold, KisTouchShortcut::matchDragType(), KisTouchShortcut::matchHoldType(), KisTouchShortcut::matchTapType(), and Tap.

◆ nativeGestureBeginEvent()

bool KisShortcutMatcher::nativeGestureBeginEvent ( QNativeGestureEvent * event)

Definition at line 826 of file kis_shortcut_matcher.cpp.

827{
828 Q_UNUSED(event);
829
830 Private::RecursionNotifier notifier(this);
831
832 DEBUG_EVENT_ACTION("entered", event);
833
834 return !notifier.isInRecursion();
835}
#define DEBUG_EVENT_ACTION(text, event)

References DEBUG_EVENT_ACTION.

◆ nativeGestureEndEvent()

bool KisShortcutMatcher::nativeGestureEndEvent ( QNativeGestureEvent * event)

Definition at line 854 of file kis_shortcut_matcher.cpp.

855{
856 Private::RecursionNotifier notifier(this);
857
858 DEBUG_EVENT_ACTION("entered", event);
859
860 if (m_d->nativeGestureShortcut) {
862 }
863
864 if (notifier.isInRecursion()) {
866 } else if (!hasRunningShortcut()) {
869 }
870
871 return true;
872}
bool tryEndNativeGestureShortcut(QNativeGestureEvent *event)

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

◆ nativeGestureEvent()

bool KisShortcutMatcher::nativeGestureEvent ( QNativeGestureEvent * event)

Definition at line 837 of file kis_shortcut_matcher.cpp.

838{
839 bool retval = false;
840
841 DEBUG_EVENT_ACTION("entered", event);
842
843 if (!hasRunningShortcut()) {
844 retval = tryRunNativeGestureShortcut( event );
845 }
846 else if (m_d->nativeGestureShortcut) {
847 m_d->nativeGestureShortcut->action()->inputEvent( event );
848 retval = true;
849 }
850
851 return retval;
852}
bool tryRunNativeGestureShortcut(QNativeGestureEvent *event)

References DEBUG_EVENT_ACTION, 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 421 of file kis_shortcut_matcher.cpp.

422{
423 Private::RecursionNotifier notifier(this);
424
425 if (notifier.isInRecursion()) {
426 return false;
427 }
428
429 bool retval = false;
430
431 if (m_d->runningShortcut) {
432 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->touchShortcut && !m_d->nativeGestureShortcut, false);
433 m_d->runningShortcut->action()->inputEvent(event);
434 retval = true;
435 }
436
437 return retval;
438}
#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 1171 of file kis_shortcut_matcher.cpp.

1172{
1173 m_d->candidateShortcuts.clear();
1174 if (m_d->actionsSuppressed()) return;
1175
1176 // Allow letting the modifiers to be matched so key_shift + middle mouse move can be matched, but key_v + mouse drag can not.
1177 bool containsOnlyModifiers = !m_d->keys.isEmpty();
1178 Q_FOREACH(const Qt::Key k, m_d->keys) {
1179 if (k != Qt::Key_Shift && k != Qt::Key_Control && k != Qt::Key_Alt && k != Qt::Key_Meta) {
1180 containsOnlyModifiers = false;
1181 break;
1182 }
1183 }
1184 if (m_d->KeyboardActionsSuppressed()
1185 && !containsOnlyModifiers && !m_d->keys.isEmpty()
1186 && m_d->buttons.isEmpty()) {
1187 return;
1188 }
1189
1190 Q_FOREACH (KisStrokeShortcut *s, m_d->strokeShortcuts) {
1191 if (s->matchReady(m_d->keys, m_d->buttons)) {
1192 m_d->candidateShortcuts.append(s);
1193 }
1194 }
1195}
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 92 of file kis_shortcut_matcher.cpp.

94 , readyShortcut(0)
95 , touchShortcut(0)
98 , actionGroupMask([] () { return AllActionGroup; })
99 , suppressAllActions(false)
101 , cursorEntered(false)
102 {}
@ AllActionGroup
KisTouchpadScrollShortcut * touchpadScrollShortcut
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 945 of file kis_shortcut_matcher.cpp.

946{
947 Private::RecursionNotifier notifier(this);
948
949
950 reset("reinitialize");
951
952 if (notifier.isInRecursion()) {
954 } else if (!hasRunningShortcut()) {
957 }
958}

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

961{
962 Private::RecursionNotifier notifier(this);
963
964 m_d->buttons.clear();
965 DEBUG_ACTION("reinitializing buttons");
966
967 if (notifier.isInRecursion()) {
969 } else if (!hasRunningShortcut()) {
972 }
973}

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

◆ reset() [1/2]

void KisShortcutMatcher::reset ( )
private

Definition at line 1062 of file kis_shortcut_matcher.cpp.

1063{
1064 m_d->keys.clear();
1065 m_d->buttons.clear();
1066 DEBUG_ACTION("reset!");
1067}

References DEBUG_ACTION, and m_d.

◆ reset() [2/2]

void KisShortcutMatcher::reset ( QString msg)
private

Definition at line 1070 of file kis_shortcut_matcher.cpp.

1071{
1072 m_d->keys.clear();
1073 m_d->buttons.clear();
1074 Q_UNUSED(msg);
1075 DEBUG_ACTION(msg);
1076}

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

1003{
1004 auto checkKey = [this, modifiers] (Qt::Key key, Qt::KeyboardModifier modifier) {
1005 return m_d->keys.contains(key) == bool(modifiers & modifier);
1006 };
1007
1008 return checkKey(Qt::Key_Shift, Qt::ShiftModifier) &&
1009 checkKey(Qt::Key_Control, Qt::ControlModifier) &&
1010 checkKey(Qt::Key_Alt, Qt::AltModifier) &&
1011 checkKey(Qt::Key_Meta, Qt::MetaModifier);
1012
1013}

References m_d.

◆ setIgnoreMultiFingerCancelWorkaroundEnalbed()

void KisShortcutMatcher::setIgnoreMultiFingerCancelWorkaroundEnalbed ( bool value)

Enabled a workaround that allows processing 3+ finger tap shortcuts, even when the system sends QEvent::TouchCancel for them. Need on some Android devices.

Definition at line 1603 of file kis_shortcut_matcher.cpp.

1604{
1605 if (value) {
1606 m_d->ignoreMultiFingerCancelWorkaround = Private::IgnoreMultiFingerCancelWorkaround();
1607 } else {
1608 m_d->ignoreMultiFingerCancelWorkaround = std::nullopt;
1609 }
1610}
float value(const T *src, size_t ch)

References m_d, and value().

◆ setInputActionGroupsMaskCallback()

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

Definition at line 1129 of file kis_shortcut_matcher.cpp.

1130{
1131 m_d->actionGroupMask = func;
1132}

References m_d.

◆ setMaxTouchPointEvent()

void KisShortcutMatcher::setMaxTouchPointEvent ( QTouchEvent * event)
private

Definition at line 1368 of file kis_shortcut_matcher.cpp.

1369{
1370 int previousNumTouchPoints = -1;
1371
1372 if (m_d->bestCandidateForTapTouchEvent) {
1373 QTouchEvent *bestTouchEvent = static_cast<QTouchEvent*>(m_d->bestCandidateForTapTouchEvent.data());
1374 previousNumTouchPoints = KisTouchShortcut::countTouchPoints(bestTouchEvent, KisTouchShortcut::pressedOnlyTouchStates());
1375 }
1376
1378
1379 if (newNumTouchPoints >= previousNumTouchPoints) {
1380#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1381 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateForTapTouchEvent);
1382#else
1383 m_d->bestCandidateForTapTouchEvent.reset(event->clone());
1384#endif
1385 }
1386}
static Qt::TouchPointStates pressedOnlyTouchStates()
static int countTouchPoints(const QTouchEvent *event, Qt::TouchPointStates allowedStates)

References KisTouchShortcut::countTouchPoints(), m_d, and KisTouchShortcut::pressedOnlyTouchStates().

◆ setTouchHoldDelay()

void KisShortcutMatcher::setTouchHoldDelay ( int value)
Returns
the currently set delay for the touch-hold actions (milliseconds)

Definition at line 1598 of file kis_shortcut_matcher.cpp.

1599{
1600 m_d->touchHoldDelayMs = value;
1601}

References m_d, and value().

◆ slotTouchHoldCompleted()

void KisShortcutMatcher::slotTouchHoldCompleted ( )
private

Definition at line 558 of file kis_shortcut_matcher.cpp.

559{
560 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->touchHoldEventPostponer);
562
563 // Can happen when multiple shortcut sources interact
564 KIS_SAFE_ASSERT_RECOVER_RETURN(!m_d->runningShortcut);
565
566 // take the very first begin event to start the action
567 QTouchEvent *event = m_d->touchHoldEventPostponer->postponedEvents().front();
568 KIS_SAFE_ASSERT_RECOVER_RETURN(event->type() == QEvent::TouchBegin);
569
570 m_d->isTouchHeld = true; // Must be set first, used in tryRunTouchShortcut.
571
572 DEBUG_TOUCH_ACTION("entered", event);
573
575 // noop, all is fine!
576 } else {
577 KIS_SAFE_ASSERT_RECOVER(0 && "should not happen")
578 {
579 // Shouldn't really happen, since KisInputManager checks whether a touch
580 // hold shortcut exists beforehand. We'll just handle this though.
581 m_d->isTouchHeld = false;
582 }
583 }
584
585 // remove the postponer to continue processing events in-place
586 m_d->touchHoldEventPostponer.reset();
587}
bool tryRunTouchShortcut(QTouchEvent *event, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
@ HoldCompleted
the postponer is still accumulating the events
#define DEBUG_TOUCH_ACTION(text, event)

References DEBUG_TOUCH_ACTION, Hold, KisTouchHoldEventsPostponer::HoldCompleted, KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, KisTouchShortcut::pressedOnlyTouchStates(), and tryRunTouchShortcut().

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

268{
269 return (m_d->runningShortcut && m_d->runningShortcut->action()
270 && m_d->runningShortcut->action()->supportsHiResInputEvents(m_d->runningShortcut->shortcutIndex()))
271 || (m_d->touchShortcut && m_d->touchShortcut->action()
272 && m_d->touchShortcut->action()->supportsHiResInputEvents(m_d->touchShortcut->shortcutIndex()))
273 || (m_d->nativeGestureShortcut && m_d->nativeGestureShortcut->action()
274 && m_d->nativeGestureShortcut->action()->supportsHiResInputEvents(m_d->nativeGestureShortcut->shortcutIndex()))
275 || (m_d->touchpadScrollShortcut && m_d->touchpadScrollShortcut->action()
276 && m_d->touchpadScrollShortcut->action()->supportsHiResInputEvents(m_d->touchpadScrollShortcut->shortcutIndex()));
277}

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

1084{
1085 m_d->suppressedSingleActionShortcuts.clear();
1086
1087 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
1088 Q_FOREACH (const QKeySequence &seq, shortcuts) {
1089 if (s->conflictsWith(seq)) {
1090 m_d->suppressedSingleActionShortcuts.insert(s);
1091 }
1092 }
1093 }
1094}
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 1048 of file kis_shortcut_matcher.cpp.

1049{
1050 Private::RecursionNotifier notifier(this);
1051
1052 DEBUG_ACTION("toolHasBeenActivated");
1053
1054 if (notifier.isInRecursion()) {
1056 } else if (!hasRunningShortcut()) {
1059 }
1060}

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

◆ touchBeginEvent()

bool KisShortcutMatcher::touchBeginEvent ( QTouchEvent * event)

Definition at line 468 of file kis_shortcut_matcher.cpp.

469{
470 DEBUG_TOUCH_ACTION("entered", event)
471
472 Private::RecursionNotifier notifier(this);
473
474 if (hasRunningShortcut()) {
475 DEBUG_ACTION("touch action rejected by a running shortcut");
476
477 // touch has been triggered while some tablet action is in progress,
478 // just consume and ignore it
479 return !notifier.isInRecursion();
480 }
481
482#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
483 QScopedPointer<QEvent> tmp;
484 KoPointerEvent::copyQtPointerEvent(event, tmp);
485 m_d->lastProcessedTouchEvent.reset(static_cast<QTouchEvent*>(tmp.take()));
486#else
487 m_d->lastProcessedTouchEvent.reset(event->clone());
488#endif
489
490 // reset state
492 if (m_d->ignoreMultiFingerCancelWorkaround) {
493 m_d->ignoreMultiFingerCancelWorkaround->lastRawTouchPointsCount = m_d->maxTouchPoints;
494 }
495 m_d->matchingIteration = 1;
496 m_d->isTouchDragDetected = false;
497 m_d->isTouchHeld = false;
498 m_d->touchActionTracked = true;
499#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
500 KoPointerEvent::copyQtPointerEvent(event, m_d->bestCandidateForTapTouchEvent);
501#else
502 m_d->bestCandidateForTapTouchEvent.reset(event->clone());
503#endif
504
505 // TODO: also check if the first point actually qualifies
506 if (hasTouchHoldShortcut()) {
507 m_d->touchHoldEventPostponer.emplace(TOUCH_SLOP, m_d->touchHoldDelayMs);
508 QObject::connect(&m_d->touchHoldEventPostponer.value(),
510 [this]() {
511 slotTouchHoldCompleted();
512 });
513 m_d->touchHoldEventPostponer->pushThrough(event);
514 if (m_d->touchHoldEventPostponer->state() == KisTouchHoldEventsPostponer::HoldCancelled) {
515 m_d->touchHoldEventPostponer.reset();
516 } else {
517 DEBUG_ACTION("thouch-hold timer is set up");
518 }
519 }
520
521 return !notifier.isInRecursion();
522}
static constexpr qreal TOUCH_SLOP
@ HoldCancelled
the hold action has been detected, the accumulated events should be dropped and the hold action shoul...

References KisTouchShortcut::countTouchPoints(), DEBUG_ACTION, DEBUG_TOUCH_ACTION, hasRunningShortcut(), hasTouchHoldShortcut(), KisTouchHoldEventsPostponer::HoldCancelled, m_d, KisTouchShortcut::pressedOnlyTouchStates(), KisTouchHoldEventsPostponer::sigHoldCompleted(), and TOUCH_SLOP.

◆ touchCancelEvent()

void KisShortcutMatcher::touchCancelEvent ( QTouchEvent * event)

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

773{
774 Q_UNUSED(event)
775
776 // The design requirement of touch-cancel handling is the following:
777 //
778 // 1) If drag-action has already been started, it is finished normally
779 // 2) If tap-action is pending, it is cancelled
780 // 3) If hold-action is pending, it is cancelled
781 // 4) If hold-action has already been started, it is ended normally
782
783 // On some Android devices, such as Xiaomi Pads, the system always eats
784 // multitouch inputs with more than two fingers, even if the user
785 // disables all gestures related to them in their system settings or
786 // uses the game boost mode that is supposed to disable gestures. So we
787 // handle those inputs even when they are cancelled, if the user wants
788 // to use it for a system gesture, they can disable the Krita shortcut.
789 if (m_d->ignoreMultiFingerCancelWorkaround) {
790 // NOTE: we cannot use the number of touch points from the actual
791 // cancel event, since Qt sets touch points as empty for the cancel
792 // event
793 if (m_d->ignoreMultiFingerCancelWorkaround->lastRawTouchPointsCount >= 3) {
794 DEBUG_ACTION("IgnoreMultiFingerCancelWorkaround: converting a cancelled action into a normally finished action")
795 touchEndEvent(event);
796 return;
797 }
798 }
799
800 Private::RecursionNotifier notifier(this);
801
802 DEBUG_TOUCH_ACTION("enter", event);
803
804 // the touch action has been overridden by some tablet action,
805 // consume and ignore it.
806 if (!m_d->touchActionTracked) {
807 KIS_SAFE_ASSERT_RECOVER(!m_d->touchHoldEventPostponer.has_value()) {
808 m_d->touchHoldEventPostponer->cancelHoldWait();
809 m_d->touchHoldEventPostponer.reset();
810 }
811 return;
812 }
813
814 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->runningShortcut || !m_d->touchShortcut);
815
817
818 if (notifier.isInRecursion()) {
820 } else if (!hasRunningShortcut()) {
823 }
824}
bool touchEndEvent(QTouchEvent *event)

References DEBUG_ACTION, DEBUG_TOUCH_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, prepareReadyShortcuts(), touchEndEvent(), tryActivateReadyShortcut(), and tryCancelAllCurrentTouchActionsImpl().

◆ touchEndEvent()

bool KisShortcutMatcher::touchEndEvent ( QTouchEvent * event)

Definition at line 686 of file kis_shortcut_matcher.cpp.

687{
688 Private::RecursionNotifier notifier(this);
689
690 DEBUG_TOUCH_ACTION("enter", event);
691
692 // the touch action has been overridden by some tablet action,
693 // consume and ignore it.
694 if (!m_d->touchActionTracked) {
695 DEBUG_ACTION("touch was not tracked");
696 KIS_SAFE_ASSERT_RECOVER(!m_d->touchHoldEventPostponer.has_value()) {
697 m_d->touchHoldEventPostponer->cancelHoldWait();
698 m_d->touchHoldEventPostponer.reset();
699 }
700 return true;
701 }
702
703 // flush all the touch-hold postiponed events if they were present
704 if (m_d->touchHoldEventPostponer) {
705 DEBUG_ACTION("flushing all postponed hold events");
706
708 m_d->touchHoldEventPostponer->cancelHoldWait();
709 // process all the postponed **update** events,
710 // the very first begin event is only used in
711 // the hold-completion operation
712 Q_FOREACH (QTouchEvent *event, m_d->touchHoldEventPostponer->postponedEvents()) {
713 if (event->type() == QEvent::TouchUpdate) {
714 (void) touchUpdateEventImpl(event);
715 }
716 }
717 m_d->touchHoldEventPostponer.reset();
718 }
719
720 m_d->touchActionTracked = false;
721
722 bool retval = false;
723
724 if (!m_d->isTouchDragDetected && m_d->bestCandidateForTapTouchEvent && !hasRunningShortcut()) {
725 retval = tryFireTapTouchShortcut(static_cast<QTouchEvent *>(m_d->bestCandidateForTapTouchEvent.data()),
727 }
728
729 // we should try and end the shortcut too (it might be that there is none? (sketch))
730 retval |= tryEndTouchShortcut(event);
731
732 if (notifier.isInRecursion()) {
734 } else if (!hasRunningShortcut()) {
737 }
738
739 return retval;
740}
bool tryFireTapTouchShortcut(QTouchEvent *event, Qt::TouchPointStates allowedStates)
bool touchUpdateEventImpl(QTouchEvent *event)
bool tryEndTouchShortcut(QTouchEvent *event)
static Qt::TouchPointStates allTouchStates()
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)

References KisTouchShortcut::allTouchStates(), DEBUG_ACTION, DEBUG_TOUCH_ACTION, forceDeactivateAllActions(), hasRunningShortcut(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, prepareReadyShortcuts(), touchUpdateEventImpl(), tryActivateReadyShortcut(), tryEndTouchShortcut(), tryFireTapTouchShortcut(), void(), and KisTouchHoldEventsPostponer::WaitingForHold.

◆ touchHoldDelay()

int KisShortcutMatcher::touchHoldDelay ( ) const
Returns
the currently set delay for the touch-hold actions (milliseconds)

Definition at line 1593 of file kis_shortcut_matcher.cpp.

1594{
1595 return m_d->touchHoldDelayMs;
1596}

References m_d.

◆ touchpadScrollBeginEvent()

bool KisShortcutMatcher::touchpadScrollBeginEvent ( QWheelEvent * event)

Definition at line 879 of file kis_shortcut_matcher.cpp.

880{
881 Private::RecursionNotifier notifier(this);
882
883 if (notifier.isInRecursion()) return false;
884
885 DEBUG_EVENT_ACTION("entered", event);
886
887 if (!hasRunningShortcut()) {
889 }
890
891 if (m_d->touchpadScrollShortcut) {
892 m_d->touchpadScrollShortcut->action()->inputEvent(event);
893 }
894
895 return bool(m_d->touchpadScrollShortcut);
896}
bool tryRunTouchpadScrollShortcut(QWheelEvent *event)

References DEBUG_EVENT_ACTION, hasRunningShortcut(), m_d, and tryRunTouchpadScrollShortcut().

◆ touchpadScrollEndEvent()

bool KisShortcutMatcher::touchpadScrollEndEvent ( QWheelEvent * event)

Definition at line 913 of file kis_shortcut_matcher.cpp.

914{
915 Private::RecursionNotifier notifier(this);
916
917 if (notifier.isInRecursion()) return false;
918
919 DEBUG_EVENT_ACTION("entered", event);
920
921 bool retval = false;
922
923 if (m_d->touchpadScrollShortcut) {
924 retval = tryEndTouchpadScrollShortcut(event);
925 }
926
927 if (notifier.isInRecursion()) {
929 } else if (!hasRunningShortcut()) {
932 }
933
934 return retval;
935}
bool tryEndTouchpadScrollShortcut(QWheelEvent *event)

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

◆ touchpadScrollEvent()

bool KisShortcutMatcher::touchpadScrollEvent ( QWheelEvent * event)

Definition at line 898 of file kis_shortcut_matcher.cpp.

899{
900 Private::RecursionNotifier notifier(this);
901
902 if (notifier.isInRecursion()) return false;
903
904 DEBUG_EVENT_ACTION("entered", event);
905
906 if (m_d->touchpadScrollShortcut) {
907 m_d->touchpadScrollShortcut->action()->inputEvent(event);
908 }
909
910 return bool(m_d->touchpadScrollShortcut);
911}

References DEBUG_EVENT_ACTION, and m_d.

◆ touchUpdateEvent()

bool KisShortcutMatcher::touchUpdateEvent ( QTouchEvent * event)

Definition at line 524 of file kis_shortcut_matcher.cpp.

525{
526 // the touch action has been overridden by some tablet action,
527 // consume and ignore it.
528 if (!m_d->touchActionTracked) return false;
529
530 if (m_d->ignoreMultiFingerCancelWorkaround) {
531 m_d->ignoreMultiFingerCancelWorkaround->lastRawTouchPointsCount =
533 }
534
535 if (m_d->touchHoldEventPostponer) {
536 m_d->touchHoldEventPostponer->pushThrough(event);
537 if (m_d->touchHoldEventPostponer->state() == KisTouchHoldEventsPostponer::HoldCancelled) {
538 // process all the postponed **update** events,
539 // the very first begin event is only used in
540 // the hold-completion operation
541 Q_FOREACH (QTouchEvent *event, m_d->touchHoldEventPostponer->postponedEvents()) {
542 if (event->type() == QEvent::TouchUpdate) {
543 (void) touchUpdateEventImpl(event);
544 }
545 }
546 m_d->touchHoldEventPostponer.reset();
547 } else {
548 // noop, we are waiting for hold
549 }
550 } else {
551 // TODO: don't enter for hold-drag events
552 return touchUpdateEventImpl(event);
553 }
554
555 return true;
556}

References KisTouchShortcut::countTouchPoints(), KisTouchHoldEventsPostponer::HoldCancelled, m_d, KisTouchShortcut::pressedOnlyTouchStates(), touchUpdateEventImpl(), and void().

◆ touchUpdateEventImpl()

bool KisShortcutMatcher::touchUpdateEventImpl ( QTouchEvent * event)
private

Definition at line 589 of file kis_shortcut_matcher.cpp.

590{
591 if (_41020().isDebugEnabled()) {
592 const int oldNumPressedPoints = KisTouchShortcut::countTouchPoints(m_d->lastProcessedTouchEvent.data(), KisTouchShortcut::pressedOnlyTouchStates());
594 if (oldNumPressedPoints != newNumPressedPoints) {
595 DEBUG_TOUCH_ACTION("touch point state changed", event)
596 }
597 }
598
599#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
600 QScopedPointer<QEvent> tmp;
601 KoPointerEvent::copyQtPointerEvent(event, tmp);
602 m_d->lastProcessedTouchEvent.reset(static_cast<QTouchEvent*>(tmp.take()));
603#else
604 m_d->lastProcessedTouchEvent.reset(event->clone());
605#endif
606
607 if (m_d->isTouchHeld) {
608 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->touchShortcut, false);
609 m_d->touchShortcut->action()->inputEvent(event);
610 return true;
611 }
612
613 bool retval = false;
614
615 // Check whether the touchpoints are relatively stationary or have
616 // been moved for dragging. If the drag is detected, until the next
617 // TouchBegin event, we'll be assuming the gesture to be of
618 // dragging type.
619 if (!m_d->isTouchDragDetected) {
621 m_d->isTouchDragDetected = true;
622 }
623 }
624
625 // Different drag shortcuts can have different drag thresholds. E.g.
626 // touch-painting shortcut will have much lower threshold value. The
627 // shortcuts will calculate the distance themselves in
628 // KisTouchShortcut::matchDragType, so we should just ask them to do that.
629 const int numStillDraggedPoints =
631 if (!hasRunningShortcut() && numStillDraggedPoints >= m_d->maxTouchPoints) {
632 m_d->maxTouchPoints = numStillDraggedPoints;
634 m_d->isTouchDragDetected = true;
635 return true;
636 }
637 }
638
639 // for a first few events we don't process the events right away. But analyze and keep track of the event with most
640 // touchpoints. This is done to prevent conditions where in three-finger-tap, two-finger-tap be preceded due to
641 // latency
642 const int numIterations = 10;
643 if (m_d->matchingIteration <= numIterations && !m_d->isTouchDragDetected) {
644 m_d->matchingIteration++;
646 return matchTouchShortcut((QTouchEvent *)m_d->bestCandidateForTapTouchEvent.data(),
649 }
650
651 if (m_d->isTouchDragDetected) {
652 if (m_d->touchShortcut
653 // TODO: use a different check without threshold! split into match() and matchBegin()
654 && !m_d->touchShortcut->matchDragType(event, KisTouchShortcut::pressedOnlyTouchStates())) {
655 // we should end the event as an event with more touchpoints was received
656 retval = tryEndTouchShortcut(event);
657 } else if (m_d->touchShortcut) {
658 m_d->touchShortcut->action()->inputEvent(event);
659 retval = true;
660 }
661 } else { // !m_d->isTouchDragDetected
662 // triggered if a new finger was added, which might result in shortcut not matching the action
663#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
664 const auto FlagReleased = Qt::TouchPointReleased;
665#else
666 const auto FlagReleased = QEventPoint::Released;
667#endif
668 if (event->touchPointStates().testFlag(FlagReleased) && !hasRunningShortcut()) {
669 const int previousNumPoints = KisTouchShortcut::countTouchPoints(event, KisTouchShortcut::allTouchStates());
670
671 // we should end the event as an event with more touchpoints was received
672 if (previousNumPoints >= m_d->maxTouchPoints) {
673 m_d->maxTouchPoints = previousNumPoints;
675 m_d->bestCandidateForTapTouchEvent.reset();
676 retval = true;
677 }
678 }
679 }
680 }
681 // TODO: update maxTouchPoints
682
683 return retval;
684}
KisTouchShortcut * matchTouchShortcut(QTouchEvent *event, Qt::TouchPointStates allowedStates, TouchShortcutMode mode)
void setMaxTouchPointEvent(QTouchEvent *event)
static qreal touchDragDistance(const QTouchEvent *event, Qt::TouchPointStates allowedStates)
const KRITAGLOBAL_EXPORT QLoggingCategory & _41020()

References _41020(), KisTouchShortcut::allTouchStates(), KisTouchShortcut::countTouchPoints(), DEBUG_TOUCH_ACTION, Drag, hasRunningShortcut(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, matchTouchShortcut(), KisTouchShortcut::pressedOnlyTouchStates(), setMaxTouchPointEvent(), Tap, TOUCH_SLOP, KisTouchShortcut::touchDragDistance(), tryEndTouchShortcut(), tryFireTapTouchShortcut(), 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 1248 of file kis_shortcut_matcher.cpp.

1249{
1250 KisStrokeShortcut *goodCandidate = 0;
1251
1252 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
1253 if (!goodCandidate || s->priority() > goodCandidate->priority()) {
1254 goodCandidate = s;
1255 }
1256 }
1257
1258 if (goodCandidate) {
1259 if (m_d->readyShortcut && m_d->readyShortcut != goodCandidate) {
1260 if (goodCandidate->action() == m_d->readyShortcut->action() &&
1261 goodCandidate->action()->trySwitchShortcut(
1262 m_d->readyShortcut->shortcutIndex(), goodCandidate->shortcutIndex())) {
1263 DEBUG_SHORTCUT("Switched previous shortcut action", m_d->readyShortcut);
1264 m_d->readyShortcut = goodCandidate;
1265 } else {
1266 DEBUG_SHORTCUT("Deactivated previous shortcut action", m_d->readyShortcut);
1267 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
1268 m_d->readyShortcut = 0;
1269 }
1270 }
1271
1272 if (!m_d->readyShortcut) {
1273 DEBUG_SHORTCUT("Preparing new ready action", goodCandidate);
1274
1282 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1283 m_d->readyShortcut = goodCandidate;
1284 }
1285 } else if (m_d->readyShortcut) {
1286 DEBUG_SHORTCUT("Deactivating action", m_d->readyShortcut);
1287 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
1288 m_d->readyShortcut = 0;
1289 }
1290}
virtual void activate(int shortcut)
virtual bool trySwitchShortcut(int oldShortcut, int newShortcut)
int priority() const override

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

◆ tryCancelAllCurrentTouchActionsImpl()

void KisShortcutMatcher::tryCancelAllCurrentTouchActionsImpl ( )
private

Definition at line 742 of file kis_shortcut_matcher.cpp.

743{
744 // discard all the postponed touch-hold events
745 if (m_d->touchHoldEventPostponer) {
747 m_d->touchHoldEventPostponer->cancelHoldWait();
748 m_d->touchHoldEventPostponer.reset();
749 }
750
751 // end the touch action if present
752 if (m_d->touchShortcut) {
753 DEBUG_ACTION("force-cancel touch action")
754
756 m_d->touchShortcut = 0;
757
759
760 // on some platforms touch-cancel event may have **no**
761 // touch points, which would greatly confuse our KoPointerEvent
762 // class, so we should just generate a normal touch-end from the
763 // last known event
764 QTouchEvent touchEvent = generateFakeTouchEndEvent(m_d->lastProcessedTouchEvent.data());
765 touchShortcut->action()->end(&touchEvent);
766 touchShortcut->action()->deactivate(touchShortcut->shortcutIndex());
767 }
768
769 m_d->touchActionTracked = false;
770}
QScopedPointer< QTouchEvent > lastProcessedTouchEvent

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), DEBUG_ACTION, KisAbstractInputAction::end(), KIS_SAFE_ASSERT_RECOVER_NOOP, KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, KisAbstractShortcut::shortcutIndex, touchShortcut, and KisTouchHoldEventsPostponer::WaitingForHold.

◆ tryEndGestureBasedShortcutImpl()

template<typename EventType , typename ShortcutType >
bool KisShortcutMatcher::tryEndGestureBasedShortcutImpl ( EventType * event,
ShortcutType ** resultShortcutPtr )
private

Definition at line 1546 of file kis_shortcut_matcher.cpp.

1547{
1548 Private::RecursionNotifier notifier(this);
1549
1550 if (*resultShortcutPtr) {
1551 // first reset running shortcut to avoid infinite recursion via end()
1552 ShortcutType *runningShortcut = *resultShortcutPtr;
1553 *resultShortcutPtr = nullptr;
1554
1556
1557 runningShortcut->action()->end(event);
1559
1560 return true;
1561 }
1562
1563 if (notifier.isInRecursion()) {
1565 } else if (!hasRunningShortcut()) {
1568 }
1569
1570 return false;
1571}

References KisAbstractShortcut::action, KisAbstractInputAction::deactivate(), DEBUG_SHORTCUT, KisAbstractInputAction::end(), forceDeactivateAllActions(), hasRunningShortcut(), prepareReadyShortcuts(), runningShortcut, KisAbstractShortcut::shortcutIndex, and tryActivateReadyShortcut().

◆ tryEndNativeGestureShortcut()

bool KisShortcutMatcher::tryEndNativeGestureShortcut ( QNativeGestureEvent * event)
private

Definition at line 1578 of file kis_shortcut_matcher.cpp.

1579{
1580 return tryEndGestureBasedShortcutImpl(event, &m_d->nativeGestureShortcut);
1581}
bool tryEndGestureBasedShortcutImpl(EventType *event, ShortcutType **resultShortcutPtr)

References m_d, and tryEndGestureBasedShortcutImpl().

◆ tryEndRunningShortcut()

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

Definition at line 1292 of file kis_shortcut_matcher.cpp.

1293{
1294 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->runningShortcut, true);
1295 KIS_SAFE_ASSERT_RECOVER(!m_d->readyShortcut) {
1296 // it shouldn't have happened, running and ready shortcuts
1297 // at the same time should not be possible
1299 }
1300
1301 if (m_d->runningShortcut && m_d->runningShortcut->matchBegin(button)) {
1302
1303 // first reset running shortcut to avoid infinite recursion via end()
1304 KisStrokeShortcut *runningShortcut = m_d->runningShortcut;
1305 m_d->runningShortcut = 0;
1306
1307 if (runningShortcut->action()) {
1308 DEBUG_EVENT_ACTION("Ending running shortcut at event", event);
1310 int shortcutIndex = runningShortcut->shortcutIndex();
1311
1312 // Keep keyed stroke shortcuts in ready state between repeated
1313 // button strokes while their activation keys are still held.
1314 QSet<Qt::MouseButton> buttonsAfterRelease = m_d->buttons;
1315 buttonsAfterRelease.remove(button);
1316 const bool keepReadyShortcut =
1317 !m_d->keys.isEmpty() &&
1318 runningShortcut->isAvailable(m_d->actionGroupMask()) &&
1319 runningShortcut->matchReady(m_d->keys, buttonsAfterRelease);
1320
1321 action->end(event);
1322
1323 if (keepReadyShortcut) {
1324 m_d->readyShortcut = runningShortcut;
1325 } else {
1326 action->deactivate(shortcutIndex);
1327 }
1328 }
1329 }
1330
1331 return !m_d->runningShortcut;
1332}
virtual bool isAvailable(KisInputActionGroupsMask mask) const

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

◆ tryEndTouchpadScrollShortcut()

bool KisShortcutMatcher::tryEndTouchpadScrollShortcut ( QWheelEvent * event)
private

Definition at line 1588 of file kis_shortcut_matcher.cpp.

1589{
1590 return tryEndGestureBasedShortcutImpl(event, &m_d->touchpadScrollShortcut);
1591}

References m_d, and tryEndGestureBasedShortcutImpl().

◆ tryEndTouchShortcut()

bool KisShortcutMatcher::tryEndTouchShortcut ( QTouchEvent * event)
private

Definition at line 1485 of file kis_shortcut_matcher.cpp.

1486{
1487 if (m_d->touchShortcut) {
1488 // first reset running shortcut to avoid infinite recursion via end()
1489 KisTouchShortcut *touchShortcut = m_d->touchShortcut;
1490
1491 DEBUG_SHORTCUT("ending", touchShortcut)
1492 touchShortcut->action()->end(event);
1493 touchShortcut->action()->deactivate(m_d->touchShortcut->shortcutIndex());
1494
1495 m_d->touchShortcut = 0; // empty it out now that we are done with it
1496
1497 return true;
1498 }
1499
1500 return false;
1501}

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

◆ tryFireTapTouchShortcut()

bool KisShortcutMatcher::tryFireTapTouchShortcut ( QTouchEvent * event,
Qt::TouchPointStates allowedStates )
private

Touch actions don't usually send focus events, since they have no hover functionality, so they should be triggered unrelated to the current focus state.

Definition at line 1388 of file kis_shortcut_matcher.cpp.

1389{
1395 if (m_d->actionsSuppressedIgnoreFocus())
1396 return false;
1397
1398 KisTouchShortcut *goodCandidate = matchTouchShortcut(event, allowedStates, TouchShortcutMode::Tap);
1399 if (goodCandidate) {
1400 DEBUG_SHORTCUT("Starting new touch-tap action", goodCandidate);
1401 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1402 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1403
1404 goodCandidate->action()->end(event);
1405 goodCandidate->action()->deactivate(goodCandidate->shortcutIndex());
1406 }
1407
1408 return goodCandidate;
1409}
virtual void begin(int shortcut, QEvent *event)

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

◆ tryRunGestureBasedShortcutImpl()

template<typename EventType , typename ShortcutType >
bool KisShortcutMatcher::tryRunGestureBasedShortcutImpl ( EventType * event,
ShortcutType ** resultShortcutPtr,
const QList< ShortcutType * > allTypedShortcuts )
private

Definition at line 1504 of file kis_shortcut_matcher.cpp.

1505{
1506 ShortcutType *goodCandidate = 0;
1507
1508 if (m_d->actionsSuppressed())
1509 return false;
1510
1511 Q_FOREACH (ShortcutType* shortcut, allTypedShortcuts) {
1512 if (shortcut->match(event) && (!goodCandidate || shortcut->priority() > goodCandidate->priority())) {
1513 goodCandidate = shortcut;
1514 }
1515 }
1516
1517 if (goodCandidate) {
1518 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1519
1520 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1521 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1523
1524 *resultShortcutPtr = goodCandidate;
1525
1526 Private::RecursionGuard guard(this);
1527
1528 DEBUG_SHORTCUT("starting", goodCandidate)
1529
1530 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1531 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1532
1533 // the tool might have opened some dialog, which could break our event loop
1534 if (guard.brokenByRecursion()) {
1535 goodCandidate->action()->end(event);
1536 *resultShortcutPtr = 0;
1537
1539 }
1540 }
1541
1542 return bool(*resultShortcutPtr);
1543}

References DEBUG_SHORTCUT, forceDeactivateAllActions(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and m_d.

◆ tryRunNativeGestureShortcut()

bool KisShortcutMatcher::tryRunNativeGestureShortcut ( QNativeGestureEvent * event)
private

Definition at line 1573 of file kis_shortcut_matcher.cpp.

1574{
1575 return tryRunGestureBasedShortcutImpl(event, &m_d->nativeGestureShortcut, m_d->nativeGestureShortcuts);
1576}
bool tryRunGestureBasedShortcutImpl(EventType *event, ShortcutType **resultShortcutPtr, const QList< ShortcutType * > allTypedShortcuts)

References m_d, and tryRunGestureBasedShortcutImpl().

◆ tryRunReadyShortcut()

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

Definition at line 1197 of file kis_shortcut_matcher.cpp.

1198{
1199 KisStrokeShortcut *goodCandidate = 0;
1200
1201 Q_FOREACH (KisStrokeShortcut *s, m_d->candidateShortcuts) {
1202 if (s->isAvailable(m_d->actionGroupMask()) &&
1203 s->matchBegin(button) &&
1204 (!goodCandidate || s->priority() > goodCandidate->priority())) {
1205
1206 goodCandidate = s;
1207 }
1208 }
1209
1210 if (goodCandidate) {
1211 if (m_d->readyShortcut) {
1212 if (m_d->readyShortcut != goodCandidate) {
1213 if (goodCandidate->action() == m_d->readyShortcut->action() &&
1214 goodCandidate->action()->trySwitchShortcut(
1215 m_d->readyShortcut->shortcutIndex(), goodCandidate->shortcutIndex())) {
1216 m_d->readyShortcut = goodCandidate;
1217 } else {
1218 m_d->readyShortcut->action()->deactivate(m_d->readyShortcut->shortcutIndex());
1219 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1220 }
1221 }
1222 m_d->readyShortcut = 0;
1223 } else {
1224 DEBUG_EVENT_ACTION("Matched *new* shortcut for event", event);
1225 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1226 }
1227
1228 DEBUG_SHORTCUT("Starting new action", goodCandidate);
1229
1230 {
1231 m_d->runningShortcut = goodCandidate;
1232 Private::RecursionGuard guard(this);
1233 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1234
1235 // the tool might have opened some dialog, which could break our event loop
1236 if (guard.brokenByRecursion()) {
1237 goodCandidate->action()->end(event);
1238 m_d->runningShortcut = 0;
1239
1241 }
1242 }
1243 }
1244
1245 return m_d->runningShortcut;
1246}
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(), KisAbstractShortcut::shortcutIndex, and KisAbstractInputAction::trySwitchShortcut().

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

1142{
1143 if (m_d->actionsSuppressedIgnoreFocus() || (keyboard && m_d->KeyboardActionsSuppressed())) {
1144 DEBUG_EVENT_ACTION("Event suppressed", event)
1145 return false;
1146 }
1147
1148 KisSingleActionShortcut *goodCandidate = 0;
1149
1150 Q_FOREACH (KisSingleActionShortcut *s, m_d->singleActionShortcuts) {
1151 if (!m_d->suppressedSingleActionShortcuts.contains(s) &&
1152 s->isAvailable(m_d->actionGroupMask()) &&
1153 s->match(keysState, param) &&
1154 (!goodCandidate || s->priority() > goodCandidate->priority())) {
1155
1156 goodCandidate = s;
1157 }
1158 }
1159
1160 if (goodCandidate) {
1161 DEBUG_EVENT_ACTION("Beginning action for event", event);
1162 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1163 goodCandidate->action()->end(0);
1164 } else {
1165 DEBUG_EVENT_ACTION("Could not match a candidate for event", event)
1166 }
1167
1168 return goodCandidate;
1169}
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.

◆ tryRunTouchpadScrollShortcut()

bool KisShortcutMatcher::tryRunTouchpadScrollShortcut ( QWheelEvent * event)
private

Definition at line 1583 of file kis_shortcut_matcher.cpp.

1584{
1585 return tryRunGestureBasedShortcutImpl(event, &m_d->touchpadScrollShortcut, m_d->touchpadScrollShortcuts);
1586}

References m_d, and tryRunGestureBasedShortcutImpl().

◆ tryRunTouchShortcut()

bool KisShortcutMatcher::tryRunTouchShortcut ( QTouchEvent * event,
Qt::TouchPointStates allowedStates,
TouchShortcutMode mode )
private

Touch actions don't usually send focus events, since they have no hover functionality, so they should be triggered unrelated to the current focus state.

Definition at line 1446 of file kis_shortcut_matcher.cpp.

1447{
1448 KisTouchShortcut *goodCandidate = matchTouchShortcut(event, allowedStates, mode);
1449
1455 if (m_d->actionsSuppressedIgnoreFocus())
1456 return false;
1457
1458 if (goodCandidate) {
1459 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->runningShortcut, false);
1460
1461 // Because we don't match keyboard or button based actions with touch system, we have to ensure that we first
1462 // deactivate an activated readyShortcut, to not throw other statemachines out of place.
1464
1465 m_d->touchShortcut = goodCandidate;
1466
1467 Private::RecursionGuard guard(this);
1468 DEBUG_SHORTCUT("Running a new touch action", goodCandidate)
1469
1470 goodCandidate->action()->activate(goodCandidate->shortcutIndex());
1471 goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
1472
1473 // the tool might have opened some dialog, which could break our event loop
1474 if (guard.brokenByRecursion()) {
1475 goodCandidate->action()->end(event);
1476 m_d->touchShortcut = 0;
1477
1479 }
1480 }
1481
1482 return m_d->touchShortcut;
1483}

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

1135{
1136 return tryRunSingleActionShortcutImpl(wheelAction, event, m_d->keys, false);
1137}

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

409{
410 Private::RecursionNotifier notifier(this);
411
412
413 if (hasRunningShortcut() || notifier.isInRecursion()) {
414 DEBUG_ACTION("Wheel event canceled.");
415 return false;
416 }
417
418 return tryRunWheelShortcut(wheelAction, event);
419}
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 315 of file kis_shortcut_matcher.h.

Member Data Documentation

◆ actionGroupMask

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

Definition at line 155 of file kis_shortcut_matcher.cpp.

◆ bestCandidateForTapTouchEvent

QScopedPointer<QEvent> KisShortcutMatcher::bestCandidateForTapTouchEvent

Definition at line 137 of file kis_shortcut_matcher.cpp.

◆ brokenByRecursion

int KisShortcutMatcher::brokenByRecursion = 0

Definition at line 161 of file kis_shortcut_matcher.cpp.

◆ buttons

QSet<Qt::MouseButton> KisShortcutMatcher::buttons

Definition at line 119 of file kis_shortcut_matcher.cpp.

◆ candidateShortcuts

QList<KisStrokeShortcut*> KisShortcutMatcher::candidateShortcuts

Definition at line 125 of file kis_shortcut_matcher.cpp.

◆ cursorEntered

bool KisShortcutMatcher::cursorEntered

Definition at line 158 of file kis_shortcut_matcher.cpp.

◆ ignoreMultiFingerCancelWorkaround

std::optional<IgnoreMultiFingerCancelWorkaround> KisShortcutMatcher::ignoreMultiFingerCancelWorkaround

Definition at line 153 of file kis_shortcut_matcher.cpp.

◆ isTouchDragDetected

bool KisShortcutMatcher::isTouchDragDetected {false}

Definition at line 135 of file kis_shortcut_matcher.cpp.

135{false};

◆ isTouchHeld

bool KisShortcutMatcher::isTouchHeld {false}

Definition at line 136 of file kis_shortcut_matcher.cpp.

136{false};

◆ keys

QSet<Qt::Key> KisShortcutMatcher::keys

Definition at line 118 of file kis_shortcut_matcher.cpp.

◆ lastProcessedTouchEvent

QScopedPointer<QTouchEvent> KisShortcutMatcher::lastProcessedTouchEvent

Definition at line 138 of file kis_shortcut_matcher.cpp.

◆ m_d

Private* const KisShortcutMatcher::m_d
private

Definition at line 361 of file kis_shortcut_matcher.h.

◆ matchingIteration

int KisShortcutMatcher::matchingIteration {0}

Definition at line 134 of file kis_shortcut_matcher.cpp.

134{0};

◆ maxTouchPoints

int KisShortcutMatcher::maxTouchPoints {0}

Definition at line 133 of file kis_shortcut_matcher.cpp.

133{0};

◆ nativeGestureShortcut

KisNativeGestureShortcut* KisShortcutMatcher::nativeGestureShortcut

Definition at line 128 of file kis_shortcut_matcher.cpp.

◆ nativeGestureShortcuts

QList<KisNativeGestureShortcut*> KisShortcutMatcher::nativeGestureShortcuts

Definition at line 115 of file kis_shortcut_matcher.cpp.

◆ polledKeys

QSet<Qt::Key> KisShortcutMatcher::polledKeys

Definition at line 121 of file kis_shortcut_matcher.cpp.

◆ readyShortcut

KisStrokeShortcut* KisShortcutMatcher::readyShortcut

Definition at line 124 of file kis_shortcut_matcher.cpp.

◆ recursiveCounter

int KisShortcutMatcher::recursiveCounter = 0

Definition at line 160 of file kis_shortcut_matcher.cpp.

◆ runningShortcut

KisStrokeShortcut* KisShortcutMatcher::runningShortcut

Definition at line 123 of file kis_shortcut_matcher.cpp.

◆ singleActionShortcuts

QList<KisSingleActionShortcut*> KisShortcutMatcher::singleActionShortcuts

Definition at line 111 of file kis_shortcut_matcher.cpp.

◆ strokeShortcuts

QList<KisStrokeShortcut*> KisShortcutMatcher::strokeShortcuts

Definition at line 113 of file kis_shortcut_matcher.cpp.

◆ suppressAllActions

void KisShortcutMatcher::suppressAllActions

Definition at line 156 of file kis_shortcut_matcher.cpp.

◆ suppressAllKeyboardActions

void KisShortcutMatcher::suppressAllKeyboardActions

Definition at line 157 of file kis_shortcut_matcher.cpp.

◆ suppressedSingleActionShortcuts

QSet<KisSingleActionShortcut*> KisShortcutMatcher::suppressedSingleActionShortcuts

Definition at line 112 of file kis_shortcut_matcher.cpp.

◆ TOUCH_SLOP

constexpr qreal KisShortcutMatcher::TOUCH_SLOP = 16
staticconstexpr

Definition at line 79 of file kis_shortcut_matcher.h.

◆ TOUCH_SLOP_SQUARED

constexpr int KisShortcutMatcher::TOUCH_SLOP_SQUARED = 16 * 16
staticconstexpr

Definition at line 78 of file kis_shortcut_matcher.h.

◆ touchActionTracked

bool KisShortcutMatcher::touchActionTracked {false}

Definition at line 139 of file kis_shortcut_matcher.cpp.

139{false};

◆ touchHoldDelayMs

int KisShortcutMatcher::touchHoldDelayMs {400}

Definition at line 140 of file kis_shortcut_matcher.cpp.

140{400};

◆ touchHoldEventPostponer

std::optional<KisTouchHoldEventsPostponer> KisShortcutMatcher::touchHoldEventPostponer

Definition at line 130 of file kis_shortcut_matcher.cpp.

◆ touchpadScrollShortcut

KisTouchpadScrollShortcut* KisShortcutMatcher::touchpadScrollShortcut

Definition at line 129 of file kis_shortcut_matcher.cpp.

◆ touchpadScrollShortcuts

QList<KisTouchpadScrollShortcut*> KisShortcutMatcher::touchpadScrollShortcuts

Definition at line 116 of file kis_shortcut_matcher.cpp.

◆ touchShortcut

KisTouchShortcut* KisShortcutMatcher::touchShortcut

Definition at line 127 of file kis_shortcut_matcher.cpp.

◆ touchShortcuts

QList<KisTouchShortcut*> KisShortcutMatcher::touchShortcuts

Definition at line 114 of file kis_shortcut_matcher.cpp.


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