简介
在某些情况下,我们需要模拟键盘按键,用程序替代人工按键操作,
可以使用的方法包含:使用 SendMessage
或 PostMessage
发送按键消息,使用 keybd_event
函数
发送按键动作(该函数被 SendInput
取代),使用 SendInput
函数发送按键动作,等等。
发送按键消息
使用 WM_KEYDOWN
或者 WM_KEYUP
并不好使,推测可能是 lParam
参数设置错误,
使用 WM_CHAR
消息都能够成功,只不过发送消息之前,需要先获取窗口句柄。
1 2 3 4 5 6
| HWND hWnd = FindWindow(NULL, "无标题 - 记事本"); HWND hEdit = FindWindowEx(hWnd, NULL, "EDIT", NULL); SendMessage(hEdit, WM_CHAR, 0x41, 0); SendMessage(hEdit, WM_KEYDOWN, VK_SPACE, 0); SendMessage(hEdit, WM_KEYUP, VK_SPACE, 0); SendMessage(hEdit, WM_CHAR, 0x41, 0);
|
调用按键事件函数
该函数格式如下所示,其中参数 bVk
设置输入的虚拟按键,参数 dwFlags
设置按下或弹起动作
1 2 3 4 5 6
| VOID WINAPI keybd_event( _In_ BYTE bVk, _In_ BYTE bScan, _In_ DWORD dwFlags, _In_ ULONG_PTR dwExtraInfo );
|
1 2 3 4 5
| keybd_event(VK_SHIFT, 0, 0, 0); keybd_event(0x41, 0, 0, 0); keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
|
调用发送输入函数
该函数格式如下所示,参数 nInputs
描述输入 INPUT
结构体数组的数量,参数 cbSize
表示对应总大小
1 2 3 4 5
| UINT WINAPI SendInput( _In_ UINT nInputs, _In_ LPINPUT pInputs, _In_ int cbSize );
|
1 2 3 4 5 6 7 8
| typedef struct tagINPUT { DWORD type; union { MOUSEINPUT mi; KEYBDINPUT ki; HARDWAREINPUT hi; }; } INPUT, *PINPUT;
|
结构体中的参数 type
可取值 INPUT_MOUSE
INPUT_KEYBOARD
INPUT_HARDWARE
来对应后续参数
1 2 3 4 5 6 7 8
| typedef struct tagMOUSEINPUT { LONG dx; LONG dy; DWORD mouseData; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } MOUSEINPUT, *PMOUSEINPUT;
|
1 2 3 4 5 6 7
| typedef struct tagKEYBDINPUT { WORD wVk; WORD wScan; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } KEYBDINPUT, *PKEYBDINPUT;
|
1 2 3 4 5
| typedef struct tagHARDWAREINPUT { DWORD uMsg; WORD wParamL; WORD wParamH; } HARDWAREINPUT, *PHARDWAREINPUT;
|
我们这里使用 INPUT_KEYBOARD
来发送键盘按键,结构体KEYBDINPUT
与 keybd_event
取值相同
1 2 3 4 5 6
| INPUT input = { 0 }; input.type = INPUT_KEYBOARD; input.ki.wVk = VK_SHIFT; SendInput(1, &input, sizeof(INPUT)); input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof(INPUT));
|
经实验发现每次发送1个信息时能够成功,但是改为同时发送2个信息就不成功,不太清楚原因。