Skip to content

Commit b950a6e

Browse files
committed
all: support keyup event (darwin)
Fixes #9
1 parent b4e6fbb commit b950a6e

14 files changed

+752
-95
lines changed

README.md

+43-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,51 @@ import "golang.design/x/hotkey"
1313

1414
## API Usage
1515

16-
Package hotkey provides the primary facility to register a system-level global hotkey shortcut to notify an application if a user triggers the desired hotkey. A hotkey must be a combination of modifiers and a single key.
16+
Package hotkey provides the basic facility to register a system-level
17+
global hotkey shortcut so that an application can be notified if a user
18+
triggers the desired hotkey. A hotkey must be a combination of modifiers
19+
and a single key.
1720

18-
Note a platform-specific detail on `macOS` due to the OS restriction (other platforms do not have this restriction): hotkey events must be handled on the "main thread". Therefore, to use this package properly, one must call the `(*Hotkey).Register` method on the main thread, and an OS app main event loop must be established. One can use the provided `golang.design/x/hotkey/mainthread` for self-contained applications. For applications based on other GUI frameworks, one has to use their provided ability to run the `(*Hotkey).Register` on the main thread. See the [examples](./examples) folder for more examples.
21+
```go
22+
func main() { mainthread.Init(fn) } // not necessary when use in Fyne, Ebiten or Gio.
23+
func fn() {
24+
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
25+
err := hk.Register()
26+
if err != nil {
27+
return
28+
}
29+
fmt.Printf("hotkey: %v is registered\n", hk)
30+
<-hk.Keydown()
31+
fmt.Printf("hotkey: %v is down\n", hk)
32+
<-hk.Keyup()
33+
fmt.Printf("hotkey: %v is up\n", hk)
34+
hk.Unregister()
35+
fmt.Printf("hotkey: %v is unregistered\n", hk)
36+
}
37+
```
38+
39+
Note platform specific details:
40+
41+
- On macOS, due to the OS restriction (other
42+
platforms does not have this restriction), hotkey events must be handled
43+
on the "main thread". Therefore, in order to use this package properly,
44+
one must start an OS main event loop on the main thread, For self-contained
45+
applications, using [golang.design/x/hotkey/mainthread](https://pkg.go.dev/golang.design/x/hotkey/mainthread) is possible.
46+
For applications based on other GUI frameworks, such as fyne, ebiten, or Gio.
47+
This is not necessary. See the "[./examples](./examples)" folder for more examples.
48+
- On Linux (X11), when AutoRepeat is enabled in the X server, the Keyup
49+
is triggered automatically and continuously as Keydown continues.
50+
51+
## Examples
1952

53+
| Description | Folder |
54+
|:------------|:------:|
55+
| A minimum example | [minimum](./examples/minimum/main.go) |
56+
| Register multiple hotkeys | [multiple](./examples/multiple/main.go) |
57+
| A example to use in GLFW | [glfw](./examples/glfw/main.go) |
58+
| A example to use in Fyne | [fyne](./examples/fyne/main.go) |
59+
| A example to use in Ebiten | [ebiten](./examples/ebiten/main.go) |
60+
| A example to use in Gio | [gio](./examples/gio/main.go) |
2061
## Who is using this package?
2162

2263
The main purpose of building this package is to support the

examples/README.md

-4
This file was deleted.

examples/ebiten/main.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ func reghk() {
3939
// Register a desired hotkey.
4040
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
4141

42-
var err error
43-
if ebiten.RunOnMainThread(func() { err = hk.Register() }); err != nil {
42+
if err := hk.Register(); err != nil {
4443
log.Println("failed to register hotkey: %v", err)
4544
return
4645
}

examples/fyne/main.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2022 The golang.design Initiative Authors.
2+
// All rights reserved. Use of this source code is governed
3+
// by a MIT license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"fyne.io/fyne/v2"
9+
"fyne.io/fyne/v2/app"
10+
"fyne.io/fyne/v2/container"
11+
"fyne.io/fyne/v2/widget"
12+
"golang.design/x/hotkey"
13+
)
14+
15+
func main() {
16+
w := app.New().NewWindow("golang.design/x/hotkey")
17+
label := widget.NewLabel("Hello golang.design!")
18+
button := widget.NewButton("Hi!", func() { label.SetText("Welcome :)") })
19+
w.SetContent(container.NewVBox(label, button))
20+
21+
go func() {
22+
// Register a desired hotkey.
23+
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
24+
if err := hk.Register(); err != nil {
25+
panic("hotkey registration failed")
26+
}
27+
// Start listen hotkey event whenever it is ready.
28+
for range hk.Keydown() {
29+
button.Tapped(&fyne.PointEvent{})
30+
}
31+
}()
32+
33+
w.ShowAndRun()
34+
}

examples/gio/main.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2022 The golang.design Initiative Authors.
2+
// All rights reserved. Use of this source code is governed
3+
// by a MIT license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"os"
9+
10+
"gioui.org/app"
11+
"gioui.org/unit"
12+
"golang.design/x/hotkey"
13+
)
14+
15+
func main() {
16+
go fn()
17+
app.Main()
18+
}
19+
20+
func fn() {
21+
w := app.NewWindow(app.Title("golang.design/x/hotkey"), app.Size(unit.Dp(200), unit.Dp(200)))
22+
23+
go reghk()
24+
25+
for range w.Events() {
26+
}
27+
}
28+
29+
func reghk() {
30+
// Register a desired hotkey.
31+
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
32+
if err := hk.Register(); err != nil {
33+
panic("hotkey registration failed")
34+
}
35+
36+
// Unregister the hotkey when keydown event is triggered
37+
for range hk.Keydown() {
38+
hk.Unregister()
39+
}
40+
41+
// Exist the app.
42+
os.Exit(0)
43+
}

examples/glfw/main.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2022 The golang.design Initiative Authors.
2+
// All rights reserved. Use of this source code is governed
3+
// by a MIT license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"fmt"
9+
"runtime"
10+
11+
"github.com/go-gl/glfw/v3.3/glfw"
12+
"golang.design/x/hotkey"
13+
)
14+
15+
func init() {
16+
runtime.LockOSThread()
17+
}
18+
19+
func main() {
20+
err := glfw.Init()
21+
if err != nil {
22+
panic(err)
23+
}
24+
defer glfw.Terminate()
25+
window, err := glfw.CreateWindow(640, 480, "golang.design/x/hotkey", nil, nil)
26+
if err != nil {
27+
panic(err)
28+
}
29+
30+
go func() {
31+
// Register a desired hotkey.
32+
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
33+
if err := hk.Register(); err != nil {
34+
panic("hotkey registration failed")
35+
}
36+
// Start listen hotkey event whenever it is ready.
37+
for range hk.Keydown() {
38+
fmt.Println("keydown!")
39+
}
40+
}()
41+
42+
window.MakeContextCurrent()
43+
for !window.ShouldClose() {
44+
window.SwapBuffers()
45+
glfw.PollEvents()
46+
}
47+
}

