C#实现驱动级模拟按键

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吧。(注意:很多网游保护都会检测这种驱动级按键,自己小心被封号吧大笑)

 

posted @ 2017-06-08 10:00  sky20080101  阅读(1129)  评论(1)    收藏  举报