Golang中如何使用RobotGo处理屏幕分辨率与鼠标移动问题

Golang中如何使用RobotGo处理屏幕分辨率与鼠标移动问题 我正在尝试获取(主)显示器的分辨率。目前,我正在为一个类似VNC的应用程序使用以下代码——其中mouse.Xmouse.Y是0…1的范围,分别对应从左到右和从下到上。

width, height := robotgo.GetScreenSize()
x := int(*mouse.X * float32(width))
y := int(*mouse.Y * float32(height))
robotgo.Move(x, y)

当系统(PC Win10)只有一个显示器时,这段代码工作正常。但是当有多个显示器时,分辨率被设置为所有显示器的整体宽度和高度——即整个桌面的分辨率。

请问有人知道robotgo是否可以获取单个(可能是主)显示器的分辨率吗?

如果不行——是否有办法简单地且跨平台地获取主显示器的分辨率?

顺便说一下,我知道SDL——但它似乎需要与robotgo不同的编译器(32位与64位)——尽管我自己还没有验证这一点。

谢谢。


更多关于Golang中如何使用RobotGo处理屏幕分辨率与鼠标移动问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何使用RobotGo处理屏幕分辨率与鼠标移动问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在RobotGo中直接获取单个显示器分辨率的功能目前确实有限。不过,我们可以通过系统调用或使用其他库来获取主显示器分辨率,然后与RobotGo配合使用。以下是跨平台的解决方案:

Windows平台示例(使用syscall):

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

type Rect struct {
    Left   int32
    Top    int32
    Right  int32
    Bottom int32
}

func GetPrimaryMonitorRect() (int, int, error) {
    user32 := syscall.NewLazyDLL("user32.dll")
    getMonitorInfo := user32.NewProc("GetMonitorInfoW")
    monitorFromPoint := user32.NewProc("MonitorFromPoint")
    getSystemMetrics := user32.NewProc("GetSystemMetrics")
    
    // 获取主显示器句柄
    point := uintptr(0) // 屏幕左上角
    monitor, _, _ := monitorFromPoint.Call(point, 0)
    
    var monitorInfo struct {
        cbSize    uint32
        rcMonitor Rect
        rcWork    Rect
        dwFlags   uint32
    }
    monitorInfo.cbSize = uint32(unsafe.Sizeof(monitorInfo))
    
    ret, _, _ := getMonitorInfo.Call(monitor, uintptr(unsafe.Pointer(&monitorInfo)))
    if ret == 0 {
        // 回退到系统指标
        width, _, _ := getSystemMetrics.Call(0)  // SM_CXSCREEN
        height, _, _ := getSystemMetrics.Call(1) // SM_CYSCREEN
        return int(width), int(height), nil
    }
    
    rect := monitorInfo.rcMonitor
    width := rect.Right - rect.Left
    height := rect.Bottom - rect.Top
    
    return int(width), int(height), nil
}

macOS平台示例:

// +build darwin

package main

import (
    "os/exec"
    "strconv"
    "strings"
)

func GetPrimaryMonitorRect() (int, int, error) {
    cmd := exec.Command("system_profiler", "SPDisplaysDataType")
    output, err := cmd.Output()
    if err != nil {
        return 0, 0, err
    }
    
    lines := strings.Split(string(output), "\n")
    for i, line := range lines {
        if strings.Contains(line, "Resolution:") {
            parts := strings.Fields(line)
            if len(parts) >= 2 {
                res := strings.Split(parts[1], "x")
                if len(res) == 2 {
                    width, _ := strconv.Atoi(res[0])
                    height, _ := strconv.Atoi(res[1])
                    return width, height, nil
                }
            }
        }
    }
    
    // 回退方案
    cmd = exec.Command("bash", "-c", "system_profiler SPDisplaysDataType | grep Resolution | head -1 | awk '{print $2}'")
    output, err = cmd.Output()
    if err == nil {
        res := strings.Split(strings.TrimSpace(string(output)), "x")
        if len(res) == 2 {
            width, _ := strconv.Atoi(res[0])
            height, _ := strconv.Atoi(res[1])
            return width, height, nil
        }
    }
    
    return 1920, 1080, nil // 默认值
}

