File tree Expand file tree Collapse file tree 3 files changed +37
-11
lines changed Expand file tree Collapse file tree 3 files changed +37
-11
lines changed Original file line number Diff line number Diff line change @@ -73,10 +73,14 @@ func New(mods []Modifier, key Key) *Hotkey {
73
73
// collaborating with the golang.design/x/hotkey/mainthread package.
74
74
func (hk * Hotkey ) Register () error { return hk .register () }
75
75
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.
77
77
func (hk * Hotkey ) Keydown () <- chan Event { return hk .keydownOut }
78
78
79
79
// 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.
80
84
func (hk * Hotkey ) Keyup () <- chan Event { return hk .keyupOut }
81
85
82
86
// Unregister unregisters the hotkey.
Original file line number Diff line number Diff line change 6
6
7
7
//go:build linux
8
8
9
+ #include <stdint.h>
9
10
#include <stdio.h>
10
11
#include <X11/Xlib.h>
11
12
#include <X11/Xutil.h>
12
13
14
+ extern void hotkeyDown (uintptr_t hkhandle );
15
+ extern void hotkeyUp (uintptr_t hkhandle );
16
+
13
17
int displayTest () {
14
18
Display * d = NULL ;
15
19
for (int i = 0 ; i < 42 ; i ++ ) {
@@ -43,10 +47,7 @@ int displayTest() {
43
47
44
48
// waitHotkey blocks until the hotkey is triggered.
45
49
// 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 ) {
50
51
Display * d = NULL ;
51
52
for (int i = 0 ; i < 42 ; i ++ ) {
52
53
d = XOpenDisplay (0 );
@@ -64,6 +65,10 @@ int waitHotkey(unsigned int mod, int key) {
64
65
XNextEvent (d , & ev );
65
66
switch (ev .type ) {
66
67
case KeyPress :
68
+ hotkeyDown (hkhandle );
69
+ continue ;
70
+ case KeyRelease :
71
+ hotkeyUp (hkhandle );
67
72
XUngrabKey (d , keycode , mod , DefaultRootWindow (d ));
68
73
XCloseDisplay (d );
69
74
return 0 ;
Original file line number Diff line number Diff line change @@ -11,13 +11,17 @@ package hotkey
11
11
/*
12
12
#cgo LDFLAGS: -lX11
13
13
14
+ #include <stdint.h>
15
+
14
16
int displayTest();
15
- int waitHotkey(unsigned int mod, int key);
17
+ int waitHotkey(uintptr_t hkhandle, unsigned int mod, int key);
16
18
*/
17
19
import "C"
18
20
import (
19
21
"context"
20
22
"errors"
23
+ "runtime"
24
+ "runtime/cgo"
21
25
"sync"
22
26
)
23
27
@@ -80,27 +84,40 @@ func (hk *Hotkey) unregister() error {
80
84
// handle registers an application global hotkey to the system,
81
85
// and returns a channel that will signal if the hotkey is triggered.
82
86
func (hk * Hotkey ) handle () {
87
+ runtime .LockOSThread ()
88
+ defer runtime .UnlockOSThread ()
83
89
// KNOWN ISSUE: if a hotkey is grabbed by others, C side will crash the program
84
90
85
91
var mod Modifier
86
92
for _ , m := range hk .mods {
87
93
mod = mod | m
88
94
}
95
+ h := cgo .NewHandle (hk )
96
+ defer h .Delete ()
97
+
89
98
for {
90
99
select {
91
100
case <- hk .ctx .Done ():
92
101
close (hk .canceled )
93
102
return
94
103
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 ))
100
105
}
101
106
}
102
107
}
103
108
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
+
104
121
// Modifier represents a modifier.
105
122
type Modifier uint32
106
123
You can’t perform that action at this time.
0 commit comments