// 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 //go:build darwin package hotkey /* #cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework Cocoa -framework Carbon #include #import #import extern void keydownCallback(uintptr_t handle); extern void keyupCallback(uintptr_t handle); int registerHotKey(int mod, int key, uintptr_t handle, EventHotKeyRef* ref); int unregisterHotKey(EventHotKeyRef ref); */ import "C" import ( "errors" "runtime/cgo" "sync" ) // Hotkey is a combination of modifiers and key to trigger an event type platformHotkey struct { mu sync.Mutex registered bool hkref C.EventHotKeyRef } func (hk *Hotkey) register() error { hk.mu.Lock() defer hk.mu.Unlock() if hk.registered { return errors.New("hotkey already registered") } // Note: we use handle number as hotkey id in the C side. // A cgo handle could ran out of space, but since in hotkey purpose // we won't have that much number of hotkeys. So this should be fine. h := cgo.NewHandle(hk) var mod Modifier for _, m := range hk.mods { mod += m } ret := C.registerHotKey(C.int(mod), C.int(hk.key), C.uintptr_t(h), &hk.hkref) if ret == C.int(-1) { return errors.New("failed to register the hotkey") } hk.registered = true return nil } func (hk *Hotkey) unregister() error { hk.mu.Lock() defer hk.mu.Unlock() if !hk.registered { return errors.New("hotkey is not registered") } ret := C.unregisterHotKey(hk.hkref) if ret == C.int(-1) { return errors.New("failed to unregister the current hotkey") } hk.registered = false return nil } //export keydownCallback func keydownCallback(h uintptr) { hk := cgo.Handle(h).Value().(*Hotkey) hk.keydownIn <- Event{} } //export keyupCallback func keyupCallback(h uintptr) { hk := cgo.Handle(h).Value().(*Hotkey) hk.keyupIn <- Event{} } // Modifier represents a modifier. // See: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h type Modifier uint32 // All kinds of Modifiers const ( ModCtrl Modifier = 0x1000 ModShift Modifier = 0x200 ModOption Modifier = 0x800 ModCmd Modifier = 0x100 ) // Key represents a key. // See: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h type Key uint8 // All kinds of keys const ( KeySpace Key = 49 Key1 Key = 18 Key2 Key = 19 Key3 Key = 20 Key4 Key = 21 Key5 Key = 23 Key6 Key = 22 Key7 Key = 26 Key8 Key = 28 Key9 Key = 25 Key0 Key = 29 KeyA Key = 0 KeyB Key = 11 KeyC Key = 8 KeyD Key = 2 KeyE Key = 14 KeyF Key = 3 KeyG Key = 5 KeyH Key = 4 KeyI Key = 34 KeyJ Key = 38 KeyK Key = 40 KeyL Key = 37 KeyM Key = 46 KeyN Key = 45 KeyO Key = 31 KeyP Key = 35 KeyQ Key = 12 KeyR Key = 15 KeyS Key = 1 KeyT Key = 17 KeyU Key = 32 KeyV Key = 9 KeyW Key = 13 KeyX Key = 7 KeyY Key = 16 KeyZ Key = 6 KeyReturn Key = 0x24 KeyEscape Key = 0x35 KeyDelete Key = 0x33 KeyTab Key = 0x30 KeyLeft Key = 0x7B KeyRight Key = 0x7C KeyUp Key = 0x7E KeyDown Key = 0x7D KeyF1 Key = 0x7A KeyF2 Key = 0x78 KeyF3 Key = 0x63 KeyF4 Key = 0x76 KeyF5 Key = 0x60 KeyF6 Key = 0x61 KeyF7 Key = 0x62 KeyF8 Key = 0x64 KeyF9 Key = 0x65 KeyF10 Key = 0x6D KeyF11 Key = 0x67 KeyF12 Key = 0x6F KeyF13 Key = 0x69 KeyF14 Key = 0x6B KeyF15 Key = 0x71 KeyF16 Key = 0x6A KeyF17 Key = 0x40 KeyF18 Key = 0x4F KeyF19 Key = 0x50 KeyF20 Key = 0x5A )