在VC中实现模拟键盘,输入内容并显示在ListBox中。
生活随笔
收集整理的這篇文章主要介紹了
在VC中实现模拟键盘,输入内容并显示在ListBox中。
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
網上找的,還沒試過,希望對樓主有幫助
模擬鍵盤按鍵 自動輸入文字
鍵盤對于每個操作電腦的人員來說是最熟悉不過的了。鍵盤上的按鍵可分為兩類: 按下后會在電腦的輸入窗口上出現對應字符的按鍵,如字母鍵和數字鍵等,我們稱之為字符鍵;按下后雖然看不到字符但會產生控制作用的按鍵,如回車鍵、光標鍵等,我們稱之為控制鍵。
對于程序員來說,鍵盤上的每個按鍵都一樣,無非是不同按鍵產生的鍵盤掃描碼不同。在不同的操作系統下,鍵盤掃描碼常常被轉換為不同的編碼以方便應用程序調用,比如在DOS系統下的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()函數得到其他窗口的句柄了。
與2001年第24期程序谷刊登的《如何寫一個聊天輔助程序》一文中作者使用ChildWindowFromPointEx的方法相比,使用AttachThreadInput似乎更能夠使鍵盤模擬具有通用性。
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);
}
//---------------------------------------------
模擬鍵盤按鍵 自動輸入文字
鍵盤對于每個操作電腦的人員來說是最熟悉不過的了。鍵盤上的按鍵可分為兩類: 按下后會在電腦的輸入窗口上出現對應字符的按鍵,如字母鍵和數字鍵等,我們稱之為字符鍵;按下后雖然看不到字符但會產生控制作用的按鍵,如回車鍵、光標鍵等,我們稱之為控制鍵。
對于程序員來說,鍵盤上的每個按鍵都一樣,無非是不同按鍵產生的鍵盤掃描碼不同。在不同的操作系統下,鍵盤掃描碼常常被轉換為不同的編碼以方便應用程序調用,比如在DOS系統下的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()函數得到其他窗口的句柄了。
與2001年第24期程序谷刊登的《如何寫一個聊天輔助程序》一文中作者使用ChildWindowFromPointEx的方法相比,使用AttachThreadInput似乎更能夠使鍵盤模擬具有通用性。
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);
}
//---------------------------------------------
本程序在Windows 2000 + C++ Builder 5下編譯通過。源程序下載地址是:[url]http://www.cfan.net.cn/qikan/[/url] cxg/0206mnj.zip。
本文轉自博客園知識天地的博客,原文鏈接:在VC中實現模擬鍵盤,輸入內容并顯示在ListBox中。?,如需轉載請自行聯系原博主。
總結
以上是生活随笔為你收集整理的在VC中实现模拟键盘,输入内容并显示在ListBox中。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: editor does not cont
- 下一篇: 元素失去焦点(隐藏软键盘)