Documentation ¶
Overview ¶
Package keybind provides an easy to use interface to assign callback functions to human readable key sequences.
Working with the X keyboard encoding is not an easy task, and the keybind package attempts to encapsulate much of the complexity. Namely, the keybind package exports two function types: KeyPressFun and KeyReleaseFun. Values of these types are functions, and have a method called 'Connect' that attaches an event handler to be run when a particular key press is issued.
This is virtually identical to the way calbacks are attached using the xevent package, but the Connect method in the keybind package has a couple extra parameters that are specific to key bindings. Namely, the key sequence to respond to (which is a combination of zero or more modifiers and exactly one key) and whether to establish a passive grab. One can still attach callbacks to Key{Press,Release} events using xevent, but it will be run for *all* Key{Press,Release} events. (This is typically what one might do when setting up an active grab.)
Initialization ¶
Before using the keybind package, you should *always* make a single call to keybind.Initialize for each X connection you're working with.
Key sequence format ¶
Key sequences are human readable strings made up of zero or more modifiers and exactly one key. Namely:
[Mod[-Mod[...]]-]KEY
Where 'Mod' can be one of: shift, lock, control, mod1, mod2, mod3, mod4, mod5, or any. You can view which keys activate each modifier using the 'xmodmap' program. (If you don't have 'xmodmap', you could also run the 'xmodmap' example in the examples directory.)
KEY must correspond to a valid keysym. Keysyms can be found by pressing keys using the 'xev' program. Alternatively, you may inspect the 'keysyms' map in xgbutil/keybind/keysymdef.go.
An example key sequence might look like 'Mod4-Control-Shift-t'. The keybinding for that key sequence is activated when all three modifiers---mod4, control and shift---are pressed along with the 't' key.
When to issue a passive grab ¶
One of the parameters of the 'Connect' method is whether to issue a passive grab or not. A passive grab is useful when you need to respond to a key press on some parent window (like the root window) without actually focusing that window. Not using a passive grab is useful when you only need to read key presses when the window is focused.
For more information on the semantics of passive grabs, please see http://tronche.com/gui/x/xlib/input/XGrabKey.html.
Also, by default, when issuing a grab on a particular (modifiers, keycode) tuple, several grabs are actually made. In particular, for each grab requested, another grab is made with the "num lock" mask, another grab is made with the "caps lock" mask, and another grab is made with both the "num lock" and "caps locks" masks. This allows key events to be reported regardless of whether caps lock or num lock is enabled.
The extra masks added can be modified by changing the xevent.IgnoreMods slice. If you modify xevent.IgnoreMods, it should be modified once on program startup (i.e., before any key or mouse bindings are established) and never modified again.
Key bindings on the root window example ¶
To run a particular function whenever the 'Mod4-Control-Shift-t' key combination is pressed (mod4 is typically the 'super' or 'windows' key, but can vary based on your system), use something like:
keybind.Initialize(XUtilValue) // call once before using keybind package keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { // do something when key is pressed }).Connect(XUtilValue, XUtilValue.RootWin(), "Mod4-Control-Shift-t", true)
Note that we issue a passive grab because Key{Press,Release} events on the root window will only be reported when the root window has focus if no grab exists.
Key bindings on a window you create example ¶
This code snippet attaches an event handler to some window you've created without using a grab. Thus, the function will only be activated when the key sequence is pressed and your window has focus.
keybind.Initialize(XUtilValue) // call once before using keybind package keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { // do something when key is pressed }).Connect(XUtilValue, your-window-id, "Mod4-t", false)
Run a function on all key press events example ¶
This code snippet actually does *not* use the keybind package, but illustrates how the Key{Press,Release} event handlers in the xevent package can still be useful. Namely, the keybind package discriminates among events depending upon the key sequences pressed, whereas the xevent package is more general: it can only discriminate at the event level.
xevent.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { // do something when any key is pressed }).Connect(XUtilValue, your-window-id)
This is the kind of handler you might use to capture all key press events. (i.e., if you have a text box for a user to type in.) Additionally, if you're using this sort of event handler, keybind.LookupString will probably be of some use. Its contract is that given a (modifiers, keycode) tuple (information found in all Key{Press,Release} events) it will return a string representation of the key pressed. We can modify the above example slightly to echo the key pressed:
xevent.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { fmt.Println("Key pressed:", keybind.LookupString(X, ev.State, ev.Detail)) }).Connect(XUtilValue, your-window-id)
More examples ¶
Complete working examples can be found in the examples directory of xgbutil. Of particular interest are probably 'keypress-english' and 'simple-keybinding'.
Index ¶
- Variables
- func DeduceKeyInfo(state uint16, detail xproto.Keycode) (uint16, xproto.Keycode)
- func Detach(xu *xgbutil.XUtil, win xproto.Window)
- func DetachPress(xu *xgbutil.XUtil, win xproto.Window)
- func DetachRelease(xu *xgbutil.XUtil, win xproto.Window)
- func DummyGrab(xu *xgbutil.XUtil) error
- func DummyUngrab(xu *xgbutil.XUtil)
- func Grab(xu *xgbutil.XUtil, win xproto.Window, mods uint16, key xproto.Keycode)
- func GrabChecked(xu *xgbutil.XUtil, win xproto.Window, mods uint16, key xproto.Keycode) error
- func GrabKeyboard(xu *xgbutil.XUtil, win xproto.Window) error
- func Initialize(xu *xgbutil.XUtil)
- func KeyMapGet(xu *xgbutil.XUtil) *xgbutil.KeyboardMapping
- func KeyMapSet(xu *xgbutil.XUtil, keyMapReply *xproto.GetKeyboardMappingReply)
- func KeyMatch(xu *xgbutil.XUtil, keyStr string, mods uint16, keycode xproto.Keycode) bool
- func KeysymGet(xu *xgbutil.XUtil, keycode xproto.Keycode, column byte) xproto.Keysym
- func KeysymGetWithMap(xu *xgbutil.XUtil, keyMap *xgbutil.KeyboardMapping, keycode xproto.Keycode, ...) xproto.Keysym
- func KeysymToStr(keysym xproto.Keysym) string
- func LookupString(xu *xgbutil.XUtil, mods uint16, keycode xproto.Keycode) string
- func MapsGet(xu *xgbutil.XUtil) (*xproto.GetKeyboardMappingReply, *xproto.GetModifierMappingReply)
- func ModGet(xu *xgbutil.XUtil, keycode xproto.Keycode) uint16
- func ModMapGet(xu *xgbutil.XUtil) *xgbutil.ModifierMapping
- func ModMapSet(xu *xgbutil.XUtil, modMapReply *xproto.GetModifierMappingReply)
- func ModifierString(mods uint16) string
- func ParseString(xu *xgbutil.XUtil, s string) (uint16, []xproto.Keycode, error)
- func SmartGrab(xu *xgbutil.XUtil, win xproto.Window) error
- func SmartUngrab(xu *xgbutil.XUtil)
- func StrToKeycodes(xu *xgbutil.XUtil, str string) []xproto.Keycode
- func Ungrab(xu *xgbutil.XUtil, win xproto.Window, mods uint16, key xproto.Keycode)
- func UngrabKeyboard(xu *xgbutil.XUtil)
- type KeyPressFun
- type KeyReleaseFun
Constants ¶
This section is empty.
Variables ¶
var ( Modifiers []uint16 = []uint16{ xproto.ModMaskShift, xproto.ModMaskLock, xproto.ModMaskControl, xproto.ModMask1, xproto.ModMask2, xproto.ModMask3, xproto.ModMask4, xproto.ModMask5, xproto.ModMaskAny, } NiceModifiers = []string{ "shift", "lock", "control", "mod1", "mod2", "mod3", "mod4", "mod5", "", } )
Functions ¶
func DeduceKeyInfo ¶
DeduceKeyInfo AND's the "ignored modifiers" out of the state returned by a Key{Press,Release} event. This is useful to connect a (state, keycode) tuple from an event with a tuple specified by the user.
func Detach ¶
Detach removes all handlers for all key events for the provided window id. This should be called whenever a window is no longer receiving events to make sure the garbage collector can release memory used to store the handler info.
func DetachPress ¶
DetachPress is the same as Detach, except it only removes handlers for key *press* events.
func DetachRelease ¶
DetachRelease is the same as Detach, except it only removes handlers for key *release* events.
func DummyUngrab ¶
DummyUngrab ungrabs the keyboard from the dummy window.
func Grab ¶
Grab grabs a key with mods on a particular window. This will also grab all combinations of modifiers found in xevent.IgnoreMods.
func GrabChecked ¶
GrabChecked Grabs a key with mods on a particular window. This is the same as Grab, except that it issue a checked request. Which means that an error could be returned and handled on the spot. (Checked requests are slower than unchecked requests.) This will also grab all combinations of modifiers found in xevent.IgnoreMods.
func GrabKeyboard ¶
GrabKeyboard grabs the entire keyboard. Returns whether GrabStatus is successful and an error if one is reported by XGB. It is possible to not get an error and the grab to be unsuccessful. The purpose of 'win' is that after a grab is successful, ALL Key*Events will be sent to that window. Make sure you have a callback attached :-)
func Initialize ¶
Initialize attaches the appropriate callbacks to make key bindings easier. i.e., update state of the world on a MappingNotify.
func KeyMapSet ¶
func KeyMapSet(xu *xgbutil.XUtil, keyMapReply *xproto.GetKeyboardMappingReply)
KeyMapSet updates XUtil.keymap. This is exported for use in the keybind package. You probably shouldn't use this. (You may need to use this if you're rolling your own event loop, and still want to use the keybind package.)
func KeyMatch ¶
KeyMatch returns true if a string representation of a key can be matched (case insensitive) to the (modifiers, keycode) tuple provided. String representations can be found in keybind/keysymdef.go
func KeysymGet ¶
KeysymGet is a shortcut alias for 'KeysymGetWithMap' using the current keymap stored in XUtil. keybind.Initialize MUST have been called before using this function.
func KeysymGetWithMap ¶
func KeysymGetWithMap(xu *xgbutil.XUtil, keyMap *xgbutil.KeyboardMapping, keycode xproto.Keycode, column byte) xproto.Keysym
KeysymGetWithMap uses the given key map and finds a keysym associated with the given keycode in the current X environment.
func KeysymToStr ¶
KeysymToStr converts a keysym to a string if one is available. If one is found, KeysymToStr also checks the 'weirdKeysyms' map, which contains a map from multi-character strings to single character representations (i.e., 'braceleft' to '{'). If no match is found initially, an empty string is returned.
func LookupString ¶
LookupString attempts to convert a (modifiers, keycode) to an english string. It essentially implements the rules described at http://goo.gl/qum9q Namely, the bulleted list that describes how key syms should be interpreted when various modifiers are pressed. Note that we ignore the logic that asks us to check if particular key codes are mapped to particular modifiers (i.e., "XK_Caps_Lock" to "Lock" modifier). We just check if the modifiers are activated. That's good enough for me. XXX: We ignore num lock stuff. XXX: We ignore MODE SWITCH stuff. (i.e., we don't use group 2 key syms.)
func MapsGet ¶
func MapsGet(xu *xgbutil.XUtil) (*xproto.GetKeyboardMappingReply, *xproto.GetModifierMappingReply)
A convenience function to grab the KeyboardMapping and ModifierMapping from X. We need to do this on startup (see Initialize) and whenever we get a MappingNotify event.
func ModGet ¶
ModGet finds the modifier currently associated with a given keycode. If a modifier doesn't exist for this keycode, then 0 is returned.
func ModMapSet ¶
func ModMapSet(xu *xgbutil.XUtil, modMapReply *xproto.GetModifierMappingReply)
ModMapSet updates XUtil.modmap. This is exported for use in the keybind package. You probably shouldn't use this. (You may need to use this if you're rolling your own event loop, and still want to use the keybind package.)
func ModifierString ¶
ModifierString takes in a keyboard state and returns a string of all modifiers in the state.
func ParseString ¶
ParseString takes a string of the format '[Mod[-Mod[...]]]-KEY', i.e., 'Mod4-j', and returns a modifiers/keycode combo. An error is returned if the string is malformed, or if no valid KEY can be found. Valid values of KEY should include almost anything returned by pressing keys with the 'xev' program. Alternatively, you may reference the keys of the 'keysyms' map defined in keybind/keysymdef.go.
func SmartGrab ¶
SmartGrab grabs the keyboard for the given window, and redirects all key events in the xevent main event loop to avoid races.
func SmartUngrab ¶
SmartUngrab reverses SmartGrab and stops redirecting all key events.
func StrToKeycodes ¶
StrToKeycodes is a wrapper around keycodesGet meant to make our search a bit more flexible if needed. (i.e., case-insensitive)
Types ¶
type KeyPressFun ¶
type KeyPressFun xevent.KeyPressFun
KeyPressFun represents a function that is called when a particular key binding is fired.
func (KeyPressFun) Run ¶
func (callback KeyPressFun) Run(xu *xgbutil.XUtil, event interface{})
type KeyReleaseFun ¶
type KeyReleaseFun xevent.KeyReleaseFun
KeyReleaseFun represents a function that is called when a particular key binding is fired.
func (KeyReleaseFun) Run ¶
func (callback KeyReleaseFun) Run(xu *xgbutil.XUtil, event interface{})