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
qshortcut.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 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
5#include "qshortcut.h"
6#include "qshortcut_p.h"
7
8#include <qevent.h>
9#include <qguiapplication.h>
10#include <qwindow.h>
11#include <private/qguiapplication_p.h>
12#include <qpa/qplatformmenu.h>
13
15
16#define QAPP_CHECK(functionName)
17 if (Q_UNLIKELY(!qApp)) {
18 qWarning("QShortcut: Initialize QGuiApplication before calling '" functionName "'.");
19 return;
20 }
21
22/*!
23 \class QShortcut
24 \brief The QShortcut class is used to create keyboard shortcuts.
25
26 \ingroup events
27 \inmodule QtGui
28
29 The QShortcut class provides a way of connecting keyboard
30 shortcuts to Qt's \l{signals and slots} mechanism, so that
31 objects can be informed when a shortcut is executed. The shortcut
32 can be set up to contain all the key presses necessary to
33 describe a keyboard shortcut, including the states of modifier
34 keys such as \uicontrol Shift, \uicontrol Ctrl, and \uicontrol Alt.
35
36 \target mnemonic
37
38 In widget applications, certain widgets can use '&' in front of a character.
39 This will automatically create a mnemonic (a shortcut) for that character,
40 e.g. "E&xit" will create the shortcut \uicontrol Alt+X (use '&&'
41 to display an actual ampersand). The widget might consume and perform
42 an action on a given shortcut. On X11 the ampersand will not be
43 shown and the character will be underlined. On Windows, shortcuts
44 are normally not displayed until the user presses the \uicontrol Alt
45 key, but this is a setting the user can change. On Mac, shortcuts
46 are disabled by default. Call \l qt_set_sequence_auto_mnemonic() to
47 enable them. However, because mnemonic shortcuts do not fit in
48 with Aqua's guidelines, Qt will not show the shortcut character
49 underlined.
50
51 For applications that use menus, it may be more convenient to
52 use the convenience functions provided in the QMenu class to
53 assign keyboard shortcuts to menu items as they are created.
54 Alternatively, shortcuts may be associated with other types of
55 actions in the QAction class.
56
57 The simplest way to create a shortcut for a particular widget is
58 to construct the shortcut with a key sequence. For example:
59
60 \snippet code/src_gui_kernel_qshortcut.cpp 0
61
62 When the user types the \l{QKeySequence}{key sequence}
63 for a given shortcut, the shortcut's activated() signal is
64 emitted. (In the case of ambiguity, the activatedAmbiguously()
65 signal is emitted.) A shortcut is "listened for" by Qt's event
66 loop when the shortcut's parent widget is receiving events.
67
68 A shortcut's key sequence can be set with setKey() and retrieved
69 with key(). A shortcut can be enabled or disabled with
70 setEnabled(), and can have "What's This?" help text set with
71 setWhatsThis().
72
73 \sa QShortcutEvent, QKeySequence, QAction
74*/
75
76/*!
77 \fn void QShortcut::activated()
78
79 This signal is emitted when the user types the shortcut's key
80 sequence.
81
82 \sa activatedAmbiguously()
83*/
84
85/*!
86 \fn void QShortcut::activatedAmbiguously()
87
88 When a key sequence is being typed at the keyboard, it is said to
89 be ambiguous as long as it matches the start of more than one
90 shortcut.
91
92 When a shortcut's key sequence is completed,
93 activatedAmbiguously() is emitted if the key sequence is still
94 ambiguous (i.e., it is the start of one or more other shortcuts).
95 The activated() signal is not emitted in this case.
96
97 \sa activated()
98*/
99
100bool QShortcutPrivate::simpleContextMatcher(QObject *object, Qt::ShortcutContext context)
101{
102 auto guiShortcut = qobject_cast<QShortcut *>(object);
103 if (QGuiApplication::applicationState() != Qt::ApplicationActive || guiShortcut == nullptr)
104 return false;
105 if (context == Qt::ApplicationShortcut)
106 return true;
107 auto focusWindow = QGuiApplication::focusWindow();
108 if (!focusWindow)
109 return false;
110 auto window = qobject_cast<const QWindow *>(guiShortcut->parent());
111 if (!window)
112 return false;
113 if (focusWindow == window && focusWindow->isTopLevel())
114 return context == Qt::WindowShortcut || context == Qt::WidgetWithChildrenShortcut;
115 return focusWindow->isAncestorOf(window, QWindow::ExcludeTransients);
116}
117
118QShortcutMap::ContextMatcher QShortcutPrivate::contextMatcher() const
119{
120 return simpleContextMatcher;
121}
122
123void QShortcutPrivate::redoGrab(QShortcutMap &map)
124{
125 Q_Q(QShortcut);
126 if (Q_UNLIKELY(!parent)) {
127 qWarning("QShortcut: No window parent defined");
128 return;
129 }
130
131 for (int id : std::as_const(sc_ids))
132 map.removeShortcut(id, q);
133
134 sc_ids.clear();
135 if (sc_sequences.isEmpty())
136 return;
137 sc_ids.reserve(sc_sequences.size());
138 for (const auto &keySequence : std::as_const(sc_sequences)) {
139 if (keySequence.isEmpty())
140 continue;
141 int id = map.addShortcut(q, keySequence, sc_context, contextMatcher());
142 sc_ids.append(id);
143 if (!sc_enabled)
144 map.setShortcutEnabled(false, id, q);
145 if (!sc_autorepeat)
146 map.setShortcutAutoRepeat(false, id, q);
147 }
148}
149
150QShortcutPrivate *QGuiApplicationPrivate::createShortcutPrivate() const
151{
152 return new QShortcutPrivate;
153}
154
155/*!
156 Constructs a QShortcut object for the \a parent, which should be a
157 QWindow or a QWidget.
158
159 Since no shortcut key sequence is specified, the shortcut will not emit any
160 signals.
161
162 \sa setKey()
163*/
164QShortcut::QShortcut(QObject *parent)
165 : QObject(*QGuiApplicationPrivate::instance()->createShortcutPrivate(), parent)
166{
167 Q_ASSERT(parent != nullptr);
168}
169
170/*!
171 Constructs a QShortcut object for the \a parent, which should be a
172 QWindow or a QWidget.
173
174 The shortcut operates on its parent, listening for \l{QShortcutEvent}s that
175 match the \a key sequence. Depending on the ambiguity of the event, the
176 shortcut will call the \a member function, or the \a ambiguousMember function,
177 if the key press was in the shortcut's \a context.
178*/
179QShortcut::QShortcut(const QKeySequence &key, QObject *parent,
180 const char *member, const char *ambiguousMember,
181 Qt::ShortcutContext context)
182 : QShortcut(parent)
183{
184 Q_D(QShortcut);
185 d->sc_context = context;
186 if (!key.isEmpty()) {
187 d->sc_sequences = { key };
188 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
189 }
190 if (member)
191 connect(this, SIGNAL(activated()), parent, member);
192 if (ambiguousMember)
193 connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember);
194}
195
196/*!
197 \since 6.0
198 Constructs a QShortcut object for the \a parent, which should be a
199 QWindow or a QWidget.
200
201 The shortcut operates on its parent, listening for \l{QShortcutEvent}s that
202 match the \a standardKey. Depending on the ambiguity of the event, the
203 shortcut will call the \a member function, or the \a ambiguousMember function,
204 if the key press was in the shortcut's \a context.
205*/
206QShortcut::QShortcut(QKeySequence::StandardKey standardKey, QObject *parent,
207 const char *member, const char *ambiguousMember,
208 Qt::ShortcutContext context)
209 : QShortcut(parent)
210{
211 Q_D(QShortcut);
212 d->sc_context = context;
213 d->sc_sequences = QKeySequence::keyBindings(standardKey);
214 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
215 if (member)
216 connect(this, SIGNAL(activated()), parent, member);
217 if (ambiguousMember)
218 connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember);
219}
220
221
222/*!
223 \fn template<typename Functor> QShortcut::QShortcut(const QKeySequence &key, QObject *parent, Functor functor, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
224 \since 5.15
225 \overload
226
227 This is a QShortcut convenience constructor which connects the shortcut's
228 \l{QShortcut::activated()}{activated()} signal to the \a functor.
229*/
230/*!
231 \fn template<typename Functor> QShortcut::QShortcut(const QKeySequence &key, QObject *parent, const QObject *context, Functor functor, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
232 \since 5.15
233 \overload
234
235 This is a QShortcut convenience constructor which connects the shortcut's
236 \l{QShortcut::activated()}{activated()} signal to the \a functor.
237
238 The \a functor can be a pointer to a member function of the \a context object.
239
240 If the \a context object is destroyed, the \a functor will not be called.
241*/
242/*!
243 \fn template<typename Functor, typename FunctorAmbiguous> QShortcut::QShortcut(const QKeySequence &key, QObject *parent, const QObject *context, Functor functor, FunctorAmbiguous functorAmbiguous, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
244 \since 5.15
245 \overload
246
247 This is a QShortcut convenience constructor which connects the shortcut's
248 \l{QShortcut::activated()}{activated()} signal to the \a functor and
249 \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
250 signal to the \a functorAmbiguous.
251
252 The \a functor and \a functorAmbiguous can be a pointer to a member
253 function of the \a context object.
254
255 If the \a context object is destroyed, the \a functor and
256 \a functorAmbiguous will not be called.
257*/
258/*!
259 \fn template<typename Functor, typename FunctorAmbiguous> QShortcut::QShortcut(const QKeySequence &key, QObject *parent, const QObject *context1, Functor functor, const QObject *context2, FunctorAmbiguous functorAmbiguous, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
260 \since 5.15
261 \overload
262
263 This is a QShortcut convenience constructor which connects the shortcut's
264 \l{QShortcut::activated()}{activated()} signal to the \a functor and
265 \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
266 signal to the \a functorAmbiguous.
267
268 The \a functor can be a pointer to a member function of the
269 \a context1 object.
270 The \a functorAmbiguous can be a pointer to a member function of the
271 \a context2 object.
272
273 If the \a context1 object is destroyed, the \a functor will not be called.
274 If the \a context2 object is destroyed, the \a functorAmbiguous
275 will not be called.
276*/
277
278/*!
279 \fn template<typename Functor> QShortcut::QShortcut(QKeySequence::StandardKey key, QObject *parent, Functor functor, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
280 \since 6.0
281 \overload
282
283 This is a QShortcut convenience constructor which connects the shortcut's
284 \l{QShortcut::activated()}{activated()} signal to the \a functor.
285*/
286/*!
287 \fn template<typename Functor> QShortcut::QShortcut(QKeySequence::StandardKey key, QObject *parent, const QObject *context, Functor functor, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
288 \since 6.0
289 \overload
290
291 This is a QShortcut convenience constructor which connects the shortcut's
292 \l{QShortcut::activated()}{activated()} signal to the \a functor.
293
294 The \a functor can be a pointer to a member function of the \a context object.
295
296 If the \a context object is destroyed, the \a functor will not be called.
297*/
298/*!
299 \fn template<typename Functor, typename FunctorAmbiguous> QShortcut::QShortcut(QKeySequence::StandardKey key, QObject *parent, const QObject *context, Functor functor, FunctorAmbiguous functorAmbiguous, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
300 \since 6.0
301 \overload
302
303 This is a QShortcut convenience constructor which connects the shortcut's
304 \l{QShortcut::activated()}{activated()} signal to the \a functor and
305 \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
306 signal to the \a functorAmbiguous.
307
308 The \a functor and \a functorAmbiguous can be a pointer to a member
309 function of the \a context object.
310
311 If the \a context object is destroyed, the \a functor and
312 \a functorAmbiguous will not be called.
313*/
314/*!
315 \fn template<typename Functor, typename FunctorAmbiguous> QShortcut::QShortcut(QKeySequence::StandardKey key, QObject *parent, const QObject *context1, Functor functor, const QObject *context2, FunctorAmbiguous functorAmbiguous, Qt::ShortcutContext shortcutContext = Qt::WindowShortcut)
316 \since 6.0
317 \overload
318
319 This is a QShortcut convenience constructor which connects the shortcut's
320 \l{QShortcut::activated()}{activated()} signal to the \a functor and
321 \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
322 signal to the \a functorAmbiguous.
323
324 The \a functor can be a pointer to a member function of the
325 \a context1 object.
326 The \a functorAmbiguous can be a pointer to a member function of the
327 \a context2 object.
328
329 If the \a context1 object is destroyed, the \a functor will not be called.
330 If the \a context2 object is destroyed, the \a functorAmbiguous
331 will not be called.
332*/
333
334/*!
335 Destroys the shortcut.
336*/
337QShortcut::~QShortcut()
338{
339 Q_D(QShortcut);
340 if (qApp) {
341 for (int id : std::as_const(d->sc_ids))
342 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id, this);
343 }
344}
345
346/*!
347 \property QShortcut::key
348 \brief the shortcut's primary key sequence
349
350 This is a key sequence with an optional combination of Shift, Ctrl,
351 and Alt. The key sequence may be supplied in a number of ways:
352
353 \snippet code/src_gui_kernel_qshortcut.cpp 1
354
355 By default, this property contains an empty key sequence.
356*/
357void QShortcut::setKey(const QKeySequence &key)
358{
359 if (key.isEmpty())
360 setKeys({});
361 else
362 setKeys({ key });
363}
364
365QKeySequence QShortcut::key() const
366{
367 Q_D(const QShortcut);
368 if (d->sc_sequences.isEmpty())
369 return QKeySequence();
370 return d->sc_sequences.first();
371}
372
373/*!
374 Sets \a keys as the list of key sequences that trigger the
375 shortcut.
376
377 \since 6.0
378
379 \sa key, keys()
380*/
381void QShortcut::setKeys(const QList<QKeySequence> &keys)
382{
383 Q_D(QShortcut);
384 if (d->sc_sequences == keys)
385 return;
386 QAPP_CHECK("setKeys");
387 d->sc_sequences = keys;
388 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
389}
390
391/*!
392 Sets the triggers to those matching the standard key \a key.
393
394 \since 6.0
395
396 \sa key, keys()
397*/
398void QShortcut::setKeys(QKeySequence::StandardKey key)
399{
400 setKeys(QKeySequence::keyBindings(key));
401}
402
403/*!
404 Returns the list of key sequences which trigger this
405 shortcut.
406
407 \since 6.0
408 \sa key, setKeys()
409*/
410QList<QKeySequence> QShortcut::keys() const
411{
412 Q_D(const QShortcut);
413 return d->sc_sequences;
414}
415
416/*!
417 \property QShortcut::enabled
418 \brief whether the shortcut is enabled
419
420 An enabled shortcut emits the activated() or activatedAmbiguously()
421 signal when a QShortcutEvent occurs that matches the shortcut's
422 key() sequence.
423
424 If the application is in \c WhatsThis mode the shortcut will not emit
425 the signals, but will show the "What's This?" text instead.
426
427 By default, this property is \c true.
428
429 \sa whatsThis
430*/
431void QShortcut::setEnabled(bool enable)
432{
433 Q_D(QShortcut);
434 if (d->sc_enabled == enable)
435 return;
436 QAPP_CHECK("setEnabled");
437 d->sc_enabled = enable;
438 for (int id : d->sc_ids)
439 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, id, this);
440}
441
442bool QShortcut::isEnabled() const
443{
444 Q_D(const QShortcut);
445 return d->sc_enabled;
446}
447
448/*!
449 \property QShortcut::context
450 \brief the context in which the shortcut is valid
451
452 A shortcut's context decides in which circumstances a shortcut is
453 allowed to be triggered. The normal context is Qt::WindowShortcut,
454 which allows the shortcut to trigger if the parent (the widget
455 containing the shortcut) is a subwidget of the active top-level
456 window.
457
458 By default, this property is set to Qt::WindowShortcut.
459*/
460void QShortcut::setContext(Qt::ShortcutContext context)
461{
462 Q_D(QShortcut);
463 if (d->sc_context == context)
464 return;
465 QAPP_CHECK("setContext");
466 d->sc_context = context;
467 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
468}
469
470Qt::ShortcutContext QShortcut::context() const
471{
472 Q_D(const QShortcut);
473 return d->sc_context;
474}
475
476/*!
477 \property QShortcut::autoRepeat
478 \brief whether the shortcut can auto repeat
479
480 If true, the shortcut will auto repeat when the keyboard shortcut
481 combination is held down, provided that keyboard auto repeat is
482 enabled on the system.
483 The default value is true.
484*/
485void QShortcut::setAutoRepeat(bool on)
486{
487 Q_D(QShortcut);
488 if (d->sc_autorepeat == on)
489 return;
490 QAPP_CHECK("setAutoRepeat");
491 d->sc_autorepeat = on;
492 for (int id : d->sc_ids)
493 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, id, this);
494}
495
496bool QShortcut::autoRepeat() const
497{
498 Q_D(const QShortcut);
499 return d->sc_autorepeat;
500}
501
502
503/*!
504 Sets the shortcut's "What's This?" help \a text.
505
506 The text will be shown when a widget application is in "What's
507 This?" mode and the user types the shortcut key() sequence.
508
509 To set "What's This?" help on a menu item (with or without a
510 shortcut key), set the help on the item's action.
511
512 By default, the help text is an empty string.
513
514 This function has no effect in applications that don't use
515 widgets.
516
517 \sa QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis()
518*/
519void QShortcut::setWhatsThis(const QString &text)
520{
521 Q_D(QShortcut);
522 d->sc_whatsthis = text;
523}
524
525/*!
526 Returns the shortcut's "What's This?" help text.
527
528 \sa setWhatsThis()
529*/
530QString QShortcut::whatsThis() const
531{
532 Q_D(const QShortcut);
533 return d->sc_whatsthis;
534}
535
536#if QT_DEPRECATED_SINCE(6,0)
537/*!
538 Returns the primary key binding's ID.
539
540 \deprecated
541
542 \sa QShortcutEvent::shortcutId()
543*/
544int QShortcut::id() const
545{
546 Q_D(const QShortcut);
547 if (d->sc_ids.isEmpty())
548 return 0;
549 return d->sc_ids.first();
550}
551#endif
552
553/*!
554 \fn QWidget *QShortcut::parentWidget() const
555
556 Returns the shortcut's parent widget.
557*/
558
559/*!
560 \internal
561*/
562bool QShortcut::event(QEvent *e)
563{
564 Q_D(QShortcut);
565 if (d->sc_enabled && e->type() == QEvent::Shortcut) {
566 auto se = static_cast<QShortcutEvent *>(e);
567 if (!d->handleWhatsThis()) {
568 Q_ASSERT_X(d->sc_ids.contains(se->shortcutId()), "QShortcut::event", "Received shortcut event from wrong shortcut");
569 if (se->isAmbiguous())
570 emit activatedAmbiguously();
571 else
572 emit activated();
573 return true;
574 }
575 }
576 return QObject::event(e);
577}
578
579QT_END_NAMESPACE
580
581#undef QAPP_CHECK
582
583#include "moc_qshortcut.cpp"
Combined button and popup list for selecting options.
#define QAPP_CHECK(functionName)
Definition qaction.cpp:19
#define qApp