在 Go 中使用 RegisterHotkey 和 PeekMessagew 时延迟不一致

问题描述 投票:0回答:1

我正在尝试编写一个简单的 Go 程序,该程序将在后台监听全局 Windows 热键,并在按下特定热键时发送 API 调用。这是我第一次学习如何使用 Windows 消息,所以这可能只是我不理解它们是如何工作的。

即使按下了热键,我对 PeekMessageW 的调用也经常返回 0,然后大约一分钟后突然立即返回所有值。这只是预期的行为吗?

我在同一个线程上做所有事情。首先,我创建一个新窗口并保存 HWND,如下所示:

func createWindow(
    user32 *syscall.DLL,
    dwExStyle uint32,
    lpClassName, lpWindowName *uint16,
    dwStyle uint32,
    x, y, nWidth, nHeight int,
    hWndParent, hMenu, hInstance uintptr,
    lpParam unsafe.Pointer,
) uintptr {
    procCreateWindowEx := user32.MustFindProc("CreateWindowExW")

    ret, _, _ := procCreateWindowEx.Call(
        uintptr(dwExStyle),
        uintptr(unsafe.Pointer(lpClassName)),
        uintptr(unsafe.Pointer(lpWindowName)),
        uintptr(dwStyle),
        uintptr(x),
        uintptr(y),
        uintptr(nWidth),
        uintptr(nHeight),
        hWndParent,
        hMenu,
        hInstance,
        uintptr(lpParam),
    )
    return ret
}

func GiveSimpleWindowPls(user32 *syscall.DLL) uintptr {
    var hwnd uintptr
    className, _ := syscall.UTF16PtrFromString("STATIC")
    windowName, _ := syscall.UTF16PtrFromString("Simple Window")

    hwnd = createWindow(
        user32,
        0,
        className,
        windowName,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        nil,
    )

    if hwnd != 0 {
        fmt.Println("HWND:", hwnd)
    } else {
        fmt.Println("Could not create window")
    }
    return hwnd
}

然后我注册我的热键:

func Register(user32 *syscall.DLL, hwnd uintptr) (map[int]*Hotkey, error) {
    reghotkey := user32.MustFindProc("RegisterHotKey")

    // Hotkeys to listen to:
    // (hardcoded for now)
    keys := map[int]*Hotkey{
        6:  {6, ModAlt + ModCtrl + ModShift, '6'},
        7:  {7, ModAlt + ModCtrl + ModShift, '7'},
        8:  {8, ModAlt + ModCtrl + ModShift, '8'},
        9:  {9, ModAlt + ModCtrl + ModShift, '9'},
        10: {10, ModAlt + ModCtrl + ModShift, '0'},
    }

    // Register hotkeys:
    for _, v := range keys {
        r1, _, err := reghotkey.Call(hwnd, uintptr(v.Id), uintptr(v.Modifiers), uintptr(v.KeyCode))
        if r1 != 1 {
            return nil, fmt.Errorf("error registering hotkey %#v: %w", v, err)
        }
    }
    return keys, nil
}

最后循环调用PeekMessageW:

const WM_HOTKEY = 0x0312

func Listen(keys map[int]*Hotkey, switcher Switcher, hwnd uintptr) {
    peekmsg := user32.MustFindProc("PeekMessageW")

    for {
        var msg = &MSG{}
        a, _, _ := peekmsg.Call(uintptr(unsafe.Pointer(msg)), hwnd, WM_HOTKEY, WM_HOTKEY, 1)
        fmt.Printf("%#v %d \n", msg, a)

        if a == 0 {
            time.Sleep(time.Millisecond * 50)
            continue
        }

        if key, ok := keys[int(msg.WPARAM)]; ok {
            fmt.Println("Hotkey was pressed:", key)

            switcher.Switch(key.Id) // for now this just does nothing and returns
        }
    }
}

起初这似乎工作得很好,但每隔一分钟左右,即使我按下热键,PeekMessageW 也开始只返回 0。然后过了一会儿,它就一个接一个地返回所有消息,就好像队列拥塞了一段时间,终于被释放了。

我期望在按下热键后能够立即(或至少在几秒钟内)查看 WM_HOTKEY 消息,这是错误的吗?该程序有时会一次停止接收这些消息长达一分钟,然后突然一次处理所有消息。队列是否被我运行的 Windows 优先处理的其他进程阻塞?

这是我第一次尝试弄清楚这是如何工作的,但我花了几个小时在网上搜索解决方案,但看不出哪里出了问题。

windows go hotkeys registerhotkey peekmessage
1个回答
0
投票

我似乎已经解决了这个问题。我认为我调用 PeekMessageW 的频率太高(每 50 毫秒),因为将睡眠时间增加到 500 可以解决问题。它的响应速度不是很好,但就我的目的而言,它做得很好。

© www.soinside.com 2019 - 2024. All rights reserved.