// xkbcommon contains Go bindings for the libxkbcommon C library. All the doc // comments here are 1-to-1 copies of the C doc comments, and may refer to // C-specific behavior that is abstracted away by the bindings. package xkbcommon import ( "errors" "unsafe" ) /* #cgo pkg-config: xkbcommon #include #include */ import "C" // @struct xkb_context // Opaque top level library context object. // // The context contains various general library data and state, like // logging level and include paths. // // Objects are created in a specific context, and multiple contexts may // coexist simultaneously. Objects from different contexts are completely // separated and do not share any memory or state. type Context C.struct_xkb_context func (c *Context) value() *C.struct_xkb_context { return (*C.struct_xkb_context)(c) } // Opaque compiled keymap object. // // The keymap object holds all of the static keyboard information obtained // from compiling XKB files. // // A keymap is immutable after it is created (besides reference counts, etc.); // if you need to change it, you must create a new one. type Keymap C.struct_xkb_keymap func (k *Keymap) value() *C.struct_xkb_keymap { return (*C.struct_xkb_keymap)(k) } // @struct xkb_state // Opaque keyboard state object. // // State objects contain the active state of a keyboard (or keyboards), such // as the currently effective layout and the active modifiers. It acts as a // simple state machine, wherein key presses and releases are the input, and // key symbols (keysyms) are the output. type State C.struct_xkb_state func (s *State) value() *C.struct_xkb_state { return (*C.struct_xkb_state)(s) } // A number used to represent a physical key on a keyboard. // // A standard PC-compatible keyboard might have 102 keys. An appropriate // keymap would assign each of them a keycode, by which the user should // refer to the key throughout the library. // // Historically, the X11 protocol, and consequentially the XKB protocol, // assign only 8 bits for keycodes. This limits the number of different // keys that can be used simultaneously in a single keymap to 256 // (disregarding other limitations). This library does not share this limit; // keycodes beyond 255 ('extended keycodes') are not treated specially. // Keymaps and applications which are compatible with X11 should not use // these keycodes. // // The values of specific keycodes are determined by the keymap and the // underlying input system. For example, with an X11-compatible keymap // and Linux evdev scan codes (see linux/input.h), a fixed offset is used: // // The keymap defines a canonical name for each key, plus possible aliases. // Historically, the XKB protocol restricts these names to at most 4 (ASCII) // characters, but this library does not share this limit. // // @code // xkb_keycode_t keycode_A = KEY_A + 8; // @endcode // // @sa xkb_keycode_is_legal_ext() xkb_keycode_is_legal_x11() type Keycode C.xkb_keycode_t // A number used to represent the symbols generated from a key on a keyboard. // // A key, represented by a keycode, may generate different symbols according // to keyboard state. For example, on a QWERTY keyboard, pressing the key // labled \ generates the symbol ‘a’. If the Shift key is held, it // generates the symbol ‘A’. If a different layout is used, say Greek, // it generates the symbol ‘α’. And so on. // // Each such symbol is represented by a *keysym* (short for “key symbol”). // Note that keysyms are somewhat more general, in that they can also represent // some “function”, such as “Left” or “Right” for the arrow keys. For more // information, see: Appendix A [“KEYSYM Encoding”][encoding] of the X Window // System Protocol. // // Specifically named keysyms can be found in the // xkbcommon/xkbcommon-keysyms.h header file. Their name does not include // the `XKB_KEY_` prefix. // // Besides those, any Unicode/ISO 10646 character in the range U+0100 to // U+10FFFF can be represented by a keysym value in the range 0x01000100 to // 0x0110FFFF. The name of Unicode keysyms is `U`, e.g. `UA1B2`. // // The name of other unnamed keysyms is the hexadecimal representation of // their value, e.g. `0xabcd1234`. // // Keysym names are case-sensitive. // // @note **Encoding:** Keysyms are 32-bit integers with the 3 most significant // bits always set to zero. See: Appendix A [“KEYSYM Encoding”][encoding] of // the X Window System Protocol. // // @ingroup keysyms // @sa XKB_KEYSYM_MAX // // [encoding]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#keysym_encoding type Keysym C.xkb_keysym_t // Index of a modifier. // // A @e modifier is a state component which changes the way keys are // interpreted. A keymap defines a set of modifiers, such as Alt, Shift, // Num Lock or Meta, and specifies which keys may @e activate which // modifiers (in a many-to-many relationship, i.e. a key can activate // several modifiers, and a modifier may be activated by several keys. // Different keymaps do this differently). // // When retrieving the keysyms for a key, the active modifier set is // consulted; this detemines the correct shift level to use within the // currently active layout (see xkb_level_index_t). // // Modifier indices are consecutive. The first modifier has index 0. // // Each modifier must have a name, and the names are unique. Therefore, it // is safe to use the name as a unique identifier for a modifier. The names // of some common modifiers are provided in the xkbcommon/xkbcommon-names.h // header file. Modifier names are case-sensitive. // // @sa xkb_keymap_num_mods() type ModIndex C.xkb_mod_index_t // A mask of modifier indices. type ModMask C.xkb_mod_mask_t var ModInvalid ModIndex = C.XKB_MOD_INVALID // Names to compile a keymap with, also known as RMLVO. // // The names are the common configuration values by which a user picks // a keymap. // // If the entire struct is NULL, then each field is taken to be NULL. // You should prefer passing NULL instead of choosing your own defaults. type RuleNames struct { // The rules file to use. The rules file describes how to interpret // the values of the model, layout, variant and options fields. // // If NULL or the empty string "", a default value is used. // If the XKB_DEFAULT_RULES environment variable is set, it is used // as the default. Otherwise the system default is used. Rules string // The keyboard model by which to interpret keycodes and LEDs. // // If NULL or the empty string "", a default value is used. // If the XKB_DEFAULT_MODEL environment variable is set, it is used // as the default. Otherwise the system default is used. Model string // A comma separated list of layouts (languages) to include in the // keymap. // // If NULL or the empty string "", a default value is used. // If the XKB_DEFAULT_LAYOUT environment variable is set, it is used // as the default. Otherwise the system default is used. Layout string // A comma separated list of variants, one per layout, which may // modify or augment the respective layout in various ways. // // Generally, should either be empty or have the same number of values // as the number of layouts. You may use empty values as in "intl,,neo". // // If NULL or the empty string "", and a default value is also used // for the layout, a default value is used. Otherwise no variant is // used. // If the XKB_DEFAULT_VARIANT environment variable is set, it is used // as the default. Otherwise the system default is used. Variant string // A comma separated list of options, through which the user specifies // non-layout related preferences, like which key combinations are used // for switching layouts, or which key is the Compose key. // // If NULL, a default value is used. If the empty string "", no // options are used. // If the XKB_DEFAULT_OPTIONS environment variable is set, it is used // as the default. Otherwise the system default is used. Options string } func (rn *RuleNames) value() *C.struct_xkb_rule_names { if rn == nil { return nil } var cStruct C.struct_xkb_rule_names if rn.Rules != "" { cStruct.rules = C.CString(rn.Rules) } if rn.Model != "" { cStruct.model = C.CString(rn.Model) } if rn.Layout != "" { cStruct.layout = C.CString(rn.Layout) } if rn.Variant != "" { cStruct.variant = C.CString(rn.Variant) } if rn.Options != "" { cStruct.options = C.CString(rn.Options) } return &cStruct } func (rn *RuleNames) free(cStruct *C.struct_xkb_rule_names) { if cStruct != nil { C.free(unsafe.Pointer(cStruct.rules)) C.free(unsafe.Pointer(cStruct.model)) C.free(unsafe.Pointer(cStruct.layout)) C.free(unsafe.Pointer(cStruct.variant)) C.free(unsafe.Pointer(cStruct.options)) } } // Get the name of a keysym. // // For a description of how keysyms are named, see @ref xkb_keysym_t. // // @param[in] keysym The keysym. // @param[out] buffer A string buffer to write the name into. // @param[in] size Size of the buffer. // // @warning If the buffer passed is too small, the string is truncated // (though still NUL-terminated); a size of at least 64 bytes is recommended. // // @returns The number of bytes in the name, excluding the NUL byte. If // the keysym is invalid, returns -1. // // You may check if truncation has occurred by comparing the return value // with the length of buffer, similarly to the snprintf(3) function. // // @sa xkb_keysym_t func (k Keysym) Name() (string, bool) { size := C.xkb_keysym_get_name(C.xkb_keysym_t(k), nil, 0) if size < 0 { return "", false } buffer := (*C.char)(C.malloc(C.size_t(size + 1))) defer C.free((unsafe.Pointer)(buffer)) C.xkb_keysym_get_name(C.xkb_keysym_t(k), buffer, C.size_t(size+1)) return C.GoString(buffer), true } // Flags for context creation. type ContextFlags C.enum_xkb_context_flags var ( // Do not apply any context flags. ContextNoFlags ContextFlags = C.XKB_CONTEXT_NO_FLAGS // Create this context with an empty include path. ContextNoDefaultIncludes ContextFlags = C.XKB_CONTEXT_NO_DEFAULT_INCLUDES // Don't take RMLVO names from the environment // // @since 0.3.0 ContextNoEnvironmentNames ContextFlags = C.XKB_CONTEXT_NO_ENVIRONMENT_NAMES // Disable the use of secure_getenv for this context, so that privileged // processes can use environment variables. Client uses at their own risk. // // @since 1.5.0 ContextNoSecureGetenv ContextFlags = C.XKB_CONTEXT_NO_SECURE_GETENV ) // Create a new context. // // @param flags Optional flags for the context, or 0. // // @returns A new context, or NULL on failure. // // @memberof xkb_context func NewContext(flags ContextFlags) (*Context, error) { ctx := C.xkb_context_new(C.enum_xkb_context_flags(flags)) if ctx == nil { return nil, errors.New("failed to create context") } return (*Context)(ctx), nil } // Release a reference on a context, and possibly free it. // // @param context The context. If it is NULL, this function does nothing. // // @memberof xkb_context func (c *Context) Unref() { C.xkb_context_unref(c.value()) } // Flags for keymap compilation. type KeymapCompileFlags C.enum_xkb_keymap_compile_flags var ( // Do not apply any flags. KeymapCompileFlagsNoFlags KeymapCompileFlags = C.XKB_KEYMAP_COMPILE_NO_FLAGS ) // Create a keymap from RMLVO names. // // The primary keymap entry point: creates a new XKB keymap from a set of // RMLVO (Rules + Model + Layouts + Variants + Options) names. // // @param context The context in which to create the keymap. // @param names The RMLVO names to use. See xkb_rule_names. // @param flags Optional flags for the keymap, or 0. // // @returns A keymap compiled according to the RMLVO names, or NULL if // the compilation failed. // // @sa xkb_rule_names // @memberof xkb_keymap func NewKeymapFromNames(ctx *Context, names *RuleNames, flags KeymapCompileFlags) (*Keymap, error) { cNames := names.value() defer names.free(cNames) keymap := C.xkb_keymap_new_from_names(ctx.value(), cNames, C.enum_xkb_keymap_compile_flags(flags)) if keymap == nil { return nil, errors.New("failed to create keymap") } return (*Keymap)(keymap), nil } // Release a reference on a keymap, and possibly free it. // // @param keymap The keymap. If it is NULL, this function does nothing. // // @memberof xkb_keymap func (k *Keymap) Unref() { C.xkb_keymap_unref(k.value()) } // Get the index of a modifier by name. // // @returns The index. If no modifier with this name exists, returns // XKB_MOD_INVALID. // // @sa xkb_mod_index_t // @memberof xkb_keymap func (k *Keymap) ModGetIndex(name string) ModIndex { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return ModIndex(C.xkb_keymap_mod_get_index(k.value(), cName)) } // Create a new keyboard state object. // // @param keymap The keymap which the state will use. // // @returns A new keyboard state object, or NULL on failure. // // @memberof xkb_state func NewState(keymap *Keymap) (*State, error) { state := C.xkb_state_new(keymap.value()) if state == nil { return nil, errors.New("failed to create state") } return (*State)(state), nil } func (s *State) Unref() { C.xkb_state_unref(s.value()) } // Specifies the direction of the key (press / release). type KeyDirection C.enum_xkb_key_direction var ( // The key was released. KeyUp KeyDirection = C.XKB_KEY_UP // The key was pressed. KeyDown KeyDirection = C.XKB_KEY_DOWN ) // Modifier and layout types for state objects. This enum is bitmaskable, // e.g. (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED) is valid to // exclude locked modifiers. // // In XKB, the DEPRESSED components are also known as 'base'. type StateComponent C.enum_xkb_state_component var ( // Depressed modifiers, i.e. a key is physically holding them. StateModsDepressed StateComponent = C.XKB_STATE_MODS_DEPRESSED // Latched modifiers, i.e. will be unset after the next non-modifier // key press. StateModsLatched StateComponent = C.XKB_STATE_MODS_LATCHED // Locked modifiers, i.e. will be unset after the key provoking the // lock has been pressed again. StateModsLocked StateComponent = C.XKB_STATE_MODS_LOCKED // Effective modifiers, i.e. currently active and affect key // processing (derived from the other state components). // Use this unless you explicitly care how the state came about. StateModsEffective StateComponent = C.XKB_STATE_MODS_EFFECTIVE // Depressed layout, i.e. a key is physically holding it. StateLayoutDepressed StateComponent = C.XKB_STATE_LAYOUT_DEPRESSED // Latched layout, i.e. will be unset after the next non-modifier // key press. StateLayoutLatched StateComponent = C.XKB_STATE_LAYOUT_LATCHED // Locked layout, i.e. will be unset after the key provoking the lock // has been pressed again. StateLayoutLocked StateComponent = C.XKB_STATE_LAYOUT_LOCKED // Effective layout, i.e. currently active and affects key processing // (derived from the other state components). // Use this unless you explicitly care how the state came about. StateLayoutEffective StateComponent = C.XKB_STATE_LAYOUT_EFFECTIVE // LEDs (derived from the other state components). STATE_LEDS StateComponent = C.XKB_STATE_LEDS ) // Update the keyboard state to reflect a given key being pressed or // released. // // This entry point is intended for *server* applications and should not be used // by *client* applications; see @ref server-client-state for details. // // A series of calls to this function should be consistent; that is, a call // with XKB_KEY_DOWN for a key should be matched by an XKB_KEY_UP; if a key // is pressed twice, it should be released twice; etc. Otherwise (e.g. due // to missed input events), situations like "stuck modifiers" may occur. // // This function is often used in conjunction with the function // xkb_state_key_get_syms() (or xkb_state_key_get_one_sym()), for example, // when handling a key event. In this case, you should prefer to get the // keysyms *before* updating the key, such that the keysyms reported for // the key event are not affected by the event itself. This is the // conventional behavior. // // @returns A mask of state components that have changed as a result of // the update. If nothing in the state has changed, returns 0. // // @memberof xkb_state // // @sa xkb_state_update_mask() func (s *State) UpdateKey(key Keycode, direction KeyDirection) StateComponent { stateComponent := C.xkb_state_update_key(s.value(), C.xkb_keycode_t(key), C.enum_xkb_key_direction(direction)) return StateComponent(stateComponent) } // Get the Unicode/UTF-8 string obtained from pressing a particular key // in a given keyboard state. // // @param[in] state The keyboard state object. // @param[in] key The keycode of the key. // @param[out] buffer A buffer to write the string into. // @param[in] size Size of the buffer. // // @warning If the buffer passed is too small, the string is truncated // (though still NUL-terminated). // // @returns The number of bytes required for the string, excluding the // NUL byte. If there is nothing to write, returns 0. // // You may check if truncation has occurred by comparing the return value // with the size of @p buffer, similarly to the snprintf(3) function. // You may safely pass NULL and 0 to @p buffer and @p size to find the // required size (without the NUL-byte). // // This function performs Capitalization and Control @ref // keysym-transformations. // // @memberof xkb_state // @since 0.4.1 func (s *State) KeyGetUtf8(key Keycode) string { size := C.xkb_state_key_get_utf8(s.value(), C.xkb_keycode_t(key), nil, 0) if size == 0 { return "" } buffer := (*C.char)(C.malloc(C.size_t(size + 1))) defer C.free((unsafe.Pointer)(buffer)) C.xkb_state_key_get_utf8(s.value(), C.xkb_keycode_t(key), buffer, C.size_t(size+1)) return C.GoString(buffer) } // Get the single keysym obtained from pressing a particular key in a // given keyboard state. // // This function is similar to xkb_state_key_get_syms(), but intended // for users which cannot or do not want to handle the case where // multiple keysyms are returned (in which case this function is // preferred). // // @returns The keysym. If the key does not have exactly one keysym, // returns XKB_KEY_NoSymbol // // This function performs Capitalization @ref keysym-transformations. // // @sa xkb_state_key_get_syms() // @memberof xkb_state func (s *State) GetOneSym(keycode Keycode) Keysym { keysym := C.xkb_state_key_get_one_sym(s.value(), C.xkb_keycode_t(keycode)) return Keysym(keysym) } // The counterpart to xkb_state_update_mask for modifiers, to be used on // the server side of serialization. // // This entry point is intended for *server* applications; see @ref // server-client-state for details. *Client* applications should use the // xkb_state_mod_*_is_active API. // // @param state The keyboard state. // @param components A mask of the modifier state components to serialize. // State components other than XKB_STATE_MODS_* are ignored. // If XKB_STATE_MODS_EFFECTIVE is included, all other state components are // ignored. // // @returns A xkb_mod_mask_t representing the given components of the // modifier state. // // @memberof xkb_state func (s *State) SerializeMods(components StateComponent) ModMask { return ModMask(C.xkb_state_serialize_mods(s.value(), C.enum_xkb_state_component(components))) } // Consumed modifiers mode. // // There are several possible methods for deciding which modifiers are // consumed and which are not, each applicable for different systems or // situations. The mode selects the method to use. // // Keep in mind that in all methods, the keymap may decide to "preserve" // a modifier, meaning it is not reported as consumed even if it would // have otherwise. type ConsumedMode C.enum_xkb_consumed_mode var ( // This is the mode defined in the XKB specification and used by libX11. // // A modifier is consumed if and only if it *may affect* key translation. // // For example, if `Control+Alt+` produces some assigned keysym, // then when pressing just ``, `Control` and `Alt` are consumed, // even though they are not active, since if they *were* active they would // have affected key translation. ConsumedModeXKB ConsumedMode = C.XKB_CONSUMED_MODE_XKB // This is the mode used by the GTK+ toolkit. // // The mode consists of the following two independent heuristics: // // - The currently active set of modifiers, excluding modifiers which do // not affect the key (as described for @ref XKB_CONSUMED_MODE_XKB), are // considered consumed, if the keysyms produced when all of them are // active are different from the keysyms produced when no modifiers are // active. // // - A single modifier is considered consumed if the keysyms produced for // the key when it is the only active modifier are different from the // keysyms produced when no modifiers are active. ConsumedModeGTK ConsumedMode = C.XKB_CONSUMED_MODE_GTK ) // Get the mask of modifiers consumed by translating a given key. // // @param state The keyboard state. // @param key The keycode of the key. // @param mode The consumed modifiers mode to use; see enum description. // // @returns a mask of the consumed modifiers. // // @memberof xkb_state // @since 0.7.0 func (s *State) KeyGetConsumedMods2(key Keycode, mode ConsumedMode) ModMask { return ModMask(C.xkb_state_key_get_consumed_mods2(s.value(), C.xkb_keycode_t(key), C.enum_xkb_consumed_mode(mode))) } // Same as xkb_state_key_get_consumed_mods2() with mode XKB_CONSUMED_MODE_XKB. // // @memberof xkb_state // @since 0.4.1 func (s *State) KeyGetConsumedMods(key Keycode) ModMask { return ModMask(C.xkb_state_key_get_consumed_mods(s.value(), C.xkb_keycode_t(key))) }