C#实现驱动级模拟按键 .
2014-04-07 11:27 10940人阅读 评论(5) 收藏 举报
.
-----------------------------Cryking原创------------------------------
-----------------------转载请注明出处,谢谢!------------------------
昨天没事又玩了下仙剑4(俺是仙剑迷大笑), 由于仙4已经玩了好几次,于是准备写个VBS脚本来实现一些自动打怪和自动行走功能,结果发现除了发送F1到F12有效外,其他按键对游戏完全没有效果。(在打怪界面使用keybd_event还有点效果) 经过了解和查看了仙4的安装要求,确定应是DirectX的原因,(仙4要求DirectX9.0以上) DirectX为了提高游戏的响应速度直接是读端口的输入,也难怪对我的模拟按键不理睬。由于网上已经有使用Winio.dll实现驱动级按键,我这就直接拿来在C#中使用了(标题有点骗人,其实都是C++的功劳),全部代码如下:
WinIo.cs类
[csharp] view plain copy print?
01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using System.Text;
05.using System.Threading.Tasks;
06.using System.Runtime.InteropServices;
07.
08.namespace csWg01
09.{
10. public enum VKKey
11. {
12. // mouse movements
13. move = 0x0001,
14. leftdown = 0x0002,
15. leftup = 0x0004,
16. rightdown = 0x0008,
17. rightup = 0x0010,
18. middledown = 0x0020,
19. //keyboard stuff
20. VK_LBUTTON = 1,
21. VK_RBUTTON = 2,
22. VK_CANCEL = 3,
23. VK_MBUTTON = 4,
24. VK_BACK = 8,
25. VK_TAB = 9,
26. VK_CLEAR = 12,
27. VK_RETURN = 13,
28. VK_SHIFT = 16,
29. VK_CONTROL = 17,
30. VK_MENU = 18,
31. VK_PAUSE = 19,
32. VK_CAPITAL = 20,
33. VK_ESCAPE = 27,
34. VK_SPACE = 32,
35. VK_PRIOR = 33,
36. VK_NEXT = 34,
37. VK_END = 35,
38. VK_HOME = 36,
39. VK_LEFT = 37,
40. VK_UP = 38,
41. VK_RIGHT = 39,
42. VK_DOWN = 40,
43. VK_SELECT = 41,
44. VK_PRINT = 42,
45. VK_EXECUTE = 43,
46. VK_SNAPSHOT = 44,
47. VK_INSERT = 45,
48. VK_DELETE = 46,
49. VK_HELP = 47,
50. VK_NUM0 = 48, //0
51. VK_NUM1 = 49, //1
52. VK_NUM2 = 50, //2
53. VK_NUM3 = 51, //3
54. VK_NUM4 = 52, //4
55. VK_NUM5 = 53, //5
56. VK_NUM6 = 54, //6
57. VK_NUM7 = 55, //7
58. VK_NUM8 = 56, //8
59. VK_NUM9 = 57, //9
60. VK_A = 65, //A
61. VK_B = 66, //B
62. VK_C = 67, //C
63. VK_D = 68, //D
64. VK_E = 69, //E
65. VK_F = 70, //F
66. VK_G = 71, //G
67. VK_H = 72, //H
68. VK_I = 73, //I
69. VK_J = 74, //J
70. VK_K = 75, //K
71. VK_L = 76, //L
72. VK_M = 77, //M
73. VK_N = 78, //N
74. VK_O = 79, //O
75. VK_P = 80, //P
76. VK_Q = 81, //Q
77. VK_R = 82, //R
78. VK_S = 83, //S
79. VK_T = 84, //T
80. VK_U = 85, //U
81. VK_V = 86, //V
82. VK_W = 87, //W
83. VK_X = 88, //X
84. VK_Y = 89, //Y
85. VK_Z = 90, //Z
86. VK_NUMPAD0 = 96, //0
87. VK_NUMPAD1 = 97, //1
88. VK_NUMPAD2 = 98, //2
89. VK_NUMPAD3 = 99, //3
90. VK_NUMPAD4 = 100, //4
91. VK_NUMPAD5 = 101, //5
92. VK_NUMPAD6 = 102, //6
93. VK_NUMPAD7 = 103, //7
94. VK_NUMPAD8 = 104, //8
95. VK_NUMPAD9 = 105, //9
96. VK_NULTIPLY = 106,
97. VK_ADD = 107,
98. VK_SEPARATOR = 108,
99. VK_SUBTRACT = 109,
100. VK_DECIMAL = 110,
101. VK_DIVIDE = 111,
102. VK_F1 = 112,
103. VK_F2 = 113,
104. VK_F3 = 114,
105. VK_F4 = 115,
106. VK_F5 = 116,
107. VK_F6 = 117,
108. VK_F7 = 118,
109. VK_F8 = 119,
110. VK_F9 = 120,
111. VK_F10 = 121,
112. VK_F11 = 122,
113. VK_F12 = 123,
114. VK_NUMLOCK = 144,
115. VK_SCROLL = 145,
116. middleup = 0x0040,
117. xdown = 0x0080,
118. xup = 0x0100,
119. wheel = 0x0800,
120. virtualdesk = 0x4000,
121. absolute = 0x8000
122. }
123. public class WinIo
124. {
125. public const int KBC_KEY_CMD = 0x64;
126. public const int KBC_KEY_DATA = 0x60;
127.
128. [DllImport("WinIo64.dll")]
129. public static extern bool InitializeWinIo();
130.
131. [DllImport("WinIo64.dll")]
132. public static extern bool GetPortVal(IntPtr wPortAddr, out int pdwPortVal,byte bSize);
133.
134. [DllImport("WinIo64.dll")]
135. public static extern bool SetPortVal(uint wPortAddr, IntPtr dwPortVal,byte bSize);
136.
137. [DllImport("WinIo64.dll")]
138. public static extern byte MapPhysToLin(byte pbPhysAddr, uint dwPhysSize,IntPtr PhysicalMemoryHandle);
139.
140. [DllImport("WinIo64.dll")]
141. public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle,byte pbLinAddr);
142.
143. [DllImport("WinIo64.dll")]
144. public static extern bool GetPhysLong(IntPtr pbPhysAddr, byte pdwPhysVal);
145.
146. [DllImport("WinIo64.dll")]
147. public static extern bool SetPhysLong(IntPtr pbPhysAddr, byte dwPhysVal);
148.
149. [DllImport("WinIo64.dll")]
150. public static extern void ShutdownWinIo();
151.
152. [DllImport("user32.dll")]
153. public static extern int MapVirtualKey(uint Ucode, uint uMapType);
154.
155. private static bool IsInitialize { get; set; }
156.
157. public static void Initialize()
158. {
159. if (InitializeWinIo())
160. {
161. KBCWait4IBE(); IsInitialize = true;
162. }
163. else
164. System.Windows.Forms.MessageBox.Show("failed");
165.
166. }
167. public static void Shutdown()
168. {
169. if (IsInitialize)
170. ShutdownWinIo();
171. IsInitialize = false;
172. }
173. ///Wait for Buffer gets empty
174. private static void KBCWait4IBE()
175. {
176. int dwVal = 0;
177. do
178. {
179. bool flag = GetPortVal((IntPtr)0x64, out dwVal, 1);
180. }
181. while ((dwVal & 0x2) > 0);
182. }
183. /// key down
184. public static void MykeyDown(VKKey vKeyCoad)
185. {
186. if (!IsInitialize) return;
187.
188. int btScancode = 0;
189. btScancode = MapVirtualKey((uint)vKeyCoad, 0);
190. KBCWait4IBE();
191. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
192. KBCWait4IBE();
193. SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);
194. KBCWait4IBE();
195. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
196. KBCWait4IBE();
197. SetPortVal(KBC_KEY_DATA, (IntPtr)btScancode, 1);
198. }
199. /// Key up
200. public static void MykeyUp(VKKey vKeyCoad)
201. {
202. if (!IsInitialize) return;
203.
204. int btScancode = 0;
205. btScancode = MapVirtualKey((uint)vKeyCoad, 0);
206. KBCWait4IBE();
207. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
208. KBCWait4IBE();
209. SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);
210. KBCWait4IBE();
211. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
212. KBCWait4IBE();
213. SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1);
214. }
215.
216. /// Simulate mouse down
217. public static void MyMouseDown(int vKeyCoad)
218. {
219. int btScancode = 0;
220. btScancode = MapVirtualKey((byte)vKeyCoad, 0);
221. KBCWait4IBE(); // 'wait for buffer gets empty
222. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD3, 1);// 'send write command
223. KBCWait4IBE();
224. SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1);// 'write in io
225. }
226. /// Simulate mouse up
227. public static void MyMouseUp(int vKeyCoad)
228. {
229. int btScancode = 0;
230. btScancode = MapVirtualKey((byte)vKeyCoad, 0);
231. KBCWait4IBE(); // 'wait for buffer gets empty
232. SetPortVal(KBC_KEY_CMD, (IntPtr)0xD3, 1); //'send write command
233. KBCWait4IBE();
234. SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1);// 'write in io
235. }
236. }
237.}
然后新建一个窗体应用,在Form1_Load事件中添加WinIo.Initialize();来初始化驱动,在Form1_FormClosed事件中使用WinIo.Shutdown();卸载驱动。
在button事件中实现模拟按键如下:
[csharp] view plain copy print?
01.private void button1_Click(object sender, EventArgs e)
02. {
03. int hwnd = FindWindow(null, "PAL4-Application");
04. IntPtr p = new IntPtr(hwnd);
05. if (p == IntPtr.Zero)
06. return;
07. SetActiveWindow(p);
08. //设置为活动窗体,防止被其他窗口挡住
09. SetForegroundWindow(p);
10. Thread.Sleep(1000);
11. int i = 0;
12. while (i < 5)
13. {
14. WinIo.MykeyDown(VKKey.VK_SPACE);
15. Thread.Sleep(100);
16. WinIo.MykeyUp(VKKey.VK_SPACE);
17. Thread.Sleep(100);
18. WinIo.MykeyDown(VKKey.VK_S);
19. Thread.Sleep(100);
20. WinIo.MykeyUp(VKKey.VK_S);
21. Thread.Sleep(500);
22. WinIo.MykeyDown(VKKey.VK_D);
23. Thread.Sleep(100);
24. WinIo.MykeyUp(VKKey.VK_D);
25. Thread.Sleep(500);
26. WinIo.MykeyDown(VKKey.VK_A);
27. Thread.Sleep(100);
28. WinIo.MykeyUp(VKKey.VK_A);
29. i++;
30. }
31. }
注意上面的代码是运行在unsafe模式下的,其中FindWindow、SetForegroundWindow、 SetActiveWindow导入如下:
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
64位的WinIo包括源码下载地址: http://www.internals.com/
如果出现WinIo.Initialize()初始化驱动失败的情况,有几点就要注意:
1.确保你当前用户的权限为管理员权限;
2.使用命令“bcdedit /set testsigning on”进入WIN7测试模式,然后重启电脑后再运行上面的代码。
3.64位系统应加载WinIo64.dll,32位系统加载WinIo32.dll.(我的环境是WIN7 64位),PS:不需要引用dll的,PInvoke模式是使用DllImport特性或LoadLibrary来加载非托管代码的,所以无论你怎么引用都会报"未能加载***.dll"的错误的。
接下来就自己写自动行走和打怪的WG吧。(注意:很多网游保护都会检测这种驱动级按键,自己小心被封号吧大笑)