SendInput模擬鍵盤輸入的問題

2021-09-07 08:16:35 字數 3075 閱讀 4112

最近接觸到這個函式,因此了解了一下,總結一下列在這。

我了解它的出發點是如何通過它向活動視窗輸入字元,這是很多程式都有的功能(我猜visual assist x就用了這個功能)。

根據msdn,此函式模擬按鍵操作,將一些訊息插入鍵盤或滑鼠的輸入流中,windows對它進行處理,生成相應的wm_keydown或wm_keyup事件,這些事件與普通鍵盤輸入一起進入應用程式的訊息迴圈,它們不僅可以轉換為wm_char訊息,還可以轉換為其它(諸如加速鍵)等訊息。

使用它來傳送字元訊息,並沒有看起來那麼簡單。這有兩個需要考慮的問題:

1. 輸入法的轉換。例如需要向活動視窗傳送一些英文本元,我們可能想象這樣來實現:獲取對應鍵盤字元的虛擬鍵碼,傳送乙個sendinput。但是如果活動視窗正在使用乙個輸入法,那麼我們傳送出去的訊息,會進入輸入法的composition視窗,最終被轉換為象形文本或被丟棄。只有當輸入法關閉時,程式執行的效果才會像我們期望的那樣,在活動視窗中顯示出英文本元。

2. 對於中文字元,應該怎麼傳送給活動視窗?由於sendinput模擬的是wm_keydown和wm_keyup事件,按照一般的思路,我們是否應該獲取中文字元的輸入法編碼(拼音或五筆碼),然後向活動視窗傳送編碼相關的sendinput?那這不僅要求活動視窗開啟輸入法,甚至還要獲知它的編碼方式。

如上所述,若直接如想象中那樣使用sendinput來輸入字元,則必須分析活動視窗的輸入法狀態。而且輸入英文時,要求關閉輸入法,輸入中文時,又要求開啟輸入法。若真要以這樣的思路來實現,則必定是難以成功的。

那麼,有沒有不依賴活動視窗輸入法狀態的方式呢?

其實是有的,使用sendinput模擬鍵盤輸入時,其引數是keybdinput結構,通過將其dwflags成員設定keyeventf_unicode就可以了。使用此方式,只需將keybdinput.wscan設定為字元的unicode編碼即可。對於英文本元,不需要關閉活動視窗的輸入法;對於中文字元,也不要求活動視窗開啟輸入法和將字元轉換為輸入法編碼。

msdn對此方式的說明為:input_keyboard支援非鍵盤的輸入方式,例如手寫識別或語音識別,通過keyeventf_unicode標識,這些方式與鍵盤(文字)輸入別無二致。如果指定了keyeventf_unicode,sendinput傳送乙個wm_keydown或wm_keyup訊息給活動視窗的執行緒訊息佇列,訊息的wparam引數為vk_packet。getmessage或peedmessage一旦獲得此訊息,就把它傳遞給translatemessage,translatemessage根據wscan中指定的unicode字元產生乙個wm_char訊息。若視窗是ansi視窗,則unicode字元會自動轉換為相應的ansi字元。

任何需要向活動視窗輸入字元(包括英文)的功能均應使用這種方式來實現。事實上,鍵盤訊息轉換為字元訊息的過程是很複雜的,這可能與鍵盤布局、區域、換檔狀態等諸多因素有關,這也是windows要使用translatemessage來轉換訊息的原因。因此,不應該試圖通過擊鍵事件來意圖向活動視窗輸入特定的字元。

經測試,sendinput還有兩個值得注意的地方:

1. 沒有為keybdinput.dwflags指定keyeventf_keyup標識時,sendinput將生成wm_keydown訊息,否則生成wm_keyup訊息,由於只有wm_keydown會轉換為字元訊息,因此,若以輸入字元為目標,則不應指定keyeventf_keyup標識。

2. 如果我們想達到實際做一次擊鍵所產生的效果:順序產生乙個wm_keydown和乙個wm_keyup事件。則必須分別以不指定keyeventf_keyup和指定keyeventf_keyup的方式執行一次sendinput操作。sendinput允許在一次呼叫中傳送多個模擬訊息:

input input[2]; 

memset(input, 0, 2 * sizeof(input));

input[0].type = input_keyboard; 

input[0].ki.wvk = data;

input[1].type = input_keyboard; 

input[1].ki.wvk = data; 

input[1].ki.dwflags = keyeventf_keyup;

sendinput(2, input, sizeof(input));

但實際上,這將導致不產生任何訊息。這兩個訊息必須分開傳送,如下所示:

input input[2]; 

memset(input, 0, 2 * sizeof(input));

input[0].type = input_keyboard; 

input[0].ki.wvk = data; 

sendinput(1, input, sizeof(input));

input[1].type = input_keyboard; 

input[1].ki.wvk = data; 

input[1].ki.dwflags = keyeventf_keyup;

sendinput(1, input + 1, sizeof(input));

關於第二點內容,我很有疑問。因為之前有人在網上帖的**是合併傳送的,想必有人這麼做過並且成功了。我不清楚是否與系統或其它因素有關。我也曾試圖嘗試解決此問題,但沒有成功:

1. 根據msdn,keybdinput.time是乙個時間戳,如果為零,系統將使用它自己的時間戳。因此我懷疑兩個一起傳送的事件,是不是因為其時間戳相同,而被忽略掉了。於是我在上述**中顯式設定了該屬性,再合併傳送,結果依然是沒有產生任何訊息。

2. 我分別嘗試了兩種情況:合併傳送的兩條訊息都沒有指定keyeventf_keyup(期望得到兩個相同的字元輸入);合併傳送的兩條訊息具有不同的虛擬鍵碼且都不指定keyeventf_keyup(期望獲得兩個不同的字元輸入)。結果依然失敗,沒有產生任何訊息。

我不清楚這是否意味著:對於鍵盤輸入,不允許將訊息合併傳送。

1. 輸入法也可以處理sendinput傳送的unicode訊息,具體方式不詳。見msdn中immgetproperty方法的參考:當dwindex引數為igp_property時,ime_prop_accept_wide_vkey是乙個可能的返回值,它表示ime會處理sendinput函式以vk_packet注入的unicode字元,若返回值無該標識,則unicode字元會直接傳送給應用程式。

SendInput模擬鍵盤輸入的問題 《轉》

最近接觸到這個函式,因此了解了一下,總結一下列在這。我了解它的出發點是如何通過它向活動視窗輸入字元,這是很多程式都有的功能 我猜visual assist x就用了這個功能 根據msdn,此函式模擬按鍵操作,將一些訊息插入鍵盤或滑鼠的輸入流中,windows對它進行處理,生成相應的wm keydow...

Python模擬鍵盤輸入

2.程式實現 import win32api import win32con win32api.keybd event 17,0,0,0 ctrl鍵位碼是17 win32api.keybd event 86,0,0,0 v鍵位碼是86 win32api.keybd event 86,0,win32c...

rpa模擬鍵盤輸入

1 基本鍵 常用鍵盤字串使用直接輸入字串的方式執行 傳送按鍵 cfan 鍵盤輸入 cfan 2 特殊功能鍵 對於shift ctrl alt三個控制鍵組合的按鍵,使用特殊字元來表示 shift 使用 ctrl 使用 alt 使用 來代替 例1 同時使用ctrl e 鍵盤輸入 e 例2 按住ctrl鍵...