go cross-platform hotkeys

¿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.