Skip to content

Instantly share code, notes, and snippets.

@BHznJNs
Created September 23, 2025 08:29
Show Gist options
  • Select an option

  • Save BHznJNs/7f8004de37a4a561b548d827e669f7d9 to your computer and use it in GitHub Desktop.

Select an option

Save BHznJNs/7f8004de37a4a561b548d827e669f7d9 to your computer and use it in GitHub Desktop.
import ctypes
import win32api
import win32con
import win32gui
import pywintypes
from ctypes import wintypes
# 1. 使用 ctypes 定义 pywin32 未封装的 API 和结构体 (已完全修正)
# =================================================================
# --- 常量定义 ---
WM_INPUT = 0x00FF
RIDEV_INPUTSINK = 0x00000100
RID_INPUT = 0x10000003
RIM_TYPEMOUSE = 0
# --- 结构体定义 (精确匹配 C 语言内存布局) ---
class RAWINPUTDEVICE(ctypes.Structure):
_fields_ = [
("usUsagePage", wintypes.USHORT),
("usUsage", wintypes.USHORT),
("dwFlags", wintypes.DWORD),
("hwndTarget", wintypes.HWND),
]
# RAWMOUSE 内部的 button data 是一个联合体
class _RAWMOUSE_STRUCT(ctypes.Structure):
_fields_ = [
("usButtonFlags", wintypes.USHORT),
("usButtonData", wintypes.USHORT),
]
class _RAWMOUSE_UNION(ctypes.Union):
_fields_ = [
("ulButtons", wintypes.ULONG),
("struct", _RAWMOUSE_STRUCT),
]
class RAWMOUSE(ctypes.Structure):
_fields_ = [
("usFlags", wintypes.USHORT),
("_buttons", _RAWMOUSE_UNION), # 匿名字段
("ulRawButtons", wintypes.ULONG),
("lLastX", wintypes.LONG),
("lLastY", wintypes.LONG),
("ulExtraInformation", wintypes.ULONG),
]
_anonymous_ = ("_buttons",) # 允许直接访问 union 内部成员
# RAWINPUT 内部的 data 也是一个联合体
class RAWKEYBOARD(ctypes.Structure): # 占位符
_fields_ = [("data", wintypes.BYTE * 20)]
class RAWHID(ctypes.Structure): # 占位符
_fields_ = [("data", wintypes.BYTE * 8)]
class RAWINPUT_DATA(ctypes.Union):
_fields_ = [
("mouse", RAWMOUSE),
("keyboard", RAWKEYBOARD),
("hid", RAWHID),
]
class RAWINPUTHEADER(ctypes.Structure):
_fields_ = [
("dwType", wintypes.DWORD),
("dwSize", wintypes.DWORD),
("hDevice", wintypes.HANDLE),
("wParam", wintypes.WPARAM),
]
class RAWINPUT(ctypes.Structure):
_fields_ = [
("header", RAWINPUTHEADER),
("data", RAWINPUT_DATA),
]
# --- 从 user32.dll 加载函数 ---
user32 = ctypes.windll.user32
RegisterRawInputDevices = user32.RegisterRawInputDevices
RegisterRawInputDevices.argtypes = [ctypes.POINTER(RAWINPUTDEVICE), wintypes.UINT, wintypes.UINT]
RegisterRawInputDevices.restype = wintypes.BOOL
GetRawInputData = user32.GetRawInputData
# 2. 使用 pywin32 编写窗口和消息循环的主体逻辑
# =================================================================
def wnd_proc(hwnd, msg, wparam, lparam):
if msg == WM_INPUT:
size = wintypes.UINT(0)
GetRawInputData(lparam, RID_INPUT, None, ctypes.byref(size), ctypes.sizeof(RAWINPUTHEADER))
buf = ctypes.create_string_buffer(size.value)
if GetRawInputData(lparam, RID_INPUT, buf, ctypes.byref(size), ctypes.sizeof(RAWINPUTHEADER)) == size.value:
raw_input = ctypes.cast(buf, ctypes.POINTER(RAWINPUT)).contents
if raw_input.header.dwType == RIM_TYPEMOUSE:
# --- 修正访问方式 ---
# 因为 data 是一个 union,需要先指定要访问的成员 (mouse)
mouse_data = raw_input.data.mouse
print(f"Relative Mouse Movement: dX={mouse_data.lLastX}, dY={mouse_data.lLastY}")
return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)
def main():
wnd_class = win32gui.WNDCLASS()
wnd_class.lpszClassName = "RawInputWindowClassFinal"
wnd_class.lpfnWndProc = wnd_proc
try:
win32gui.RegisterClass(wnd_class)
except win32gui.error as e:
if e.winerror != 1410: # ERROR_CLASS_ALREADY_EXISTS
raise e
hwnd = win32gui.CreateWindow(
wnd_class.lpszClassName, "Raw Input Test Window",
0, 0, 0, 0, 0, None, None,
win32api.GetModuleHandle(None), None
)
if not hwnd:
raise RuntimeError("Failed to create window.")
device = RAWINPUTDEVICE(1, 2, RIDEV_INPUTSINK, hwnd)
if not RegisterRawInputDevices(ctypes.byref(device), 1, ctypes.sizeof(RAWINPUTDEVICE)):
raise RuntimeError(f"Failed to register raw input devices. Error code: {ctypes.get_last_error()}")
print("正在捕获原始鼠标移动数据... 按 Ctrl+C 停止。")
win32gui.PumpMessages()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n程序已停止。")
except (RuntimeError, pywintypes.error) as e:
print(f"发生错误:{e}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment