# Keyboard State

Keyboard state encompasses all of the transitory information necessary to map a physical key press or release to an appropriate event. The Xkb keyboard state consists of primitive components and additional derived components that are maintained for efficiency reasons. Figure 5.1 shows the components of Xkb keyboard state and their relationships.

Xkb State

## Keyboard State Description

The Xkb keyboard state is comprised of the state of all keyboard modifiers, the keyboard group, and the state of the pointer buttons. These are grouped into the following components:

- The locked group and locked modifiers

- The latched group and latched modifiers

- The base group and base modifiers

- The effective group and effective modifiers

- The state of the core pointer buttons

The modifiers are Shift, Lock, Control, and Mod1 – Mod5, as defined by the core protocol. A modifier can be thought of as a toggle that is either set or unset. All modifiers are initially unset. When a modifier is locked, it is set and remains set for all future key events, until it is explicitly unset. A latched modifier is set, but automatically unsets after the next key event that does not change the keyboard state. Locked and latched modifier state can be changed by keyboard activity or via Xkb extension library functions.

modifiers

The Xkb extension provides support for keysym groups, as defined by ISO9995:

keysym groups
group keysym
group ISO9995

Group

  A logical state of a keyboard providing access to a collection of characters. A group usually contains a set of characters that logically belong together and that may be arranged on several shift levels within that group.

The Xkb extension supports up to four keysym groups. Groups are named beginning with one and indexed beginning with zero. All group states are indicated using the group index. At any point in time, there is zero or one locked group, zero or one latched group, and one base group. When a group is locked, it supersedes any previous locked group and remains the locked group for all future key events, until a new group is locked. A latched group applies only to the next key event that does not change the keyboard state. The locked and latched group can be changed by keyboard activity or via Xkb extension library functions.

Changing to a different group changes the keyboard state to produce characters from a different group. Groups are typically used to switch between keysyms of different languages and locales.

The pointer buttons are Button1 – Button5, as defined by the core protocol.

The base group and base modifiers represent keys that are physically or logically down. These and the pointer buttons can be changed by keyboard activity and not by Xkb requests. It is possible for a key to be logically down, but not physically down, and neither latched nor locked.

Keys may be logically down when they are physically up because of their electrical properties or because of the keyboard extension in the X server having filtered the key release, for esoteric reasons.

base group
group base
base modifiers
modifiers base

The effective modifiers are the bitwise union of the locked, latched, and the base modifiers.

effective modifiers
modifiers effective

The effective group is the arithmetic sum of the group indices of the latched group, locked group, and base group, which is then normalized by some function. The result is a meaningful group index.

effective group
group effective

- n = number of keyboard groups, 1<= n <= 4
- 0 <= any of locked, latched, or base group < n
- effective group = f(locked group + latched group + base group)

The function f ensures that the effective group is within range. The precise function is specified for the keyboard and can be retrieved through the keyboard description. It may wrap around, clamp down, or default. Few applications will actually examine the effective group, and far fewer still will examine the locked, latched, and base groups.

There are two circumstances under which groups are normalized:

1. The global locked or effective group changes. In this case, the changed group is normalized into range according to the settings of the groups_wrap field of the XkbControlsRec structure for the keyboard (see section 10.7.1).

2. The Xkb library is interpreting an event with an effective group that is legal for the keyboard as a whole, but not for the key in question. In this case, the group to use for this event only is determined using the group_info field of the key symbol mapping (XkbSymMapRec) for the event key.

Each nonmodifier key on a keyboard has zero or more symbols, or keysyms, associated with it. These are the logical symbols that the key can generate when it is pressed. The set of all possible keysyms for a keyboard is divided into groups. Each key is associated with zero or more groups; each group contains one or more symbols. When a key is pressed, the determination of which symbol for the key is selected is based on the effective group and the shift level, which is determined by which modifiers are set.

A client that does not explicitly call Xkb functions, but that otherwise makes use of an X library containing the Xkb extension, will have keyboard state represented in bits 0 – 14 of the state field of events that report modifier and button state. Such a client is said to be Xkb-capable. A client that does explicitly call Xkb functions is an Xkb-aware client. The Xkb keyboard state includes information derived from the effective state and from two server parameters that can be set through the keyboard extension. The following components of keyboard state pertain to Xkb-capable and Xkb-aware clients:

Xkb-capable client
Xkb-aware client

- lookup state: lookup group and lookup modifiers

- grab state: grab group and grab modifiers

The lookup modifiers and lookup group are represented in the state field of core X events. The modifier state and keycode of a key event are used to determine the symbols associated with the event. For KeyPress and KeyRelease events, the lookup modifiers are computed as:

       ((base | latched | locked) & ~server_internal_modifiers)

lookup modifiers
modifiers lookup
lookup group
group lookup

Otherwise the lookup modifiers are computed as:

       (((base | latched | (locked & ~ignore_locks)) & ~server_internal_modifiers)

The lookup group is the same as the effective group.

When an Xkb-capable or Xkb-aware client wishes to map a keycode to a keysym, it should use the lookup state — the lookup group and the lookup modifiers.

lookup state
state lookup

The grab state is the state used when matching events to passive grabs. If the event activates a grab, the grab modifiers and grab group are represented in the state field of core X events; otherwise, the lookup state is used. The grab modifiers are computed as:

       (((base | latched | (locked & ~ignore_locks)) & ~server_internal_modifiers)

grab state
state grab
grab modifiers
modifiers grab
grab group
group grab

If the server’s IgnoreGroupLock control (see section 10.7.3) is not set, the grab group is the same as the effective group. Otherwise, the grab group is computed from the base group and latched group, ignoring the locked group.

The final three components of Xkb state are applicable to clients that are not linked with an Xlib containing the X keyboard extension library and therefore are not aware of the keyboard extension (Xkb-unaware clients):

- The compatibility modifier state

- The compatibility lookup modifier state

- The compatibility grab modifier state

The X11 protocol interpretation of modifiers does not include direct support for multiple groups. When an Xkb-extended X server connects to an Xkb-unaware client, the compatibility states remap the keyboard group into a core modifier whenever possible. The compatibility state corresponds to the effective modifier and effective group state, with the group remapped to a modifier. The compatibility lookup and grab states correspond to the lookup and grab states, respectively, with the group remapped to a modifier. The compatibility lookup state is reported in events that do not trigger passive grabs; otherwise, the compatibility grab state is reported.

## Changing the Keyboard State

### Changing Modifiers

The functions in this section that change the use of modifiers use a mask in the parameter affect. It is a bitwise inclusive OR of the legal modifier masks:

Real Modifier Masks

Mask
ShiftMask
LockMask
ControlMask
Mod1Mask
Mod2Mask
Mod3Mask
Mod4Mask
Mod5Mask

To lock and unlock any of the eight real keyboard modifiers, use `XkbLockModifiers`:

Bool `XkbLockModifiers` Display *display unsigned int device_spec unsigned int affect unsigned int values

display

  connection to the X server

device_spec

  device ID, or XkbUseCoreKbd

affect

  mask of real modifiers whose lock state is to change

values

  1 ⇒ lock, 0 ⇒ unlock; only for modifiers selected by affect

`XkbLockModifiers` sends a request to the server to lock the real modifiers selected by both affect and values and to unlock the real modifiers selected by affect but not selected by values. `XkbLockModifiers` does not wait for a reply from the server. It returns True if the request was sent, and False otherwise.

To latch and unlatch any of the eight real keyboard modifiers, use `XkbLatchModifiers`:

Bool `XkbLatchModifiers` Display *display unsigned int device_spec unsigned int affect unsigned int values

display

  connection to the X server

device_spec

  device ID, or XkbUseCoreKbd

affect

  mask of modifiers whose latch state is to change

values

  1 ⇒ latch, 0 ⇒ unlatch; only for mods selected by affect

`XkbLatchModifiers` sends a request to the server to latch the real modifiers selected by both affect and values and to unlatch the real modifiers selected by affect but not selected by values. `XkbLatchModifiers` does not wait for a reply from the server. It returns True if the request was sent, and False otherwise.

real modifiers
modifiers real
mask real modifiers
XkbLockModifiers
XkbLatchModifiers

### Changing Groups

Reference the keysym group indices with these symbolic constants:

Symbolic Group Names

Symbolic Name | Value
XkbGroup1Index | 0
XkbGroup2Index | 1
XkbGroup3Index | 2
XkbGroup4Index | 3

To lock the keysym group, use `XkbLockGroup`.

Bool `XkbLockGroup` Display *display unsigned int device_spec unsigned int group

display

  connection to the X server

device_spec

  device ID, or XkbUseCoreKbd

group

  index of the keysym group to lock

`XkbLockGroup` sends a request to the server to lock the specified group and does not wait for a reply. It returns True if the request was sent and False otherwise.

To latch the keysym group, use `XkbLatchGroup`.

Bool `XkbLatchGroup` Display *display unsigned int device_spec unsigned int group

display

  connection to the X server

device_spec

  device ID, or XkbUseCoreKbd

group

  index of the keysym group to latch

`XkbLatchGroup` sends a request to the server to latch the specified group and does not wait for a reply. It returns True if the request was sent and False otherwise.

keysym groups
group keysym
XkbLockGroup
XkbLatchGroup

## Determining Keyboard State

Xkb keyboard state may be represented in an XkbStateRec structure:

    typedef struct {
        unsigned char      group;                /* effective group index */
        unsigned char      base_group;           /* base group index */
        unsigned char      latched_group;        /* latched group index */
        unsigned char      locked_group;         /* locked group index */
        unsigned char      mods;                 /* effective modifiers */
        unsigned char      base_mods;            /* base modifiers */
        unsigned char      latched_mods;         /* latched modifiers */
        unsigned char      locked_mods;          /* locked modifiers */
        unsigned char      compat_state;         /* effective group ⇒ modifiers */
        unsigned char      grab_mods;            /* modifiers used for grabs */
        unsigned char      compat_grab_mods;     /* mods used for compatibility
                                                    mode grabs */
        unsigned char      lookup_mods;          /* mods used to lookup symbols */
        unsigned char      compat_lookup_mods;   /* mods used for compatibility
                                                    lookup */
        unsigned short     ptr_buttons;          /* 1 bit ⇒ corresponding
                                                    pointer btn is down */
    } XkbStateRec, *XkbStatePtr;

To obtain the keyboard state, use `XkbGetState`.

Status `XkbGetState` Display *display unsigned int device_spec XkbStatePtr state_return

display

  connection to the X server

device_spec

  device ID, or XkbUseCoreKbd

state_return

  backfilled with Xkb state

The `XkbGetState` function queries the server for the current keyboard state, waits for a reply, and then backfills state_return with the results.

All group values are expressed as group indices in the range [0..3]. Modifiers and the compatibility modifier state values are expressed as the bitwise union of the core X11 modifier masks. The pointer button state is reported as in the core X11 protocol.

XkbStateRec
XkbGetState

## Tracking Keyboard State

The Xkb extension reports XkbStateNotify events to clients wanting notification whenever the Xkb state changes. The changes reported include changes to any aspect of the keyboard state: when a modifier is set or unset, when the current group changes, or when a pointer button is pressed or released. As with all Xkb events, XkbStateNotify events are reported to all interested clients without regard to the current keyboard input focus or grab state.

There are many different types of Xkb state changes. Xkb defines an event detail mask corresponding to each type of change. The event detail masks are listed in Table 5.3.

XkbStateNotify Event Detail Masks

Mask | Value
--- | ---
XkbModifierStateMask | (1L << 0)
XkbModifierBaseMask | (1L << 1)
XkbModifierLatchMask | (1L << 2)
XkbModifierLockMask | (1L << 3)
XkbGroupStateMask | (1L << 4)
XkbGroupBaseMask | (1L << 5)
XkbGroupLatchMask | (1L << 6)
XkbGroupLockMask | (1L << 7)
XkbCompatStateMask | (1L << 8)
XkbGrabModsMask | (1L << 9)
XkbCompatGrabModsMask | (1L << 10)
XkbLookupModsMask | (1L << 11)
XkbCompatLookupModsMask | (1L << 12)
XkbPointerButtonMask | (1L << 13)
XkbAllStateComponentsMask | (0x3fff)

To track changes in the keyboard state for a particular device, select to receive XkbStateNotify events by calling either `XkbSelectEvents` or `XkbSelectEventDetails` (see section 4.3).

To receive XkbStateNotify events under all possible conditions, use `XkbSelectEvents` and pass XkbStateNotifyMask in both bits_to_change and values_for_bits.

To receive XkbStateNotify events only under certain conditions, use `XkbSelectEventDetails` using XkbStateNotify as the event_type and specifying the desired state changes in bits_to_change and values_for_bits using mask bits from Table 5.3.

The structure for XkbStateNotify events is:

    typedef struct {
        int            type;            /* Xkb extension base event code */
        unsigned long  serial;          /* X server serial number for event */
        Bool           send_event;      /* True ⇒ synthetically generated */
        Display *      display;         /* server connection where event generated */
        Time           time;            /* server time when event generated */
        int            xkb_type;        /* XkbStateNotify */
        int            device;          /* Xkb device ID,
                                           will not be XkbUseCoreKbd */
        unsigned int   changed;         /* bits indicating what has changed */
        int            group;           /* group index of effective group */
        int            base_group;      /* group index of base group */
        int            latched_group;   /* group index of latched group */
        int            locked_group;    /* group index of locked group */
        unsigned int   mods;            /* effective modifiers */
        unsigned int   base_mods;       /* base modifiers */
        unsigned int   latched_mods;    /* latched modifiers */
        unsigned int   locked_mods;     /* locked modifiers */
        int            compat_state;    /* computed compatibility state */
        unsigned char  grab_mods;       /* modifiers used for grabs */
        unsigned char  compat_grab_mods; /* modifiers used for compatibility grabs */
        unsigned char  lookup_mods;     /* modifiers used to lookup symbols */
        unsigned char  compat_lookup_mods; /* mods used for compatibility look up */
        int            ptr_buttons;     /* core pointer buttons */
        KeyCode        keycode;         /* keycode causing event,
                                           0 if programmatic */
        char           event_type;      /* core event if req_major or req_minor
                                           non zero */
        char           req_major;       /* major request code if program trigger,
                                           else 0 */
        char           req_minor;       /* minor request code if program trigger,
                                           else 0 */
    } XkbStateNotifyEvent;

When you receive an XkbStateNotify event, the changed field indicates which elements of keyboard state have changed. This will be the bitwise inclusive OR of one or more of the XkbStateNotify event detail masks shown in Table 5.3. All fields reported in the event are valid, but only those indicated in changed have changed values.

The group field is the group index of the effective keysym group. The base_group, latched_group, and locked_group fields are set to a group index value representing the base group, the latched group, and the locked group, respectively. The X server can set the modifier and compatibility state fields to a union of the core modifier mask bits; this union represents the corresponding modifier states. The ptr_buttons field gives the state of the core pointer buttons as a mask composed of an inclusive OR of zero or more of the core pointer button masks.

Xkb state changes can occur either in response to keyboard activity or under application control. If a key event caused the state change, the keycode field gives the keycode of the key event, and the event_type field is set to either KeyPress or KeyRelease. If a pointer button event caused the state change, the keycode field is zero, and the event_type field is set to either ButtonPress or ButtonRelease. Otherwise, the major and minor codes of the request that caused the state change are given in the req_major and req_minor fields, and the keycode field is zero. The req_major value is the same as the major extension opcode.

events XkbStateNotify
XkbStateNotifyEvent