在golang中实施全局热键? [英] Implement a global hotkey in golang?

查看:189
本文介绍了在golang中实施全局热键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有人想在Go(golang)中创建跨平台(Mac,Linux,Windows)全局热键-您在操作系统中的任意位置按热键组合,然后在终端中打印了一些内容。

Let's say someone wants to create a cross-platform (Mac, Linux, Windows) global hotkey in Go (golang) - you press a hotkey combination anywhere in OS and let's say something is printed in terminal.

当前,(2016年7月)我还没有找到可以做到这一点的图书馆,所以也许我们可以找到一种解决方法。

Currently, (July 2016) I haven't found any library to do that, so maybe we can find a way together.

当然,这涉及到每个操作系统对某些本机OS绑定的调用,但是有关如何执行此操作的信息很少。

It would involve, of course, calls to some native OS bindings for each OS, but there is very sparse information on how to do it.

从Google搜索中判断,应该使用 addGlobalMonitorForEventsMatchingMask

Judging from Googling one should use addGlobalMonitorForEventsMatchingMask

编辑:删除了无用的示例

useless example removed

看起来像嫌疑犯是 XGrabKey ,但是在附近看不到任何示例代码 https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+XGrabKey&type=Repositories&ref=searchresults

Looks like the suspect is XGrabKey, though, no example code anywhere in near sight https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+XGrabKey&type=Repositories&ref=searchresults

似乎我们需要使用 RegisterHotKey ,但是尝试查找一些示例代码无济于事:< a href = https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+RegisterHotKey rel = noreferrer> https://github.com/search?utf8=% E2%9C%93& q = language%3Ago + RegisterHotKey

It seems that we need to use RegisterHotKey, but trying to find some example code leads nowhere: https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+RegisterHotKey

一些有趣的跨平台项目(使用Java)是 https://github.com/tulskiy/jkeymaster

Some interesting cross-platform project to research (in Java) is https://github.com/tulskiy/jkeymaster

任何帮助

推荐答案

在大多数具有简单系统调用的操作系统上都是可能的,在Go中,您可以使用软件包 syscall 进行系统调用,而无需任何额外的C代码或cgo编译器。

This is possible on most operating systems with simple system calls, in Go you can use package syscall to do system calls without any extra C code or cgo compiler.

请注意, syscall 软件包的在线官方文档仅显示linux接口。其他操作系统的界面略有不同,例如在Windows上, syscall 软件包还包含 syscall.DLL 类型, syscall.LoadDLL() syscall.MustLoadDLL()函数等等。要查看这些内容,请在本地运行 godoc 工具,例如

Note that the online official documentation of the syscall package shows only the linux interface. Other operating systems have slightly different interface, e.g. on Windows the syscall package also contains a syscall.DLL type, syscall.LoadDLL() and syscall.MustLoadDLL() functions, among others. To view these, run the godoc tool locally, e.g.

godoc -http=:6060

这将启动一个托管与相似的网页的Web服务器godoc.org ,导航至 http:// localhost:6060 / pkg / syscall / 。您还可以在线查看特定于平台的文档,有关详细信息,请参见如何访问特定于平台的软件包文档?

This starts a webserver that hosts a web page similar to godoc.org, navigate to http://localhost:6060/pkg/syscall/. You can also see platform-specific doc online, for details, see How to access platform specific package documentation?

在这里,我以纯Go语言提供了一个完整的,可运行的Windows解决方案。完整的示例应用程序可在转到游乐场上找到。它不能在操场上运行,下载并在本地运行(在Windows上)。

Here I present a complete, runnable Windows solution in pure Go. The complete example application is available on the Go Playground. It doesn't run on the playground, download it and run it locally (on Windows).

让我们定义类型描述我们要使用的热键。这不是特定于Windows的,只是为了使我们的代码更好。 Hotkey.String()方法提供人性化的热键显示名称,例如 Hotkey [Id:1,Alt + Ctrl + O ]

Let's define the type to describe hotkeys we want to use. This is not Windows-specific, just to make our code nicer. The Hotkey.String() method provides a human-friendly display name of the hotkey such as "Hotkey[Id: 1, Alt+Ctrl+O]".

const (
    ModAlt = 1 << iota
    ModCtrl
    ModShift
    ModWin
)

type Hotkey struct {
    Id        int // Unique id
    Modifiers int // Mask of modifiers
    KeyCode   int // Key code, e.g. 'A'
}

