KGuiAddons

kkeysequencerecorder.cpp
1/*
2 SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
3 SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
4 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
5 SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kkeysequencerecorder.h"
11
12#include "keyboardgrabber_p.h"
13#include "kguiaddons_debug.h"
14#include "shortcutinhibition_p.h"
15#include "waylandinhibition_p.h"
16
17#include <QGuiApplication>
18#include <QKeyEvent>
19#include <QPointer>
20#include <QTimer>
21#include <QWindow>
22
23#include <array>
24#include <chrono>
25
26/// Singleton whose only purpose is to tell us about other sequence recorders getting started
27class KKeySequenceRecorderGlobal : public QObject
28{
30public:
31 static KKeySequenceRecorderGlobal *self()
32 {
33 static KKeySequenceRecorderGlobal s_self;
34 return &s_self;
35 }
36
38 void sequenceRecordingStarted();
39};
40
41class KKeySequenceRecorderPrivate : public QObject
42{
44public:
45 // Copy of QKeySequencePrivate::MaxKeyCount from private header
46 enum { MaxKeyCount = 4 };
47
48 KKeySequenceRecorderPrivate(KKeySequenceRecorder *qq);
49
50 bool isKeyCombinationAccepted(QKeyCombination keyCombination) const;
51
52 void controlModifierlessTimeout();
53 bool eventFilter(QObject *watched, QEvent *event) override;
54 void handleKeyPress(QKeyEvent *event);
55 void handleKeyRelease(QKeyEvent *event);
56 void finishRecording();
57 void receivedRecording();
58
59 KKeySequenceRecorder *q;
60 QKeySequence m_currentKeySequence;
61 QKeySequence m_previousKeySequence;
62 QPointer<QWindow> m_window;
63 KKeySequenceRecorder::Patterns m_patterns;
64 bool m_isRecording;
65 bool m_multiKeyShortcutsAllowed;
66
67 Qt::KeyboardModifiers m_currentModifiers;
68 QTimer m_modifierlessTimer;
69 std::unique_ptr<ShortcutInhibition> m_inhibition;
70 // For use in modifier only shortcuts
71 Qt::KeyboardModifiers m_lastPressedModifiers;
72 bool m_isReleasingModifierOnly = false;
73 std::chrono::nanoseconds m_modifierFirstReleaseTime;
74};
75
77
78// Copied here from KKeyServer
79static bool isShiftAsModifierAllowed(int keyQt)
80{
81 // remove any modifiers
82 keyQt &= ~Qt::KeyboardModifierMask;
83
84 // Shift only works as a modifier with certain keys. It's not possible
85 // to enter the SHIFT+5 key sequence for me because this is handled as
86 // '%' by qt on my keyboard.
87 // The working keys are all hardcoded here :-(
88 if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) {
89 return true;
90 }
91
92 if (QChar::isLetter(keyQt)) {
93 return true;
94 }
95
96 switch (keyQt) {
97 case Qt::Key_Return:
98 case Qt::Key_Space:
100 case Qt::Key_Tab:
101 case Qt::Key_Backtab:
102 case Qt::Key_Escape:
103 case Qt::Key_Print:
105 case Qt::Key_Pause:
106 case Qt::Key_PageUp:
107 case Qt::Key_PageDown:
108 case Qt::Key_Insert:
109 case Qt::Key_Delete:
110 case Qt::Key_Home:
111 case Qt::Key_End:
112 case Qt::Key_Up:
113 case Qt::Key_Down:
114 case Qt::Key_Left:
115 case Qt::Key_Right:
116 case Qt::Key_Enter:
117 case Qt::Key_SysReq:
118 case Qt::Key_CapsLock:
119 case Qt::Key_NumLock:
120 case Qt::Key_Help:
121 case Qt::Key_Back:
122 case Qt::Key_Forward:
123 case Qt::Key_Stop:
124 case Qt::Key_Refresh:
127 case Qt::Key_OpenUrl:
128 case Qt::Key_HomePage:
129 case Qt::Key_Search:
132 case Qt::Key_VolumeUp:
134 case Qt::Key_BassUp:
135 case Qt::Key_BassDown:
136 case Qt::Key_TrebleUp:
147 case Qt::Key_Memo:
148 case Qt::Key_ToDoList:
149 case Qt::Key_Calendar:
152 case Qt::Key_Standby:
158 case Qt::Key_PowerOff:
159 case Qt::Key_WakeUp:
160 case Qt::Key_Eject:
162 case Qt::Key_WWW:
163 case Qt::Key_Sleep:
165 case Qt::Key_Shop:
166 case Qt::Key_History:
168 case Qt::Key_HotLinks:
170 case Qt::Key_Finance:
176 case Qt::Key_Book:
177 case Qt::Key_CD:
178 case Qt::Key_Clear:
180 case Qt::Key_Close:
181 case Qt::Key_Copy:
182 case Qt::Key_Cut:
183 case Qt::Key_Display:
184 case Qt::Key_DOS:
186 case Qt::Key_Excel:
187 case Qt::Key_Explorer:
188 case Qt::Key_Game:
189 case Qt::Key_Go:
190 case Qt::Key_iTouch:
191 case Qt::Key_LogOff:
192 case Qt::Key_Market:
193 case Qt::Key_Meeting:
194 case Qt::Key_MenuKB:
195 case Qt::Key_MenuPB:
196 case Qt::Key_MySites:
197 case Qt::Key_News:
199 case Qt::Key_Option:
200 case Qt::Key_Paste:
201 case Qt::Key_Phone:
202 case Qt::Key_Reply:
203 case Qt::Key_Reload:
207 case Qt::Key_Save:
208 case Qt::Key_Send:
209 case Qt::Key_Spell:
211 case Qt::Key_Support:
212 case Qt::Key_TaskPane:
213 case Qt::Key_Terminal:
214 case Qt::Key_Tools:
215 case Qt::Key_Travel:
216 case Qt::Key_Video:
217 case Qt::Key_Word:
218 case Qt::Key_Xfer:
219 case Qt::Key_ZoomIn:
220 case Qt::Key_ZoomOut:
221 case Qt::Key_Away:
223 case Qt::Key_WebCam:
225 case Qt::Key_Pictures:
226 case Qt::Key_Music:
227 case Qt::Key_Battery:
229 case Qt::Key_WLAN:
230 case Qt::Key_UWB:
234 case Qt::Key_Subtitle:
236 case Qt::Key_Time:
237 case Qt::Key_Select:
238 case Qt::Key_View:
239 case Qt::Key_TopMenu:
240 case Qt::Key_Suspend:
242 case Qt::Key_Launch0:
243 case Qt::Key_Launch1:
244 case Qt::Key_Launch2:
245 case Qt::Key_Launch3:
246 case Qt::Key_Launch4:
247 case Qt::Key_Launch5:
248 case Qt::Key_Launch6:
249 case Qt::Key_Launch7:
250 case Qt::Key_Launch8:
251 case Qt::Key_Launch9:
252 case Qt::Key_LaunchA:
253 case Qt::Key_LaunchB:
254 case Qt::Key_LaunchC:
255 case Qt::Key_LaunchD:
256 case Qt::Key_LaunchE:
257 case Qt::Key_LaunchF:
258 case Qt::Key_Shift:
259 case Qt::Key_Control:
260 case Qt::Key_Meta:
261 case Qt::Key_Alt:
262 case Qt::Key_Super_L:
263 case Qt::Key_Super_R:
264 return true;
265
266 default:
267 return false;
268 }
269}
270
271static bool isOkWhenModifierless(int key)
272{
273 // this whole function is a hack, but especially the first line of code
274 if (QKeySequence(key).toString().length() == 1) {
275 return false;
276 }
277
278 switch (key) {
279 case Qt::Key_Return:
280 case Qt::Key_Space:
281 case Qt::Key_Tab:
282 case Qt::Key_Backtab: // does this ever happen?
284 case Qt::Key_Delete:
285 return false;
286 default:
287 return true;
288 }
289}
290
291bool KKeySequenceRecorderPrivate::isKeyCombinationAccepted(QKeyCombination keyCombination) const
292{
293 const bool inputIncludesModifiers = keyCombination.keyboardModifiers();
294 const bool inputIncludesKey = keyCombination.key();
295
296 const KKeySequenceRecorder::Pattern basePatterns[] = {
300 };
301
302 for (const auto &pattern : basePatterns) {
303 if (!(m_patterns & pattern)) {
304 continue;
305 }
306
307 const bool patternIncludesModifiers = pattern & (KKeySequenceRecorder::Modifier | KKeySequenceRecorder::ModifierAndKey);
308 const bool patternIncludesKey = pattern & (KKeySequenceRecorder::Key | KKeySequenceRecorder::ModifierAndKey);
309
310 if (inputIncludesModifiers != patternIncludesModifiers) {
311 // TODO KF7: drop isOkWhenModifierless() and require users to pass the Key pattern explicitly
312 if (!(patternIncludesModifiers && patternIncludesKey && isOkWhenModifierless(keyCombination.key()))) {
313 continue;
314 }
315 }
316
317 if (inputIncludesKey == patternIncludesKey) {
318 return true;
319 }
320 }
321
322 return false;
323}
324
325static QKeySequence appendToSequence(const QKeySequence &sequence, int key)
326{
327 if (sequence.count() >= KKeySequenceRecorderPrivate::MaxKeyCount) {
328 qCWarning(KGUIADDONS_LOG) << "Cannot append to a key to a sequence which is already of length" << sequence.count();
329 return sequence;
330 }
331
332 std::array<int, KKeySequenceRecorderPrivate::MaxKeyCount> keys{sequence[0].toCombined(),
333 sequence[1].toCombined(),
334 sequence[2].toCombined(),
335 sequence[3].toCombined()};
336 // When the user presses Mod(s)+Alt+Print, the SysReq event is fired only
337 // when the Alt key is released. Before we get the Mod(s)+SysReq event, we
338 // first get a Mod(s)+Alt event, which we have to ignore.
339 // Known limitation: only works when the Alt key is released before the Mod(s) key(s).
342 if (sequence.count() > 0 && (sequence[sequence.count() - 1].toCombined() & ~Qt::KeyboardModifierMask) == Qt::Key_Alt) {
343 keys[sequence.count() - 1] = key;
344 return QKeySequence(keys[0], keys[1], keys[2], keys[3]);
345 }
346 }
347 keys[sequence.count()] = key;
348 return QKeySequence(keys[0], keys[1], keys[2], keys[3]);
349}
350
351KKeySequenceRecorderPrivate::KKeySequenceRecorderPrivate(KKeySequenceRecorder *qq)
352 : QObject(qq)
353 , q(qq)
354{
355}
356
357void KKeySequenceRecorderPrivate::controlModifierlessTimeout()
358{
359 if (m_currentKeySequence != 0 && !m_currentModifiers) {
360 // No modifier key pressed currently. Start the timeout
361 m_modifierlessTimer.start(600);
362 } else {
363 // A modifier is pressed. Stop the timeout
364 m_modifierlessTimer.stop();
365 }
366}
367
368bool KKeySequenceRecorderPrivate::eventFilter(QObject *watched, QEvent *event)
369{
370 if (!m_isRecording) {
371 return QObject::eventFilter(watched, event);
372 }
373
374 if (event->type() == QEvent::ShortcutOverride || event->type() == QEvent::ContextMenu) {
375 event->accept();
376 return true;
377 }
378 if (event->type() == QEvent::KeyRelease) {
379 handleKeyRelease(static_cast<QKeyEvent *>(event));
380 return true;
381 }
382 if (event->type() == QEvent::KeyPress) {
383 handleKeyPress(static_cast<QKeyEvent *>(event));
384 return true;
385 }
386 return QObject::eventFilter(watched, event);
387}
388
389static Qt::KeyboardModifiers keyToModifier(int key)
390{
391 switch (key) {
392 case Qt::Key_Meta:
393 case Qt::Key_Super_L:
394 case Qt::Key_Super_R:
395 // Qt doesn't properly recognize Super_L/Super_R as MetaModifier
396 return Qt::MetaModifier;
397 case Qt::Key_Shift:
398 return Qt::ShiftModifier;
399 case Qt::Key_Control:
400 return Qt::ControlModifier;
401 case Qt::Key_Alt:
402 return Qt::AltModifier;
403 default:
404 return Qt::NoModifier;
405 }
406}
407
408void KKeySequenceRecorderPrivate::handleKeyPress(QKeyEvent *event)
409{
410 m_isReleasingModifierOnly = false;
411 m_currentModifiers = event->modifiers() & modifierMask;
412 const int key = event->key();
413 switch (key) {
414 case -1:
415 qCWarning(KGUIADDONS_LOG) << "Got unknown key";
416 // Old behavior was to stop recording here instead of continuing like this
417 return;
418 case 0:
419 break;
420 case Qt::Key_AltGr:
421 // or else we get unicode salad
422 break;
423 case Qt::Key_Super_L:
424 case Qt::Key_Super_R:
425 case Qt::Key_Shift:
426 case Qt::Key_Control:
427 case Qt::Key_Alt:
428 case Qt::Key_Meta:
429 m_currentModifiers |= keyToModifier(key);
430 m_lastPressedModifiers = m_currentModifiers;
431 controlModifierlessTimeout();
432 Q_EMIT q->currentKeySequenceChanged();
433 break;
434 default:
435 m_lastPressedModifiers = Qt::NoModifier;
436
437 QKeyCombination keyCombination;
438 if ((key == Qt::Key_Backtab) && (m_currentModifiers & Qt::ShiftModifier)) {
439 keyCombination = QKeyCombination(m_currentModifiers, Qt::Key_Tab);
440 } else if (isShiftAsModifierAllowed(key)) {
441 keyCombination = QKeyCombination(m_currentModifiers, Qt::Key(key));
442 } else {
443 keyCombination = QKeyCombination(m_currentModifiers & ~Qt::ShiftModifier, Qt::Key(key));
444 }
445
446 if (!isKeyCombinationAccepted(keyCombination)) {
447 return;
448 }
449
450 m_currentKeySequence = appendToSequence(m_currentKeySequence, keyCombination.toCombined());
451 Q_EMIT q->currentKeySequenceChanged();
452 // Now we are in a critical region (race), where recording is still
453 // ongoing, but key sequence has already changed (potentially) to the
454 // longest. But we still want currentKeySequenceChanged to trigger
455 // before gotKeySequence, so there's only so much we can do about it.
456 if ((!m_multiKeyShortcutsAllowed) || (m_currentKeySequence.count() == MaxKeyCount)) {
457 finishRecording();
458 break;
459 }
460 controlModifierlessTimeout();
461 }
462 event->accept();
463}
464
465// Turn a bunch of modifiers into mods + key
466// so that the ordering is always Meta + Ctrl + Alt + Shift
467static QKeyCombination prettifyModifierOnly(QKeyCombination modifierOnly)
468{
469 const Qt::KeyboardModifiers modifier = modifierOnly.keyboardModifiers();
470 if (modifier & Qt::ShiftModifier) {
471 return Qt::Key_Shift | (modifier & ~Qt::ShiftModifier);
472 } else if (modifier & Qt::AltModifier) {
473 return Qt::Key_Alt | (modifier & ~Qt::AltModifier);
474 } else if (modifier & Qt::ControlModifier) {
475 return Qt::Key_Control | (modifier & ~Qt::ControlModifier);
476 } else if (modifier & Qt::MetaModifier) {
477 return Qt::Key_Meta | (modifier & ~Qt::MetaModifier);
478 } else {
479 return Qt::Key(0);
480 }
481}
482
483void KKeySequenceRecorderPrivate::handleKeyRelease(QKeyEvent *event)
484{
485 Qt::KeyboardModifiers modifiers = event->modifiers() & modifierMask;
486
487 switch (event->key()) {
488 case -1:
489 return;
490 case Qt::Key_Super_L:
491 case Qt::Key_Super_R:
492 case Qt::Key_Meta:
493 case Qt::Key_Shift:
494 case Qt::Key_Control:
495 case Qt::Key_Alt:
496 modifiers &= ~keyToModifier(event->key());
497 }
498 if ((modifiers & m_currentModifiers) < m_currentModifiers) {
499 constexpr auto releaseTimeout = std::chrono::milliseconds(200);
500 const auto currentTime = std::chrono::steady_clock::now().time_since_epoch();
501 if (!m_isReleasingModifierOnly) {
502 m_isReleasingModifierOnly = true;
503 m_modifierFirstReleaseTime = currentTime;
504 }
505 if (!modifiers && (currentTime - m_modifierFirstReleaseTime) < releaseTimeout) {
506 const auto keyCombination = QKeyCombination(m_lastPressedModifiers, Qt::Key(0));
507 if (isKeyCombinationAccepted(keyCombination)) {
508 m_currentKeySequence = appendToSequence(m_currentKeySequence, prettifyModifierOnly(keyCombination).toCombined());
509 m_lastPressedModifiers = Qt::NoModifier;
510 }
511 }
512 m_currentModifiers = modifiers;
513 Q_EMIT q->currentKeySequenceChanged();
514 if (m_currentKeySequence.count() == (m_multiKeyShortcutsAllowed ? MaxKeyCount : 1)) {
515 finishRecording();
516 }
517 controlModifierlessTimeout();
518 };
519}
520
521void KKeySequenceRecorderPrivate::receivedRecording()
522{
523 m_modifierlessTimer.stop();
524 m_isRecording = false;
525 m_currentModifiers = Qt::NoModifier;
526 m_lastPressedModifiers = Qt::NoModifier;
527 m_isReleasingModifierOnly = false;
528 if (m_inhibition) {
529 m_inhibition->disableInhibition();
530 }
531 QObject::disconnect(KKeySequenceRecorderGlobal::self(), &KKeySequenceRecorderGlobal::sequenceRecordingStarted, q, &KKeySequenceRecorder::cancelRecording);
532 Q_EMIT q->recordingChanged();
533}
534
535void KKeySequenceRecorderPrivate::finishRecording()
536{
537 receivedRecording();
538 Q_EMIT q->gotKeySequence(m_currentKeySequence);
539}
540
542 : QObject(parent)
543 , d(new KKeySequenceRecorderPrivate(this))
544{
545 d->m_isRecording = false;
546 d->m_patterns = ModifierAndKey;
547 d->m_multiKeyShortcutsAllowed = true;
548
549 setWindow(window);
550 connect(&d->m_modifierlessTimer, &QTimer::timeout, d.get(), &KKeySequenceRecorderPrivate::finishRecording);
551}
552
553KKeySequenceRecorder::~KKeySequenceRecorder() noexcept
554{
555 if (d->m_inhibition && d->m_inhibition->shortcutsAreInhibited()) {
556 d->m_inhibition->disableInhibition();
557 }
558}
559
561{
562 d->m_previousKeySequence = d->m_currentKeySequence;
563
564 KKeySequenceRecorderGlobal::self()->sequenceRecordingStarted();
565 connect(KKeySequenceRecorderGlobal::self(),
566 &KKeySequenceRecorderGlobal::sequenceRecordingStarted,
567 this,
570
571 if (!d->m_window) {
572 qCWarning(KGUIADDONS_LOG) << "Cannot record without a window";
573 return;
574 }
575 d->m_isRecording = true;
576 d->m_currentKeySequence = QKeySequence();
577 if (d->m_inhibition) {
578 d->m_inhibition->enableInhibition();
579 }
580 Q_EMIT recordingChanged();
581 Q_EMIT currentKeySequenceChanged();
582}
583
585{
586 setCurrentKeySequence(d->m_previousKeySequence);
587 d->receivedRecording();
588 Q_ASSERT(!isRecording());
589}
590
592{
593 return d->m_isRecording;
594}
595
597{
598 // We need a check for count() here because there's a race between the
599 // state of recording and a length of currentKeySequence.
600 if (d->m_isRecording && d->m_currentKeySequence.count() < KKeySequenceRecorderPrivate::MaxKeyCount) {
601 return appendToSequence(d->m_currentKeySequence, d->m_currentModifiers);
602 } else {
603 return d->m_currentKeySequence;
604 }
605}
606
607void KKeySequenceRecorder::setCurrentKeySequence(const QKeySequence &sequence)
608{
609 if (d->m_currentKeySequence == sequence) {
610 return;
611 }
612 d->m_currentKeySequence = sequence;
613 Q_EMIT currentKeySequenceChanged();
614}
615
617{
618 return d->m_window;
619}
620
621void KKeySequenceRecorder::setWindow(QWindow *window)
622{
623 if (window == d->m_window) {
624 return;
625 }
626
627 if (d->m_window) {
628 d->m_window->removeEventFilter(d.get());
629 }
630
631 if (window) {
632 window->installEventFilter(d.get());
633 qCDebug(KGUIADDONS_LOG) << "listening for events in" << window;
634 }
635
636 if (qGuiApp->platformName() == QLatin1String("wayland")) {
637#ifdef WITH_WAYLAND
638 d->m_inhibition.reset(new WaylandInhibition(window));
639#endif
640 } else {
641 d->m_inhibition.reset(new KeyboardGrabber(window));
642 }
643
644 d->m_window = window;
645
646 Q_EMIT windowChanged();
647}
648
650{
651 return d->m_multiKeyShortcutsAllowed;
652}
653
654void KKeySequenceRecorder::setMultiKeyShortcutsAllowed(bool allowed)
655{
656 if (allowed == d->m_multiKeyShortcutsAllowed) {
657 return;
658 }
659 d->m_multiKeyShortcutsAllowed = allowed;
660 Q_EMIT multiKeyShortcutsAllowedChanged();
661}
662
663#if KGUIADDONS_BUILD_DEPRECATED_SINCE(6, 12)
665{
666 return d->m_patterns & Key;
667}
668
669void KKeySequenceRecorder::setModifierlessAllowed(bool allowed)
670{
671 if (allowed) {
672 setPatterns(d->m_patterns | Key);
673 } else {
674 setPatterns(d->m_patterns & ~Key);
675 }
676}
677
679{
680 return d->m_patterns & Modifier;
681}
682
683void KKeySequenceRecorder::setModifierOnlyAllowed(bool allowed)
684{
685 if (allowed) {
686 setPatterns(d->m_patterns | Modifier);
687 } else {
688 setPatterns(d->m_patterns & ~Modifier);
689 }
690}
691#endif
692
693void KKeySequenceRecorder::setPatterns(Patterns patterns)
694{
695 if (!patterns) {
696 return;
697 }
698
699 if (patterns == d->m_patterns) {
700 return;
701 }
702
703#if KGUIADDONS_BUILD_DEPRECATED_SINCE(6, 12)
704 const bool oldModifierlessAllowed = modifierlessAllowed();
705 const bool oldModifierOnlyAllowed = modifierOnlyAllowed();
706#endif
707
708 d->m_patterns = patterns;
709 Q_EMIT patternsChanged();
710
711#if KGUIADDONS_BUILD_DEPRECATED_SINCE(6, 12)
712 if (modifierlessAllowed() != oldModifierlessAllowed) {
713 Q_EMIT modifierlessAllowedChanged();
714 }
715 if (modifierOnlyAllowed() != oldModifierOnlyAllowed) {
716 Q_EMIT modifierOnlyAllowedChanged();
717 }
718#endif
719}
720
721KKeySequenceRecorder::Patterns KKeySequenceRecorder::patterns() const
722{
723 return d->m_patterns;
724}
725
726#include "kkeysequencerecorder.moc"
727#include "moc_kkeysequencerecorder.cpp"
Record a QKeySequence by listening to key events in a window.
Patterns patterns
Specifies what components the recorded shortcut must have, for example whether the shortcut must cont...
Q_INVOKABLE void startRecording()
Start recording.
bool multiKeyShortcutsAllowed
Controls the amount of key combinations that are captured until recording stops and gotKeySequence is...
bool modifierOnlyAllowed
It makes it acceptable for the key sequence to be just a modifier (e.g.
KKeySequenceRecorder(QWindow *window, QObject *parent=nullptr)
Constructor.
QKeySequence currentKeySequence
The recorded key sequence.
bool isRecording
Whether key events are currently recorded.
QWindow * window
The window in which the key events are happening that should be recorded.
void cancelRecording()
Stops the recording session.
Pattern
The Pattern type specifies what components the recorded shortcut must have, e.g.
@ Modifier
The recorded shortcut must contain one or more modifier keys (Meta, Shift, Ctrl, or Alt).
@ Key
The recorded shortcut must contain only one regular key, e.g.
@ ModifierAndKey
The recorded shortcut must contain one or more modifier keys followed by a regular key,...
bool modifierlessAllowed
If key presses of "plain" keys without a modifier are considered to be a valid finished key combinati...
char * toString(const EngineQuery &query)
bool isShiftAsModifierAllowed(int keyQt)
bool isLetter(char32_t ucs4)
ShortcutOverride
Qt::Key key() const const
Qt::KeyboardModifiers keyboardModifiers() const const
int toCombined() const const
int count() const const
QObject(QObject *parent)
Q_EMITQ_EMIT
Q_OBJECTQ_OBJECT
Q_SIGNALSQ_SIGNALS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
virtual bool event(QEvent *e)
virtual bool eventFilter(QObject *watched, QEvent *event)
QObject * parent() const const
UniqueConnection
typedef KeyboardModifiers
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 11:55:06 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.