examples/go.mod

+20-2
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,37 @@ module golang.design/x/hotkey/examples
33
go 1.17
44

55
require (
6+
fyne.io/fyne/v2 v2.1.2
7+
gioui.org v0.0.0-20220104172405-7751d737403e
8+
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec
69
github.com/hajimehoshi/ebiten/v2 v2.3.0-alpha.4.0.20220103082943-8418c4a65551
710
golang.design/x/hotkey v0.2.1
811
)
912

1013
require (
11-
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec // indirect
14+
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
15+
gioui.org/shader v1.0.6 // indirect
16+
github.com/davecgh/go-spew v1.1.1 // indirect
17+
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect
18+
github.com/fsnotify/fsnotify v1.4.9 // indirect
19+
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect
20+
github.com/godbus/dbus/v5 v5.0.4 // indirect
21+
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
1222
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect
23+
github.com/pmezard/go-difflib v1.0.0 // indirect
24+
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
25+
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
26+
github.com/stretchr/testify v1.7.0 // indirect
27+
github.com/yuin/goldmark v1.4.0 // indirect
1328
golang.design/x/mainthread v0.3.0 // indirect
14-
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
29+
golang.org/x/exp v0.0.0-20210722180016-6781d3edade3 // indirect
1530
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
1631
golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5 // indirect
32+
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
1733
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
1834
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
35+
golang.org/x/text v0.3.6 // indirect
36+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
1937
)
2038

2139
replace golang.design/x/hotkey => ../

0 commit comments

Comments
 (0)