// String returns a human-friendly display name of the hotkey
// such as "Hotkey[Id: 1, Alt+Ctrl+O]"
func (h *Hotkey) String() string {
    mod := &bytes.Buffer{}
    if h.Modifiers&ModAlt != 0 {
        mod.WriteString("Alt+")
    }
    if h.Modifiers&ModCtrl != 0 {
        mod.WriteString("Ctrl+")
    }
    if h.Modifiers&ModShift != 0 {
        mod.WriteString("Shift+")
    }
    if h.Modifiers&ModWin != 0 {
        mod.WriteString("Win+")
    }
    return fmt.Sprintf("Hotkey[Id: %d, %s%c]", h.Id, mod, h.KeyCode)
}

窗口 user32.dll 包含用于全局热键管理的功能。让我们加载它:

The windows user32.dll contains functions for global hotkey management. Let's load it:

user32 := syscall.MustLoadDLL("user32")
defer user32.Release()

它具有 RegisterHotkey() 用于注册全局热键的函数:

It has a RegisterHotkey() function for registering global hotkeys:

reghotkey := user32.MustFindProc("RegisterHotKey")

使用此功能,我们注册一些热键,即 ALT + CTRL + O ALT + SHIFT + M ALT + CTRL + X (将用于退出应用程序):

Using this, let's register some hotkeys, namely ALT+CTRL+O, ALT+SHIFT+M, ALT+CTRL+X (which will be used to exit from the app):

// Hotkeys to listen to:
keys := map[int16]*Hotkey{
    1: &Hotkey{1, ModAlt + ModCtrl, 'O'},  // ALT+CTRL+O
    2: &Hotkey{2, ModAlt + ModShift, 'M'}, // ALT+SHIFT+M
    3: &Hotkey{3, ModAlt + ModCtrl, 'X'},  // ALT+CTRL+X
}

// Register hotkeys:
for _, v := range keys {
    r1, _, err := reghotkey.Call(
        0, uintptr(v.Id), uintptr(v.Modifiers), uintptr(v.KeyCode))
    if r1 == 1 {
        fmt.Println("Registered", v)
    } else {
        fmt.Println("Failed to register", v, ", error:", err)
    }
}

我们需要一种方法来监听按下这些热键的事件。为此, user32.dll 包含 PeekMessage() 函数:

We need a way to "listen" to events of pressing those hotkeys. For this, user32.dll contains the PeekMessage() function:

peekmsg := user32.MustFindProc("PeekMessageW")

PeekMessage()将消息存储到 MSG 结构,让我们对其进行定义:

PeekMessage() stores the message into an MSG struct, let's define it:

type MSG struct {
    HWND   uintptr
    UINT   uintptr
    WPARAM int16
    LPARAM int64
    DWORD  int32
    POINT  struct{ X, Y int64 }
}

现在这是我们的监听循环,可以监听并对其进行操作全局按键(这里只需将按下的热键打印到控制台,如果按下 CTRL + ALT + X ,则退出应用程序):

Now here's our listening loop which listens and acts on global key presses (here just simply print the pressed hotkey to the console, and if CTRL+ALT+X is pressed, exit from the app):

for {
    var msg = &MSG{}
    peekmsg.Call(uintptr(unsafe.Pointer(msg)), 0, 0, 0, 1)

    // Registered id is in the WPARAM field:
    if id := msg.WPARAM; id != 0 {
        fmt.Println("Hotkey pressed:", keys[id])
        if id == 3 { // CTRL+ALT+X = Exit
            fmt.Println("CTRL+ALT+X pressed, goodbye...")
            return
        }
    }

    time.Sleep(time.Millisecond * 50)
}

我们完成了!

开始打印以上应用程序:

Starting the above application prints:

Registered Hotkey[Id: 1, Alt+Ctrl+O]
Registered Hotkey[Id: 2, Alt+Shift+M]
Registered Hotkey[Id: 3, Alt+Ctrl+X]

现在让我们按一些已注册的热键(任何应用程序都处于焦点状态,不一定是我们的应用程序),我们将在控制台上看到:

Now let's press some of the registered hotkeys (with any app being in focus, not necessarily our app), we'll see on the console:

Hotkey pressed: Hotkey[Id: 1, Alt+Ctrl+O]
Hotkey pressed: Hotkey[Id: 1, Alt+Ctrl+O]
Hotkey pressed: Hotkey[Id: 2, Alt+Shift+M]
Hotkey pressed: Hotkey[Id: 3, Alt+Ctrl+X]
CTRL+ALT+X pressed, goodbye...

这篇关于在golang中实施全局热键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