如何使用ctypes将SendInput函数封装到python中?

问题描述 投票:0回答:1

我试图让user32.dll中的SendInput函数在python中使用ctypes.I am a noob but from what I read from the docs you have to create the structs the function requires in python and then pass it to the function.

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))

在microsoft的文档中,我指导自己从INPUT结构有一个工会,但我想,如果我只需要KEYBDINPUT,那么它是同样的事情,如果我有一个工会。

https:/docs.microsoft.comen-uswindowswin32apiwinuserns-winuser-input。

https:/docs.microsoft.comen-uswindowswin32apiwinuserns-winuser-keybdinput。

https:/docs.microsoft.comen-uswindowswin32apiwinusernf-winuser-sendinput。

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

所以,如果有另一种方式在python中,你可以发送扫描码,这将工作,我将非常感谢它。

python ctypes
1个回答
0
投票

定义整个联盟,或者至少是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
© www.soinside.com 2019 - 2024. All rights reserved.