├── .gitignore
├── Readme.md
├── __init__.py
├── ctypes_key.py
├── ctypes_key_creator.py
├── example.py
├── key_strategy.py
└── new_down_up.py
/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bode135/VirtualKey_with_Ctypes/81ef6ea303130a1c0c11010fb69f7ac308729850/.gitignore
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # 驱动级按键模拟
2 | ## 基于ctypes实现
3 | > 更新后新增了两个scancode_down_up和keybd_event两种驱动级模拟方法,
4 | > 使用教程见[`VirTualKey使用说明`](https://zhuanlan.zhihu.com/p/355885881)
5 | > 后续将更新实际项目案例.
6 | ----------------------------------------------------------
7 | 2021.1.9更新:
8 | 推荐使用keyboard和mouse模块.
9 | git上搜keyboard就行.
10 | ======================================
11 | 10.21日更新:
12 |
13 | # 安装:
14 | ```
15 | pip install VirtualKey
16 | ```
17 | > ctypes方案对比[`pydamo`](https://github.com/bode135/pydamo "jump to the pydamo project")方案(我不知道怎么用ctypes做后台),不支持后台模拟,但支持64位python。
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | name = "VirtualKeyWithCtypes"
2 |
3 | from .ctypes_key import PressKey, ReleaseKey
4 | from .example import down_up, vk
5 | from .new_down_up import keybd_event, scancodes, scancode_down_up
--------------------------------------------------------------------------------
/ctypes_key.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 | import time
3 |
4 | SendInput = ctypes.windll.user32.SendInput
5 |
6 | PUL = ctypes.POINTER(ctypes.c_ulong)
7 | class KeyBdInput(ctypes.Structure):
8 | _fields_ = [("wVk", ctypes.c_ushort),
9 | ("wScan", ctypes.c_ushort),
10 | ("dwFlags", ctypes.c_ulong),
11 | ("time", ctypes.c_ulong),
12 | ("dwExtraInfo", PUL)]
13 |
14 | class HardwareInput(ctypes.Structure):
15 | _fields_ = [("uMsg", ctypes.c_ulong),
16 | ("wParamL", ctypes.c_short),
17 | ("wParamH", ctypes.c_ushort)]
18 |
19 | class MouseInput(ctypes.Structure):
20 | _fields_ = [("dx", ctypes.c_long),
21 | ("dy", ctypes.c_long),
22 | ("mouseData", ctypes.c_ulong),
23 | ("dwFlags", ctypes.c_ulong),
24 | ("time",ctypes.c_ulong),
25 | ("dwExtraInfo", PUL)]
26 |
27 | class Input_I(ctypes.Union):
28 | _fields_ = [("ki", KeyBdInput),
29 | ("mi", MouseInput),
30 | ("hi", HardwareInput)]
31 |
32 | class Input(ctypes.Structure):
33 | _fields_ = [("type", ctypes.c_ulong),
34 | ("ii", Input_I)]
35 |
36 | def PressKey(hexKeyCode):
37 |
38 | extra = ctypes.c_ulong(0)
39 | ii_ = Input_I()
40 | ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0, 0, ctypes.pointer(extra) )
41 | x = Input( ctypes.c_ulong(1), ii_ )
42 | ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
43 |
44 | def ReleaseKey(hexKeyCode):
45 |
46 | extra = ctypes.c_ulong(0)
47 | ii_ = Input_I()
48 | ii_.ki = KeyBdInput( hexKeyCode, 0x48, 0x0002, 0, ctypes.pointer(extra) )
49 | x = Input( ctypes.c_ulong(1), ii_ )
50 | ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
51 |
52 |
53 | def PressAltTab():
54 |
55 | PressKey(0x012) #Alt
56 | PressKey(0x09) #Tab
57 |
58 | time.sleep(2) #optional : if you want to see the atl-tab overlay
59 |
60 | ReleaseKey(0x09) #~Tab
61 | ReleaseKey(0x012) #~Alt
62 |
63 |
64 | if __name__ =="__main__":
65 |
66 | PressAltTab()
--------------------------------------------------------------------------------
/ctypes_key_creator.py:
--------------------------------------------------------------------------------
1 | from ctypes import POINTER, c_ulong, Structure, c_ushort, c_short, c_long, byref, windll, pointer, sizeof, Union
2 | from bdtime import tt, vk
3 |
4 | PUL = POINTER(c_ulong)
5 |
6 |
7 | class KeyBdInput(Structure):
8 | _fields_ = [("wVk", c_ushort),
9 | ("wScan", c_ushort),
10 | ("dwFlags", c_ulong),
11 | ("time", c_ulong),
12 | ("dwExtraInfo", PUL)]
13 |
14 |
15 | class HardwareInput(Structure):
16 | _fields_ = [("uMsg", c_ulong),
17 | ("wParamL", c_short),
18 | ("wParamH", c_ushort)]
19 |
20 |
21 | class MouseInput(Structure):
22 | _fields_ = [("dx", c_long),
23 | ("dy", c_long),
24 | ("mouseData", c_ulong),
25 | ("dwFlags", c_ulong),
26 | ("time", c_ulong),
27 | ("dwExtraInfo", PUL)]
28 |
29 |
30 | class Input_I(Union):
31 | _fields_ = [("ki", KeyBdInput),
32 | ("mi", MouseInput),
33 | ("hi", HardwareInput)]
34 |
35 |
36 | class Input(Structure):
37 | _fields_ = [("type", c_ulong),
38 | ("ii", Input_I)]
39 |
40 |
41 | class POINT(Structure):
42 | _fields_ = [("x", c_ulong),
43 | ("y", c_ulong)]
44 |
45 |
46 | def get_mpos():
47 | orig = POINT()
48 | windll.user32.GetCursorPos(byref(orig))
49 | return int(orig.x), int(orig.y)
50 |
51 |
52 | def set_mpos(pos):
53 | x, y = pos
54 | windll.user32.SetCursorPos(x, y)
55 |
56 |
57 | MOUSEEVENTF_LEFTDOWN = 0x0002
58 | MOUSEEVENTF_LEFTUP = 0x0004
59 |
60 | MOUSEEVENTF_RIGHTDOWN = 0x00008
61 | MOUSEEVENTF_RIGHTUP = 0x0010
62 |
63 |
64 | def move_click(pos, move_back=False):
65 | origx, origy = get_mpos()
66 | set_mpos(pos)
67 | FInputs = Input * 2
68 | extra = c_ulong(0)
69 | ii_ = Input_I()
70 | ii_.mi = MouseInput(0, 0, 0, 2, 0, pointer(extra))
71 |
72 | tt.sleep(0.1)
73 |
74 | ii2_ = Input_I()
75 | ii2_.mi = MouseInput(0, 0, 0, 4, 0, pointer(extra))
76 | x = FInputs((0, ii_), (0, ii2_))
77 | windll.user32.SendInput(2, pointer(x), sizeof(x[0]))
78 | if move_back:
79 | set_mpos((origx, origy))
80 | return origx, origy
81 |
82 | def move_right_click(pos, move_back=False):
83 | origx, origy = get_mpos()
84 | set_mpos(pos)
85 | FInputs = Input * 2
86 | extra = c_ulong(0)
87 | ii_ = Input_I()
88 | ii_.mi = MouseInput(0, 0, 0, MOUSEEVENTF_RIGHTDOWN, 0, pointer(extra))
89 |
90 | tt.sleep(0.1)
91 |
92 | ii2_ = Input_I()
93 | ii2_.mi = MouseInput(0, 0, 0, MOUSEEVENTF_RIGHTUP, 0, pointer(extra))
94 | x = FInputs((0, ii_), (0, ii2_))
95 | windll.user32.SendInput(2, pointer(x), sizeof(x[0]))
96 | if move_back:
97 | set_mpos((origx, origy))
98 | return origx, origy
99 |
100 | def sendkey(scancode, pressed):
101 | FInputs = Input * 1
102 | extra = c_ulong(0)
103 | ii_ = Input_I()
104 | flag = 0x8
105 | ii_.ki = KeyBdInput(0, 0, flag, 0, pointer(extra))
106 | InputBox = FInputs((1, ii_))
107 | if scancode is None:
108 | return
109 | InputBox[0].ii.ki.wScan = scancode
110 | InputBox[0].ii.ki.dwFlags = 0x8
111 |
112 | if not (pressed):
113 | InputBox[0].ii.ki.dwFlags |= 0x2
114 |
115 | windll.user32.SendInput(1, pointer(InputBox), sizeof(InputBox[0]))
116 |
117 | if __name__ == '__main__':
118 |
119 | tt.sleep(1)
120 | move_click(get_mpos())
121 | tt.sleep(1)
122 | move_right_click(get_mpos())
123 |
124 | def hex_to_dec(int_hex):
125 | if(isinstance(int_hex, (int, float))):
126 | int_hex = str(int_hex)
127 | int_dec = int(int_hex, 16)
128 | return int_dec
129 |
130 | class ScanCode:
131 | q = hex_to_dec(10)
132 | w = hex_to_dec(11)
133 | e = hex_to_dec(12)
134 | r = hex_to_dec(13)
135 | pass
136 |
137 | from keyboard import *
138 |
139 | sc = ScanCode()
140 |
141 | tt.sleep(1)
142 | sendkey(scancode=sc.e, pressed=1)
143 |
144 | # Using Keyboard module in Python
145 | import keyboard
146 |
147 | # It writes the content to output
148 | keyboard.write("GEEKS FOR GEEKS\n")
149 |
150 | # It writes the keys r, k and endofline
151 | keyboard.press_and_release('shift + r, shift + k, \n')
152 | keyboard.press_and_release('R, K')
153 |
154 | # it blocks until ctrl is pressed
155 | keyboard.wait('Ctrl')
--------------------------------------------------------------------------------
/example.py:
--------------------------------------------------------------------------------
1 | from .ctypes_key import PressKey, ReleaseKey
2 | from bdtime import vk, tt
3 |
4 | # press any ch
5 | def down_up(ch, t = 0.5):
6 | ch = vk.conv_ord(ch)
7 | PressKey(ch)
8 | tt.sleep(t)
9 | ReleaseKey(ch)
10 | return 1
11 |
12 | def main():
13 | # KeyDown and KeyUp
14 | ch = 'a'
15 | tt.sleep(1)
16 | down_up(ch)
17 |
18 | # select all
19 | tt.sleep(1)
20 | PressKey(vk.ctrl)
21 | PressKey(vk.a)
22 | tt.sleep(0.5)
23 | ReleaseKey(vk.a)
24 | ReleaseKey(vk.ctrl)
25 |
26 | return 1
27 |
28 |
29 | if __name__ == '__main__':
30 | main()
--------------------------------------------------------------------------------
/key_strategy.py:
--------------------------------------------------------------------------------
1 | from .ctypes_key import PressKey, ReleaseKey
2 | from bdtime import vk, tt
3 |
4 | # press any ch
5 | def down_up(ch, t = 0.5):
6 | ch = vk.conv_ord(ch)
7 | PressKey(ch)
8 | tt.sleep(t)
9 | ReleaseKey(ch)
10 |
11 |
12 | if __name__ == '__main__':
13 | main()
--------------------------------------------------------------------------------
/new_down_up.py:
--------------------------------------------------------------------------------
1 | from ctypes import POINTER, c_ulong, Structure, c_ushort, c_short, c_long, byref, windll, pointer, sizeof, Union
2 | from bdtime import tt, vk
3 | import keyboard
4 | import win32con
5 |
6 |
7 | PUL = POINTER(c_ulong)
8 |
9 |
10 | class KeyBdInput(Structure):
11 | _fields_ = [("wVk", c_ushort),
12 | ("wScan", c_ushort),
13 | ("dwFlags", c_ulong),
14 | ("time", c_ulong),
15 | ("dwExtraInfo", PUL)]
16 |
17 |
18 | class HardwareInput(Structure):
19 | _fields_ = [("uMsg", c_ulong),
20 | ("wParamL", c_short),
21 | ("wParamH", c_ushort)]
22 |
23 |
24 | class MouseInput(Structure):
25 | _fields_ = [("dx", c_long),
26 | ("dy", c_long),
27 | ("mouseData", c_ulong),
28 | ("dwFlags", c_ulong),
29 | ("time", c_ulong),
30 | ("dwExtraInfo", PUL)]
31 |
32 |
33 | class Input_I(Union):
34 | _fields_ = [("ki", KeyBdInput),
35 | ("mi", MouseInput),
36 | ("hi", HardwareInput)]
37 |
38 |
39 | class Input(Structure):
40 | _fields_ = [("type", c_ulong),
41 | ("ii", Input_I)]
42 |
43 |
44 | class POINT(Structure):
45 | _fields_ = [("x", c_ulong),
46 | ("y", c_ulong)]
47 |
48 |
49 | def get_mpos():
50 | orig = POINT()
51 | windll.user32.GetCursorPos(byref(orig))
52 | return int(orig.x), int(orig.y)
53 |
54 |
55 | def set_mpos(pos):
56 | x, y = pos
57 | windll.user32.SetCursorPos(x, y)
58 |
59 |
60 | MOUSEEVENTF_LEFTDOWN = 0x0002
61 | MOUSEEVENTF_LEFTUP = 0x0004
62 |
63 | MOUSEEVENTF_RIGHTDOWN = 0x00008
64 | MOUSEEVENTF_RIGHTUP = 0x0010
65 |
66 |
67 | def move_click(pos, move_back=False):
68 | origx, origy = get_mpos()
69 | set_mpos(pos)
70 | FInputs = Input * 2
71 | extra = c_ulong(0)
72 | ii_ = Input_I()
73 | ii_.mi = MouseInput(0, 0, 0, 2, 0, pointer(extra))
74 |
75 | tt.sleep(0.1)
76 |
77 | ii2_ = Input_I()
78 | ii2_.mi = MouseInput(0, 0, 0, 4, 0, pointer(extra))
79 | x = FInputs((0, ii_), (0, ii2_))
80 | windll.user32.SendInput(2, pointer(x), sizeof(x[0]))
81 | if move_back:
82 | set_mpos((origx, origy))
83 | return origx, origy
84 |
85 | def move_right_click(pos, move_back=False):
86 | origx, origy = get_mpos()
87 | set_mpos(pos)
88 | FInputs = Input * 2
89 | extra = c_ulong(0)
90 | ii_ = Input_I()
91 | ii_.mi = MouseInput(0, 0, 0, MOUSEEVENTF_RIGHTDOWN, 0, pointer(extra))
92 |
93 | tt.sleep(0.1)
94 |
95 | ii2_ = Input_I()
96 | ii2_.mi = MouseInput(0, 0, 0, MOUSEEVENTF_RIGHTUP, 0, pointer(extra))
97 | x = FInputs((0, ii_), (0, ii2_))
98 | windll.user32.SendInput(2, pointer(x), sizeof(x[0]))
99 | if move_back:
100 | set_mpos((origx, origy))
101 | return origx, origy
102 |
103 | def sendkey(scancode, pressed=1):
104 | """
105 | Reference:
106 | [MOUSEINPUT structure (winuser.h)]
107 | (https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput)
108 | [scancodes](https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
109 |
110 | :param scancode: 扫描码, 若为tuple, 则取第一个.
111 | :param pressed:
112 | :return:
113 | """
114 | if isinstance(scancode, tuple):
115 | scancode = scancode[0] # 若按键有两个扫描码, 类型: tuple; 则取第一个扫描码 .
116 |
117 | FInputs = Input * 1
118 | extra = c_ulong(0)
119 | ii_ = Input_I()
120 | flag = 0x8
121 | ii_.ki = KeyBdInput(0, 0, flag, 0, pointer(extra))
122 | InputBox = FInputs((1, ii_))
123 | if scancode is None:
124 | return
125 | InputBox[0].ii.ki.wScan = scancode
126 | InputBox[0].ii.ki.dwFlags = 0x8
127 |
128 | if not (pressed):
129 | InputBox[0].ii.ki.dwFlags |= 0x2
130 | # windll.user32.GetAsyncKeyState(scancodes.get('alt')[0])
131 | # scancodes.get('q')
132 | # windll.user32.GetAsyncKeyState(vk.q)
133 | #
134 | # for i in range(10):
135 | # tt.sleep(1)
136 | # if tt.stop():
137 | # break
138 | # print(windll.user32.GetAsyncKeyState(vk.q))
139 |
140 | windll.user32.SendInput(1, pointer(InputBox), sizeof(InputBox[0]))
141 | return 1
142 |
143 |
144 | class scancodes:
145 | @classmethod
146 | def get(self, key):
147 | # 一个字符一般对应两个扫描码
148 | return keyboard.key_to_scan_codes(key)
149 |
150 | @classmethod
151 | def ret_one_scancode(self, key):
152 | # 只返回一个
153 | return keyboard.key_to_scan_codes(key)[0]
154 |
155 | def scancode_down_up(key, t=0.5):
156 | # 基于扫描码: ScanCodes, scancodes类
157 | return sendkey(scancode=scancodes.get(key))
158 |
159 |
160 | def keybd_event(ch, t=0.1):
161 | # 基于虚拟按键码: VirtualKeyCodes, vk类
162 | ret = windll.user32.keybd_event(
163 | vk.conv_ord(ch),
164 | scancodes.get(ch)[0],
165 | win32con.KEYEVENTF_EXTENDEDKEY | 0,
166 | 0,
167 | )
168 | return ret
169 |
170 |
171 |
172 | if __name__ == '__main__':
173 | # tt.sleep(1)
174 | # move_click(get_mpos())
175 | # tt.sleep(1)
176 | # move_right_click(get_mpos())
177 | #
178 | # def hex_to_dec(int_hex):
179 | # if (isinstance(int_hex, (int, float))):
180 | # int_hex = str(int_hex)
181 | # int_dec = int(int_hex, 16)
182 | # return int_dec
183 | tt.sleep(1)
184 | scancode_down_up('a')
185 |
186 | tt.sleep(0.1)
187 | keybd_event('a')
188 |
189 |
190 | # @tt.run_f_with_during(5, 1)
191 | # def f():
192 | # sendkey(scancode=scancodes.get('e'))
193 | # tt.sleep(0.01)
194 | # sendkey(scancode=scancodes.get('w'))
195 | # tt.sleep(0.01)
196 | # sendkey(scancode=scancodes.get('q'))
197 | # f()
198 | #
199 | # tt.sleep(1)
200 | # windll.user32.keybd_event(vk.q, scancodes.get('q')[0])
201 | # tt.sleep(1)
202 | # windll.user32.keybd_event(vk.q, scancodes.get('w')[0])
203 | # tt.sleep(1)
204 | # windll.user32.keybd_event(vk.q, scancodes.get('e')[0])
205 | #
206 | # tt.sleep(1)
207 | # windll.user32.keybd_event(2, scancodes.get(''))
208 |
209 |
--------------------------------------------------------------------------------