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

如何用Python获取鼠标原始信号(X、Y或位移值)?

获取鼠标原始输入值的可行方案

要绕过系统屏幕分辨率限制的坐标映射,直接获取鼠标原始位移数据,得从输入设备驱动层读取数据,以下是不同平台的具体实现方案:

Windows平台

方法1:用ctypes直接调用Windows原生API

Windows的GetRawInputData可以直接获取输入设备的原始数据,无需依赖第三方库:

import ctypes
from ctypes import wintypes

# 定义所需的结构体和函数
user32 = ctypes.WinDLL('user32', use_last_error=True)

class RAWINPUTDEVICELIST(ctypes.Structure):
    _fields_ = [("hDevice", wintypes.HANDLE), ("dwType", wintypes.DWORD)]

class RAWINPUTHEADER(ctypes.Structure):
    _fields_ = [("dwType", wintypes.DWORD), ("dwSize", wintypes.DWORD),
                ("hDevice", wintypes.HANDLE), ("wParam", wintypes.WPARAM)]

RID_INPUT = 0x10000003
RIM_TYPEMOUSE = 0x00000000

# 注册原始输入设备
raw_input_device = wintypes.RAWINPUTDEVICE()
raw_input_device.usUsagePage = 0x01
raw_input_device.usUsage = 0x02  # 鼠标设备
raw_input_device.dwFlags = 0x00000001  # RIDEV_INPUTSINK
raw_input_device.hwndTarget = wintypes.HWND(0)

user32.RegisterRawInputDevices(ctypes.byref(raw_input_device), 1, ctypes.sizeof(raw_input_device))

# 监听消息循环
msg = wintypes.MSG()
while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0:
    if msg.message == 0x00FF:  # WM_INPUT
        data_size = wintypes.DWORD()
        user32.GetRawInputData(wintypes.HRAWINPUT(msg.lParam), RID_INPUT, None, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER))
        raw_data = ctypes.create_string_buffer(data_size.value)
        user32.GetRawInputData(wintypes.HRAWINPUT(msg.lParam), RID_INPUT, raw_data, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER))
        
        # 解析鼠标原始位移
        mouse_data = ctypes.cast(raw_data, ctypes.POINTER(wintypes.RAWMOUSE))
        print(f"原始位移: X={mouse_data.contents.lLastX}, Y={mouse_data.contents.lLastY}")
    user32.TranslateMessage(ctypes.byref(msg))
    user32.DispatchMessageW(ctypes.byref(msg))

方法2:使用pywin32封装的API

如果觉得ctypes太繁琐,可以用pywin32库调用相同的Windows API,逻辑和上面一致,只是封装更友好。

Linux平台

方法1:使用evdev库(推荐)

Linux下所有输入设备都通过/dev/input目录暴露,evdev库可以直接读取鼠标设备的原始事件:

from evdev import InputDevice, ecodes

# 找到鼠标设备(可通过`ls /dev/input/`查看,通常是eventX)
mouse = InputDevice('/dev/input/event3')

for event in mouse.read_loop():
    if event.type == ecodes.EV_REL:
        if event.code == ecodes.REL_X:
            print(f"X轴原始位移: {event.value}")
        elif event.code == ecodes.REL_Y:
            print(f"Y轴原始位移: {event.value}")

注意:运行需要root权限,或者将当前用户加入input用户组。

方法2:直接读取设备文件

如果不想用第三方库,可以直接打开/dev/input/event*文件,解析原始事件结构体(需了解Linux输入事件格式)。

macOS平台

通过pyobjc调用Quartz框架的API,获取原始鼠标输入:

import Quartz

class MouseListener(Quartz.CGEventTapCallBack):
    def __call__(self, proxy, type, event, refcon):
        if type == Quartz.kCGEventMouseMoved:
            # 获取原始位移(相对于上一次事件的偏移)
            dx = Quartz.CGEventGetIntegerValueField(event, Quartz.kCGMouseEventDeltaX)
            dy = Quartz.CGEventGetIntegerValueField(event, Quartz.kCGMouseEventDeltaY)
            print(f"原始位移: X={dx}, Y={dy}")
        return event

# 创建事件监听
tap = Quartz.CGEventTapCreate(
    Quartz.kCGHIDEventTap,
    Quartz.kCGHeadInsertEventTap,
    Quartz.kCGEventTapOptionListenOnly,
    Quartz.CGEventMaskBit(Quartz.kCGEventMouseMoved),
    MouseListener(),
    None
)

# 运行事件循环
run_loop_source = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), run_loop_source, Quartz.kCFRunLoopDefaultMode)
Quartz.CGEventTapEnable(tap, True)
Quartz.CFRunLoopRun()

需要安装pyobjc库(pip install pyobjc)。

这些方案的核心都是绕开系统的屏幕坐标映射,直接从输入设备的驱动层读取原始位移数据,完全不受屏幕分辨率限制,适合机器人项目的位移计算需求。

内容的提问来源于stack exchange,提问作者Sujith Christopher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:01:24