Qt第三方库QHotKey设置小键盘数字快捷键

一、看了一圈没有找到可以设置小键盘的情况。

这两天在研究快捷键的使用。发现qt的里的快捷键不是全局的。找了两个第三方快捷键QHotKey,还有一个QxtGlobalShortcut。但是这两个都不能设置小键盘的数字。

比如QKeySequenceEdit (Ctrl+1) 这个快捷键,这个1只会响应主键盘的数字1对应的键盘码是0x31.而小键盘的1键盘码是0x61.

所以就算是设置成功了,再按快捷键的时候也是响应的主键盘的,按小键盘没用。

二、准备工作

0、键盘码对应关系

 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_OBJECTfriend class QHotkeyPrivate;//! Specifies whether this hotkey is currently registered or notQ_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)//! Holds the shortcut this hotkey will be triggered onQ_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut RESET resetShortcut)public://! Defines shortcut with native keycodesclass QHOTKEY_SHARED_EXPORT NativeShortcut {public://! The native keycodequint32 key;//! The native modifiersquint32 modifier;//! Creates an invalid native shortcutNativeShortcut();//! Creates a valid native shortcut, with the given key and modifiersNativeShortcut(quint32 key, quint32 modifier = 0);//! Checks, whether this shortcut is valid or notbool isValid() const;//! Equality operatorbool operator ==(const NativeShortcut &other) const;//! Inequality operatorbool operator !=(const NativeShortcut &other) const;private:bool valid;};//! Constructorexplicit QHotkey(QObject *parent = Q_NULLPTR);//! Constructs a hotkey with a shortcut and optionally registers itexplicit QHotkey(const QKeySequence &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);//! Constructs a hotkey with a key and modifiers and optionally registers itexplicit QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false, QObject *parent = Q_NULLPTR);//! Constructs a hotkey from a native shortcut and optionally registers itexplicit QHotkey(const NativeShortcut &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);//! Destructor~QHotkey();//! READ-Accessor for QHotkey::registeredbool isRegistered() const;//! READ-Accessor for QHotkey::shortcut - the key and modifiers as a QKeySequenceQKeySequence shortcut() const;//! READ-Accessor for QHotkey::shortcut - the key onlyQt::Key keyCode() const;//! READ-Accessor for QHotkey::shortcut - the modifiers onlyQt::KeyboardModifiers modifiers() const;//! Get the current native shortcutNativeShortcut currentNativeShortcut() const;public slots://! WRITE-Accessor for QHotkey::registeredbool setRegistered(bool registered);//! WRITE-Accessor for QHotkey::shortcutbool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);//! WRITE-Accessor for QHotkey::shortcutbool setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false);//! RESET-Accessor for QHotkey::shortcutbool resetShortcut();//! Set this hotkey to a native shortcutbool setNativeShortcut(NativeShortcut nativeShortcut, bool autoRegister = false);signals://! Will be emitted if the shortcut is pressedvoid activated(QPrivateSignal);//! NOTIFY-Accessor for QHotkey::registeredvoid 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;} elsereturn 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);elsereturn 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};elsereturn {};
}

到这里已经大致知道什么原因了。

