这两天在研究快捷键的使用。发现qt的里的快捷键不是全局的。找了两个第三方快捷键QHotKey,还有一个QxtGlobalShortcut。但是这两个都不能设置小键盘的数字。
比如QKeySequenceEdit (Ctrl+1) 这个快捷键,这个1只会响应主键盘的数字1对应的键盘码是0x31.而小键盘的1键盘码是0x61.
所以就算是设置成功了,再按快捷键的时候也是响应的主键盘的,按小键盘没用。
Qt中的Qt::key0-9 对应的是0x30-0x39
windows 下 主键盘上的数字0-9对应的是0x30-0x39 刚好和qt的一致。
windwos下 小键盘上的数字0-9对应的键盘码是0x60-0x69.
看了Qt的Qt::key 枚举发现并没有 VK_NUMPAD0=0x60的枚举值。
仅有的0x60也是对应 Qt::Key_QuoteLeft并不是对应的小键盘的VK_NUMPAD0, 0x61-0x69是缺失状态。
还有一点需要注意的是,在看qt枚举的时候,发现在键盘(NumLock)不选中的情况下的小键盘0-9的码值。
对应的QKeySequenceEdit表现为:
alt+1->
alt+9->
其他的可以自己试试。但是这个不是我想要的。
是不是qt没有枚举全windows键盘码,导致第三方库都办法响应小键盘的0-9?如果我把小键盘码搞进去是不是就能响应了?
接下来就查看源码。
在注册快捷键的时候用的是这两个函数 setShortcut 以及他的重载。
-
- //! A class to define global, systemwide Hotkeys
- class QHOTKEY_SHARED_EXPORT QHotkey : public QObject
- {
- Q_OBJECT
- friend class QHotkeyPrivate;
-
- //! Specifies whether this hotkey is currently registered or not
- Q_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)
- //! Holds the shortcut this hotkey will be triggered on
- Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut RESET resetShortcut)
-
- public:
- //! Defines shortcut with native keycodes
- class QHOTKEY_SHARED_EXPORT NativeShortcut {
- public:
- //! The native keycode
- quint32 key;
- //! The native modifiers
- quint32 modifier;
-
- //! Creates an invalid native shortcut
- NativeShortcut();
- //! Creates a valid native shortcut, with the given key and modifiers
- NativeShortcut(quint32 key, quint32 modifier = 0);
-
- //! Checks, whether this shortcut is valid or not
- bool isValid() const;
-
- //! Equality operator
- bool operator ==(const NativeShortcut &other) const;
- //! Inequality operator
- bool operator !=(const NativeShortcut &other) const;
-
- private:
- bool valid;
- };
-
- //! Constructor
- explicit QHotkey(QObject *parent = Q_NULLPTR);
- //! Constructs a hotkey with a shortcut and optionally registers it
- explicit QHotkey(const QKeySequence &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);
- //! Constructs a hotkey with a key and modifiers and optionally registers it
- explicit QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false, QObject *parent = Q_NULLPTR);
- //! Constructs a hotkey from a native shortcut and optionally registers it
- explicit QHotkey(const NativeShortcut &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);
- //! Destructor
- ~QHotkey();
-
- //! READ-Accessor for QHotkey::registered
- bool isRegistered() const;
- //! READ-Accessor for QHotkey::shortcut - the key and modifiers as a QKeySequence
- QKeySequence shortcut() const;
- //! READ-Accessor for QHotkey::shortcut - the key only
- Qt::Key keyCode() const;
- //! READ-Accessor for QHotkey::shortcut - the modifiers only
- Qt::KeyboardModifiers modifiers() const;
-
- //! Get the current native shortcut
- NativeShortcut currentNativeShortcut() const;
-
- public slots:
- //! WRITE-Accessor for QHotkey::registered
- bool setRegistered(bool registered);
-
- //! WRITE-Accessor for QHotkey::shortcut
- bool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);
-
- //! WRITE-Accessor for QHotkey::shortcut
- bool setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false);
- //! RESET-Accessor for QHotkey::shortcut
- bool resetShortcut();
-
- //! Set this hotkey to a native shortcut
- bool setNativeShortcut(NativeShortcut nativeShortcut, bool autoRegister = false);
-
- signals:
- //! Will be emitted if the shortcut is pressed
- void activated(QPrivateSignal);
-
- //! NOTIFY-Accessor for QHotkey::registered
- void registeredChanged(bool registered);
-
- private:
- Qt::Key _keyCode;
- Qt::KeyboardModifiers _modifiers;
-
- NativeShortcut _nativeShortcut;
- bool _registered;
- };
挑一个看看源码
- bool QHotkey::setShortcut(const QKeySequence &shortcut, bool autoRegister)
- {
- if(shortcut.isEmpty()) {
- return resetShortcut();
- } else 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);
- }
发现也是解析出来key(0-9 a-z) 和 组合键。(ctrl shift alt ...)
然后调用了 setShortCut.
-
- 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 {
- qCWarning(logQHotkey) << "Unable to map shortcut to native keys. Key:" << keyCode << "Modifiers:" << modifiers;
- _keyCode = Qt::Key_unknown;
- _modifiers = Qt::NoModifier;
- _nativeShortcut = NativeShortcut();
- return false;
- }
- }
看了这两个函数就知道了。问题肯定是出在这里了。解析完是Qt::key 然而Qt::key中并没有小键盘的数字。所以?? 那是肯定不会响应的。
那么问题来了,怎么解决。
我的方法简单粗暴。直接把VK_NUMPAD0-9 强制转换成 Qt::key 但是这种会覆盖那个Qt::key中的0x60(Qt::Key_QuoteLeft) ,但是不管了。先搞再说。
于是我测试了一下:
- QKeySequence keySequenceFromString = (QKeySequence(Qt::CTRL , Qt::ALT , VK_NUMPAD1));
-
- m_pMousePointGetHot->setShortcutEx(keySequenceFromString, true))
发现不行会出错。
Keysequences with multiple shortcuts are not allowed! " "Only the first shortcut will be used!
这两句话就是在解析的时候 之后调用setShortcut的时候 函数头出现的。意思很清晰。
到这里。麻了。难道思路有问题。
于是我看到了第二个setShortcut函数。
bool QHotkey::setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister)
上面的图片有内容。
我想着抛弃Qt::key中的0-9数字,把他转换成VK_NUMPAD0-9。搞个转换函数强制塞进去试试
-
- Qt::Key TransNumToPadNum(const Qt::Key k)
- {
- switch (k)
- {
- case Qt::Key_0:
- return Qt::Key(VK_NUMPAD0);
- break;
- case Qt::Key_1:
- return Qt::Key(VK_NUMPAD1);
- break;
- case Qt::Key_2:
- return Qt::Key(VK_NUMPAD2);
- break;
- case Qt::Key_3:
- return Qt::Key(VK_NUMPAD3);
- break;
- case Qt::Key_4:
- return Qt::Key(VK_NUMPAD4);
- break;
- case Qt::Key_5:
- return Qt::Key(VK_NUMPAD5);
- break;
- case Qt::Key_6:
- return Qt::Key(VK_NUMPAD6);
- break;
- case Qt::Key_7:
- return Qt::Key(VK_NUMPAD7);
- break;
- case Qt::Key_8:
- return Qt::Key(VK_NUMPAD8);
- break;
- case Qt::Key_9:
- return Qt::Key(VK_NUMPAD9);
- break;
- default:
- return k;
- break;
- }
- }
雅黑,可以了,发现不报错了。
但是快捷键按键没有效果....
于是就跟进去看看里面的源码:可以跟着看。
QHotkey::setShortcut ->
QHotkeyPrivate::instance()->nativeShortcut -> 这里判断了按键是否有效。
QHotkeyPrivate::nativeShortcutInvoked->
- QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcutInvoked(Qt::Key keycode, Qt::KeyboardModifiers modifiers)
- {
- bool ok1, ok2 = false;
- auto k = nativeKeycode(keycode, ok1);
- auto m = nativeModifiers(modifiers, ok2);
- if(ok1 && ok2)
- return {k, m};
- else
- return {};
- }
到这里已经大致知道什么原因了。
在转换的时候 ok1是false的。就看看nativeKeycode:
这里就是根源了。他把qt的key对应起来windows的键盘码做了一个转换。问题找到了。
就是在这里地方。还是因为qt里的qt::key 没有小键盘。所以根本不可能映射。
于是我修改了一下这个对应关系,新增VK_NUMPAD0-9。
- quint32 QHotkeyPrivateWin::nativeKeycode(Qt::Key keycode, bool &ok)
- {
- ok = true;
- switch (keycode)
- {
- case VK_NUMPAD0:
- case VK_NUMPAD1:
- case VK_NUMPAD2:
- case VK_NUMPAD3:
- case VK_NUMPAD4:
- case VK_NUMPAD5:
- case VK_NUMPAD6:
- case VK_NUMPAD7:
- case VK_NUMPAD8:
- case VK_NUMPAD9:
- return keycode;
- default:
- break;
- }
- if(keycode <= 0xFFFF) {//Try to obtain the key from it's "character"
- const SHORT vKey = VkKeyScanW(keycode);
- if(vKey > -1)
- return LOBYTE(vKey);
- }
-
- //find key from switch/case --> Only finds a very small subset of keys
- switch (keycode)
- ...
-
- }
这样外面的key如果是小键盘的话就不会出错了。
再次测试。响应了,他可以了。完美,牛逼!!!
- QKeySequence keySequenceFromString = "Ctrl+Alt+1";
-
- Qt::Key keyCode = Qt::Key(k[0] & ~Qt::KeyboardModifierMask);
- Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(k[0] & Qt::KeyboardModifierMask);
- keyCode = ui.keySequenceEdit->TransNumToPadNum(keyCode);
- QKeySequence ktmpex(keyCode, modifiers);
- ktmp = ktmpex;
- // 报错Keysequences with multiple shortcuts are not allowed! "
- // "Only the first shortcut will be used!
- //m_pMousePointGetHot->setShortcutWithPad(ktmp, true);
- m_pMousePointGetHot->setShortcut(keyCode, modifiers, true);
-
- // 这里要把组合键和单键摘出来,调用另外一个setShortCut
在qhotkey.h中我新建一个注册快捷键的函数(其实搞了两个,但是用的是红色圈住的)
实现如下:这里有个弊端就是小键盘的字符必须
- /*
- 包含小键盘数字, 但是小键盘数字仅作为最后一个快捷按键使用
- */
- bool QHotkey::setShortcutWithPad(const QKeySequence& shortcut, bool autoRegister) {
- if (shortcut.isEmpty()) {
- return resetShortcut();
- }
- else if (shortcut.count() > 1) {
- qCWarning(logQHotkey, "Keysequences with multiple shortcuts are not allowed! "
- "Only the first shortcut will be used!");
- }
- // 小键盘数字
- quint32 keyCode = shortcut[shortcut.count() -1];
-
- return setShortcut((Qt::Key)keyCode,
- Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask),
- autoRegister);
- }
直接用这个bool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);这个函数也行,但是传递keycode的时候要传递 小键盘的0-9 VK_NUMPAD0-9。
由于Qt里是用的QKeySequenceEdit,但是他无法键入小键盘的keycode.所以重新简单集成封装一下:
CustomKeySeqEdit.h
- #pragma once
-
- #include
- #include
-
- class CustomKeySeqEdit : public QKeySequenceEdit
- {
- Q_OBJECT
-
- public:
- CustomKeySeqEdit(QWidget *parent);
- ~CustomKeySeqEdit();
- void setKeyNumPadNumber(bool b);
- bool isKeyNumPadNumber();
- Qt::Key TransNumToPadNum(const Qt::Key k);
- private:
- void keyPressEvent(QKeyEvent* e) override;
- //virtual bool nativeEvent(const QByteArray& eventType, void* message, long* result);
- private:
- bool m_isNumPad = false;
- };
CustomKeySeqEdit.cpp
- #include "CustomKeySeqEdit.h"
- #include
- #include
//提供消息关键字的识别 -
-
- CustomKeySeqEdit::CustomKeySeqEdit(QWidget *parent)
- : QKeySequenceEdit(parent)
- {
- //this->installEventFilter(this);
- }
-
- CustomKeySeqEdit::~CustomKeySeqEdit()
- {}
-
- void CustomKeySeqEdit::setKeyNumPadNumber(bool b)
- {
- m_isNumPad = b;
- }
-
- bool CustomKeySeqEdit::isKeyNumPadNumber()
- {
- return m_isNumPad;
- }
-
- // 这个很垃圾,不应该放在这里。但是为了测试快些就随便放了
- Qt::Key CustomKeySeqEdit::TransNumToPadNum(const Qt::Key k)
- {
- switch (k)
- {
- case Qt::Key_0:
- return Qt::Key(VK_NUMPAD0);
- break;
- case Qt::Key_1:
- return Qt::Key(VK_NUMPAD1);
- break;
- case Qt::Key_2:
- return Qt::Key(VK_NUMPAD2);
- break;
- case Qt::Key_3:
- return Qt::Key(VK_NUMPAD3);
- break;
- case Qt::Key_4:
- return Qt::Key(VK_NUMPAD4);
- break;
- case Qt::Key_5:
- return Qt::Key(VK_NUMPAD5);
- break;
- case Qt::Key_6:
- return Qt::Key(VK_NUMPAD6);
- break;
- case Qt::Key_7:
- return Qt::Key(VK_NUMPAD7);
- break;
- case Qt::Key_8:
- return Qt::Key(VK_NUMPAD8);
- break;
- case Qt::Key_9:
- return Qt::Key(VK_NUMPAD9);
- break;
- default:
- return k;
- break;
- }
- }
-
- #include
- void CustomKeySeqEdit::keyPressEvent(QKeyEvent* e)
- {
- if (e->key() < Qt::Key_0 || e->key() > Qt::Key_9) {
- return QKeySequenceEdit::keyPressEvent(e);
- }
- // 我们只关心小键盘
- int keyCode = e->nativeVirtualKey();
- m_isNumPad = false;
- qDebug() <<"key:" << e->key() << keyCode;
- if (keyCode >= 0x60 && keyCode <= 0x69) {
- m_isNumPad = true;
- }
- QKeySequenceEdit::keyPressEvent(e);
-
- }
- /* 这个不行,不会响应。
- bool CustomKeySeqEdit::nativeEvent(const QByteArray& eventType, void* message, long* result)
- {
- MSG* msg = static_cast
(message); - switch (msg->message)
- {
- case WM_KEYDOWN:
- {
- m_isNumPad = false;
- int value = msg->wParam;
- if (value >= VK_NUMPAD0 && value <= VK_NUMPAD9) {
- m_isNumPad = true;
- }
- }
- break;
- default:
- break;
- }
- return false;
- }
- */
使用:
至此,算是愉快结束了。 可以用QKeySequenceEdit使用小键盘的数字了。
可以正常拾取坐标啦!!!