如何用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
相关产品推荐
相关产品推荐

