我有以下脚本每隔xx秒发送一次键盘键(默认情况下为 F15 ),受到在线发现的一些代码的启发
我想删除与鼠标事件相关的类型和联合,但无法使其工作。特别是,我不知道如何删除类MOUSEINPUT
和类型_INPUTunion
的联合(删除它们将停止发送键盘键)。
有关如何将脚本修剪到最小的任何建议(即只保留与键盘相关的代码)?
以下代码将发送密钥“C”以便能够进行调试。
#!/python
import ctypes
import sys
import time
LONG = ctypes.c_long
DWORD = ctypes.c_ulong
ULONG_PTR = ctypes.POINTER(DWORD)
WORD = ctypes.c_ushort
class MOUSEINPUT(ctypes.Structure):
_fields_ = (
('dx', LONG), ('dy', LONG), ('mouseData', DWORD),
('dwFlags', DWORD), ('time', DWORD),
('dwExtraInfo', ULONG_PTR)
)
class KEYBDINPUT(ctypes.Structure):
_fields_ = (
('wVk', WORD), ('wScan', WORD),
('dwFlags', DWORD), ('time', DWORD),
('dwExtraInfo', ULONG_PTR)
)
class _INPUTunion(ctypes.Union):
_fields_ = (('mi', MOUSEINPUT), ('ki', KEYBDINPUT))
class INPUT(ctypes.Structure):
_fields_ = (('type', DWORD), ('union', _INPUTunion))
def SendInput(*inputs):
print(inputs[0].union.mi)
nInputs = len(inputs)
LPINPUT = INPUT * nInputs
pInputs = LPINPUT(*inputs)
cbSize = ctypes.c_int(ctypes.sizeof(INPUT))
return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)
INPUT_KEYBOARD = 1
def Input(structure):
if isinstance(structure, KEYBDINPUT):
return INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))
else:
raise TypeError('Cannot create INPUT structure (keyboard)!')
def Keyboard(code, flags=0):
return Input(KEYBDINPUT(code, code, flags, 0, None))
if __name__ == '__main__':
nb_cycles = 10
while nb_cycles != 0:
time.sleep(2) # 3 seconds
# Key "c" for debug, but ideally use 0x7E for "F15"
SendInput(Keyboard(ord("C")))
sys.stdout.write(".")
nb_cycles -= 1
答案 0 :(得分:3)
“ Bible ”用于这样的任务:[Python 3]: ctypes - A foreign function library for Python。我修改了你的代码(发现了一堆问题,其中一些是关键的)。
code.py :
#!/usr/bin/env python3
import sys
import time
import ctypes
from ctypes import wintypes
class KEYBDINPUT(ctypes.Structure):
_fields_ = [
("wVk", wintypes.WORD),
("wScan", wintypes.WORD),
("dwFlags", wintypes.DWORD),
("time", wintypes.DWORD),
("dwExtraInfo", ctypes.POINTER(wintypes.ULONG)),
]
class INPUT(ctypes.Structure):
_fields_ = [
("type", wintypes.DWORD),
("ki", KEYBDINPUT),
("padding", ctypes.c_ubyte * 8)
]
INPUT_KEYBOARD = 1 # Also defined by win32con if you have pywin32 installed
INPUT_LEN = ctypes.sizeof(INPUT)
LPINPUT = ctypes.POINTER(INPUT)
SendInput = ctypes.windll.user32.SendInput
SendInput.argtypes = [wintypes.UINT, LPINPUT, ctypes.c_int]
SendInput.restype = wintypes.UINT
def send_input(_input):
return SendInput(1, ctypes.byref(_input), INPUT_LEN)
def keyboard(code, flags=0):
return INPUT(INPUT_KEYBOARD, (KEYBDINPUT(code, 0, flags, 0, None)))
def main():
time.sleep(2)
nb_cycles = 3
for _ in range(nb_cycles):
time.sleep(0.5) # 3 seconds
# Key "c" for debug, but ideally use 0x7E for "F15"
ret = send_input(keyboard(ord("C")))
#print(ret)
sys.stdout.write(".")
sys.stdout.flush()
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注强>:
最初,我定义了 INPUT 结构只有1个 st 2个成员,但看了[MS.Docs]: INPUT structure并注意到了联合包括:
进行了一些测试并注意到 MOUSEINPUT 具有3 struct 中最大的尺寸,并且 8 字节大于 KEYBDINPUT (对于两者 32位和 64位),所以我添加了(虚拟) )( padding )成员。通常情况下,当接收类型设置的 INPUT 结构时,我不希望 SendInput 超出 KEYBDINPUT 大小到 INPUT_KEYBOARD ,但[MS.Docs]: SendInput function的 cbSize
def SendInput(*inputs):
- 在 Python , * 之前,参数与 C完全不同。检查[SO]: Expanding tuples into arguments(我没有找到官方文档)。我修改了这个函数,只发送一个这样的结构
始终为通过 ctypes 调用的函数定义 argtypes (以及 restype )。否则,它们将默认为ctypes.c_int
(这可能会导致一些令人讨厌的错误,尤其是 64位:[SO]: Python ctypes cdll.LoadLibrary, instantiate an object, execute its method, private variable address truncated (@CristiFati's answer))
将ctypes.wintypes
用于 Win 特定类型,不要重新发明轮子。更不用说有时可能会出现不匹配的情况(我最近看到的是ctypes.c_bool
vs。 wintypes.BOOL
)
我将您的功能重命名为[Python]: PEP 8 -- Style Guide for Python Code。我还删除了一些不再需要的内容
其他不值得单独提及的小变化
至于测试,我使用了记事本窗口(或任何其他对用户输入“敏感”):
time.sleep(2)
)只是为了给出用户有时间切换窗口,并注意 c s“神奇地”出现...或者只是从控制台启动脚本,按 Ctrl ,注意它已被取消。