打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Windows API 教程(八) 注册快捷键

Windows API 教程(八) 注册快捷键

茵蒂克丝

注册快捷键与hook监听键盘的区别

快捷键注册是针对某一个窗口的,注册之后当这个窗口收到快捷键,操作系统就会发送 WM_HOTKEY 消息来通知该窗口。所以快捷键注册是没办法监听全局的,比如你要定义一个快捷键 Ctrl + ` 在桌面上也能调出你的窗口,可是这个消息是发给桌面这个程序去了没办法触发你的程序。 快捷键收到消息之后消息会被转发给注册的hwnd 相当于截断了消息,如果要做全局监听的话还是推荐用 hook。

控制台注册快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <Windows.h>
 
int main()
{
    MSG msg = {0};
    HWND hConsole = GetActiveWindow(); // 获取当前显示窗口的句柄(即控制台这个窗口的句柄)
 
    RegisterHotKey(
        hConsole,   // 注册快捷键的窗口句柄
        1,          // 热键标识符
        MOD_CONTROL | MOD_NOREPEAT, // Ctrl 键  No Repeat 不重复发送
        'A'         // A
    );  // Ctrl + A
 
    RegisterHotKey(hConsole, 2, MOD_CONTROL | MOD_NOREPEAT,'B');// Ctrl + B
    RegisterHotKey(hConsole, 3, MOD_ALT | MOD_NOREPEAT,'A');    // Alt + A
    RegisterHotKey(hConsole, 4, MOD_ALT | MOD_NOREPEAT,'B');    // Alt + B
    RegisterHotKey(hConsole, 5, MOD_NOREPEAT,'S');              // 直接按 S
 
     
    // 循环获取操作系统发来的消息
    while (GetMessage(&msg, NULL, 0, 0) != 0)
    {
        // 当收到快捷键消息时
        if (msg.message == WM_HOTKEY)
        {
            switch(msg.wParam)
            {
                case 1:
                    printf("Ctrl + A 被按下! \n\n");
                break;
 
                case 2:
                    printf("Ctrl + B 被按下! \n\n");
                break;
 
                case 3:
                    printf("Alt + A 被按下! \n\n");
                break;
                 
                case 4:
                    printf("Alt + B 被按下! \n\n");
                break;
 
                case 5:
                    printf("S 被按下! \n\n");
                break;
            }
        }
    }
}

窗口注册快捷键

在window窗体开发中,窗口过程函数中实际上还可以通过 WM_KEYUP WM_KEYDOWN 等消息获取到用户的按键,大家可以通过如下类似的代码来查看窗口收到的消息(其实控制台下也是可以这样拿的)

1
2
3
4
case WM_KEYDOWN:
    wsprintf(text, "wParam : 0x%x  lParam : 0x%x", wParam, lParam);
    echo(text);
break;

不过这种的缺点也是很明显的,就是复合键等快捷键定义没有使用 WM_HOTKEY 方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <Windows.h>
 
void echo(LPSTR str)
{
    MessageBox(NULL, str, TEXT("提示"), MB_OK);
}
 
// 5. 窗口过程处理
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{  
    CHAR text[50];
    switch(msg)
    {
    // 窗口创建消息
    case WM_CREATE:
        RegisterHotKey(
            hwnd,   // 注册快捷键的窗口句柄
            1,      // 热键标识符避免热键冲突
            MOD_CONTROL | MOD_NOREPEAT, // Ctrl 键  No Repeat 不重复发送
            'A'     // A
            ); // Ctrl + A
        RegisterHotKey(hwnd, 2, MOD_CONTROL | MOD_NOREPEAT,'B');// Ctrl + B
        RegisterHotKey(hwnd, 3, MOD_ALT | MOD_NOREPEAT,'A');    // Alt + A
        RegisterHotKey(hwnd, 4, MOD_ALT | MOD_NOREPEAT,'B');    // Alt + B
        RegisterHotKey(hwnd, 5, MOD_NOREPEAT,'S');              // 直接按 S
    break;
 
    // 快捷键消息
    case WM_HOTKEY:
 
        switch(wParam)
        {
            case 1:
                printf("Ctrl + A 被按下! \n\n");
            break;
 
            case 2:
                printf("Ctrl + B 被按下! \n\n");
            break;
 
            case 3:
                printf("Alt + A 被按下! \n\n");
            break;
             
            case 4:
                printf("Alt + B 被按下! \n\n");
            break;
 
            case 5:
                printf("S 被按下! \n\n");
            break;
        }      
    break;
 
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;
    char text[30];
 
    const char szClassName[] = "myWindowClass";
 
    // 1. 设置注册窗口结构体
    wc.cbSize        = sizeof(WNDCLASSEX);              // 注册窗口结构体的大小
    wc.style         = 0;                               // 窗口的样式
    wc.lpfnWndProc   = WndProc;                         // 指向窗口处理过程的函数指针
    wc.cbClsExtra    = 0;                               // 指定紧跟在窗口类结构后的附加字节数
    wc.cbWndExtra    = 0;                               // 指定紧跟在窗口事例后的附加字节数
    wc.hInstance     = hInstance;                       // 本模块的实例句柄
    wc.hIcon         = LoadIcon(hInstance, IDI_APPLICATION);    // 图标的句柄
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);     // 光标的句柄
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);        // 背景画刷的句柄
    wc.lpszMenuName  = NULL;                            // 指向菜单的指针
    wc.lpszClassName = szClassName;                     // 指向类名称的指针
    wc.hIconSm       = LoadIcon(hInstance, IDI_APPLICATION);    // 和窗口类关联的小图标
 
    // 2. 使用【窗口结构体】注册窗口
    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
 
    // 3. 创建窗口
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,       // 窗口的扩展风格
        szClassName,            // 指向注册类名的指针
        TEXT("窗口标题"),       // 指向窗口名称的指针
        WS_OVERLAPPEDWINDOW,    // 窗口风格
        CW_USEDEFAULT, CW_USEDEFAULT, 350, 200, // 窗口的 x,y 坐标以及宽高
        NULL,                   // 父窗口的句柄
        NULL,                   // 菜单的句柄
        hInstance,              // 应用程序实例的句柄
        NULL                    // 指向窗口的创建数据
        );
 
    if(hwnd == NULL)
    {
        MessageBox(NULL, TEXT("窗口创建失败"), TEXT("错误"),MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
 
    // 4. 显示窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
 
    // 6. 消息循环
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

Ctrl + Alt 等复杂组合键

还是在控制台下编写例子,其实没有差多少

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <Windows.h>
 
int main()
{
    MSG msg = {0};
    HWND hConsole = GetActiveWindow();
 
    // Ctrl + D
    RegisterHotKey(hConsole,1,MOD_CONTROL | MOD_NOREPEAT,'D');
    // Win键 + Z
    RegisterHotKey(hConsole,2,MOD_WIN | MOD_NOREPEAT,'Z');
    // Ctrl + Alt + S
    RegisterHotKey(hConsole,3,MOD_CONTROL | MOD_ALT | MOD_NOREPEAT,'S');
    // Ctrl + Alt + Shift + A
    RegisterHotKey(hConsole,4,MOD_CONTROL | MOD_ALT | MOD_SHIFT | MOD_NOREPEAT,'A');
     
    // 循环获取操作系统发来的消息
    while (GetMessage(&msg, NULL, 0, 0) != 0)
    {
        // 当收到快捷键消息时
        if (msg.message == WM_HOTKEY)
        {
            printf("收到 WM_HOTKEY 快捷键消息\n");
            printf("wParam : 0x%x  lParam : 0x%x \n", msg.wParam, msg.lParam);
 
            switch(msg.wParam)
            {
                case 1:
                    printf("Ctrl + D 被按下! \n\n");
                break
 
                case 2:
                    printf("Win + Z 被按下! \n\n");
                break
 
                case 3:
                    printf("Ctrl + Alt + S 被按下! \n\n");
                break
 
                case 4:
                    printf("Ctrl + Alt + Shift + A 被按下! \n\n");
                break
            }
        }
    }
}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
VC系统热键的注册
VB入门技巧N例(3)
delphi 设置敏感键
全局键盘钩子
Delphi 全局热键KeyPress 和 热键 API(RegisterHotKey、UnRegisterHotKey、GlobalAddAtom、GlobalDeleteAtom、GlobalFindAtom)
C# 如何实现热键注册 RegisterHotKey
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服