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

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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值