最近玩游戲有點入迷,心急升級經驗,於是某天開始"掛屍體",一系列手動操作之后決定寫一個外掛,模擬一系列鍵盤和鼠標操作,沒做過游戲winform也用得少,開始以為只要簡單調用winApi的鍵盤和鼠標就能夠實現...結果
后來才發現游戲一般都禁用了winAPI,最后找了一個驅動級的模擬PS2端口的三方庫(WinIO),因為是64位的電腦涉及到數字證書之類的比較麻煩,不過最后好歹都實現了需要的功能,里面寫了一些截取屏幕指定坐標圖片與采集的圖片做對比,
以實現什么時候該點什么時候不該點的判斷,一些關鍵的代碼當做隨筆記錄下來.
將游戲窗體保持最前

[DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int Width, int Height, int flags); /// <summary> /// 得到當前活動的窗口 /// </summary> /// <returns></returns> [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern System.IntPtr GetForegroundWindow(); [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); private void button1_Click(object sender, EventArgs e) { IntPtr hwnd; hwnd = FindWindow(null, "XXXX"); //根據程序標題獲取句柄 SetWindowPos(hwnd, -1, 0, 0, 0, 0, 1 | 2); //設置在最前 }
64位win7操作 winIO

public class WinIO { public const int KBC_KEY_CMD = 0x64;//輸入鍵盤按下消息的端口 public const int KBC_KEY_DATA = 0x60;//輸入鍵盤彈起消息的端口 [DllImport("WinIo64.dll")] public static extern bool InitializeWinIo(); [DllImport("WinIo64.dll")] public static extern bool GetPortVal(IntPtr wPortAddr, out int pdwPortVal, byte bSize); [DllImport("WinIo64.dll")] public static extern bool SetPortVal(uint wPortAddr, IntPtr dwPortVal, byte bSize); [DllImport("WinIo64.dll")] public static extern byte MapPhysToLin(byte pbPhysAddr, uint dwPhysSize, IntPtr PhysicalMemoryHandle); [DllImport("WinIo64.dll")] public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, byte pbLinAddr); [DllImport("WinIo64.dll")] public static extern bool GetPhysLong(IntPtr pbPhysAddr, byte pdwPhysVal); [DllImport("WinIo64.dll")] public static extern bool SetPhysLong(IntPtr pbPhysAddr, byte dwPhysVal); [DllImport("WinIo64.dll")] public static extern void ShutdownWinIo(); [DllImport("user32.dll")] public static extern int MapVirtualKey(uint Ucode, uint uMapType); private WinIO() { IsInitialize = true; } public static void Initialize() { if (InitializeWinIo()) { KBCWait4IBE(); IsInitialize = true; } } public static void Shutdown() { if (IsInitialize) ShutdownWinIo(); IsInitialize = false; } private static bool IsInitialize { get; set; } ///等待鍵盤緩沖區為空 private static void KBCWait4IBE() { int dwVal = 0; do { bool flag = GetPortVal((IntPtr)0x64, out dwVal, 1); } while ((dwVal & 0x2) > 0); } /// 模擬鍵盤標按下 public static void KeyDown(Keys vKeyCoad) { if (!IsInitialize) return; int btScancode = 0; btScancode = MapVirtualKey((uint)vKeyCoad, 0); KBCWait4IBE(); SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_DATA, (IntPtr)btScancode, 1); } /// 模擬鍵盤彈出 public static void KeyUp(Keys vKeyCoad) { if (!IsInitialize) return; int btScancode = 0; btScancode = MapVirtualKey((uint)vKeyCoad, 0); KBCWait4IBE(); SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1); KBCWait4IBE(); SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1); } }
調用:
1.初始實例: WinIO.Initialize();
2.模擬按鍵
WinIO.KeyDown(Keys.A); // 按下A
Thread.Sleep(100);
WinIO.KeyUp(Keys.A); // 松開A
3.窗體關閉之后注銷: WinIO.Shutdown(); // 用完后注銷
當然WINIO在64位下沒有正式的數字證書,用得時候需要手動在測試模式下為sys文件導入證書. 命令 ( bcdedit /set testsigning on )
鼠標模擬

1 [DllImport("user32.dll")] 2 private static extern int SetCursorPos(int x, int y); 3 4 public enum MouseEventFlags 5 { 6 Move = 0x0001, 7 LeftDown = 0x0002, 8 LeftUp = 0x0004, 9 RightDown = 0x0008, 10 RightUp = 0x0010, 11 MiddleDown = 0x0020, 12 MiddleUp = 0x0040, 13 Wheel = 0x0800, 14 Absolute = 0x8000 15 } 16 [DllImport("User32")] 17 public extern static void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo); 18 19 /// <summary> 20 /// 移動鼠標到指定的坐標點 21 /// </summary> 22 public void MoveMouseToPoint() 23 { 24 string settingValue = ConfigurationManager.AppSettings.Get("Point"); 25 string[] pList = settingValue.Split(','); 26 Point centerP = new Point(int.Parse(pList[0]), int.Parse(pList[1])); 27 if (checkBox1.Checked) 28 { 29 SetCursorPos(centerP.X, centerP.Y); 30 mouse_event((int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), 0, 0, 0, IntPtr.Zero); 31 mouse_event((int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), 0, 0, 0, IntPtr.Zero); 32 } 33 } 34 /// <summary> 35 /// /// 設置鼠標的移動范圍 36 /// </summary> 37 public void SetMouseRectangle(Rectangle rectangle) 38 { 39 System.Windows.Forms.Cursor.Clip = rectangle; 40 }
最后還有一點采集游戲中固定位置的圖片到內存中與事先采集好的圖片做對比的代碼下次再上傳