-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
1,253 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# These are supported funding model platforms | ||
|
||
github: [changkun] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] | ||
patreon: # Replace with a single Patreon username | ||
open_collective: # Replace with a single Open Collective username | ||
ko_fi: # Replace with a single Ko-fi username | ||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel | ||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry | ||
liberapay: # Replace with a single Liberapay username | ||
issuehunt: # Replace with a single IssueHunt username | ||
otechie: # Replace with a single Otechie username | ||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Copyright 2021 The golang.design Initiative Authors. | ||
# All rights reserved. Use of this source code is governed | ||
# by a MIT license that can be found in the LICENSE file. | ||
# | ||
# Written by Changkun Ou <changkun.de> | ||
|
||
name: hotkey | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
|
||
jobs: | ||
platform_test: | ||
|
||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
|
||
steps: | ||
|
||
- name: install xvfb libx11-dev | ||
run: | | ||
sudo apt update | ||
sudo apt install -y xvfb libx11-dev | ||
if: ${{ runner.os == 'Linux' }} | ||
|
||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-go@v2 | ||
with: | ||
stable: 'false' | ||
go-version: '1.16.0' | ||
|
||
- name: TestLinux | ||
run: | | ||
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & | ||
export DISPLAY=:99.0 | ||
sleep 5s | ||
go test -v -covermode=atomic ./... | ||
if: ${{ runner.os == 'Linux' }} | ||
|
||
- name: TestOthers | ||
run: | | ||
go test -v -covermode=atomic ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,70 @@ | ||
# hotkey | ||
cross platform hotkey package | ||
# hotkey [![PkgGoDev](https://pkg.go.dev/badge/golang.design/x/hotkey)](https://pkg.go.dev/golang.design/x/hotkey) ![](https://changkun.de/urlstat?mode=github&repo=golang-design/hotkey) ![hotkey](https://github.com/golang-design/hotkey/workflows/hotkey/badge.svg?branch=main) | ||
|
||
cross platform hotkey package in Go | ||
|
||
```go | ||
import "golang.design/x/hotkey" | ||
``` | ||
|
||
## Features | ||
|
||
- Cross platform supports: macOS, Linux (X11), and Windows | ||
- Global hotkey registration without focus on a window | ||
|
||
## API Usage | ||
|
||
Package `hotkey` provides the basic facility to register a system-level | ||
hotkey so that the application can be notified if a user triggers the | ||
desired hotkey. By definition, a hotkey is a combination of modifiers | ||
and a single key, and thus register a hotkey that contains multiple | ||
keys is not supported at the moment. Furthermore, because of OS | ||
restriction, hotkey events must be handled on the main thread. | ||
|
||
Therefore, in order to use this package properly, here is a complete | ||
example that corporates the [mainthread](https://golang.design/s/mainthread) | ||
package: | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"context" | ||
|
||
"golang.design/x/hotkey" | ||
"golang.design/x/mainthread" | ||
) | ||
|
||
// initialize mainthread facility so that hotkey can be | ||
// properly registered to the system and handled by the | ||
// application. | ||
func main() { mainthread.Init(fn) } | ||
func fn() { // Use fn as the actual main function. | ||
var ( | ||
mods = []hotkey.Modifier{hotkey.ModCtrl} | ||
k = hotkey.KeyS | ||
) | ||
|
||
// Register a desired hotkey. | ||
hk, err := hotkey.Register(mods, k) | ||
if err != nil { | ||
panic("hotkey registration failed") | ||
} | ||
|
||
// Start listen hotkey event whenever you feel it is ready. | ||
triggered := hk.Listen(context.Background()) | ||
for range triggered { | ||
println("hotkey ctrl+s is triggered") | ||
} | ||
} | ||
``` | ||
|
||
## Who is using this package? | ||
|
||
The main purpose of building this package is to support the | ||
[midgard](https://changkun.de/s/midgard) project. | ||
|
||
To know more projects, check our [wiki](https://github.com/golang-design/clipboard/wiki) page. | ||
|
||
## License | ||
|
||
MIT | © 2021 The golang.design Initiative Authors, written by [Changkun Ou](https://changkun.de). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright 2021 The golang.design Initiative Authors. | ||
// All rights reserved. Use of this source code is governed | ||
// by a MIT license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"context" | ||
|
||
"golang.design/x/hotkey" | ||
"golang.design/x/mainthread" | ||
) | ||
|
||
func main() { mainthread.Init(fn) } | ||
func fn() { | ||
var ( | ||
mods = []hotkey.Modifier{hotkey.ModCtrl} | ||
k = hotkey.KeyS | ||
) | ||
|
||
hk, err := hotkey.Register(mods, k) | ||
if err != nil { | ||
panic("hotkey registration failed") | ||
} | ||
|
||
triggered := hk.Listen(context.Background()) | ||
for range triggered { | ||
println("hotkey ctrl+s is triggered") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
module golang.design/x/hotkey | ||
|
||
go 1.16 | ||
go 1.16 | ||
|
||
require ( | ||
golang.design/x/mainthread v0.2.1 | ||
golang.org/x/sys v0.0.0-20210122093101-04d7465088b8 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
golang.design/x/mainthread v0.2.1 h1:IUGVW1acDfKoQtFeeS/RD/YYiKK8jxwkJXIQuKuL+ig= | ||
golang.design/x/mainthread v0.2.1/go.mod h1:vYX7cF2b3pTJMGM/hc13NmN6kblKnf4/IyvHeu259L0= | ||
golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210122093101-04d7465088b8 h1:de2yTH1xuxjmGB7i6Z5o2z3RCHVa0XlpSZzjd8Fe6bE= | ||
golang.org/x/sys v0.0.0-20210122093101-04d7465088b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2021 The golang.design Initiative Authors. | ||
// All rights reserved. Use of this source code is governed | ||
// by a MIT license that can be found in the LICENSE file. | ||
// | ||
// Written by Changkun Ou <changkun.de> | ||
|
||
// Package hotkey provides the basic facility to register a system-level | ||
// hotkey so that the application can be notified if a user triggers the | ||
// desired hotkey. By definition, a hotkey is a combination of modifiers | ||
// and a single key, and thus register a hotkey that contains multiple | ||
// keys is not supported at the moment. Furthermore, because of OS | ||
// restriction, hotkey events must be handled on the main thread. | ||
// | ||
// Therefore, in order to use this package properly, here is a complete | ||
// example that corporates the golang.design/x/mainthread package: | ||
// | ||
// package main | ||
// | ||
// import ( | ||
// "context" | ||
// | ||
// "golang.design/x/hotkey" | ||
// "golang.design/x/mainthread" | ||
// ) | ||
// | ||
// // initialize mainthread facility so that hotkey can be | ||
// // properly registered to the system and handled by the | ||
// // application. | ||
// func main() { mainthread.Init(fn) } | ||
// func fn() { // Use fn as the actual main function. | ||
// var ( | ||
// mods = []hotkey.Modifier{hotkey.ModCtrl} | ||
// k = hotkey.KeyS | ||
// ) | ||
// | ||
// // Register a desired hotkey. | ||
// hk, err := hotkey.Register(mods, k) | ||
// if err != nil { | ||
// panic("hotkey registration failed") | ||
// } | ||
// | ||
// // Start listen hotkey event whenever you feel it is ready. | ||
// triggered := hk.Listen(context.Background()) | ||
// for range triggered { | ||
// println("hotkey ctrl+s is triggered") | ||
// } | ||
// } | ||
package hotkey | ||
|
||
import ( | ||
"context" | ||
"runtime" | ||
|
||
"golang.design/x/mainthread" | ||
) | ||
|
||
// Event represents a hotkey event | ||
type Event struct{} | ||
|
||
// Hotkey is a combination of modifiers and key to trigger an event | ||
type Hotkey struct { | ||
mods []Modifier | ||
key Key | ||
|
||
in chan<- Event | ||
out <-chan Event | ||
} | ||
|
||
// Register registers a combination of hotkeys. If the hotkey has | ||
// registered. This function will invalidates the old registration | ||
// and overwrites its callback. | ||
func Register(mods []Modifier, key Key) (*Hotkey, error) { | ||
in, out := newEventChan() | ||
hk := &Hotkey{mods, key, in, out} | ||
|
||
var err error | ||
mainthread.Call(func() { err = hk.register() }) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
runtime.SetFinalizer(hk, func(hk *Hotkey) { | ||
hk.unregister() | ||
}) | ||
|
||
return hk, nil | ||
} | ||
|
||
// Listen handles a hotkey event and triggers a call to fn. | ||
// The hotkey listen hook terminates when the context is canceled. | ||
func (hk *Hotkey) Listen(ctx context.Context) <-chan Event { | ||
mainthread.Go(func() { hk.handle(ctx) }) | ||
return hk.out | ||
} | ||
|
||
// newEventChan returns a sender and a receiver of a buffered channel | ||
// with infinite capacity. | ||
func newEventChan() (chan<- Event, <-chan Event) { | ||
in, out := make(chan Event), make(chan Event) | ||
|
||
go func() { | ||
var q []Event | ||
|
||
for { | ||
e, ok := <-in | ||
if !ok { | ||
close(out) | ||
return | ||
} | ||
q = append(q, e) | ||
for len(q) > 0 { | ||
select { | ||
case out <- q[0]: | ||
q = q[1:] | ||
case e, ok := <-in: | ||
if ok { | ||
q = append(q, e) | ||
break | ||
} | ||
for _, e := range q { | ||
out <- e | ||
} | ||
close(out) | ||
return | ||
} | ||
} | ||
} | ||
}() | ||
return in, out | ||
} |
Oops, something went wrong.