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

茵蒂克丝

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

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

控制台注册快捷键


#include 
#include 

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");
				break;

				case 2:
					printf("Ctrl + B 被按下! \n");
				break;

				case 3:
					printf("Alt + A 被按下! \n");
				break;
				
				case 4:
					printf("Alt + B 被按下! \n");
				break;

				case 5:
					printf("S 被按下! \n");
				break;
			}
		}
	}
}

hotkey_console

窗口注册快捷键

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

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

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

#include 

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");
			break;

			case 2:
				printf("Ctrl + B 被按下! \n");
			break;

			case 3:
				printf("Alt + A 被按下! \n");
			break;
			
			case 4:
				printf("Alt + B 被按下! \n");
			break;

			case 5:
				printf("S 被按下! \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;
}

hotkey_window

Ctrl + Alt 等复杂组合键

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


#include 
#include 

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");
				break

				case 2:
					printf("Win + Z 被按下! \n");
				break

				case 3:
					printf("Ctrl + Alt + S 被按下! \n");
				break

				case 4:
					printf("Ctrl + Alt + Shift + A 被按下! \n");
				break;
			}
		}
	}
}

hotkey_complex

文章索引
上一讲: Windows API 教程(七) hook 监听
下一讲: Windows API 教程(九) 网络编程

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

You are commenting using your WordPress.com account. Log Out /  更改 )

Google+ photo

You are commenting using your Google+ account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

Connecting to %s