歡迎大家提意見,不斷改進
基于上一篇的鼠标記程器的框架和知識,這次實現一個簡單的鼠标按鍵精靈。按鍵精靈類軟件經常被用在遊戲外挂和程序界面的自動化測試,模拟控制鼠标、鍵盤、外部設備的狀态,通過執行提前錄制好的規則、腳本來則可以實現批量處理。
整個程序比較簡單,實現方式如下:
1、首先創建對話框和對話框上的控件,然後就是注冊熱鍵,因為一旦鼠标自動點擊開始,就隻能通過鍵盤組合鍵來讓整個過程停止。特别要注意的是,注冊的熱鍵盡量不要和其它程序注冊的一樣,否則會沖突,沖突後可能會失效,因此注冊的越特殊越好。
這裡注冊了2組熱鍵,CTRL SHIFT F4用來鎖定或釋放鼠标的位置,CTRL SHIFT F6用來停止鼠标自動點擊的過程。注冊的熱鍵要在程序退出時主動調用UnregisterHotKey删除掉。
RegisterHotKey(hWndDlg, WM_MOUSE_POS, MOD_CONTROL | MOD_SHIFT, VK_F4);
RegisterHotKey(hWndDlg, WM_MOUSE_STOP, MOD_CONTROL | MOD_SHIFT, VK_F6);
2、這裡使用CreateDialogParam創建非模式對話框,制定自己的消息循環,非模式對話框可以正常接收鍵盤、鼠标消息。
3、消息及邏輯處理
- 程序啟動過後,首先創建定時器,用來實時獲取鼠标的位置。
- 處理熱鍵
熱鍵的消息處理邏輯
3、啟動按鈕處理,啟動定時器開始模拟鼠标點擊,開始和結束時間的邏輯比較簡單暫時沒有實現。
通過mouse_event實現模拟鼠标點擊,但殺軟、防火牆、部分遊戲則可能屏蔽mouse_event。這些程序一般會挂接鈎子或采用驅動,識别消息到底是不是由外部真正的鍵盤和鼠标産生的,如果不是會丢棄掉,主要是為了防止記錄鍵盤和鼠标的木馬程序。
完整的程序代碼如下:
#define WM_MOUSE_POS WM_USER 100
#define WM_MOUSE_STOP WM_USER 100
#define ID_TIMER_MOUSE 1
#define ID_TIMER_CLICK 2
BOOL CALLBACK WndDlg(HWND,UINT,WPARAM,LPARAM);
BOOL CALLBACK AboutDlg(HWND,UINT,WPARAM,LPARAM);
HINSTANCE hInst;
POINT g_mousePos = { 0, 0 };
bool g_lockMouse = false;
SYSTEMTIME g_startSt = { 0 }, g_endSt = { 0 };
int g_clickType = 0; //0表示單擊,1表示雙擊
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nShowCmd)
{
HWND hWndDlg = CreateDialogParam(hInst, "IDD_DIALOG1", NULL, (DLGPROC)WndDlg, NULL);
HWND hWndComboBox = GetDlgItem(hWndDlg, IDC_COMBO_SELECT_TYPE);
SendMessage(hWndComboBox, CB_ADDSTRING, 0, (LPARAM)TEXT("單擊左鍵"));
SendMessage(hWndComboBox, CB_ADDSTRING, 0, (LPARAM)TEXT("雙擊左鍵"));
SendMessage(hWndComboBox, CB_SETCURSEL, 0, 0);
SYSTEMTIME st = { 2020,1,0,1,1,0,0,0 }; //默認設置持續1小時,當心此處的時間的有效性
SendMessage(GetDlgItem(hWndDlg, IDC_DTP_CONTINUE), DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
SetWindowText(GetDlgItem(hWndDlg, IDC_INTERVAL), "1000");
SetWindowText(hWndDlg, "鼠标模拟");
ShowWindow(hWndDlg, SW_SHOW);
//注冊的熱鍵盡量不要和其它程序注冊的一樣,否則會沖突,沖突後會失效,殺軟等也會屏蔽熱鍵和mouse_event
RegisterHotKey(hWndDlg, WM_MOUSE_POS, MOD_CONTROL | MOD_SHIFT, VK_F4);
RegisterHotKey(hWndDlg, WM_MOUSE_STOP, MOD_CONTROL | MOD_SHIFT, VK_F6);
msg msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
//if (msg.message == WM_KEYDOWN) {
// if (msg.wParam == VK_F3) g_lockMouse = !g_lockMouse;
//}
if (!IsDialogMessage(hWndDlg, &msg)) {// 如果消息沒有被處理, 返回值為0
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
UnregisterHotKey(hWndDlg, WM_MOUSE_POS);
UnregisterHotKey(hWndDlg, WM_MOUSE_STOP);
return 0;
}
void CALLBACK UpdateMousePosTimeProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
if (g_lockMouse) return;
GetCursorPos(&g_mousePos);
TCHAR str[64] = { 0 };
wsprintf(str, "%d , %d", g_mousePos);
SetWindowText(GetDlgItem(hwnd, IDC_MOUSE_POS), str);
}
void SetStartBtnState(HWND hwnd, BOOL state)
{
EnableWindow(GetDlgItem(hwnd, IDC_BTN_STOP), !state);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_START), state);
}
//此處未處理開始和結束時間
void CALLBACK MouseClickTimeProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
SetCursorPos(g_mousePos.x, g_mousePos.y);
Sleep(200);
for (int i = 0; i <= g_clickType; i ) {
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, g_mousePos.x, g_mousePos.y, 0, 0);
}
}
void StartMouseClickTimer(HWND hwnd)
{
TCHAR str[1024] = { 0 };
GetWindowText(GetDlgItem(hwnd, IDC_INTERVAL), str, 1000);
int inteval = atoi(str);
if (inteval < 100) {
MessageBox(hwnd, "間隔時間要大于等于100", "錯誤", MB_YESNO);
return;
}
g_clickType = SendMessage(GetDlgItem(hwnd, IDC_COMBO_SELECT_TYPE), CB_GETCURSEL, 0, 0);
SetTimer(hwnd, ID_TIMER_CLICK, inteval, MouseClickTimeProc);
}
BOOL CALLBACK WndDlg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
SetTimer(hwnd, ID_TIMER_MOUSE, 100, UpdateMousePosTimeProc);
SetStartBtnState(hwnd, TRUE);
return TRUE;
case WM_HOTKEY:
if (HIWORD(lParam) == VK_F4 && LOWORD(lParam) == (MOD_CONTROL | MOD_SHIFT)) {
g_lockMouse = !g_lockMouse;
}
if (HIWORD(lParam) == VK_F6 && LOWORD(lParam) == (MOD_CONTROL | MOD_SHIFT)) {
SetStartBtnState(hwnd, TRUE);
KillTimer(hwnd, ID_TIMER_CLICK);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BTN_START:
SetStartBtnState(hwnd, FALSE);
StartMouseClickTimer(hwnd);
break;
case IDC_BTN_STOP:
SetStartBtnState(hwnd, TRUE);
KillTimer(hwnd, ID_TIMER_CLICK);
break;
}
return TRUE;
case WM_CLOSE:
KillTimer(hwnd, ID_TIMER_MOUSE);
KillTimer(hwnd, ID_TIMER_CLICK);
DestroyWindow(hwnd);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
default:
return FALSE;
}
return FALSE;
}
原創文章,請勿轉載
,