qt_demoe/third/3rd_qhotkey/qhotkey.cpp

350 lines
9.2 KiB
C++

#include "qhotkey.h"
#include "qhotkey_p.h"
#include <QCoreApplication>
#include <QAbstractEventDispatcher>
#include <QMetaMethod>
#include <QThread>
#include <QDebug>
QHotkey::QHotkey(QObject *parent) : QObject(parent)
{
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = 0;
_registered = false;
}
QHotkey::QHotkey(const QKeySequence &sequence, bool autoRegister, QObject *parent) : QHotkey(parent)
{
setShortcut(sequence, autoRegister);
}
QHotkey::QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister, QObject *parent) : QHotkey(parent)
{
setShortcut(keyCode, modifiers, autoRegister);
}
QHotkey::QHotkey(const 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();
} else {
return QKeySequence(_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();
} else if (shortcut.count() > 1) {
qDebug() << "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);
} else {
return true;
}
} else {
qDebug() << "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);
} else {
return true;
}
} else {
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = NativeShortcut();
return true;
}
}
bool QHotkey::setRegistered(bool registered)
{
if (_registered && !registered) {
return QHotkeyPrivate::instance()->removeShortcut(this);
} else if (!_registered && registered) {
if (!_nativeShortcut.isValid()) {
return false;
} else {
return QHotkeyPrivate::instance()->addShortcut(this);
}
} else {
return true;
}
}
// ---------- QHotkeyPrivate implementation ----------
QHotkeyPrivate::QHotkeyPrivate()
{
shortcuts = QMultiHash<QHotkey::NativeShortcut, QHotkey *>();
Q_ASSERT_X(qApp, Q_FUNC_INFO, "QHotkey requires QCoreApplication to be instantiated");
qApp->eventDispatcher()->installNativeEventFilter(this);
}
QHotkeyPrivate::~QHotkeyPrivate()
{
if (!shortcuts.isEmpty()) {
qDebug() << "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();
} else {
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;
} else {
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;
} else {
if (res) {
emit hotkey->registeredChanged(false);
}
return res;
}
}
void QHotkeyPrivate::activateShortcut(QHotkey::NativeShortcut shortcut)
{
QMetaMethod signal = QMetaMethod::fromSignal(&QHotkey::activated);
foreach (QHotkey *hkey, shortcuts.values(shortcut)) {
signal.invoke(hkey, Qt::QueuedConnection);
}
}
bool QHotkeyPrivate::addShortcutInvoked(QHotkey *hotkey)
{
QHotkey::NativeShortcut shortcut = hotkey->_nativeShortcut;
if (!shortcuts.contains(shortcut)) {
if (!registerShortcut(shortcut)) {
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) {
return unregisterShortcut(shortcut);
} else {
return true;
}
}
QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcutInvoked(Qt::Key keycode, Qt::KeyboardModifiers modifiers)
{
bool ok1, ok2 = false;
quint32 k = nativeKeycode(keycode, ok1);
quint32 m = nativeModifiers(modifiers, ok2);
if (ok1 && ok2) {
return QHotkey::NativeShortcut(k, m);
} else {
return QHotkey::NativeShortcut();
}
}
QHotkey::NativeShortcut::NativeShortcut()
{
this->key = Qt::Key_unknown;
this->modifier = Qt::NoModifier;
this->valid = false;
}
QHotkey::NativeShortcut::NativeShortcut(quint32 key, quint32 modifier)
{
this->key = key;
this->modifier = modifier;
this->valid = true;
}
bool QHotkey::NativeShortcut::isValid() const
{
return valid;
}
bool QHotkey::NativeShortcut::operator ==(const QHotkey::NativeShortcut &other) const
{
return (key == other.key) &&
(modifier == other.modifier) &&
valid == other.valid;
}
bool QHotkey::NativeShortcut::operator !=(const QHotkey::NativeShortcut &other) const
{
return (key != other.key) ||
(modifier != other.modifier) ||
valid != other.valid;
}
uint qHash(const QHotkey::NativeShortcut &key)
{
return qHash(key.key) ^ qHash(key.modifier);
}
uint qHash(const QHotkey::NativeShortcut &key, uint seed)
{
return qHash(key.key, seed) ^ qHash(key.modifier, seed);
}