【问题标题】:How to wrap the SendInput function to python using ctypes如何使用 ctypes 将 SendInput 函数包装到 python
【发布时间】:2020-06-04 08:21:06
【问题描述】:

我正在尝试使用 ctypes 从 user32.dll 获取 SendInput 函数以在 python 中工作。我是一个菜鸟,但从我从文档中读到的内容中,您必须在 python 中创建函数所需的结构,然后将其传递给函数。

import ctypes
import keyboard
from ctypes import *
lib = windll.user32

KEYEVENTF_SCANCODE = 0x8
KEYEVENTF_KEYUP = 0x2
SPACEBAR = 57 # 0x39
INPUT_KEYBOARD = 1


class KEYBDINPUT(Structure):
    _fields_ = [('wVk' , c_ushort) , ('wScan' , c_ushort)
    , ('dwFlags' , c_ulong) , ('time' , c_ulong) , ('dwExtraInfo' , c_ulong)]
class INPUT(Structure):
    _fields_ = [('type' , c_ulong) ,('ki' , KEYBDINPUT)]


lib.SendInput.restype = c_uint
lib.SendInput.argtypes = [c_uint , INPUT , c_int]

keybdinput_obj = KEYBDINPUT(0 , SPACEBAR , KEYEVENTF_SCANCODE , 0 , 0)
input_obj = INPUT(INPUT_KEYBOARD , keybdinput_obj)
keyboard.wait('u')
lib.SendInput(1 , byref(input_obj) , sizeof(INPUT))
keybdinput_obj = KEYBDINPUT(0 , SPACEBAR , KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP , 0 , 0)
input_obj = INPUT(INPUT_KEYBOARD , keybdinput_obj)
lib.SendInput(1 , byref(input_obj) , sizeof(INPUT))

在我从 INPUT 结构引导自己的微软文档中有一个联合,但我想如果我只需要 KEYBDINPUT 那么它就像我有一个联合一样。

https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input

https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput

我几乎被卡住了,因为我看不出这里出了什么问题,所以我寻求帮助。程序应该在我按键盘上的“u”后发送一个空格(这是为了调试目的)和我这样做是因为我希望它作为扫描码而不是虚拟按键发送。

因此,如果在 python 中有另一种方式可以发送扫描码,那将是可行的,我将不胜感激。

【问题讨论】:

  • 您可以使用 PyWin32PyInput 模块。

标签: python ctypes


【解决方案1】:

定义整个联合,或者至少是 MOUSEINPUT,它是联合的最大成员。您可以通过 print(sizeof(INPUT)) 测试您的定义是否正确,并且它应该与在 C 程序中打印 INPUT 结构的大小一致。我的 32 位大小为 28,64 位 C 结构的大小为 40。

另外,SendInput 的第二个参数是 POINTER(INPUT),而不是 INPUT,并且 ULONG_PTR 不一定是 c_ulong,因为它取决于运行 32 位或 64 位 Python。

这是一个经过测试的示例:

import ctypes
from ctypes import *
from ctypes import wintypes as w

KEYEVENTF_SCANCODE = 0x8
KEYEVENTF_UNICODE = 0x4
KEYEVENTF_KEYUP = 0x2
SPACE = 0x39
INPUT_KEYBOARD = 1

# not defined by wintypes
ULONG_PTR = c_ulong if sizeof(c_void_p) == 4 else c_ulonglong

class KEYBDINPUT(Structure):
    _fields_ = [('wVk' ,w.WORD),
                ('wScan',w.WORD),
                ('dwFlags',w.DWORD),
                ('time',w.DWORD),
                ('dwExtraInfo',ULONG_PTR)]

class MOUSEINPUT(Structure):
    _fields_ = [('dx' ,w.LONG),
                ('dy',w.LONG),
                ('mouseData',w.DWORD),
                ('dwFlags',w.DWORD),
                ('time',w.DWORD),
                ('dwExtraInfo',ULONG_PTR)]

class HARDWAREINPUT(Structure):
    _fields_ = [('uMsg' ,w.DWORD),
                ('wParamL',w.WORD),
                ('wParamH',w.WORD)]

class DUMMYUNIONNAME(Union):
    _fields_ = [('mi',MOUSEINPUT),
                ('ki',KEYBDINPUT),
                ('hi',HARDWAREINPUT)] 

class INPUT(Structure):
    _anonymous_ = ['u']
    _fields_ = [('type',w.DWORD),
                ('u',DUMMYUNIONNAME)]

print(sizeof(INPUT))

lib = WinDLL('user32')
lib.SendInput.argtypes = w.UINT,POINTER(INPUT),c_int
lib.SendInput.restype = w.UINT

def send_scancode(code):
    i = INPUT()
    i.type = INPUT_KEYBOARD
    i.ki = KEYBDINPUT(0,code,KEYEVENTF_SCANCODE,0,0)
    lib.SendInput(1,byref(i),sizeof(INPUT))
    i.ki.dwFlags |= KEYEVENTF_KEYUP
    lib.SendInput(1,byref(i),sizeof(INPUT))

def send_unicode(s):
    i = INPUT()
    i.type = INPUT_KEYBOARD
    for c in s:
        i.ki = KEYBDINPUT(0,ord(c),KEYEVENTF_UNICODE,0,0)
        lib.SendInput(1,byref(i),sizeof(INPUT))
        i.ki.dwFlags |= KEYEVENTF_KEYUP
        lib.SendInput(1,byref(i),sizeof(INPUT))

send_scancode(SPACE)
send_unicode('The quick brown fox jumped over the lazy dog')

在运行 64 位 Python 3.6 的终端上输出:

C:\>example
40

C:\> The quick brown fox jumped over the lazy dog

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 2018-10-02
    • 2022-11-20
    • 2013-01-30
    • 2014-04-20
    • 2012-06-18
    • 1970-01-01
    相关资源
    最近更新 更多