本節將向讀者介紹如何使用鍵盤滑鼠操控模擬技術,鍵盤滑鼠操控模擬技術是一種非常實用的技術,可以自動化執行一些重覆性的任務,提高工作效率,在Windows系統下,通過使用各種鍵盤滑鼠控制函數實現動態捕捉和模擬特定功能的操作。鍵盤滑鼠的模擬是實現自動化的必備流程,通常我們可以使用`keybd_event(... ...
本節將向讀者介紹如何使用鍵盤滑鼠操控模擬技術,鍵盤滑鼠操控模擬技術是一種非常實用的技術,可以自動化執行一些重覆性的任務,提高工作效率,在Windows系統下,通過使用各種鍵盤滑鼠控制函數實現動態捕捉和模擬特定功能的操作。
鍵盤滑鼠的模擬是實現自動化的必備流程,通常我們可以使用keybd_event()
實現對鍵盤的擊鍵模擬,使用SetCursorPos()
實現對滑鼠的模擬,使用兩者的配合讀者可以很容易的實現對鍵盤滑鼠的控制,本節將依次封裝實現,模擬鍵盤滑鼠控制功能,讀者可根據自己的實際需求選用不同的函數片段。
12.2.1 模擬鍵盤按鍵
模擬按鍵的核心功能是通過調用keybd_event()
函數實現的,如下是這段代碼的完整實現,首先MySetKeyBig()
函數該函數用於設置鍵盤狀態是否為大小寫,用戶可以傳入一個狀態值來設置當前輸入法大小寫模式,MyAnalogKey()
函數用於實現模擬鍵盤按鍵,該函數接收一個英文字元串,並自動實現擊鍵操作,代碼實現並不複雜,讀者可自行測試功能。
#include <windows.h>
#include <iostream>
using namespace std;
// 設置鍵盤大小寫狀態 為TRUE則切換大寫狀態,否則切換小寫狀態
VOID MySetKeyBig(BOOL big = FALSE)
{
// 判斷鍵盤CapsLock鍵是否開啟狀態,開啟狀態則為大寫,否則為小寫
if (GetKeyState(VK_CAPITAL))
{
// 如果當前鍵盤狀態為大寫,要求改小寫,則模擬按鍵CapsLock切換狀態
if (!big)
{
keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
std::cout << "[鍵盤狀態] " << "切換大寫" << std::endl;
}
else
{
// 如果當前鍵盤狀態為小寫,要求改大寫,則模擬按鍵CapsLock切換狀態
if (big)
{
keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
std::cout << "[鍵盤狀態] " << "切換小寫" << std::endl;
}
}
// 模擬鍵盤按鍵
VOID MyAnalogKey(char* str)
{
int iLen = 0;
char* tmp = NULL;
INPUT* keys = NULL;
BOOL bOldState = FALSE;
// 保存此操作前的鍵盤狀態
bOldState = (BOOL)GetKeyState(VK_CAPITAL);
iLen = lstrlen(str);
tmp = (char*)malloc(iLen);
memmove(tmp, str, iLen);
for (int i = 0; i < iLen; i++)
{
// 某些符號非直屬鍵盤按鍵,這裡只過濾轉換兩個,以後用到其它字元自行添加過濾
if (tmp[i] == ' ')
{
// 產生一個擊鍵消息步驟:按下->抬起
keybd_event(VK_SPACE, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event(VK_SPACE, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
else if (tmp[i] == ',')
{
keybd_event(VK_OEM_COMMA, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event(VK_OEM_COMMA, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
else if (tmp[i] >= 'a' && tmp[i] <= 'z')
{
// 根據字元大小寫切換鍵盤大小寫狀態
MySetKeyBig(0);
// keybd_event只識別大寫
keybd_event((BYTE)tmp[i] - 32, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event((BYTE)tmp[i] - 32, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
else if ((tmp[i] >= 'A' && tmp[i] <= 'Z') || (tmp[i] >= '0' && tmp[i] <= '9'))
{
MySetKeyBig(1);
keybd_event((BYTE)tmp[i], NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event((BYTE)tmp[i], NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
else
{
keybd_event((BYTE)tmp[i] + 64, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
keybd_event((BYTE)tmp[i] + 64, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
}
Sleep(50);
}
// 恢復此操作之前的鍵盤狀態
MySetKeyBig(bOldState);
free(tmp);
}
int main(int argc, char *argv[])
{
Sleep(5000);
MyAnalogKey((char*)"Love life , Love LyShark WelCome LyShark Cpp Home ...");
system("pause");
return 0;
}
讀者可自行編譯並運行上述代碼片段,將游標移動到記事本中,等待五秒鐘,則會依次敲擊如下所示的鍵盤按鍵;
12.2.2 設置窗體最大化
如下代碼實現了設置一個窗體置頂並將該窗體最大化顯示的效果,該代碼實現原理是通過使用EnumWindows
函數傳遞一個回調函數,實現對特定窗體的枚舉,當找到對應窗體句柄後則將該窗體句柄傳遞給global_hwnd
全局句柄中,當獲取到Google
瀏覽器句柄之後則通過GetSystemMetrics
函數得到當前全屏窗體的像素比,通過調用SetWindowPos
可將一個窗體設置為置頂顯示,最後可調用SendMessage
函數向特定窗體句柄發送最大化消息,使其填充滿整個屏幕,代碼如下所示;
#include <iostream>
#include <windows.h>
using namespace std;
HWND global_hwnd = 0;
// 將字元串逆序
char * Reverse(char str[])
{
int n = strlen(str);
int i;
char temp;
for (i = 0; i < (n / 2); i++)
{
temp = str[i];
str[i] = str[n - i - 1];
str[n - i - 1] = temp;
}
return str;
}
// 窗體枚舉回調函數
BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
char WindowName[MAXBYTE] = { 0 };
DWORD ThreadId, ProcessId = 0;
GetWindowText(hwnd, WindowName, sizeof(WindowName));
ThreadId = GetWindowThreadProcessId(hwnd, &ProcessId);
printf("句柄: %-9d --> 線程ID: %-6d --> 進程ID: %-6d --> 名稱: %s \n", hwnd, ThreadId, ProcessId, WindowName);
// 首先逆序輸出字元串,然後比較前13個字元
if (strncmp(Reverse(WindowName), "emorhC elgooG", 13) == 0)
{
global_hwnd = hwnd;
}
return TRUE;
}
int main(int argc, char* argv[])
{
// 枚舉Google瀏覽器句柄
EnumWindows(lpEnumFunc, 0);
std::cout << "瀏覽器句柄: " << global_hwnd << std::endl;
if (global_hwnd != 0)
{
// 獲取系統屏幕寬度與高度 (像素)
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
std::cout << "屏幕X: " << cx << " 屏幕Y: " << cy << std::endl;
// 傳入指定的HWND句柄
HWND hForeWnd = GetForegroundWindow();
DWORD dwCurID = GetCurrentThreadId();
DWORD dwForeID = GetWindowThreadProcessId(hForeWnd, NULL);
AttachThreadInput(dwCurID, dwForeID, TRUE);
// 將該窗體呼出到頂層
ShowWindow(global_hwnd, SW_SHOWNORMAL);
SetWindowPos(global_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(global_hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(global_hwnd);
AttachThreadInput(dwCurID, dwForeID, FALSE);
// 發送最大化消息
SendMessage(global_hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); // 最大化
// SendMessage(global_hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); // 最小化
// SendMessage(global_hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); // 關閉
}
system("pause");
return 0;
}
讀者可自行編譯並運行上述程式,此時會將谷歌瀏覽器全屏並置頂顯示,輸出信息如下圖所示;
12.2.3 讀取與設置剪輯板
讀取與設置剪輯版可用於對數據的拷貝與設置,調用setClipbar
函數並傳入一段字元串可實現將傳入字元串拷貝到剪輯版的功能,使用getClipBoardValue
則可實現讀取剪輯版中的內容到程式內。
#include <iostream>
#include <windows.h>
#include <time.h>
// 將字元串寫入到剪切板
BOOL setClipbar(const char* data)
{
int contentSize = strlen(data) + 1;
HGLOBAL hMemory; LPTSTR lpMemory;
// 打開剪切板
if (!OpenClipboard(NULL))
{
return FALSE;
}
// 清空剪切板
if (!EmptyClipboard())
{
return FALSE;
}
// 對剪切板分配記憶體
if (!(hMemory = GlobalAlloc(GMEM_MOVEABLE, contentSize)))
{
return FALSE;
}
// 鎖定記憶體區域
if (!(lpMemory = (LPTSTR)GlobalLock(hMemory)))
{
return FALSE;
}
// 複製數據到記憶體區域,解除記憶體鎖定
memcpy_s(lpMemory, contentSize, data, contentSize);
GlobalUnlock(hMemory);
// 設置剪切板數據
if (!SetClipboardData(CF_TEXT, hMemory))
{
return FALSE;
}
// std::cout << "已複製: " << data << " 長度: " << contentSize << std::endl;
return CloseClipboard();
}
// 獲取剪切板內容
char* getClipBoardValue()
{
// 初始化
char* url, *pData;
size_t length;
// 打開剪切板
if (!OpenClipboard(NULL))
{
return FALSE;
}
// 獲取剪切板內的數據
HANDLE hData = GetClipboardData(CF_TEXT);
if (hData == NULL)
{
return FALSE;
}
// 獲取數據長度
length = GlobalSize(hData);
url = (char*)malloc(length + 1);
// 將數據轉換為字元
pData = (char*)GlobalLock(hData);
strcpy_s(url, length, pData);
// 清理工作
url[length] = 0;
GlobalUnlock(hData);
CloseClipboard();
// 返回結果並釋放記憶體
char* result = _strdup(url);
free(url);
return result;
}
int main(int argc, char *argv[])
{
Sleep(5000);
for (size_t i = 0; i < 10; i++)
{
// 填充字元串
char MyData[256] = { 0 };
sprintf(MyData, "hello lyshark --> %d", i);
// 設置到剪輯版
BOOL set_flag = setClipbar(MyData);
if (set_flag == TRUE)
{
// std::cout << "[*] 已設置" << std::endl;
// 獲取剪輯版
char *data = getClipBoardValue();
std::cout << "[剪輯版數據] = " << data << std::endl;
}
}
system("pause");
return 0;
}
運行上述程式,依次實現填充字元串並設置到剪輯版,最後再通過getClipBoardValue
函數從剪輯版內讀出數據,如下圖所示;
本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/95b1ad6c.html
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
文章出處:https://www.cnblogs.com/LyShark/p/17749290.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!