Git Product home page Git Product logo

hotkey's Introduction

hotkey PkgGoDev hotkey

cross platform hotkey package in 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 global hotkey shortcut so that an application can be notified if a user triggers the desired hotkey. A hotkey must be a combination of modifiers and a single key.

package main

import (
	"log"

	"golang.design/x/hotkey"
	"golang.design/x/hotkey/mainthread"
)

func main() { mainthread.Init(fn) } // Not necessary when use in Fyne, Ebiten or Gio.
func fn() {
	hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
	err := hk.Register()
	if err != nil {
		log.Fatalf("hotkey: failed to register hotkey: %v", err)
		return
	}

	log.Printf("hotkey: %v is registered\n", hk)
	<-hk.Keydown()
	log.Printf("hotkey: %v is down\n", hk)
	<-hk.Keyup()
	log.Printf("hotkey: %v is up\n", hk)
	hk.Unregister()
	log.Printf("hotkey: %v is unregistered\n", hk)
}

Note platform specific details:

  • On macOS, due to the OS restriction (other platforms does not have this restriction), hotkey events must be handled on the "main thread". Therefore, in order to use this package properly, one must start an OS main event loop on the main thread, For self-contained applications, using golang.design/x/hotkey/mainthread is possible. It is uncessary or applications based on other GUI frameworks, such as fyne, ebiten, or Gio. See the "./examples" folder for more examples.
  • On Linux (X11), when AutoRepeat is enabled in the X server, the Keyup is triggered automatically and continuously as Keydown continues.
  • On Linux (X11), some keys may be mapped to multiple Mod keys. To correctly register the key combination, one must use the correct underlying keycode combination. For example, a regular Ctrl+Alt+S might be registered as: Ctrl+Mod2+Mod4+S.
  • If this package did not include a desired key, one can always provide the keycode to the API. For example, if a key code is 0x15, then the corresponding key is hotkey.Key(0x15).

Examples

Description Folder
A minimum example minimum
Register multiple hotkeys multiple
A example to use in GLFW glfw
A example to use in Fyne fyne
A example to use in Ebiten ebiten
A example to use in Gio gio

Who is using this package?

The main purpose of building this package is to support the midgard project.

To know more projects, check our wiki page.

License

MIT | © 2021 The golang.design Initiative Authors, written by Changkun Ou.

hotkey's People

Contributors

changkun avatar data-niklas avatar seamory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

hotkey's Issues

Question: Can other keys be used apart from the ones that hardcoded in library?

As subject goes, can we use other keys to listen for - for example, Alt (Linux / Windows) and Space ?
I tried to pass the key code myself instead of key.KeyS for example, but got an error about integer overflow, which is expected.
For example, when tried to use Alt from the keysymdef.h file

#define XK_Alt_L                         0xffe9  /* Left alt */

and passing it down to hotkey.New(), you get the error about int overflow
image
because

type Key uint8

What is the reason for this limitation and would it be possible to workaround / change it?

Thanks for the library!

Windows Hotkey Always "S"

There seems to be an error in hotkey_windows.go at line 26. It always gives KeyS as the key instead of the key from hk.

I am still fairly new to golang, so I am not sure if how I think it should be fixed would work.

ERROR: hotkey: xxx is registered

I am trying to use this library with wails GUI library and everytime I get the error message that a hotkey is registered
image

ERROR: hotkey: 109+4+1 is registered

X Error of failed request:  BadAccess (attempt to access private resource denied)
  Major opcode of failed request:  33 (X_GrabKey)
  Serial number of failed request:  10
  Current serial number in output stream:  11

exit status 1

no matter which key I am using with any modifier
not even sure where to look for some additional debuggin info, would you have any advice / help?

documentation

I want to make an autoclick in Go. Looking through you readme, i still dont understand how to use it and what everything is for.
Please update your documention for clarity

(also, what does for range triggered do? why for range and not if triggered

Are there any ways to detect key holding press?

I'm try to detect key which press for long time under the windows platform, but it's seem like no ways.

When I press key, and keep on, until I release the key after a while. And the log tell me that the Keydown and Keyup trigger many times.

So are there any ways to detect key holding press? Thx.

Media Key support?

Would it be possible to add the ability to recognize media key events? (PlayPause / Prev / Next)? Especially on Windows this would be very useful. (Windows's native media key API doesn't really work for non-UWP apps)

Hotkey shortcut monitoring will hijack information

Hotkey shortcut monitoring will hijack the information of the shortcut key. When I run the following code, I copy a piece of text and paste it in the browser's search box. The information is hijacked, and it can only be paused when I end the program.

package main

import (
	"golang.design/x/clipboard"
	"log"
	"sync"

	"golang.design/x/hotkey"
	"golang.design/x/hotkey/mainthread"
)

func main() {
	mainthread.Init(fn)
}

func fn() {
	err := clipboard.Init()
	if err != nil {
		panic(err)
	}
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		defer wg.Done()
		for {
			err := listenHotkey(hotkey.KeyC, hotkey.ModCtrl)
			if err != nil {
				log.Println(err)
			}
		}
	}()
	go func() {
		defer wg.Done()
		for {
			err := listenHotkey(hotkey.KeyV, hotkey.ModCtrl)
			if err != nil {
				log.Println(err)
			}
			//imageData := clipboard.Read(clipboard.FmtImage)
			//base64String := base64.StdEncoding.EncodeToString(imageData)
			//log.Println(base64String)
			textData := clipboard.Read(clipboard.FmtText)
			log.Println(string(textData))
		}
	}()
	wg.Wait()
}

