You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何初始化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()

关键修改说明

  1. MOUSEINPUT结构体定义
    严格匹配Windows API的字段顺序和数据类型,确保系统能正确解析输入参数。
  2. INPUT联合结构更新
    在INPUT的内部联合中添加mi字段,通过_anonymous_简化外部访问语法,直接用inp.mi即可操作鼠标输入数据。
  3. 事件标志设置
    相对移动仅需MOUSEEVENTF_MOVE;绝对移动必须同时携带MOUSEEVENTF_ABSOLUTE,且要将屏幕坐标转换为0-65535的范围(Windows API强制要求)。
  4. 调用逻辑对齐
    保持与原键盘模拟一致的send_input封装,确保输入数组能正确传递给系统API。

排查要点

  • 若鼠标无响应,检查dwFlags是否正确:绝对移动必须带MOUSEEVENTF_ABSOLUTE,否则dx/dy会被识别为相对值。
  • 可添加错误检查定位问题:
    error = ctypes.get_last_error()
    if error != 0:
        print(f"SendInput调用失败,错误码:{error}")
    

内容的提问来源于stack exchange,提问作者Arthur Suksta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:20:34