vc+如何實現模擬鍵盤輸入,自動輸入文字(創世紀篇)
鍵盤對於每一個操做電腦的人員來講是最熟悉不過的了。鍵盤上的按鍵可分爲兩類: 按下後會在電腦的輸入窗口上出現對應字符的按鍵,如字母鍵和數字鍵等,咱們稱之爲字符鍵;按下後雖然看不到字符但會產生控制做用的按鍵,如回車鍵、光標鍵等,咱們稱之爲控制鍵。
對於vc+程序員來講,鍵盤上的每一個按鍵都同樣,無非是不一樣按鍵產生的鍵盤掃描碼不一樣。在不一樣的操做系統下,鍵盤掃描碼經常被轉換爲不一樣的編碼以方便應用程序調用,好比在Windows系統下的ASCII碼,在Windows系統下的虛擬鍵盤碼等等。
有時咱們但願能以程序的方式模擬鍵盤按鍵,以達到自動輸入文字或者控制操做的目的。在DOS系統下一般使用中斷調用,產生鍵盤的掃描碼的方法來實現。在Windows 系統下,因爲Windows自己的一些限制和特色,通常不直接使用中斷調用。
瞭解一點Windows編程的朋友應該知道, Windows系統是經過消息的傳遞(或稱事件的發生)來控制各個應用程序的執行和數據通訊的。例如:應用程序打開和關閉會產生相應的窗口消息,鼠標的移動、點擊動做會產生相應的鼠標消息,一樣鍵盤的按下、彈起也會產生相應的鍵盤消息。那麼若是用程序產生鍵盤消息,也就達到了模擬鍵盤按鍵的目的。
有了這樣的思路,咱們如今就來實驗一下。
首先要知道在Windows系統中與鍵盤按鍵相關的消息有:WM_KEYDOWN、WM_KEYUP、 WM_SYSKEYDOWN、WM_SYSKEYUP、WM_CHAR等。其中,WM_KEYDOWN爲鍵按下,WM_KEYUP爲鍵彈起,WM_SYSKEYDOWN爲系統鍵按下,WM_SYSKEYUP爲系統鍵彈起,WM_CHAR爲按鍵對應的字符。
要模擬鍵盤產生鍵盤消息,咱們就發送一條鍵盤消息給指定窗口。好比要模擬一個字母鍵「A」,能夠這樣:PostMessage(hWnd, WM_CHAR, 'A', 0); 模擬按一個回車:PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0)。這裏的關鍵問題是要肯定窗口句柄(hWnd),使用GetFocus()函數能夠獲得鍵盤光標所在窗口句柄,但該函數只能獲得當前進程內的窗口句柄。
若是要獲得其餘應用程序的鍵盤光標所在窗口句柄,須要調用 AttachThreadInput()函數。該函數的做用就是將其餘窗口線程的輸入附加到本窗口線程的輸入操做中,這樣就能夠調用GetFocus()函數獲得其餘窗口的句柄了。
AttachThreadInput()函數的原形以下:
BOOL AttachThreadInput(
DWORD idAttach, // 須要附加的線程ID
DWORD idAttachTo, // 附加到的線程ID
BOOL fAttach // true 附加 false 取消
);
函數使用的過程大體以下:
HWND hWnd;
hWnd = GetForegroundWindow(); // 獲得當前窗口
if (hWnd == Form1->Handle) return; // 排除程序自己的窗口
DWORD FormThreadID = GetCurrentThreadId(); // 本程序的線程ID
// 當前窗口的線程ID
DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL);
// 附加輸入線程
AttachThreadInput(CWndThreadID, FormThreadID, true);
// 獲得當前鍵盤光標所在的窗口
hWnd = GetFocus();
// 取消附加的輸入線程
AttachThreadInput(CWndThreadID, FormThreadID, false);
hWnd就是當前鍵盤光標所在的窗口句柄。另外,通過測試發現,在Windows2000系統下發送字符消息(WM_CHAR)時,若是字符是一個漢字,則該字符對應的虛擬鍵盤碼高位不爲0,這樣獲得的字符就不正確。解決辦法是作一個「與」運算: ch & 0xFF就能夠了。
下面又到了給出例程的時間了。例程「刷刷刷」可以在鍵盤光標所在的文本輸入框中自動輸入文字(中文、英文、數字),程序使用C++ Builder 5開發。首先運行C++ Builder並新建工程。接着,將窗體Form1的邊框樣式(BorderStyle)改成對話框(bsDialog),並放置相應控件如圖所示,其中SS_Text是一個用於輸入文本的TComboBox控件,固然,你能夠在設計階段預先向控件中輸入一些經常使用文本,以便程序運行後能夠直接選用; txtTimes和txtDelay爲TEdit控件,分別用於控制發送文本的次數和間隔時間;chkAutoWrap和chkAutoNumber爲TCheckBox控件,決定是否在每一行發送文本後面自動回車或自動加記數編號; 以上控件包含在Panel1(TPanel控件)中; Timer1用於控制循環發送和時間間隔。
下面是程序清單:
-
- //--------------------------------------------
-
- #include
-
- #pragma hdrstop
-
- #include "Unit1.h"
-
- //--------------------------------------------
-
- #pragma package(smart_init)
-
- #pragma resource "*.dfm"
-
-
- int nTotalTimes, // 發送本文的總次數
-
- nTimes; // 已經發送的次數
-
- TForm1 *Form1;
-
- //--------------------------------------------
-
- __fastcall TForm1::TForm1(TComponent* Owner)
-
- : TForm(Owner)
-
- {
-
- }
-
- //--------------------------------------------
-
- void __fastcall TForm1::btnStartClick(TObject *Sender) // 開始刷屏
-
- { if (SS_Text->Text.IsEmpty())
-
- {
-
- // 文本不能爲空
-
- ShowMessage("請輸入刷刷文本!");
-
- SS_Text->SetFocus();
-
- return;
-
- }
-
- __try
-
- {
-
- // Timer1->Interval取值爲n秒(最小爲50毫秒)
-
- int Interval = StrToInt(txtDelay->Text);
-
- Timer1->Interval = (Interval > 0) ? Interval * 1000 : 50;
-
- // nTotalTimes取值爲n次(最小爲0次)
-
- nTotalTimes = StrToInt(txtTimes->Text);
-
- if (nTotalTimes < 0)
-
- nTotalTimes = 0;
-
- nTimes = 0;
-
- Timer1->Enabled = true;
-
- }
-
- __except(EXCEPTION_EXECUTE_HANDLER)
-
- {
-
- ShowMessage("請輸入數值類型數據!");
-
- return;
-
- }
-
- btnStart->Enabled = false;
-
- btnStop->Enabled = true;
-
- Panel1->Enabled = false;
-
- Application->Minimize(); // 最小化刷刷窗口
-
- }
-
- //--------------------------------------------
- void __fastcall TForm1::btnStopClick(TObject *Sender)// 中止刷屏
-
- {
-
- Timer1->Enabled = false;
-
- btnStart->Enabled = true;
-
- btnStop->Enabled = false;
-
- Panel1->Enabled = true;
-
- }
-
- //--------------------------------------------
-
- void __fastcall TForm1::Timer1Timer(TObject *Sender)
-
- {
-
- // 現刷屏nTimes次,到nTotalTimes次後完成。
-
- if (nTimes == nTotalTimes)
-
- {
-
- btnStopClick(Sender);
-
- return;
-
- }
-
-
- HWND hWnd;
-
- hWnd = GetForegroundWindow(); // 獲得當前窗口
-
- if (hWnd == Form1->Handle) return; // 不須要程序自己的窗口
-
-
- DWORD FormThreadID = GetCurrentThreadId();
-
- DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL);
-
-
- // 附加輸入線程
-
- AttachThreadInput(CWndThreadID, FormThreadID, true);
-
- hWnd = GetFocus(); // 獲得當前鍵盤光標所在的窗口
-
- AttachThreadInput(CWndThreadID, FormThreadID, false); // 取消
-
- if (hWnd == NULL) return;
-
-
- nTimes++;
-
- for (int i = 1; i <= SS_Text->Text.Length(); i++)
-
- { // 模擬鍵盤按鍵輸入文本
-
- PostMessage(hWnd, WM_CHAR, (WPARAM)(SS_Text->Text[i] & 0xFF), 0);
-
- }
-
-
- if (chkAutoNumber->Checked)
-
- { // 自動編號
-
- AnsiString Lines = IntToStr(nTimes);
-
- for (int j = 1; j <= Lines.Length(); j++)
-
- PostMessage(hWnd, WM_CHAR, (WPARAM)(Lines[j]), 0);
-
- }
-
-
- if (chkAutoWrap->Checked) // 自動回車
-
- PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0);
-
- }
-
- //-----------
- end
歡迎關注本站公眾號,獲取更多信息