我有以下脚本每 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
Run Code Online (Sandbox Code Playgroud)
像这样的任务的“圣经”:[Python.Docs]: ctypes - Python 的外部函数库。
我修改了你的代码(发现了一堆问题,其中一些很关键)。
代码00.py:
#!/usr/bin/env python
import sys
import time
import ctypes as ct
from ctypes import wintypes as wt
class KEYBDINPUT(ct.Structure):
_fields_ = [
("wVk", wt.WORD),
("wScan", wt.WORD),
("dwFlags", wt.DWORD),
("time", wt.DWORD),
("dwExtraInfo", wt.PULONG),
]
class INPUT(ct.Structure):
_fields_ = [
("type", wt.DWORD),
("ki", KEYBDINPUT),
("padding", ct.c_ubyte * 8)
]
INPUT_KEYBOARD = 1 # Also defined by win32con if you have pywin32 installed
INPUT_LEN = ct.sizeof(INPUT)
LPINPUT = ct.POINTER(INPUT)
user32_dll = ct.windll.user32
SendInput = user32_dll.SendInput
SendInput.argtypes = [wt.UINT, LPINPUT, ct.c_int]
SendInput.restype = wt.UINT
def send_input(_input):
return SendInput(1, ct.byref(_input), INPUT_LEN)
def keyboard(code, flags=0):
return INPUT(INPUT_KEYBOARD, (KEYBDINPUT(code, code, flags, 0, None)))
def main(*argv):
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 {0:s} {1:d}bit on {2:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
Run Code Online (Sandbox Code Playgroud)
注意事项:
最初,我定义了只有 1 st 2 个成员的INPUT结构,但查看了[MS.Docs]: INPUT 结构并注意到联合包括:
做了一些测试,并指出MOUSEINPUT具有最大尺寸从3的结构S,和它的8个大于字节KEYBDINPUT(对于两个 32位和64位),所以我添加的(伪)(填充)构件。通常,我不希望SendInput在接收类型设置为INPUT_KEYBOARD的INPUT结构时超出KEYBDINPUT大小,但[MS.Docs]需要INPUT大小: SendInput 函数的cbSize arg
def SendInput(*inputs):- 在Python 中,参数前的星号( * ) 与C 中的完全不同。检查[SO]:将元组扩展为参数(我没有找到官方文档)。我修改了函数,使它只发送一个这样的结构
始终为通过ctypes调用的函数定义argtypes(和restype)。否则它们将默认为ctypes.c_int(这可能会导致一些严重的错误,尤其是在64 位上:[SO]: C 函数通过 ctypes 从 Python 调用返回不正确的值(@CristiFati 的答案))
将ctypes.wintypes用于Win特定类型,不要重新发明轮子。更不用说有时可能会发生不匹配(我最近看到的是ctypes.c_bool 与 wintypes.BOOL)
我将您的函数重命名为[Python]:PEP 8 --符合Python 代码的样式指南。我还删除了其中一些不再需要的
其他不值得单独提及的小改动
至于测试,我使用了记事本窗口(或任何其他对用户输入“敏感”的窗口):
... 或者只是从控制台启动脚本,按下(并按住)Ctrl,然后注意KeyboardInterrupt ( Ctrl + C) 的发生。
| 归档时间: |
|
| 查看次数: |
2166 次 |
| 最近记录: |