Linux平台示例(使用xrandr):

// +build linux

package main

import (
    "os/exec"
    "strconv"
    "strings"
)

func GetPrimaryMonitorRect() (int, int, error) {
    cmd := exec.Command("xrandr")
    output, err := cmd.Output()
    if err != nil {
        return 0, 0, err
    }
    
    lines := strings.Split(string(output), "\n")
    for _, line := range lines {
        if strings.Contains(line, " connected") && strings.Contains(line, "primary") {
            parts := strings.Fields(line)
            for _, part := range parts {
                if strings.Contains(part, "x") && strings.Contains(part, "+0+0") {
                    res := strings.Split(part, "+")[0]
                    dims := strings.Split(res, "x")
                    if len(dims) == 2 {
                        width, _ := strconv.Atoi(dims[0])
                        height, _ := strconv.Atoi(dims[1])
                        return width, height, nil
                    }
                }
            }
        }
    }
    
    return 1920, 1080, nil // 默认值
}

与RobotGo集成的完整示例:

package main

import (
    "fmt"
    "runtime"
    
    "github.com/go-vgo/robotgo"
)

func main() {
    // 获取主显示器分辨率
    primaryWidth, primaryHeight, err := GetPrimaryMonitorRect()
    if err != nil {
        // 回退到RobotGo的全屏分辨率
        primaryWidth, primaryHeight = robotgo.GetScreenSize()
    }
    
    fmt.Printf("主显示器分辨率: %dx%d\n", primaryWidth, primaryHeight)
    
    // 使用主显示器分辨率进行鼠标移动
    mouseX := float32(0.5) // 示例:屏幕水平中心
    mouseY := float32(0.5) // 示例:屏幕垂直中心
    
    x := int(mouseX * float32(primaryWidth))
    y := int(mouseY * float32(primaryHeight))
    
    robotgo.Move(x, y)
    fmt.Printf("鼠标移动到: (%d, %d)\n", x, y)
    
    // 获取当前鼠标位置(相对于整个桌面)
    currentX, currentY := robotgo.GetMousePos()
    fmt.Printf("当前鼠标位置: (%d, %d)\n", currentX, currentY)
}

// 根据平台选择相应的实现
func GetPrimaryMonitorRect() (int, int, error) {
    switch runtime.GOOS {
    case "windows":
        return GetPrimaryMonitorRectWindows()
    case "darwin":
        return GetPrimaryMonitorRectMac()
    case "linux":
        return GetPrimaryMonitorRectLinux()
    default:
        return 1920, 1080, nil
    }
}

替代方案:使用go-ole(仅Windows,但更稳定):

// +build windows

package main

import (
    "github.com/go-ole/go-ole"
    "github.com/go-ole/go-ole/oleutil"
)

func GetPrimaryMonitorRectOLE() (int, int, error) {
    ole.CoInitialize(0)
    defer ole.CoUninitialize()
    
    unknown, _ := oleutil.CreateObject("WScript.Shell")
    ws, _ := unknown.QueryInterface(ole.IID_IDispatch)
    defer ws.Release()
    
    // 获取屏幕宽度和高度
    widthVar, _ := oleutil.CallMethod(ws, "RegRead", 
        "HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics\\AppliedDPI")
    dpi := int(widthVar.Val)
    
    // 计算实际分辨率(基于DPI缩放)
    sysWidth, _ := oleutil.GetProperty(ws, "ScreenWidth")
    sysHeight, _ := oleutil.GetProperty(ws, "ScreenHeight")
    
    width := int(sysWidth.Val) * 96 / dpi
    height := int(sysHeight.Val) * 96 / dpi
    
    return width, height, nil
}

这些解决方案提供了跨平台获取主显示器分辨率的方法,可以与RobotGo的鼠标移动功能配合使用。对于多显示器环境,建议将鼠标坐标限制在主显示器范围内,或者实现显示器识别逻辑来确定目标显示器。

回到顶部