Package keybind

import "github.com/BurntSushi/xgbutil/keybind"
Overview
Index

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, column byte) 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
    func (callback KeyPressFun) Connect(xu *xgbutil.XUtil, win xproto.Window, keyStr string, grab bool) error
    func (callback KeyPressFun) Run(xu *xgbutil.XUtil, event interface{})
type KeyReleaseFun
    func (callback KeyReleaseFun) Connect(xu *xgbutil.XUtil, win xproto.Window, keyStr string, grab bool) error
    func (callback KeyReleaseFun) Run(xu *xgbutil.XUtil, event interface{})

Package files

callback.go doc.go encoding.go keybind.go keysymdef.go xutil.go

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", "",
    }
)

func DeduceKeyInfo

func DeduceKeyInfo(state uint16,
    detail xproto.Keycode) (uint16, xproto.Keycode)

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

func Detach(xu *xgbutil.XUtil, win xproto.Window)

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

func DetachPress(xu *xgbutil.XUtil, win xproto.Window)

DetachPress is the same as Detach, except it only removes handlers for key *press* events.

func DetachRelease

func DetachRelease(xu *xgbutil.XUtil, win xproto.Window)

DetachRelease is the same as Detach, except it only removes handlers for key *release* events.

func DummyGrab

func DummyGrab(xu *xgbutil.XUtil) error

DummyGrab grabs the keyboard and sends all key events to the dummy window.

func DummyUngrab

func DummyUngrab(xu *xgbutil.XUtil)

DummyUngrab ungrabs the keyboard from the dummy window.

func Grab

func Grab(xu *xgbutil.XUtil, win xproto.Window,
    mods uint16, key xproto.Keycode)

Grab grabs a key with mods on a particular window. This will also grab all combinations of modifiers found in xevent.IgnoreMods.

func GrabChecked

func GrabChecked(xu *xgbutil.XUtil, win xproto.Window,
    mods uint16, key xproto.Keycode) error

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

func GrabKeyboard(xu *xgbutil.XUtil, win xproto.Window) error

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

func Initialize(xu *xgbutil.XUtil)

Initialize attaches the appropriate callbacks to make key bindings easier. i.e., update state of the world on a MappingNotify.

func KeyMapGet

func KeyMapGet(xu *xgbutil.XUtil) *xgbutil.KeyboardMapping

KeyMapGet accessor.

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

func KeyMatch(xu *xgbutil.XUtil,
    keyStr string, mods uint16, keycode xproto.Keycode) bool

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

func KeysymGet(xu *xgbutil.XUtil, keycode xproto.Keycode,
    column byte) xproto.Keysym

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

func KeysymToStr(keysym xproto.Keysym) string

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

func LookupString(xu *xgbutil.XUtil, mods uint16,
    keycode xproto.Keycode) string

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

func ModGet(xu *xgbutil.XUtil, keycode xproto.Keycode) uint16

ModGet finds the modifier currently associated with a given keycode. If a modifier doesn't exist for this keycode, then 0 is returned.

func ModMapGet

func ModMapGet(xu *xgbutil.XUtil) *xgbutil.ModifierMapping

ModMapGet accessor.

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

func ModifierString(mods uint16) string

ModifierString takes in a keyboard state and returns a string of all modifiers in the state.

func ParseString

func ParseString(
    xu *xgbutil.XUtil, s string) (uint16, []xproto.Keycode, error)

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

func SmartGrab(xu *xgbutil.XUtil, win xproto.Window) error

SmartGrab grabs the keyboard for the given window, and redirects all key events in the xevent main event loop to avoid races.

func SmartUngrab

func SmartUngrab(xu *xgbutil.XUtil)

SmartUngrab reverses SmartGrab and stops redirecting all key events.

func StrToKeycodes

func StrToKeycodes(xu *xgbutil.XUtil, str string) []xproto.Keycode

StrToKeycodes is a wrapper around keycodesGet meant to make our search a bit more flexible if needed. (i.e., case-insensitive)

func Ungrab

func Ungrab(xu *xgbutil.XUtil, win xproto.Window,
    mods uint16, key xproto.Keycode)

Ungrab undoes Grab. It will handle all combinations od modifiers found in xevent.IgnoreMods.

func UngrabKeyboard

func UngrabKeyboard(xu *xgbutil.XUtil)

UngrabKeyboard undoes GrabKeyboard.

type KeyPressFun

type KeyPressFun xevent.KeyPressFun

KeyPressFun represents a function that is called when a particular key binding is fired.

func (KeyPressFun) Connect

func (callback KeyPressFun) Connect(xu *xgbutil.XUtil, win xproto.Window,
    keyStr string, grab bool) error

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) Connect

func (callback KeyReleaseFun) Connect(xu *xgbutil.XUtil, win xproto.Window,
    keyStr string, grab bool) error

func (KeyReleaseFun) Run

func (callback KeyReleaseFun) Run(xu *xgbutil.XUtil, event interface{})