¿Implementar una tecla de acceso directo global en Golang?
cross-platform hotkeys (2)
Digamos que alguien quiere crear una tecla de acceso directo global multiplataforma (Mac, Linux, Windows) en Go (golang): presiona una combinación de teclas de acceso rápido en cualquier parte del sistema operativo y digamos que algo se imprime en el terminal.
Actualmente, (julio de 2016) no he encontrado ninguna biblioteca para hacer eso, así que tal vez podamos encontrar un camino juntos.
Implicaría, por supuesto, llamadas a algunos enlaces de sistema operativo nativos para cada sistema operativo, pero hay información muy escasa sobre cómo hacerlo.
Mac
A juzgar por googlear, se debe usar addGlobalMonitorForEventsMatchingMask
EDIT: ejemplo inútil eliminado
Linux
Parece que el sospechoso es XGrabKey
, sin embargo, no hay código de ejemplo cerca https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+XGrabKey&type=Repositories&ref=searchresults
Windows
Parece que necesitamos usar RegisterHotKey
, pero intentar encontrar algún código de ejemplo no conduce a ninguna parte: https://github.com/search?utf8=%E2%9C%93&q=language%3Ago+RegisterHotKey
Algunos interesantes proyectos multiplataforma para investigar (en Java) son https://github.com/tulskiy/jkeymaster
Cualquier ayuda sería muy apreciada!
Esto es posible en la mayoría de los sistemas operativos con llamadas simples al sistema, en Go puede usar package syscall
para hacer llamadas al sistema sin ningún código C adicional o compilador cgo.
Tenga en cuenta que la documentación oficial en línea del paquete syscall
muestra solo la interfaz de Linux. Otros sistemas operativos tienen una interfaz ligeramente diferente, por ejemplo, en Windows, el paquete syscall
también contiene las syscall.DLL
, syscall.LoadDLL()
y syscall.MustLoadDLL()
, entre otras. Para verlos, ejecute la herramienta godoc
localmente, por ejemplo
godoc -http=:6060
Esto inicia un servidor web que aloja una página web similar a godoc.org
, navegue a http://localhost:6060/pkg/syscall/
.
Aquí presento una solución de Windows completa y ejecutable en Go puro. La aplicación de ejemplo completa está disponible en Go Playground . No se ejecuta en el patio de recreo, descárguelo y ejecútelo localmente (en Windows).
Vamos a definir el tipo para describir las teclas de acceso rápido que queremos usar. Esto no es específico de Windows, solo para hacer que nuestro código sea mejor. El método Hotkey.String()
proporciona un nombre de visualización amigable para las personas, como "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)
}
Windows user32.dll
contiene funciones para la administración global de teclas de user32.dll
rápido. Vamos a cargarlo:
user32 := syscall.MustLoadDLL("user32")
defer user32.Release()
Tiene una función RegisterHotkey()
para registrar teclas de acceso rápido globales:
reghotkey := user32.MustFindProc("RegisterHotKey")
Usando esto, registremos algunas teclas de acceso rápido, a saber ALT + CTRL + O , ALT + MAYÚS + M , ALT + CTRL + X (que se usarán para salir de la aplicación):
// 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)
}
}
Necesitamos una forma de "escuchar" los eventos de presionar esas teclas de acceso rápido. Para esto, user32.dll
contiene la función PeekMessage()
:
peekmsg := user32.MustFindProc("PeekMessageW")
PeekMessage()
almacena el mensaje en una estructura MSG
, definámoslo:
type MSG struct {
HWND uintptr
UINT uintptr
WPARAM int16
LPARAM int64
DWORD int32
POINT struct{ X, Y int64 }
}
Ahora aquí está nuestro bucle de escucha que escucha y actúa al presionar las teclas globales (aquí simplemente imprima la tecla de acceso rápido presionada en la consola, y si presiona CTRL + ALT + X , salga de la aplicación):
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)
}
¡Y hemos terminado!
A partir de la aplicación anterior se imprime:
Registered Hotkey[Id: 1, Alt+Ctrl+O]
Registered Hotkey[Id: 2, Alt+Shift+M]
Registered Hotkey[Id: 3, Alt+Ctrl+X]
Ahora presionemos algunas de las teclas de acceso rápido registradas (con cualquier aplicación enfocada, no necesariamente nuestra aplicación), veremos en la consola:
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...
Se puede hacer. Por ejemplo, el motor de juegos Azul3d puede hacer eso https://github.com/azul3d/engine/tree/master/keyboard . El fragmento de código de OSX no se compila porque falta el archivo AppDelegate.h. Puede escribirlo a mano o compilar primero el proyecto con XCode, que se encarga de la contabilidad, y luego ver AppDelegate.h y AppDelegate.m. En Linux para registrar el flujo de pulsaciones de teclas, puede leer el archivo de ID / dev / input / event $ que se realiza aquí https://github.com/MarinX/keylogger . En Windows necesitará algunos syscalls como en este código https://github.com/eiannone/keyboard . Tanto en nix como en win, ni siquiera necesitas cgo y puedes ser feliz con syscalls y pure go.