![](/img/trans.png)
[英]Wrap C Function returning array of unknown size using ctypes python
[英]How to wrap the SendInput function to python using ctypes
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 結構引導自己的微軟文檔中,有一個聯合,但我想如果我只需要 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 中有另一種方法可以發送掃描碼,那將很有效,我將不勝感激。
定義整個聯合,或者至少是 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')
Output 在終端上運行 64 位 Python 3.6:
C:\>example
40
C:\> The quick brown fox jumped over the lazy dog
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.