在转换的时候 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 keysswitch (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 <QKeySequenceEdit>
#include <QKeyEvent>class CustomKeySeqEdit  : public QKeySequenceEdit
{Q_OBJECTpublic: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 <windows.h>
#include <windowsx.h>  //提供消息关键字的识别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 <QDebug>
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<MSG*>(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使用小键盘的数字了。

可以正常拾取坐标啦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/28348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】SpringBoot:构建实时聊天应用

文章目录 引言项目初始化添加依赖 配置WebSocket创建WebSocket配置类创建WebSocket处理器 创建前端页面创建聊天页面 测试与部署示例&#xff1a;编写单元测试 部署扩展功能用户身份验证消息持久化群组聊天 结论 引言 随着实时通信技术的快速发展&#xff0c;聊天应用在现代We…

Luma AI如何注册:文生视频领域的新星

文章目录 Luma AI如何注册&#xff1a;文生视频领域的新星一、Luma 注册方式二、Luma 的效果三、Luma 的优势四、Luma 的功能总结 Luma AI如何注册&#xff1a;文生视频领域的新星 近年来&#xff0c;Luma AI 凭借其在文生视频领域的创新技术&#xff0c;逐渐成为行业的新星。…

MySQL基础——多表查询和事务

目录 1多表关系 2多表查询概述 3连接查询 3.1内连接 3.2左外连接 3.3右外连接 3.4自连接 4联合查询 5子查询 5.1标量子查询(子查询结果为单个值) 5.2列子查询(子查询结果为一列) 5.3行子查询(子查询结果为一行) 5.4表子查询(子查询结果为多行多列) 6事务简介和操…

vulnhub靶场-xxe打靶教程

目录 靶机导入 信息收集 发现IP 端口扫描 目录扫描 漏洞利用 靶机下载地址&#xff1a;XXE Lab: 1 ~ VulnHub 靶机导入 导入虚拟机 开启虚拟机 信息收集 发现IP arp-scan -l 发现靶机IP是192.168.202.150 端口扫描 使用nmap进行扫描 nmap -sS -A 192.168.202.150 …

EasyRecovery2024数据恢复神器#电脑必备良品

EasyRecovery数据恢复软件&#xff0c;让你的数据重见天日&#xff01; 大家好&#xff01;今天我要给大家种草一个非常实用的软件——EasyRecovery数据恢复软件&#xff01;你是不是也曾经遇到过不小心删除了重要的文件&#xff0c;或者电脑突然崩溃导致数据丢失的尴尬情况呢&…

初识PHP

一、格式 每行以分号结尾 <?phpecho hello; ?>二、echo函数和print函数 作用&#xff1a;两个函数都是输出内容到页面中&#xff0c;多用于代码调试。 <?php echo "<h1 styletext-align: center;>test</h1>"; print "<h1 stylet…

【vue3中使用$refs】

在使用uniapp官网里的uni-popup弹出层组件时&#xff0c;要将vue2转换成vue3,&#xff0c;这里遇到了一个问题&#xff1a;vue2可以通过this访问到绑定的ref&#xff0c;但是vue3没有了this,应该怎么办呢&#xff1f; 解决方法&#xff1a; !

Footer组件在home 、search 显示,在登录、注册隐藏

footer组件显示与隐藏 我们可以根据组件身上的$route获取当前路由的信息&#xff0c;通过路由路径判断Footer显示与隐藏。配置的路由的时候&#xff0c;可以给路由添加路由元信息【meta】&#xff0c;路由需要配置对象&#xff0c;它的key不能瞎写、胡写、乱写 <template&…

基于 Nginx Ingress + 云效 AppStack 实现灰度发布

作者&#xff1a;子丑 场景简介 灰度发布是降低生产部署风险&#xff0c;提升线上服务稳定性的重要手段&#xff0c;这在当前快速迭代的软件研发中尤为重要。相对于 K8s 默认的滚动部署或者简单的 Pod 分批&#xff0c;基于流量特征的灰度发布验证更精准&#xff0c;风险更低…

从 Acme.Sh V3.0 说说 ZeroSSL

熟悉明月的都知道&#xff0c;明月一直都在使用 acme.sh 作为服务器端申请、部署、续期免费 SSL 证书的主要工具&#xff0c;今天在帮一个站长申请 SSL 证书的时候发现 acme.sh v3.0 开始默认的免费 SSL 证书变更为&#xff1a;ZeroSSL 了&#xff0c;这个 ZeroSSL 其实跟明月一…

在 C++ 中使用不同平台的时间函数及比较

在 C 编程中&#xff0c;时间函数的选择对于性能测量、任务调度和时间戳记录至关重要。不同的操作系统提供了不同的时间函数&#xff0c;同时在同一个平台上&#xff0c;也可能有多种不同的时间函数可供选择。本文将介绍在 C 中常用的时间函数&#xff0c;并比较它们在不同平台…

通俗范畴论2 有向图与准范畴

退一步海阔天空&#xff0c;在正式进入范畴论之前&#xff0c;我们可以重新审视一下我们是如何认识世界的&#xff0c;有了这个对人类认识世界过程的底层理解&#xff0c;可以帮助我们更好地理解范畴论。 对于人类认识世界&#xff0c;最神奇的一点就是这个世界居然是可以认识…

Elasticsearch 认证模拟题 - 22

一、题目 索引 task 索引中文档的 fielda 字段内容包括了 hello & world&#xff0c;索引后&#xff0c;要求使用 match_phrase query 查询 hello & world 或者 hello and world 都能匹配该文档 1.1 考点 分词器 1.2 答案 # 创建符合条件的 task 索引&#xff0c;…

算法人生(22):从“生成对抗网络”看“逆商提升”

​ 在图像生成与编辑、音频合成、视频生成领域里&#xff0c;有一个非常重要的深度学习方法——生成对抗网络&#xff08;简称GANs&#xff09;&#xff0c;它是由两个神经网络组成的模型&#xff0c;分别为生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discr…

采煤vr事故灾害应急模拟救援训练降低生命财产损失

在化工工地&#xff0c;设备繁多、环境复杂&#xff0c;潜藏着众多安全隐患&#xff0c;稍有不慎便可能引发安全事故。为了保障工地的安全&#xff0c;我们急需一套全面、高效的安全管理解决方案。web3d开发公司深圳华锐视点研发的工地安全3D模拟仿真隐患排查系统&#xff0c;正…

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类?

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类&#xff1f; 制作耳机壳的胶粘剂有很多种类&#xff0c;常见的有环氧树脂胶水、UV树脂胶、快干胶、热熔胶等。 这些胶粘剂都有不同的特点和适用场景&#xff0c;可以根据自己的需求选择合适的类型。 例如&#xff1a; 环氧树脂…

pdf转图片,pdf转图片在线转

pdf转图片的方法&#xff0c;对于许多人来说可能是一个稍显陌生的操作。然而&#xff0c;在日常生活和工作中&#xff0c;我们有时确实需要将pdf文件转换为图片格式&#xff0c;以便于在特定的场合或平台上进行分享、展示或编辑。以下&#xff0c;我们将详细介绍一个pdf转成图片…

用宝塔部署vue+springboot上线公网详细步骤

首先自己在腾讯云中按照教程安装好宝塔。这是宝塔面板&#xff0c;获取登录宝塔的网址和账号密码。 1.在navicat新建数据库 如果出现权限问题&#xff0c;可以在宝塔数据库面板phpMyAdmin中进行权限设置 navicat可以修改用户权限 2.在宝塔面板新建数据库 3.将前端打包的dist文件…

linux 部署瑞数6实战(维普,药监局)第一部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx 本文章未经许可禁止转载&…

【星海随笔】云解决方案学习日志篇(二) kafka、Zookeeper、Fielbeat

Elastic 中国社区官方博客 https://blog.csdn.net/ubuntutouch/category_9209092.html Kafka kafka的源代码是基于Scala语言编写的&#xff0c;运行在Java虚拟机&#xff08;即:JVM&#xff09;上。因此&#xff0c;在安装kafka之前需要先安装JDK Kafka 为什么依赖 Zookeepe…