Skip to content

Commit b4e6fbb

Browse files
committed
all: support keyup event (linux, x11)
Updates #9
1 parent 743f5b9 commit b4e6fbb

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

hotkey.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,14 @@ func New(mods []Modifier, key Key) *Hotkey {
7373
// collaborating with the golang.design/x/hotkey/mainthread package.
7474
func (hk *Hotkey) Register() error { return hk.register() }
7575

76-
// Keydown returns a channel that receives a signal when hotkey is triggered.
76+
// Keydown returns a channel that receives a signal when the hotkey is triggered.
7777
func (hk *Hotkey) Keydown() <-chan Event { return hk.keydownOut }
7878

7979
// Keyup returns a channel that receives a signal when the hotkey is released.
80+
//
81+
// Platform specific details:
82+
// - On Linux (X11), When AutoRepeat is enabled in the X server, the Keyup
83+
// is triggered automatically and continuously as Keydown continues.
8084
func (hk *Hotkey) Keyup() <-chan Event { return hk.keyupOut }
8185

8286
// Unregister unregisters the hotkey.

hotkey_linux.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66

77
//go:build linux
88

9+
#include <stdint.h>
910
#include <stdio.h>
1011
#include <X11/Xlib.h>
1112
#include <X11/Xutil.h>
1213

14+
extern void hotkeyDown(uintptr_t hkhandle);
15+
extern void hotkeyUp(uintptr_t hkhandle);
16+
1317
int displayTest() {
1418
Display* d = NULL;
1519
for (int i = 0; i < 42; i++) {
@@ -43,10 +47,7 @@ int displayTest() {
4347

4448
// waitHotkey blocks until the hotkey is triggered.
4549
// this function crashes the program if the hotkey already grabbed by others.
46-
int waitHotkey(unsigned int mod, int key) {
47-
// FIXME: handle registered hotkey properly.
48-
// XSetErrorHandler(handleErrors);
49-
50+
int waitHotkey(uintptr_t hkhandle, unsigned int mod, int key) {
5051
Display* d = NULL;
5152
for (int i = 0; i < 42; i++) {
5253
d = XOpenDisplay(0);
@@ -64,6 +65,10 @@ int waitHotkey(unsigned int mod, int key) {
6465
XNextEvent(d, &ev);
6566
switch(ev.type) {
6667
case KeyPress:
68+
hotkeyDown(hkhandle);
69+
continue;
70+
case KeyRelease:
71+
hotkeyUp(hkhandle);
6772
XUngrabKey(d, keycode, mod, DefaultRootWindow(d));
6873
XCloseDisplay(d);
6974
return 0;

hotkey_linux.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ package hotkey
1111
/*
1212
#cgo LDFLAGS: -lX11
1313
14+
#include <stdint.h>
15+
1416
int displayTest();
15-
int waitHotkey(unsigned int mod, int key);
17+
int waitHotkey(uintptr_t hkhandle, unsigned int mod, int key);
1618
*/
1719
import "C"
1820
import (
1921
"context"
2022
"errors"
23+
"runtime"
24+
"runtime/cgo"
2125
"sync"
2226
)
2327

@@ -80,27 +84,40 @@ func (hk *Hotkey) unregister() error {
8084
// handle registers an application global hotkey to the system,
8185
// and returns a channel that will signal if the hotkey is triggered.
8286
func (hk *Hotkey) handle() {
87+
runtime.LockOSThread()
88+
defer runtime.UnlockOSThread()
8389
// KNOWN ISSUE: if a hotkey is grabbed by others, C side will crash the program
8490

8591
var mod Modifier
8692
for _, m := range hk.mods {
8793
mod = mod | m
8894
}
95+
h := cgo.NewHandle(hk)
96+
defer h.Delete()
97+
8998
for {
9099
select {
91100
case <-hk.ctx.Done():
92101
close(hk.canceled)
93102
return
94103
default:
95-
ret := C.waitHotkey(C.uint(mod), C.int(hk.key))
96-
if ret != 0 {
97-
continue
98-
}
99-
hk.keydownIn <- Event{}
104+
_ = C.waitHotkey(C.uintptr_t(h), C.uint(mod), C.int(hk.key))
100105
}
101106
}
102107
}
103108

109+
//export hotkeyDown
110+
func hotkeyDown(h uintptr) {
111+
hk := cgo.Handle(h).Value().(*Hotkey)
112+
hk.keydownIn <- Event{}
113+
}
114+
115+
//export hotkeyUp
116+
func hotkeyUp(h uintptr) {
117+
hk := cgo.Handle(h).Value().(*Hotkey)
118+
hk.keyupIn <- Event{}
119+
}
120+
104121
// Modifier represents a modifier.
105122
type Modifier uint32
106123

0 commit comments

Comments
 (0)