鼠标指针偏移至非预期位置排查:分辨率差异是否为诱因?
1440p分辨率下Runelite窗口鼠标定位偏移问题
问题背景
接手了一个无人维护的项目,核心要实现两个功能:
- 定位窗口与小地图的偏移量
- 根据给定偏移量将光标移至目标位置
实际运行时鼠标确实会移动,但始终偏到非预期位置。后来发现原项目开发者用的是1080p分辨率,而我用的是1440p,测试确认这就是偏移的根源。
代码示例
window_capture.py
import win32gui from typing import List import time class WindowCapture(): CLIENT_TOP_BORDER: int = 28.0 CLIENT_SIDE_BORDER: int = 43.0 OFFSET_MINIMAP_X: float = 1359.0 OFFSET_MINIMAP_Y: float = 83.0 OFFSET_RUN_X: float = 0.0 OFFSET_RUN_Y: float = 0.0 OFFSET_LOGOUT_X: float = 0.0 OFFSET_LOGOUT_Y: float = 0.0 def __init__(self): self.window = self.get_window('Runelite') self.center_screen = self.get_center_window(self.window) self.center_minimap = self.get_center_minimap(self.window) self.run_button = self.get_run_button(self.window) self.logout_cross = self.get_logout_cross(self.window) def get_window(self, windowname: str) -> List[int]: '''Returns the position of the window and the size of the window excluding the borders.''' # Get window handle. hwnd = win32gui.FindWindowEx(None, None, None, windowname) # Set window to foreground. win32gui.SetForegroundWindow(hwnd) # Get the window size. rect = win32gui.GetWindowRect(hwnd) # print("debug rect", rect) # Adjust size for borders # x(left) = 1280 x = rect[0] # y(top) = 28 y = rect[1] + self.CLIENT_TOP_BORDER # w(right) = 2560 - 43 = 2517 w = rect[2] - self.CLIENT_SIDE_BORDER # h(bottom) = 1401 - 28 = 1373 h = rect[3] - self.CLIENT_TOP_BORDER print(x, y, w, h) return [x, y, w, h]
问题根源
代码里全是硬编码的绝对像素值,这些值都是基于1080p分辨率写死的:
CLIENT_TOP_BORDER、CLIENT_SIDE_BORDER是固定像素,不同分辨率下窗口边框的实际像素宽度不一样OFFSET_MINIMAP_X/Y这类偏移量是1080p下的绝对坐标,1440p下界面元素的相对位置不变,但绝对像素坐标会按分辨率比例放大,直接用旧值肯定错位
解决方案
核心思路:用相对比例替代硬编码像素
所有界面元素的位置都按窗口客户端区域的宽高比例计算,这样不管什么分辨率都能适配。
修正后的代码
import win32gui from typing import List import time import ctypes # 开启DPI感知,避免系统缩放导致的像素值错误 ctypes.windll.shcore.SetProcessDpiAwareness(2) class WindowCapture(): # 基于原1080p客户端区域的相对比例(假设原客户端宽1920,高1080) REL_MINIMAP_X_RATIO: float = 1359.0 / 1920 REL_MINIMAP_Y_RATIO: float = 83.0 / 1080 def __init__(self): self.window = self.get_window('Runelite') self.center_screen = self.get_center_window(self.window) self.center_minimap = self.get_center_minimap(self.window) self.run_button = self.get_run_button(self.window) self.logout_cross = self.get_logout_cross(self.window) def get_window(self, windowname: str) -> List[int]: '''返回去除边框后的窗口位置和尺寸''' hwnd = win32gui.FindWindowEx(None, None, None, windowname) win32gui.SetForegroundWindow(hwnd) # 获取窗口整体矩形 window_rect = win32gui.GetWindowRect(hwnd) # 获取客户端区域(窗口内部不含边框的区域) client_rect = win32gui.GetClientRect(hwnd) # 把客户端区域的左上角/右下角转换为屏幕坐标 client_top_left = win32gui.ClientToScreen(hwnd, (0, 0)) client_bottom_right = win32gui.ClientToScreen(hwnd, (client_rect[2], client_rect[3])) x = client_top_left[0] y = client_top_left[1] w = client_bottom_right[0] h = client_bottom_right[1] print(x, y, w, h) return [x, y, w, h] def get_center_minimap(self, window): # 计算当前客户端区域的宽高 client_width = window[2] - window[0] client_height = window[3] - window[1] # 用比例计算实际偏移 minimap_x = window[0] + self.REL_MINIMAP_X_RATIO * client_width minimap_y = window[1] + self.REL_MINIMAP_Y_RATIO * client_height return (minimap_x, minimap_y)
额外说明
- 如果不确定原1080p下的客户端区域尺寸,可以在原环境中打印
client_rect的值来替换比例计算的分母 - 系统显示缩放(比如Windows的125%/150%)也会影响像素值,代码开头的
SetProcessDpiAwareness能解决这个问题
内容的提问来源于stack exchange,提问作者crNh
相关产品推荐
相关产品推荐

