快捷键注册是针对某一个窗口的,注册之后当这个窗口收到快捷键,操作系统就会发送 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; } |
还是在控制台下编写例子,其实没有差多少
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 } } } } |
联系客服