您的位置:首页 > 编程语言 > Qt开发

Qt获取键盘按键事件(Windows API)----StateReader系列

2015-03-17 13:39 2679 查看
Qt对于系统底层,一直没有很好的支持,例如串口并口通信,还有我们经常都会用到的全局热键,等等。既然Qt可能出于某种原因,不对这些进行支持,我们就只能自己写代码,调用系统相关的API了。

需求:获取Caps Lock键的状态,并使程序在后台运行时能够及时得到Caps Lock键的状态。

方法有两种,一是注册全局热键(想法很好,可惜注册后这个键原先的功能就没了,不采用)。二是隔一段时间读取一次按键状态(很好用,而且CPU消耗也不大)

1. 使用RegisterHotKey函数 注册全局热键

BOOL RegisterHotKey( HWND hWnd, int id, UINT fsModifiers, UINT vk );

HWND类型是Windows中的窗口句柄类型,在Qt中,QWidget及其子类均可使用winId()函数得到。

在本文,第二个参数是”virtual key 虚拟键”相对应的数字。

后面两个参数,一个是修饰键,一个是普通按键。例如,假设我们想注册Ctrl+F4这个热键组合,则fsModifiers就是MOD_CONTROL,而vk就是VK_F4。

主要步骤为用RegisterHotKey向系统注册全局的快捷键,然后重载QApplication的winEventFilter函数,并响应msg为WM_HOTKEY时的消息,整个过程类似于在Windows下的OnMessage进行消息响应,只是这次是在Qt中。

//MyApp类
class MyAPP : public QApplication{
.......
virtual bool winEventFilter(MSG *msg, long *result);

signals:
void getF10HotKey();
void getF11HotKey();
};

bool MyApp::winEventFilter(MSG *msg, long *result){
if(WM_HOTKEY == msg->message){
if(msg->wParam == VK_F10){
//qDebug("VK_F10 winEventFilter.");
emit getF10HotKey();
}
if(msg->wParam == VK_F11){
//qDebug("VK_F11 winEventFilter.");
emit getF11HotKey();
}
return true;
}
return false;
}

//QtTopic类
class QtTopic : public QWidget{
public:
void registerGlobalKey();
private slots:
void hotKeyF10Received();
void hotKeyF11Received();
};

void QtTopic::registerGlobalKey(){ //注册全局键
if(RegisterHotKey(this->winId(), 0x79, 0, VK_F10)){//0x79 is VK_F10, wParam is 121
qDebug("F10 registered for QtTopic.");
}
if(RegisterHotKey(this->winId(), 0x7A, 0, VK_F11)){//wParam is 122
qDebug("F11 registered for QtTopic.");
}
}
void QtTopic::hotKeyF10Received(){ //F10被按下
qDebug("F10 received.");
if(box->isChecked()) box->setChecked(false);

void QtTopic::hotKeyF11Received(){
qDebug("F11 received.");
if(!box->isChecked()) box->setChecked(true);
}

//Main
int main(int argc,  char *argv[]){
Q_INIT_RESOURCE(qttopic);
MyApp app(argc, argv);

QtTopic topic;
topic.show();

QObject::connect(&app, SIGNAL(getF10HotKey()), &topic, SLOT(hotKeyF10Received()));
QObject::connect(&app, SIGNAL(getF11HotKey()), &topic, SLOT(hotKeyF11Received()));

return app.exec();
}


2.GetKeyState() 定时读取状态

函数原型 SHORT GetKeyState(int nVirtKey);

其中,形参是虚拟键;

GetKeyState可以返回不同的值来表示键是否被按下、键是否被触发,或者是关闭状态。

进入正题部分:

这里我们继续用Thread来读取按键状态:

基本思路是每隔1s读取一次键盘状态,通过发送信号,来使另一个类中的槽来读取键盘的状态。

#include "windows.h"  //需要加入的头文件


//QueryKeyThread
class QueryKeyThread : public QThread
{
Q_OBJECT
...
public:
void run();
signals:
void QueryResult(bool cap, bool num);
};

void QueryKeyThread::run()
{
while(!stopped)
{
bool caps = false, nums = false;
if(GetKeyState(VK_CAPITAL) & 0x0001)
{
caps = true;
}
if(LOBYTE(GetKeyState(VK_NUMLOCK)))
{
nums = true;
}
emit QueryResult(caps, nums);
msleep(1000);
}
}


//StateReader
class StateReader : public QDialog
{
...
protected slots:
//Thread Back
void QueryResult(bool cap, bool num);
...
};
StateReader::StateReader(QWidget *parent) :
QDialog(parent),
ui(new Ui::StateReader)
{
...
QueryKeyThread *pThread_KeyPress = new QueryKeyThread();
connect(pThread_KeyPress, SIGNAL(QueryResult(bool,bool)),
this, SLOT(QueryResult(bool,bool)));
pThread_KeyPress->start();
...
}

void StateReader::QueryResult(bool cap, bool num)
{
if(cap)
{
qDebug() << "Caps ON";
systemIcon->setIcon(QIcon(":/images/up3.ico"));
systemIcon->setToolTip("Caps On");
ui->checkBoxCap->setChecked(true);
ui->checkBoxCap->setDisabled(true);
}
else
{
qDebug() << "Caps OFF";
systemIcon->setIcon(QIcon(":/images/down3.ico"));
systemIcon->setToolTip("Caps OFF");
ui->checkBoxCap->setChecked(false);
ui->checkBoxCap->setDisabled(true);
}

if(num)
{
ui->checkBoxNum->setChecked(true);
ui->checkBoxNum->setDisabled(true);
}
else
{
ui->checkBoxNum->setChecked(false);
ui->checkBoxNum->setDisabled(true);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: