如何初始化MOUSEINPUT类,扩展Python模拟输入代码的鼠标功能?
基于原键盘模拟代码扩展鼠标功能的实现方案
首先给出完整的修改后代码,包含正确初始化的MOUSEINPUT结构和鼠标操作函数:
import ctypes from ctypes import wintypes # 加载系统库并定义常量 user32 = ctypes.WinDLL('user32', use_last_error=True) INPUT_MOUSE = 0 INPUT_KEYBOARD = 1 INPUT_HARDWARE = 2 MOUSEEVENTF_MOVE = 0x0001 MOUSEEVENTF_ABSOLUTE = 0x8000 MOUSEEVENTF_LEFTDOWN = 0x0002 MOUSEEVENTF_LEFTUP = 0x0004 MOUSEEVENTF_RIGHTDOWN = 0x0008 MOUSEEVENTF_RIGHTUP = 0x0010 MOUSEEVENTF_MIDDLEDOWN = 0x0020 MOUSEEVENTF_MIDDLEUP = 0x0040 MOUSEEVENTF_WHEEL = 0x0800 MOUSEEVENTF_HWHEEL = 0x1000 # 定义MOUSEINPUT结构体(严格对应Windows API结构) class MOUSEINPUT(ctypes.Structure): _fields_ = (('dx', wintypes.LONG), ('dy', wintypes.LONG), ('mouseData', wintypes.DWORD), ('dwFlags', wintypes.DWORD), ('time', wintypes.DWORD), ('dwExtraInfo', wintypes.ULONG_PTR)) # 保留原键盘模拟的KEYBDINPUT结构 class KEYBDINPUT(ctypes.Structure): _fields_ = (('wVk', wintypes.WORD), ('wScan', wintypes.WORD), ('dwFlags', wintypes.DWORD), ('time', wintypes.DWORD), ('dwExtraInfo', wintypes.ULONG_PTR)) class HARDWAREINPUT(ctypes.Structure): _fields_ = (('uMsg', wintypes.DWORD), ('wParamL', wintypes.WORD), ('wParamH', wintypes.WORD)) # 修改INPUT结构体,加入MOUSEINPUT的联合字段 class INPUT(ctypes.Structure): class _INPUT(ctypes.Union): _fields_ = (('ki', KEYBDINPUT), ('mi', MOUSEINPUT), ('hi', HARDWAREINPUT)) _anonymous_ = ('_input',) _fields_ = (('type', wintypes.DWORD), ('_input', _INPUT)) # 封装SendInput调用,与原键盘逻辑保持一致 def send_input(inputs): nInputs = len(inputs) INPUT_ARRAY = INPUT * nInputs input_array = INPUT_ARRAY(*inputs) user32.SendInput(nInputs, ctypes.byref(input_array), ctypes.sizeof(INPUT)) # 相对移动鼠标 def move_mouse_rel(dx, dy): mi = MOUSEINPUT() mi.dx = dx mi.dy = dy mi.mouseData = 0 mi.dwFlags = MOUSEEVENTF_MOVE mi.time = 0 mi.dwExtraInfo = 0 inp = INPUT() inp.type = INPUT_MOUSE inp.mi = mi send_input([inp]) # 绝对移动鼠标(基于屏幕分辨率转换坐标) def move_mouse_abs(x, y): screen_width = user32.GetSystemMetrics(0) screen_height = user32.GetSystemMetrics(1) # 转换为Windows API要求的0-65535范围坐标 abs_x = int((x / screen_width) * 65535) abs_y = int((y / screen_height) * 65535) mi = MOUSEINPUT() mi.dx = abs_x mi.dy = abs_y mi.mouseData = 0 mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE mi.time = 0 mi.dwExtraInfo = 0 inp = INPUT() inp.type = INPUT_MOUSE inp.mi = mi send_input([inp]) # 测试函数 def MouseTest(): # 相对移动:向右100像素,向下50像素 move_mouse_rel(100, 50) # 可选:绝对移动到屏幕中心 # screen_width = user32.GetSystemMetrics(0) # screen_height = user32.GetSystemMetrics(1) # move_mouse_abs(screen_width//2, screen_height//2) if __name__ == '__main__': MouseTest()
关键修改说明
- MOUSEINPUT结构体定义
严格匹配Windows API的字段顺序和数据类型,确保系统能正确解析输入参数。 - INPUT联合结构更新
在INPUT的内部联合中添加mi字段,通过_anonymous_简化外部访问语法,直接用inp.mi即可操作鼠标输入数据。 - 事件标志设置
相对移动仅需MOUSEEVENTF_MOVE;绝对移动必须同时携带MOUSEEVENTF_ABSOLUTE,且要将屏幕坐标转换为0-65535的范围(Windows API强制要求)。 - 调用逻辑对齐
保持与原键盘模拟一致的send_input封装,确保输入数组能正确传递给系统API。
排查要点
- 若鼠标无响应,检查
dwFlags是否正确:绝对移动必须带MOUSEEVENTF_ABSOLUTE,否则dx/dy会被识别为相对值。 - 可添加错误检查定位问题:
error = ctypes.get_last_error() if error != 0: print(f"SendInput调用失败,错误码:{error}")
内容的提问来源于stack exchange,提问作者Arthur Suksta
相关产品推荐
相关产品推荐

