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

鼠标指针偏移至非预期位置排查:分辨率差异是否为诱因?

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分辨率写死的:

  1. CLIENT_TOP_BORDER、CLIENT_SIDE_BORDER是固定像素,不同分辨率下窗口边框的实际像素宽度不一样
  2. 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)

额外说明

  1. 如果不确定原1080p下的客户端区域尺寸,可以在原环境中打印client_rect的值来替换比例计算的分母
  2. 系统显示缩放(比如Windows的125%/150%)也会影响像素值,代码开头的SetProcessDpiAwareness能解决这个问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:24:23