func listenHotkey(key hotkey.Key, mods ...hotkey.Modifier) (err error) {
	var ms []hotkey.Modifier
	ms = append(ms, mods...)
	hk := hotkey.New(ms, key)

	err = hk.Register()
	if err != nil {
		return
	}

	<-hk.Keydown()
	log.Printf("hotkey: %v is down\n", hk)
	<-hk.Keyup()
	log.Printf("hotkey: %v is up\n", hk)
	hk.Unregister()
	return
}

BadAccess (X_GrabKey) when registering combination is obtained by others

Hotkey register causes the app to crash with the following output:

ventsi@localhost:/media/sf_prosper> go run app.go 
X Error of failed request:  BadAccess (attempt to access private resource denied)
  Major opcode of failed request:  33 (X_GrabKey)
  Serial number of failed request:  10
  Current serial number in output stream:  11
exit status 1

Commenting out the code to register hotkey fixes the issue:
image

This is openSUSE Leap 15.3 running in VirtualBox.

Allow listen on key up

The current Hotkey.Listen API can only trigger hotkey's keydown events. This lacks the ability to listen to keyup events.

We need to break the current API to enable this ability in the next version.

Linux hotkey can not be canceled correctly

Description

The Linux C code event loop only returns after the hotkey was pressed. The hotkey can not be canceled while waitHotkey waits for a new hotkey. hk.Unregister() can be successfully called, but the hotkey is only unregistered after it was triggered.

Steps to reproduce

  1. Register a simple hotkey on Linux
  2. Unregister the hotkey

Notes

hk := h.New([]h.Modifier{h.ModCtrl}, h.KeyM)
hk.Register()
go func() {
  time.Sleep(time.Second * 1)
  fmt.Println("Hotkey will be unregistered")
  hk.Unregister()
  fmt.Println("Hotkey unregistered")
  hk.Register()
  fmt.Println("Registered again")
}()
<-hk.Keydown()

This code blocks. I would expect the chan to be closed and the program to exit.

hotkey/hotkey_linux.c

Lines 64 to 77 in a5dde31

while(1) {
XNextEvent(d, &ev);
switch(ev.type) {
case KeyPress:
hotkeyDown(hkhandle);
continue;
case KeyRelease:
hotkeyUp(hkhandle);
XUngrabKey(d, keycode, mod, DefaultRootWindow(d));
XCloseDisplay(d);
return 0;
}
}
}

I would expect that the above loop checks, if the hotkey was unregistered. XNextEvent also blocks until the next event, but that should be fine as long as a lot of events are triggered. Else something like XPending could be used to check, if new events can be processed.

Can multiple hotkeys be registered at the same time?

For example, listening to Ctrl+1 and Ctrl+2 at the same time.
my test failed on OSX, is this not allowed, or is it used incorrectly?

package main

import (
	"context"
	"golang.design/x/hotkey"
	"golang.design/x/mainthread"
)

func register(tag chan bool, mods []hotkey.Modifier, k hotkey.Key, output string) {
	go func() {
		hk, err := hotkey.Register(mods, k)
		if err != nil {
			panic("hotkey registration failed")
		}
		triggered := hk.Listen(context.Background())
		<-tag
		for range triggered {
			println("hotkey", output)
		}
	}()
}

func fn() {
	c := make(chan bool, 1)
	c <- true
	register(c, []hotkey.Modifier{hotkey.ModCtrl}, hotkey.Key1, "1")
	c <- true
	register(c, []hotkey.Modifier{hotkey.ModCtrl}, hotkey.Key2, "2")
}

func main() {
	mainthread.Init(fn)
}

Export Hotkeys

I'd like to save the hotkey struct to a datastore on file so the user dosn't have to re enter the desired hotkey.

Seems like I need to store the hotkey via string function and reconstruct it at runtime?
Would be better to have the fields declared public so I can easily export them

Allow unregister hotkeys

There seems to be a TODO for Darwin and an UnregisterHotKey already for Windows. Any plans on adding implementation for Darwin and using the one available for Windows?

Space key?

Thanks for the library, it works like a charm.

Just wanted to ask why Space key is not available with this package?

I could make a PR to add the space key here if wanted

Not working on Ubuntu 18?

The .Register() call succeeds without returning an error, but the shortcuts I'm trying (Ctrl + Shift + O and Ctrl + Shift + P) just aren't receiving any events. Using sudo showkey I see the same keycodes for ctrl (29), shift (42), and O (24) as I do in a Ubuntu 22 VM where the hotkey does work. Are there dependencies that may not be present in Ubuntu 18? Any ideas on how to debug?

Isolate OS runApp

hotkey package runs an internal application that will take over the mainthread.

This limits the package usage, which cannot collaborate with other GUI packages, such as fyne, gio, ebiten, and etc.

Figure out a way to provide native OS features in an isolated package, such as app, so that users can choose to use that package or not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.