前言
之间做待办列表的时候提过全局热键的功能,当时说后面会单独讲解跨平台设置全局热键的方法,今天就来兑现当时的承诺。话不多说,先来看一下实现效果:
QxtGlobalShortcut和QHotkey介绍
因为要想实现全局热键功能,无非要对按键事件进行过滤并处理,但是不同平台过滤和处理的方法又不同,所以对系统底层事件了解不是很清楚的话,自己实现起来就很有难度。而且很多人都觉得我就只是想添加一个全局热键而已,没必要那么大费周章吧,那么此时我们就要寻求可用的第三方库了。
github上有很多实现,但是支持跨平台且方便好用、稳定可靠的我只找到了两个,一个就是QxtGlobalShortcut(Qt5版本是QxtGlobalShortcut5),用这个库的人相对也比较多,我今天也主要介绍这种方法,另一个就是QHotkey,该库用的人较少,但是功能也很不错,具有以下特性:
- 在Windows,Mac和X11上均可使用
- 易于使用,可QKeySequence用于轻松快捷输入
- 支持几乎所有常用键(取决于操作系统和键盘布局)
- 允许直接输入键/修饰键组合
- 支持同一快捷方式的多个QHotkey实例(具有优化)
- 线程安全-可以在所有线程上使用(请参阅线程安全部分)
- 如果需要,允许使用本机键码和修饰符
QxtGlobalShortcut项目地址:https://github.com/ddqd/qxtglobalshortcut5
QHotkey项目地址:https://github.com/xtuer/QHotkey
QxtGlobalShortcut使用方法
1、要想使用QxtGlobalShortcut,需要先到上方的github地址中下载该库,然后解压后放入自己的工程路径下,例如我将其放在了工程中的3rd文件中:
2、然后在项目.pro文件中加入下面这句话:
include(3rd/qxtglobalshortcut5/qxt.pri)
当然这里的3rd/qxtglobalshortcut5/qxt.pri是我的路径,大家设置成自己的具体路径即可。
3、然后在需要使用全局热键的文件中添加头文件:
#include “qxtglobalshortcut.h”
4、现在就可以愉快的设置全局热键了,最简单的注册全局热键的方法只需要两行代码即可:
QxtGlobalShortcut *m_pShortcutA = new QxtGlobalShortcut(QKeySequence("Ctrl+A"), this);connect(m_pShortcutA, SIGNAL(activated()), this, SLOT(ctrlA()));
当然这样用有时候也会有一些问题,比如当我要注册的热键已经被占用时,此时会注册失败,但我们又没有任何提示,所以通常我会采用如下方法注册全局热键:
m_pShortcutA = new QxtGlobalShortcut(this);if (m_pShortcutA->setShortcut(QKeySequence("Ctrl+A"))) connect(m_pShortcutA, SIGNAL(activated()), this, SLOT(ctrlA()));else g_MainWin->myMessageBox(1, "ctrl+A 快捷键已占用", 1);
除了注册热键,QxtGlobalShortcut还提供了setEnabled(bool)方法,该方法可以设置某个全局热键
是否可用:
m_pShortcutA->setEnabled(false);
那么注册完全局热键后,如果我不想用了,或者程序退出时要怎么反注册呢?QxtGlobalShortcut虽然有反注册功能unsetShortcut(),但其是一个私有接口,不对外开发,但是查看源码发现,QxtGlobalShortcut析构时会自动执行发注册操作,所以我们不必再做处理:
QxtGlobalShortcut::~QxtGlobalShortcut(){ if (qxt_d().key != 0) qxt_d().unsetShortcut();}
如果真的需要在程序运行中使某个全局热键无效的话,可以使用我们上面说的setEnabled()函数。
示例代码
#ifndef GLOBALSHORTCUT_H#define GLOBALSHORTCUT_H#include #include "qxtglobalshortcut.h"#include #include //全局热键class GlobalShortcut : public QWidget{ Q_OBJECTpublic: explicit GlobalShortcut(QWidget *parent = 0);signals:public slots: void setShortcut(); //设置全局热键 void setShortcutEnabled(); //设置全局热键是否有效 void ctrlA(); //按下Ctrl+A响应 void ctrlB(); //按下Ctrl+B响应private: QPushButton * m_pSetShortcut_Button; QLabel *m_pLabel; QPushButton * m_psetEnabled_Button; QxtGlobalShortcut *m_pShortcutA; QxtGlobalShortcut *m_pShortcutB;};#endif // GLOBALSHORTCUT_H
#include "GlobalShortcut.h"#include "widget.h"#include GlobalShortcut::GlobalShortcut(QWidget *parent) : QWidget(parent){ this->resize(350, 200); this->setAttribute(Qt::WA_DeleteOnClose); this->setWindowTitle("全局热键"); m_pSetShortcut_Button = new QPushButton("注册全局热键 Ctrl+A、Ctrl+B", this); m_psetEnabled_Button = new QPushButton("设置全局热键无效", this); m_pLabel = new QLabel(this); m_pLabel->setAlignment(Qt::AlignCenter); QFont font; font.setPointSize(18); m_pLabel->setFont(font); QVBoxLayout *pVLayout = new QVBoxLayout(); pVLayout->addWidget(m_pSetShortcut_Button); pVLayout->addWidget(m_psetEnabled_Button); pVLayout->addWidget(m_pLabel); this->setLayout(pVLayout); connect(m_pSetShortcut_Button, SIGNAL(clicked(bool)), this, SLOT(setShortcut())); connect(m_psetEnabled_Button, SIGNAL(clicked(bool)), this, SLOT(setShortcutEnabled()));}//设置全局热键void GlobalShortcut::setShortcut(){ //方法1 //m_pShortcutA = new QxtGlobalShortcut(QKeySequence("Ctrl+A"), this); //方法2 m_pShortcutA = new QxtGlobalShortcut(this); if (m_pShortcutA->setShortcut(QKeySequence("Ctrl+A"))) { connect(m_pShortcutA, SIGNAL(activated()), this, SLOT(ctrlA())); } else g_MainWin->myMessageBox(1, "ctrl+A 快捷键已占用", 1); m_pShortcutB = new QxtGlobalShortcut(this); if (m_pShortcutB->setShortcut(QKeySequence("Ctrl+B"))) { connect(m_pShortcutB, SIGNAL(activated()), this, SLOT(ctrlB())); m_pLabel->setText("全局热键可使用"); QPalette palette; palette.setColor(QPalette::WindowText, Qt::blue); m_pLabel->setPalette(palette); } else g_MainWin->myMessageBox(1, "ctrl+B 快捷键已占用", 1);}//取消全局热键void GlobalShortcut::setShortcutEnabled(){ bool bFlag = m_pShortcutA->isEnabled(); bFlag = !bFlag; m_pShortcutA->setEnabled(bFlag); m_pShortcutB->setEnabled(bFlag); if (bFlag) { m_psetEnabled_Button->setText("设置全局热键无效"); m_pLabel->setText("全局热键可使用"); QPalette palette; palette.setColor(QPalette::WindowText, Qt::blue); m_pLabel->setPalette(palette); } else { m_psetEnabled_Button->setText("设置全局热键有效"); m_pLabel->setText("全局热键已禁用"); QPalette palette; palette.setColor(QPalette::WindowText, Qt::red); m_pLabel->setPalette(palette); }}//按下Ctrl+A响应void GlobalShortcut::ctrlA(){ g_MainWin->myMessageBox(0, "你按下了 ctrl+A 快捷键", 1);}//按下Ctrl+B响应void GlobalShortcut::ctrlB(){ g_MainWin->myMessageBox(0, "你按下了 ctrl+B 快捷键", 1);}