Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qshortcutmap.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include "private/qobject_p.h"
7#include "qkeysequence.h"
8#include "qdebug.h"
9#include "qevent.h"
10#include "qlist.h"
12#include "qwindow.h"
13#include <private/qkeymapper_p.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qscopeguard.h>
16
17#include <algorithm>
18
20
21Q_STATIC_LOGGING_CATEGORY(lcShortcutMap, "qt.gui.shortcutmap")
22
23/* \internal
24 Entry data for QShortcutMap
25 Contains:
26 Keysequence for entry
27 Pointer to parent owning the sequence
28*/
29
31{
33 : keySequence(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
34 {}
35
36 QShortcutEntry(const QKeySequence &k)
37 : keySequence(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
38 {}
39
40 QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a, QShortcutMap::ContextMatcher m)
42 {}
43
44 bool correctContext() const { return contextMatcher(owner, context); }
45
46 bool operator<(const QShortcutEntry &f) const
47 { return keySequence < f.keySequence; }
48
49 QKeySequence keySequence;
51 bool enabled : 1;
52 bool autorepeat : 1;
53 signed int id;
54 QObject *owner;
56};
58
59#ifdef Dump_QShortcutMap
60/*! \internal
61 QDebug operator<< for easy debug output of the shortcut entries.
62*/
63static QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se)
64{
65 QDebugStateSaver saver(dbg);
66 if (!se)
67 return dbg << "QShortcutEntry(0x0)";
68 dbg.nospace()
69 << "QShortcutEntry(" << se->keyseq
70 << "), id(" << se->id << "), enabled(" << se->enabled << "), autorepeat(" << se->autorepeat
71 << "), owner(" << se->owner << ')';
72 return dbg;
73}
74#endif // Dump_QShortcutMap
75
76/* \internal
77 Private data for QShortcutMap
78*/
80{
81 Q_DECLARE_PUBLIC(QShortcutMap)
82
83public:
90 QShortcutMap *q_ptr; // Private's parent
91
92 QList<QShortcutEntry> shortcuts; // All shortcuts!
93
94 int currentId; // Global shortcut ID number
95 int ambigCount; // Index of last enabled ambiguous dispatch
97 QList<QKeySequence> currentSequences; // Sequence for the current state
98 QList<QKeySequence> newEntries;
99 QKeySequence prevSequence; // Sequence for the previous identical match
100 QList<const QShortcutEntry*> identicals; // Last identical matches
101};
102
103
104/*! \internal
105 QShortcutMap constructor.
106*/
107QShortcutMap::QShortcutMap()
108 : d_ptr(new QShortcutMapPrivate(this))
109{
110 resetState();
111}
112
113/*! \internal
114 QShortcutMap destructor.
115*/
116QShortcutMap::~QShortcutMap()
117{
118}
119
120/*! \internal
121 Adds a shortcut to the global map.
122 Returns the id of the newly added shortcut.
123*/
124int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &keySequence, Qt::ShortcutContext context, ContextMatcher matcher)
125{
126 Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner");
127 Q_ASSERT_X(!keySequence.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
128 Q_D(QShortcutMap);
129
130 QShortcutEntry newEntry(owner, keySequence, context, --(d->currentId), true, matcher);
131 const auto it = std::upper_bound(d->shortcuts.begin(), d->shortcuts.end(), newEntry);
132 d->shortcuts.insert(it, newEntry); // Insert sorted
133 qCDebug(lcShortcutMap).nospace()
134 << "QShortcutMap::addShortcut(" << owner << ", "
135 << keySequence << ", " << context << ") added shortcut with ID " << d->currentId;
136 return d->currentId;
137}
138
139/*! \internal
140 Removes a shortcut from the global map.
141 If \a owner is \nullptr, all entries in the map with the key sequence specified
142 is removed. If \a key is null, all sequences for \a owner is removed from
143 the map. If \a id is 0, any identical \a key sequences owned by \a owner
144 are removed.
145 Returns the number of sequences removed from the map.
146*/
147
148int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &keySequence)
149{
150 Q_D(QShortcutMap);
151 int itemsRemoved = 0;
152 bool allOwners = (owner == nullptr);
153 bool allKeys = keySequence.isEmpty();
154 bool allIds = id == 0;
155
156 auto debug = qScopeGuard([&](){
157 qCDebug(lcShortcutMap).nospace()
158 << "QShortcutMap::removeShortcut(" << id << ", " << owner << ", "
159 << keySequence << ") removed " << itemsRemoved << " shortcuts(s)";
160 });
161
162 // Special case, remove everything
163 if (allOwners && allKeys && allIds) {
164 itemsRemoved = d->shortcuts.size();
165 d->shortcuts.clear();
166 return itemsRemoved;
167 }
168
169 int i = d->shortcuts.size()-1;
170 while (i>=0)
171 {
172 const QShortcutEntry &entry = d->shortcuts.at(i);
173 int entryId = entry.id;
174 if ((allOwners || entry.owner == owner)
175 && (allIds || entry.id == id)
176 && (allKeys || entry.keySequence == keySequence)) {
177 d->shortcuts.removeAt(i);
178 ++itemsRemoved;
179 }
180 if (id == entryId)
181 return itemsRemoved;
182 --i;
183 }
184 return itemsRemoved;
185}
186
187/*! \internal
188 Changes the enable state of a shortcut to \a enable.
189 If \a owner is \nullptr, all entries in the map with the key sequence specified
190 is removed. If \a key is null, all sequences for \a owner is removed from
191 the map. If \a id is 0, any identical \a key sequences owned by \a owner
192 are changed.
193 Returns the number of sequences which are matched in the map.
194*/
195int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &keySequence)
196{
197 Q_D(QShortcutMap);
198 int itemsChanged = 0;
199 bool allOwners = (owner == nullptr);
200 bool allKeys = keySequence.isEmpty();
201 bool allIds = id == 0;
202
203 int i = d->shortcuts.size()-1;
204 while (i>=0)
205 {
206 const QShortcutEntry &entry = d->shortcuts.at(i);
207 if ((allOwners || entry.owner == owner)
208 && (allIds || entry.id == id)
209 && (allKeys || entry.keySequence == keySequence)) {
210 d->shortcuts[i].enabled = enable;
211 ++itemsChanged;
212 }
213 if (id == entry.id)
214 return itemsChanged;
215 --i;
216 }
217 qCDebug(lcShortcutMap).nospace()
218 << "QShortcutMap::setShortcutEnabled(" << enable << ", " << id << ", "
219 << owner << ", " << keySequence << ") = " << itemsChanged;
220 return itemsChanged;
221}
222
223/*! \internal
224 Changes the auto repeat state of a shortcut to \a enable.
225 If \a owner is \nullptr, all entries in the map with the key sequence specified
226 is removed. If \a key is null, all sequences for \a owner is removed from
227 the map. If \a id is 0, any identical \a key sequences owned by \a owner
228 are changed.
229 Returns the number of sequences which are matched in the map.
230*/
231int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &keySequence)
232{
233 Q_D(QShortcutMap);
234 int itemsChanged = 0;
235 bool allOwners = (owner == nullptr);
236 bool allKeys = keySequence.isEmpty();
237 bool allIds = id == 0;
238
239 int i = d->shortcuts.size()-1;
240 while (i>=0)
241 {
242 QShortcutEntry entry = d->shortcuts.at(i);
243 if ((allOwners || entry.owner == owner)
244 && (allIds || entry.id == id)
245 && (allKeys || entry.keySequence == keySequence)) {
246 d->shortcuts[i].autorepeat = on;
247 ++itemsChanged;
248 }
249 if (id == entry.id)
250 return itemsChanged;
251 --i;
252 }
253 qCDebug(lcShortcutMap).nospace()
254 << "QShortcutMap::setShortcutAutoRepeat(" << on << ", " << id << ", "
255 << owner << ", " << keySequence << ") = " << itemsChanged;
256 return itemsChanged;
257}
258
259/*! \internal
260 Resets the state of the statemachine to NoMatch
261*/
262void QShortcutMap::resetState()
263{
264 Q_D(QShortcutMap);
265 d->currentState = QKeySequence::NoMatch;
266 clearSequence(d->currentSequences);
267}
268
269/*! \internal
270 Returns the current state of the statemachine
271*/
272QKeySequence::SequenceMatch QShortcutMap::state()
273{
274 Q_D(QShortcutMap);
275 return d->currentState;
276}
277
278/*! \internal
279 Uses nextState(QKeyEvent) to check for a grabbed shortcut.
280
281 If so, it is dispatched using dispatchEvent().
282
283 Returns true if a shortcut handled the event.
284
285 \sa nextState, dispatchEvent
286*/
287bool QShortcutMap::tryShortcut(QKeyEvent *e)
288{
289 Q_D(QShortcutMap);
290
291 if (e->key() == Qt::Key_unknown)
292 return false;
293
294 QKeySequence::SequenceMatch previousState = state();
295
296 switch (nextState(e)) {
297 case QKeySequence::NoMatch:
298 // In the case of going from a partial match to no match we handled the
299 // event, since we already stated that we did for the partial match. But
300 // in the normal case of directly going to no match we say we didn't.
301 return previousState == QKeySequence::PartialMatch;
302 case QKeySequence::PartialMatch:
303 // For a partial match we don't know yet if we will handle the shortcut
304 // but we need to say we did, so that we get the follow-up key-presses.
305 return true;
306 case QKeySequence::ExactMatch: {
307 // Save number of identical matches before dispatching
308 // to keep QShortcutMap and tryShortcut reentrant.
309 const int identicalMatches = d->identicals.size();
310 resetState();
311 dispatchEvent(e);
312 // If there are no identicals we've only found disabled shortcuts, and
313 // shouldn't say that we handled the event.
314 return identicalMatches > 0;
315 }
316 }
317 Q_UNREACHABLE_RETURN(false);
318}
319
320/*! \internal
321 Returns the next state of the statemachine
322 If return value is SequenceMatch::ExactMatch, then a call to matches()
323 will return a QObjects* list of all matching objects for the last matching
324 sequence.
325*/
326QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e)
327{
328 Q_D(QShortcutMap);
329 // Modifiers can NOT be shortcuts...
330 if (e->key() >= Qt::Key_Shift &&
331 e->key() <= Qt::Key_ScrollLock)
332 return d->currentState;
333
334 QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
335
336 // We start fresh each time..
337 d->identicals.clear();
338
339 result = find(e);
340 if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) {
341 // Try to find a match without keypad modifier
342 result = find(e, Qt::KeypadModifier);
343 }
344 if (result == QKeySequence::NoMatch && e->modifiers() & Qt::ShiftModifier) {
345 // If Shift + Key_Backtab, also try Shift + Qt::Key_Tab
346 if (e->key() == Qt::Key_Backtab) {
347 QKeyEvent pe = QKeyEvent(e->type(), Qt::Key_Tab, e->modifiers(), e->text());
348 result = find(&pe);
349 }
350 }
351
352 // Does the new state require us to clean up?
353 if (result == QKeySequence::NoMatch)
354 clearSequence(d->currentSequences);
355 d->currentState = result;
356
357 qCDebug(lcShortcutMap).nospace() << "QShortcutMap::nextState(" << e << ") = " << result;
358 return result;
359}
360
361
362/*! \internal
363 Determines if an enabled shortcut has a matching key sequence.
364*/
365bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
366{
367 Q_D(const QShortcutMap);
368 QShortcutEntry entry(seq); // needed for searching
369 const auto itEnd = d->shortcuts.cend();
370 auto it = std::lower_bound(d->shortcuts.cbegin(), itEnd, entry);
371
372 for (;it != itEnd; ++it) {
373 if (entry.keySequence.matches(it->keySequence) == QKeySequence::ExactMatch
374 && (*it).correctContext() && (*it).enabled) {
375 return true;
376 }
377 }
378
379 //end of the loop: we didn't find anything
380 return false;
381}
382
383/*! \internal
384 Returns the next state of the statemachine, based
385 on the new key event \a e.
386 Matches are appended to the list of identicals,
387 which can be access through matches().
388 \sa matches
389*/
390QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifiers)
391{
392 Q_D(QShortcutMap);
393 if (!d->shortcuts.size())
394 return QKeySequence::NoMatch;
395
396 createNewSequences(e, d->newEntries, ignoredModifiers);
397 qCDebug(lcShortcutMap) << "Possible input sequences:" << d->newEntries;
398
399 // Should never happen
400 if (d->newEntries == d->currentSequences) {
401 Q_ASSERT_X(e->key() != Qt::Key_unknown || e->text().size(),
402 "QShortcutMap::find", "New sequence to find identical to previous");
403 return QKeySequence::NoMatch;
404 }
405
406 // Looking for new identicals, scrap old
407 d->identicals.clear();
408
409 bool partialFound = false;
410 bool identicalDisabledFound = false;
411 QList<QKeySequence> okEntries;
412 QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
413 for (int i = d->newEntries.size()-1; i >= 0 ; --i) {
414 QShortcutEntry entry(d->newEntries.at(i)); // needed for searching
415 qCDebug(lcShortcutMap) << "Looking for shortcuts matching" << entry.keySequence;
416
417 QKeySequence::SequenceMatch bestMatchForEntry = QKeySequence::NoMatch;
418
419 const auto itEnd = d->shortcuts.constEnd();
420 auto it = std::lower_bound(d->shortcuts.constBegin(), itEnd, entry);
421 for (; it != itEnd; ++it) {
422 QKeySequence::SequenceMatch match = entry.keySequence.matches(it->keySequence);
423 qCDebug(lcShortcutMap) << " -" << match << "for shortcut" << it->keySequence;
424
425 // If we got a valid match, there might still be more keys to check against,
426 // but if we get no match, we know that there are no more possible matches.
427 if (match == QKeySequence::NoMatch)
428 break;
429
430 bestMatchForEntry = qMax(bestMatchForEntry, match);
431
432 if ((*it).correctContext()) {
433 if (match == QKeySequence::ExactMatch) {
434 if ((*it).enabled)
435 d->identicals.append(&*it);
436 else
437 identicalDisabledFound = true;
438 } else if (match == QKeySequence::PartialMatch) {
439 // We don't need partials, if we have identicals
440 if (d->identicals.size())
441 break;
442 // We only care about enabled partials, so we don't consume
443 // key events when all partials are disabled!
444 partialFound |= (*it).enabled;
445 }
446 } else {
447 qCDebug(lcShortcutMap) << " - But context was not correct";
448 }
449 }
450
451 // If the type of match improves (ergo, NoMatch->Partial, or Partial->Exact), clear the
452 // previous list. If this match is equal or better than the last match, append to the list
453 if (bestMatchForEntry > result) {
454 okEntries.clear();
455 qCDebug(lcShortcutMap) << "Found better match (" << d->newEntries << "), clearing key sequence list";
456 }
457 if (bestMatchForEntry && bestMatchForEntry >= result) {
458 okEntries << d->newEntries.at(i);
459 qCDebug(lcShortcutMap) << "Added ok key sequence" << d->newEntries;
460 }
461 }
462
463 if (d->identicals.size()) {
464 result = QKeySequence::ExactMatch;
465 } else if (partialFound) {
466 result = QKeySequence::PartialMatch;
467 } else if (identicalDisabledFound) {
468 result = QKeySequence::ExactMatch;
469 } else {
470 clearSequence(d->currentSequences);
471 result = QKeySequence::NoMatch;
472 }
473 if (result != QKeySequence::NoMatch)
474 d->currentSequences = okEntries;
475 qCDebug(lcShortcutMap) << "Returning shortcut match == " << result;
476 return result;
477}
478
479/*! \internal
480 Clears \a seq to an empty QKeySequence.
481 Same as doing (the slower)
482 \snippet code/src_gui_kernel_qshortcutmap.cpp 0
483*/
484void QShortcutMap::clearSequence(QList<QKeySequence> &ksl)
485{
486 ksl.clear();
487 d_func()->newEntries.clear();
488}
489
490/*! \internal
491 Alters \a seq to the new sequence state, based on the
492 current sequence state, and the new key event \a e.
493*/
494void QShortcutMap::createNewSequences(QKeyEvent *e, QList<QKeySequence> &ksl, int ignoredModifiers)
495{
496 Q_D(QShortcutMap);
497 QList<QKeyCombination> possibleKeys = QKeyMapper::possibleKeys(e);
498 qCDebug(lcShortcutMap) << "Creating new sequences for" << e
499 << "with ignoredModifiers=" << Qt::KeyboardModifiers(ignoredModifiers);
500 int pkTotal = possibleKeys.size();
501 if (!pkTotal)
502 return;
503
504 int ssActual = d->currentSequences.size();
505 int ssTotal = qMax(1, ssActual);
506 // Resize to possible permutations of the current sequence(s).
507 ksl.resize(pkTotal * ssTotal);
508
509 int index = ssActual ? d->currentSequences.at(0).count() : 0;
510 for (int pkNum = 0; pkNum < pkTotal; ++pkNum) {
511 for (int ssNum = 0; ssNum < ssTotal; ++ssNum) {
512 int i = (pkNum * ssTotal) + ssNum;
513 QKeySequence &curKsl = ksl[i];
514 if (ssActual) {
515 const QKeySequence &curSeq = d->currentSequences.at(ssNum);
516 curKsl.setKey(curSeq[0], 0);
517 curKsl.setKey(curSeq[1], 1);
518 curKsl.setKey(curSeq[2], 2);
519 curKsl.setKey(curSeq[3], 3);
520 } else {
521 curKsl.setKey(QKeyCombination::fromCombined(0), 0);
522 curKsl.setKey(QKeyCombination::fromCombined(0), 1);
523 curKsl.setKey(QKeyCombination::fromCombined(0), 2);
524 curKsl.setKey(QKeyCombination::fromCombined(0), 3);
525 }
526 const int key = possibleKeys.at(pkNum).toCombined();
527 curKsl.setKey(QKeyCombination::fromCombined(key & ~ignoredModifiers), index);
528 }
529 }
530}
531
532/*! \internal
533 Converts keyboard button states into modifier states
534*/
535int QShortcutMap::translateModifiers(Qt::KeyboardModifiers modifiers)
536{
537 int result = 0;
538 if (modifiers & Qt::ShiftModifier)
539 result |= Qt::SHIFT;
540 if (modifiers & Qt::ControlModifier)
541 result |= Qt::CTRL;
542 if (modifiers & Qt::MetaModifier)
543 result |= Qt::META;
544 if (modifiers & Qt::AltModifier)
545 result |= Qt::ALT;
546 return result;
547}
548
549/*! \internal
550 Returns the list of QShortcutEntry's matching the last Identical state.
551*/
552QList<const QShortcutEntry*> QShortcutMap::matches() const
553{
554 Q_D(const QShortcutMap);
555 return d->identicals;
556}
557
558/*! \internal
559 Dispatches QShortcutEvents to widgets who grabbed the matched key sequence.
560*/
561void QShortcutMap::dispatchEvent(QKeyEvent *e)
562{
563 Q_D(QShortcutMap);
564 if (!d->identicals.size())
565 return;
566
567 const QKeySequence &curKey = d->identicals.at(0)->keySequence;
568 if (d->prevSequence != curKey) {
569 d->ambigCount = 0;
570 d->prevSequence = curKey;
571 }
572 // Find next
573 const QShortcutEntry *current = nullptr, *next = nullptr;
574 int i = 0, enabledShortcuts = 0;
575 QList<const QShortcutEntry*> ambiguousShortcuts;
576 while(i < d->identicals.size()) {
577 current = d->identicals.at(i);
578 if (current->enabled || !next){
579 ++enabledShortcuts;
580 if (lcShortcutMap().isDebugEnabled())
581 ambiguousShortcuts.append(current);
582 if (enabledShortcuts > d->ambigCount + 1)
583 break;
584 next = current;
585 }
586 ++i;
587 }
588 d->ambigCount = (d->identicals.size() == i ? 0 : d->ambigCount + 1);
589 // Don't trigger shortcut if we're autorepeating and the shortcut is
590 // grabbed with not accepting autorepeats.
591 if (!next || (e->isAutoRepeat() && !next->autorepeat))
592 return;
593 // Dispatch next enabled
594 if (lcShortcutMap().isDebugEnabled()) {
595 if (ambiguousShortcuts.size() > 1) {
596 qCDebug(lcShortcutMap) << "The following shortcuts are about to be activated ambiguously:";
597 for (const QShortcutEntry *entry : std::as_const(ambiguousShortcuts))
598 qCDebug(lcShortcutMap).nospace() << "- " << entry->keySequence << " (belonging to " << entry->owner << ")";
599 }
600
601 qCDebug(lcShortcutMap).nospace()
602 << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\""
603 << next->keySequence.toString() << "\", " << next->id << ", "
604 << static_cast<bool>(enabledShortcuts>1) << ") to object(" << next->owner << ')';
605 }
606 QShortcutEvent se(next->keySequence, next->id, enabledShortcuts > 1);
607 QCoreApplication::sendEvent(const_cast<QObject *>(next->owner), &se);
608}
609
610QList<QKeySequence> QShortcutMap::keySequences(bool getAll) const
611{
612 Q_D(const QShortcutMap);
613 QList<QKeySequence> keys;
614 for (auto sequence : d->shortcuts) {
615 bool addSequence = false;
616 if (sequence.enabled) {
617 if (getAll || sequence.context == Qt::ApplicationShortcut ||
618 sequence.owner == QGuiApplication::focusObject()) {
619 addSequence = true;
620 } else {
621 QObject *possibleWindow = sequence.owner;
622 while (possibleWindow) {
623 if (qobject_cast<QWindow *>(possibleWindow))
624 break;
625 possibleWindow = possibleWindow->parent();
626 }
627 if (possibleWindow == QGuiApplication::focusWindow()) {
628 if (sequence.context == Qt::WindowShortcut) {
629 addSequence = true;
630 } else if (sequence.context == Qt::WidgetWithChildrenShortcut) {
631 QObject *possibleWidget = QGuiApplication::focusObject();
632 while (possibleWidget->parent()) {
633 possibleWidget = possibleWidget->parent();
634 if (possibleWidget == sequence.owner) {
635 addSequence = true;
636 break;
637 }
638 }
639 }
640 }
641 }
642 if (addSequence)
643 keys << sequence.keySequence;
644 }
645 }
646 return keys;
647
648}
649
650/* \internal
651 QShortcutMap dump function, only available when DEBUG_QSHORTCUTMAP is
652 defined.
653*/
654#if defined(Dump_QShortcutMap)
655void QShortcutMap::dumpMap() const
656{
657 Q_D(const QShortcutMap);
658 for (int i = 0; i < d->shortcuts.size(); ++i)
659 qDebug().nospace() << &(d->shortcuts.at(i));
660}
661#endif
662
663QT_END_NAMESPACE
Definition qlist.h:81
QList< const QShortcutEntry * > identicals
QKeySequence prevSequence
QList< QKeySequence > newEntries
QList< QShortcutEntry > shortcuts
QList< QKeySequence > currentSequences
QKeySequence::SequenceMatch currentState
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
Q_DECLARE_TYPEINFO(QShortcutEntry, Q_RELOCATABLE_TYPE)
QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a, QShortcutMap::ContextMatcher m)
bool correctContext() const
QShortcutEntry(const QKeySequence &k)
Qt::ShortcutContext context
QKeySequence keySequence
bool operator<(const QShortcutEntry &f) const