如何使用ctypes将SendInput函数包装到python [英] How to wrap the SendInput function to python using ctypes

查看:178
本文介绍了如何使用ctypes将SendInput函数包装到python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to get the SendInput function from user32.dll to work in python using 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))

在我从INPUT结构中指导自己的Microsoft文档中,有一个联合,但是我认为如果我只需要KEYBDINPUT,那就像我有一个联合一样.

In the microsoft docs at which I guided myself from the INPUT struct had an union but i figured if I would only need the KEYBDINPUT then it's the same thing as if i had an union.

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

https://docs.microsoft.com/zh-CN/windows/win32/api/winuser/ns-winuser-keybdinput

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

我几乎卡住了,因为我看不到这里出了什么问题,所以我寻求帮助.该程序应该在我按键盘上的'u'之后发送空格(这是出于调试目的),并且我这样做是因为我希望它作为扫描代码而不是虚拟按键发送.

I pretty much got stuck because i can't see what's going wrong here so I am asking for help.The program is supposed to send a space after i press 'u' on the keyboard (this was for debugging purposes) and i do it this way because i want it to send as a scancode instead of a virtual keypress.

因此,如果python中还有另一种方法可以发送扫描代码,那将起作用,我将非常感激.

So if there is another way in python with with which you can send scancodes , that'll work and I would appreciate it a lot .

推荐答案

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

Define the whole union, or at least MOUSEINPUT, which is the largest member of the union. You can test that your definition is the correct size by print(sizeof(INPUT)) and it should agree with printing the size of an INPUT structure in a C program. I got size 28 for 32-bit and 40 for 64-bit C structure.

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

Also, your second parameter to SendInput is POINTER(INPUT), not INPUT, and ULONG_PTR is not necessarily c_ulong because it depends on running 32-bit or 64-bit Python.

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

Here's a tested example:

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的终端上的输出:

Output on terminal running 64-bit Python 3.6:

C:\>example
40

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

这篇关于如何使用ctypes将SendInput函数包装到python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