VC++模擬鍵盤輸入(keybd_event() 、 PostMessage() /SendMessage()、SendInput())詳解
[摘要:VC摹擬鍵盤輸進(jìn) 找了一周,終究找到摹擬鍵盤輸進(jìn)的方式了,不外話道照樣要看靠譜的開源項(xiàng)目,才干快速找到辦理題目的方式啊,空話未幾道,進(jìn)進(jìn)主題。 摹擬鍵盤的方式有三種(我]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?VC++模擬鍵盤輸入
找了一周,終于找到模擬鍵盤輸入的方法了,不過話說還是要看靠譜的開源項(xiàng)目,才能快速找到解決問題的方法啊,廢話不多說,進(jìn)入主題。
模擬鍵盤的方法有三種(我只百度到三種,⊙﹏⊙b汗):keybd_event() 、?PostMessage() /SendMessage()、SendInput(),方法內(nèi)的參數(shù)暫省略。。。
首先,keybd_event()方法原型:
VOID keybd_event(
BYTE bVk, // virtual-key code
BYTE bScan, // hardware scan code
DWORD dwFlags, // flags specifying various function options
DWORD dwExtraInfo // additional data associated with keystroke
);
網(wǎng)上大部分流傳的都是這么寫的:(我想說就因?yàn)榭吹剿麄冞@么說的,然后我嘗試了好多方式,都沒有成功,只能說好吧,我的掃描碼必須設(shè)置,我不一般可以了吧,囧?。。?/p>
)
最后幸虧看到tightvnc的源碼才看到他們都是使用掃描碼了,然后我嘗試了一下:
? ? ?//輸入字符'A',通過,就這么通過了,對于一個(gè)菜鳥來說,我找的好辛苦??!至少花費(fèi)了我兩天時(shí)間
? ? ?keybd_event(65,MapVirtualKey(0x41, 0),0,0);
? ? ?Sleep(300);
? ? ?keybd_event(65,MapVirtualKey(0x41, 0),KEYEVENTF_KEYUP,0);
其次,PostMessage()/SendMessage()方法原型:
? ? ? B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
參數(shù)
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含義的兩個(gè)值:
? ? (HWND_BROADCAST:消息被寄送到系統(tǒng)的所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口。消息不被寄送到子窗口。備注:需要以
HWND_BROADCAST方式通信的應(yīng)用程序應(yīng)當(dāng)用函數(shù) RegisterwindwosMessage來獲得應(yīng)用程序間通信的獨(dú)特的消息。
NULL:此函數(shù)的操作和調(diào)用參數(shù)dwThread設(shè)置為當(dāng)前線程的標(biāo)識符PostThreadMessage函數(shù)一樣。)
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函數(shù)調(diào)用成功,返回非零值:如果函數(shù)調(diào)用失敗,返回值是零。若想獲得更多的錯(cuò)誤信息,請調(diào)用GetLastError函數(shù)。
PostMessage()和SendMessage()是有區(qū)別的,前者是傳到指定窗口句柄即可,類似于UDP傳輸協(xié)議,后者是傳到指定句柄后,要一直等到其傳送的參數(shù)被指定窗口收到,并且返回結(jié)果,類似于TCP傳輸協(xié)議。
俺用這個(gè)方法驗(yàn)證的是往TXT文本框輸入內(nèi)容:
? ? ?//向txt文本窗口傳送字符,成功
? ? ?:: SendMessage(HWND(0x0004097E),WM_CHAR,WPARAM('a'),0); ?//發(fā)送一個(gè)字符a
? ? ?說明HWND(0x0004097E)是獲取TXT文本輸入框的句柄(用VS2008 工具欄下的spy++獲取到,再強(qiáng)制轉(zhuǎn)型一下,強(qiáng)調(diào)一下,是輸入框的句柄,而不是TXT的句柄——輸入框的句柄是TXT文本框下面的一個(gè)子句柄,不太懂可以百度一下,主要是我沒嘗試就不介紹如何全部獲取TXT文本內(nèi)所有的句柄了,包括菜單欄句柄等等)
最后介紹一下SendInput的使用方法:
? ? UINT SendInput(
? ? ? ? UINT nInputs, ? ? // count of input events
? ? ? ? LPINPUT pInputs, ?// array of input events
? ? ? ? int cbSize ? ? ? ?// size of structure
? ?);
此方法需要用到的數(shù)據(jù)結(jié)構(gòu)INPUT,結(jié)構(gòu)如下:
? ? typedef struct tagINPUT {
? ? ? ? DWORD ? type;
? ? ? ? union {
? ? ? ? ? ? MOUSEINPUT ? ? ?mi;
? ? ? ? ? ? KEYBDINPUT ? ? ?ki;
? ? ? ? ? ? HARDWAREINPUT ? hi;
? ? ? };
? ? } INPUT, *PINPUT;
SendInput方法可以模擬傳輸鍵盤和鼠標(biāo)的功能。以鍵盤輸入為例:
void inputKey()
{
? ? ? ? ::SetForegroundWindow(hWnd);//把接收窗口放在最前,同時(shí)使窗口獲取焦點(diǎn)(好吧,說的像android,獲取焦點(diǎn)。。。)
INPUT keyEvent = {0};
? ? ? ? keyEvent.type = INPUT_KEYBOARD;//如果是鼠標(biāo)設(shè)置鼠標(biāo)的INPUT_MOUSE
? ? ? ? keyEvent.ki.wVk = 0x41;//字符A
? ? ? ? keyEvent.ki.wScan = MapVirtualKey(0x41, 0);//又像前面別人說的,可能一般不需要設(shè)置吧,我覺得還是這樣靠譜,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//之前我沒映射就沒成功,不信你試試,you ?can ?you ?up!!
? ? ? ? :: SendInput(1, &keyEvent, sizeof(keyEvent));
Sleep(1000); //別為為啥,就想讓他睡會(huì)
? ? ? ? keyEvent.ki.dwFlags = KEYEVENTF_KEYUP;//默認(rèn)keyEvent.ki.dwFlags ?= 0 ,即?KEYEVENTF_KEYDOWN
::SendInput(1, &keyEvent, sizeof(keyEvent));
}
OK,就這些,花費(fèi)了我一周多的時(shí)間啊,才弄好,希望可以幫助到需要的同志?。?/p>