123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- #include "qhotkey.h"
- #include "qhotkey_p.h"
- #include <QAbstractEventDispatcher>
- #include <QCoreApplication>
- #include <QDebug>
- #include <QMetaMethod>
- #include <QThread>
- Q_LOGGING_CATEGORY(logQHotkey, "QHotkey")
- void QHotkey::addGlobalMapping(const QKeySequence& shortcut,
- QHotkey::NativeShortcut nativeShortcut)
- {
- QMetaObject::invokeMethod(
- QHotkeyPrivate::instance(),
- "addMappingInvoked",
- Qt::QueuedConnection,
- Q_ARG(Qt::Key, Qt::Key(shortcut[0] & ~Qt::KeyboardModifierMask)),
- Q_ARG(Qt::KeyboardModifiers,
- Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask)),
- Q_ARG(QHotkey::NativeShortcut, nativeShortcut));
- }
- bool QHotkey::isPlatformSupported()
- {
- return QHotkeyPrivate::isPlatformSupported();
- }
- QHotkey::QHotkey(QObject* parent)
- : QObject(parent)
- , _keyCode(Qt::Key_unknown)
- , _modifiers(Qt::NoModifier)
- , _registered(false)
- {}
- QHotkey::QHotkey(const QKeySequence& shortcut,
- bool autoRegister,
- QObject* parent)
- : QHotkey(parent)
- {
- setShortcut(shortcut, autoRegister);
- }
- QHotkey::QHotkey(Qt::Key keyCode,
- Qt::KeyboardModifiers modifiers,
- bool autoRegister,
- QObject* parent)
- : QHotkey(parent)
- {
- setShortcut(keyCode, modifiers, autoRegister);
- }
- QHotkey::QHotkey(QHotkey::NativeShortcut shortcut,
- bool autoRegister,
- QObject* parent)
- : QHotkey(parent)
- {
- setNativeShortcut(shortcut, autoRegister);
- }
- QHotkey::~QHotkey()
- {
- if (_registered)
- QHotkeyPrivate::instance()->removeShortcut(this);
- }
- QKeySequence QHotkey::shortcut() const
- {
- if (_keyCode == Qt::Key_unknown)
- return QKeySequence();
- return QKeySequence(static_cast<int>(_keyCode | _modifiers));
- }
- Qt::Key QHotkey::keyCode() const
- {
- return _keyCode;
- }
- Qt::KeyboardModifiers QHotkey::modifiers() const
- {
- return _modifiers;
- }
- QHotkey::NativeShortcut QHotkey::currentNativeShortcut() const
- {
- return _nativeShortcut;
- }
- bool QHotkey::isRegistered() const
- {
- return _registered;
- }
- bool QHotkey::setShortcut(const QKeySequence& shortcut, bool autoRegister)
- {
- if (shortcut.isEmpty())
- return resetShortcut();
- if (shortcut.count() > 1) {
- qCWarning(logQHotkey,
- "Keysequences with multiple shortcuts are not allowed! "
- "Only the first shortcut will be used!");
- }
- return setShortcut(
- Qt::Key(shortcut[0] & ~Qt::KeyboardModifierMask),
- Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask),
- autoRegister);
- }
- bool QHotkey::setShortcut(Qt::Key keyCode,
- Qt::KeyboardModifiers modifiers,
- bool autoRegister)
- {
- if (_registered) {
- if (autoRegister) {
- if (!QHotkeyPrivate::instance()->removeShortcut(this))
- return false;
- } else
- return false;
- }
- if (keyCode == Qt::Key_unknown) {
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = NativeShortcut();
- return true;
- }
- _keyCode = keyCode;
- _modifiers = modifiers;
- _nativeShortcut =
- QHotkeyPrivate::instance()->nativeShortcut(keyCode, modifiers);
- if (_nativeShortcut.isValid()) {
- if (autoRegister)
- return QHotkeyPrivate::instance()->addShortcut(this);
- return true;
- }
- qCWarning(logQHotkey) << "Unable to map shortcut to native keys. Key:"
- << keyCode << "Modifiers:" << modifiers;
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = NativeShortcut();
- return false;
- }
- bool QHotkey::resetShortcut()
- {
- if (_registered && !QHotkeyPrivate::instance()->removeShortcut(this)) {
- return false;
- }
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = NativeShortcut();
- return true;
- }
- bool QHotkey::setNativeShortcut(QHotkey::NativeShortcut nativeShortcut,
- bool autoRegister)
- {
- if (_registered) {
- if (autoRegister) {
- if (!QHotkeyPrivate::instance()->removeShortcut(this))
- return false;
- } else
- return false;
- }
- if (nativeShortcut.isValid()) {
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = nativeShortcut;
- if (autoRegister)
- return QHotkeyPrivate::instance()->addShortcut(this);
- return true;
- }
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = NativeShortcut();
- return true;
- }
- bool QHotkey::setRegistered(bool registered)
- {
- if (_registered && !registered)
- return QHotkeyPrivate::instance()->removeShortcut(this);
- if (!_registered && registered) {
- if (!_nativeShortcut.isValid())
- return false;
- return QHotkeyPrivate::instance()->addShortcut(this);
- }
- return true;
- }
- // ---------- QHotkeyPrivate implementation ----------
- QHotkeyPrivate::QHotkeyPrivate()
- {
- Q_ASSERT_X(qApp,
- Q_FUNC_INFO,
- "QHotkey requires QCoreApplication to be instantiated");
- qApp->eventDispatcher()->installNativeEventFilter(this);
- }
- QHotkeyPrivate::~QHotkeyPrivate()
- {
- if (!shortcuts.isEmpty())
- qCWarning(logQHotkey)
- << "QHotkeyPrivate destroyed with registered shortcuts!";
- if (qApp && qApp->eventDispatcher())
- qApp->eventDispatcher()->removeNativeEventFilter(this);
- }
- QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcut(
- Qt::Key keycode,
- Qt::KeyboardModifiers modifiers)
- {
- Qt::ConnectionType conType =
- (QThread::currentThread() == thread() ? Qt::DirectConnection
- : Qt::BlockingQueuedConnection);
- QHotkey::NativeShortcut res;
- if (!QMetaObject::invokeMethod(this,
- "nativeShortcutInvoked",
- conType,
- Q_RETURN_ARG(QHotkey::NativeShortcut, res),
- Q_ARG(Qt::Key, keycode),
- Q_ARG(Qt::KeyboardModifiers, modifiers))) {
- return QHotkey::NativeShortcut();
- }
- return res;
- }
- bool QHotkeyPrivate::addShortcut(QHotkey* hotkey)
- {
- if (hotkey->_registered)
- return false;
- Qt::ConnectionType conType =
- (QThread::currentThread() == thread() ? Qt::DirectConnection
- : Qt::BlockingQueuedConnection);
- bool res = false;
- if (!QMetaObject::invokeMethod(this,
- "addShortcutInvoked",
- conType,
- Q_RETURN_ARG(bool, res),
- Q_ARG(QHotkey*, hotkey))) {
- return false;
- }
- if (res)
- emit hotkey->registeredChanged(true);
- return res;
- }
- bool QHotkeyPrivate::removeShortcut(QHotkey* hotkey)
- {
- if (!hotkey->_registered)
- return false;
- Qt::ConnectionType conType =
- (QThread::currentThread() == thread() ? Qt::DirectConnection
- : Qt::BlockingQueuedConnection);
- bool res = false;
- if (!QMetaObject::invokeMethod(this,
- "removeShortcutInvoked",
- conType,
- Q_RETURN_ARG(bool, res),
- Q_ARG(QHotkey*, hotkey))) {
- return false;
- }
- if (res)
- emit hotkey->registeredChanged(false);
- return res;
- }
- void QHotkeyPrivate::activateShortcut(QHotkey::NativeShortcut shortcut)
- {
- QMetaMethod signal = QMetaMethod::fromSignal(&QHotkey::activated);
- for (QHotkey* hkey : shortcuts.values(shortcut))
- signal.invoke(hkey, Qt::QueuedConnection);
- }
- void QHotkeyPrivate::releaseShortcut(QHotkey::NativeShortcut shortcut)
- {
- QMetaMethod signal = QMetaMethod::fromSignal(&QHotkey::released);
- for (QHotkey* hkey : shortcuts.values(shortcut))
- signal.invoke(hkey, Qt::QueuedConnection);
- }
- void QHotkeyPrivate::addMappingInvoked(Qt::Key keycode,
- Qt::KeyboardModifiers modifiers,
- QHotkey::NativeShortcut nativeShortcut)
- {
- mapping.insert({ keycode, modifiers }, nativeShortcut);
- }
- bool QHotkeyPrivate::addShortcutInvoked(QHotkey* hotkey)
- {
- QHotkey::NativeShortcut shortcut = hotkey->_nativeShortcut;
- if (!shortcuts.contains(shortcut)) {
- if (!registerShortcut(shortcut)) {
- qCWarning(logQHotkey)
- << QHotkey::tr("Failed to register %1. Error: %2")
- .arg(hotkey->shortcut().toString(), error);
- return false;
- }
- }
- shortcuts.insert(shortcut, hotkey);
- hotkey->_registered = true;
- return true;
- }
- bool QHotkeyPrivate::removeShortcutInvoked(QHotkey* hotkey)
- {
- QHotkey::NativeShortcut shortcut = hotkey->_nativeShortcut;
- if (shortcuts.remove(shortcut, hotkey) == 0)
- return false;
- hotkey->_registered = false;
- emit hotkey->registeredChanged(true);
- if (shortcuts.count(shortcut) == 0) {
- if (!unregisterShortcut(shortcut)) {
- qCWarning(logQHotkey)
- << QHotkey::tr("Failed to unregister %1. Error: %2")
- .arg(hotkey->shortcut().toString(), error);
- return false;
- }
- return true;
- }
- return true;
- }
- QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcutInvoked(
- Qt::Key keycode,
- Qt::KeyboardModifiers modifiers)
- {
- if (mapping.contains({ keycode, modifiers }))
- return mapping.value({ keycode, modifiers });
- bool ok1 = false;
- auto k = nativeKeycode(keycode, ok1);
- bool ok2 = false;
- auto m = nativeModifiers(modifiers, ok2);
- if (ok1 && ok2)
- return { k, m };
- return {};
- }
- QHotkey::NativeShortcut::NativeShortcut()
- : key()
- , modifier()
- , valid(false)
- {}
- QHotkey::NativeShortcut::NativeShortcut(quint32 key, quint32 modifier)
- : key(key)
- , modifier(modifier)
- , valid(true)
- {}
- bool QHotkey::NativeShortcut::isValid() const
- {
- return valid;
- }
- bool QHotkey::NativeShortcut::operator==(QHotkey::NativeShortcut other) const
- {
- return (key == other.key) && (modifier == other.modifier) &&
- valid == other.valid;
- }
- bool QHotkey::NativeShortcut::operator!=(QHotkey::NativeShortcut other) const
- {
- return (key != other.key) || (modifier != other.modifier) ||
- valid != other.valid;
- }
- uint qHash(QHotkey::NativeShortcut key)
- {
- return qHash(key.key) ^ qHash(key.modifier);
- }
- uint qHash(QHotkey::NativeShortcut key, uint seed)
- {
- return qHash(key.key, seed) ^ qHash(key.modifier, seed);
- }
|