# Key Event Processing in the Server

This section describes the steps involved in processing a key event within the server when XKB is present. Key events can be generated due to keyboard activity and passed to XKB by the DDX layer, or they can be synthesized by another extension, such as XTEST.

## Applying Global Controls

When the X Keyboard Extension receives a key event, it first checks the global key controls to decide whether to process the event immediately or at all. The global key controls which might affect the event, in descending order of priority, are:

- If a key is pressed while the BounceKeys control is enabled, the extension generates the event only if the key is active. When a key is released, the server deactivates the key and starts a bounce keys timer with an interval specified by the debounce delay.

  If the bounce keys timer expires or if some other key is pressed before the timer expires, the server reactivates the corresponding key and deactivates the timer. Neither expiration nor deactivation of a bounce keys timer causes an event.

- If the SlowKeys control is enabled, the extension sets a slow keys timer with an interval specified by the slow keys delay, but does not process the key event immediately. The corresponding key release deactivates this timer.

  If the slow keys timer expires, the server generates a key press for the corresponding key, sends an XkbAccessXNotify and deactivates the timer.

- The extension processes key press events normally whether or not the RepeatKeys control is active, but if RepeatKeys are enabled and per-key autorepeat is enabled for the event key, the extension processes key press events normally, but it also initiates an autorepeat timer with an interval specified by the autorepeat delay. The corresponding key release deactivates the timer.

  If the autorepeat timer expires, the server generates a key release and a key press for the corresponding key and reschedules the timer according to the autorepeat interval.

Key events are processed by each global control in turn: if the BounceKeys control accepts a key event, SlowKeys considers it. Once SlowKeys allows or synthesizes an event, the RepeatKeys control acts on it.

## Key Behavior

Once an event is accepted by all of the controls or generated by a timer, the server checks the per-key behavior of the corresponding key. This extension currently defines the following key behaviors:

Behavior | Effect
--- | ---
KB_Default | Press and release events are processed normally.
KB_Lock | If a key is logically up (i.e. the corresponding bit of the core key map is cleared) when it is pressed, the key press is processed normally and the corresponding release is ignored. If the key is logically down when pressed, the key press is ignored but the corresponding release is processed normally.

KB_RadioGroup

flags: CARD8

index: CARD8

If another member of the radio group specified by index is logically down when a key is pressed, the server synthesizes a key release for the member that is logically down and then processes the new key press event normally.

If the key itself is logically down when pressed, the key press event is ignored, but the processing of the corresponding key release depends on the value of the RGAllowNone bit in flags . If it is set, the key release is processed normally; otherwise the key release is also ignored.

All other key release events are ignored.

KB_Overlay1 key: KEYCODE | If the Overlay1 control is enabled, events from this key are reported as if they came from the key specified in key . Otherwise, press and release events are processed normally.
KB_Overlay2 key: KEYCODE | If the Overlay2 control is enabled, events from this key are reported as if they came from the key specified in key . Otherwise, press and release events are processed normally.

The X server uses key behavior to determine whether to process or filter out any given key event; key behavior is independent of keyboard modifier or group state (each key has exactly one behavior.

Key behaviors can be used to simulate any of these types of keys or to indicate an unmodifiable physical, electrical or software driver characteristic of a key. An optional permanent flag can modify any of the supported behaviors and indicates that behavior describes an unalterable physical, electrical or software aspect of the keyboard. Permanent behaviors cannot be changed or set by the XkbSetMap request. The permanent flag indicates a characteristic of the underlying system that XKB cannot affect, so XKB treats all permanent behaviors as if they were KB_Default and does not filter key events described in the table above.

## Key Actions

Once the server has applied the global controls and per-key behavior and has decided to process a key event, it applies key actions to determine the effects of the key on the internal state of the server. A key action consists of an operator and some optional data. XKB supports actions which:

- change base, latched or locked modifiers or group

- move the core pointer or simulate core pointer button events

- change most aspects of keyboard behavior

- terminate or suspend the server

- send a message to interested clients

- simulate events on other keys

Each key has an optional list of actions. If present, this list parallels the list of symbols associated with the key (i.e. it has one action per symbol associated with the key). For key press events, the server looks up the action to be applied from this list using the key symbol mapping associated with the event key, just as a client looks up symbols as described in Determining the KeySym Associated with a Key Event; if the event key does not have any actions, the server uses the SA_NoAction event for that key regardless of modifier or group state.

Key actions have essentially two halves; the effects on the server when the key is pressed and the effects when the key is released. The action applied for a key press event determines the further actions, if any, that are applied to the corresponding release event or to events that occur while the key is held down. Clients can change the actions associated with a key while the key is down without changing the action applied next time the key is released; subsequent press-release pairs will use the newly bound key action.

Most actions directly change the state of the keyboard or server; some actions also modify other actions that occur simultaneously with them. Two actions occur simultaneously if the keys which invoke the actions are both logically down at the same time, regardless of the order in which they are pressed or delay between the activation of one and the other.

Most actions which affect keyboard modifier state accept a modifier definition (see Virtual Modifiers) named mods and a boolean flag name useModMap among their arguments. These two fields combine to specify the modifiers affected by the action as follows: If useModMap is True , the action sets any modifiers bound by the modifier mapping to the key that initiated the action; otherwise, the action sets the modifiers specified by mods . For brevity in the text of the following definitions, we refer to this combination of useModMap and mods as the "action modifiers."

The X Keyboard Extension supports the following actions:

Action | Effect
--- | ---

SA_NoAction

- No direct effect, though SA_NoAction events may change the effect of other server actions (see below).

SA_SetMods

mods: MOD_DEF

useModMap: BOOL

clearLocks: BOOL

- Key press adds any action modifiers to the keyboard’s base modifiers.

- Key release clears any action modifiers in the keyboard’s base modifiers, provided that no other key which affects the same modifiers is logically down.

- If no keys were operated simultaneously with this key and clearLocks is set, release unlocks any action modifiers.

SA_LatchMods

mods: MOD_DEF

useModMap: BOOL

clearLocks: BOOL

latchToLock: BOOL

- Key press and release events have the same effect as for SA_SetMods ; if no keys were operated simultaneously with the latching modifier key, key release events have the following additional effects:

- Modifiers that were unlocked due to clearLocks have no further effect.

- If latchToLock is set, key release locks and then unlatches any remaining action modifiers that are already latched.

- Finally, key release latches any action modifiers that were not used by the clearLocks or latchToLock flags.

SA_LockMods

mods: MOD_DEF

useModMap: BOOL

noLock: BOOL

noUnlock: BOOL

- Key press sets the base and possibly the locked state of any action modifiers. If noLock is True , only the base state is changed.

- For key release events, clears any action modifiers in the keyboard’s base modifiers, provided that no other key which affects the same modifiers is down. If noUnlock is False and any of the action modifiers were locked before the corresponding key press occurred, key release unlocks them.

SA_SetGroup

group: INT8

groupAbsolute: BOOL

clearLocks: BOOL

- If groupAbsolute is set, key press events change the base keyboard group to group ; otherwise, they add group to the base keyboard group. In either case, the resulting effective keyboard group is brought back into range depending on the value of the GroupsWrap control for the keyboard.

- If an SA_ISOLock key is pressed while this key is held down, key release has no effect, otherwise it cancels the effects of the press.

- If no keys were operated simultaneously with this key and clearLocks is set, key release also sets the locked keyboard group to Group1 .

SA_LatchGroup

group: INT8

groupAbsolute: BOOL

clearLocks: BOOL

latchToLock: BOOL

- Key press and release events have the same effect as an SA_SetGroup action; if no keys were operated simultaneously with the latching group key and the clearLocks flag was not set or had no effect, key release has the following additional effects:

- If latchToLock is set and the latched keyboard group is non-zero, the key release adds the delta applied by the corresponding key press to the locked keyboard group and subtracts it from the latched keyboard group. The locked and effective keyboard group are brought back into range according to the value of the global GroupsWrap control for the keyboard.

- Otherwise, key release adds the key press delta to the latched keyboard group.

SA_LockGroup

group: INT8

groupAbsolute: BOOL

- If groupAbsolute is set, key press sets the locked keyboard group to group . Otherwise, key press adds group to the locked keyboard group. In either case, the resulting locked and effective group is brought back into range depending on the value of the GroupsWrap control for the keyboard.

- Key release has no effect.

SA_MovePtr

x, y: INT16

noAccel: BOOL

absoluteX: BOOL

absoluteY: BOOL

- If MouseKeys are not enabled, this action behaves like SA_NoAction , otherwise this action cancels any pending repeat key timers for this key and has the following additional effects.

- Key press generates a core pointer MotionNotify event instead of the usual KeyPress . If absoluteX is True , x specifies the new pointer X coordinate, otherwise x is added to the current pointer X coordinate; absoluteY and y specify the new Y coordinate in the same way.

- If noAccel is False , and the MouseKeysAccel keyboard control is enabled, key press also initiates the mouse keys timer for this key; every time this timer expires, the cursor moves again. The distance the cursor moves in these subsequent events is determined by the mouse keys acceleration as described in The MouseKeysAccel Control.

- Key release disables the mouse keys timer (if it was initiated by the corresponding key press) but has no other effect and is ignored (does not generate an event of any type).

SA_PtrBtn

button: CARD8

count: CARD8

useDfltBtn: BOOL

- If MouseKeys are not enabled, this action behaves like SA_NoAction .

- If useDfltBtn is set, the event is generated for the current default core button. Otherwise, the event is generated for the button specified by button .

- If the mouse button specified for this action is logically down, the key press and corresponding release are ignored and have no effect.

- Otherwise, key press causes one or more core pointer button events instead of the usual key press. If count is 0 , key press generates a single ButtonPress event; if count is greater than 0 , key press generates count pairs of ButtonPress and ButtonRelease events.

- If count is 0 , key release generates a core pointer ButtonRelease which matches the event generated by the corresponding key press; if count is non-zero, key release does not cause a ButtonRelease event. Key release never causes a key release event.

SA_LockPtrBtn

button: BUTTON

noLock: BOOL

noUnlock: BOOL

useDfltBtn: BOOL

- If MouseKeys are not enabled, this action behaves like SA_NoAction .

- Otherwise, if the button specified by useDfltBtn and button is not locked, key press causes a ButtonPress instead of a key press and locks the button. If the button is already locked or if noLock is True , key press is ignored and has no effect.

- If the corresponding key press was ignored, and if noUnlock is False , key release generates a ButtonRelease event instead of a key release event and unlocks the specified button. If the corresponding key press locked a button, key release is ignored and has no effect.

SA_SetPtrDflt

affect: CARD8

value: CARD8

dfltBtnAbs: BOOL

- If MouseKeys are not enabled, this action behaves like SA_NoAction .

- Otherwise, both key press and key release are ignored, but key press changes the pointer value specified by affect to value , as follows:

- If which is SA_AffectDfltBtn , value and dfltBtnAbs specify the default pointer button used by the various pointer actions as follow: If dfltBtnAbs is True, value specifies the button to be used, otherwise, value specifies the amount to be added to the current default button. In either case, illegal button choices are wrapped back into range.

SA_ISOLock

dfltIsGroup: False

mods: MOD_DEF

useModMap: BOOL

noLock: BOOL

noUnlock: BOOL

noAffectMods: BOOL

noAffectGrp: BOOL

noAffectPtr: BOOL

noAffectCtrls: BOOL

or

dfltIsGroup: True

group: INT8

groupAbsolute: BOOL

noAffectMods: BOOL

noAffectGrp: BOOL

noAffectPtr: BOOL

noAffectCtrls: BOOL

- If dfltIsGroup is True , key press sets the base group specified by groupAbsolute and group . Otherwise, key press sets the action modifiers in the keyboard’s base modifiers.

- Key release clears the base modifiers or group that were set by the key press; it may have additional effects if no other appropriate actions occur simultaneously with the SA_ISOLock operation.

- If noAffectMods is False , any SA_SetMods or SA_LatchMods actions that occur simultaneously with the ISOLock action are treated as SA_LockMods instead.

- If noAffectGrp is False , any SA_SetGroup or SA_LatchGroup actions that occur simultaneously with this action are treated as SA_LockGroup actions instead.

- If noAffectPtr is False , SA_PtrBtn actions that occur simultaneously with the SA_ISOLock action are treated as SA_LockPtrBtn actions instead.

- If noAffectCtrls is False , any SA_SetControls actions that occur simultaneously with the SA_ISOLock action are treated as SA_LockControls actions instead.

- If no other actions were transformed by the SA_ISOLock action, key release locks the group or modifiers specified by the action arguments.

SA_TerminateServer

- Key press terminates the server. Key release is ignored.

- This action is optional; servers are free to ignore it. If ignored, it behaves like SA_NoAction .

SA_SwitchScreen

num: INT8

switchApp: BOOL

screenAbs: BOOL

- If the server supports this action and multiple screens or displays (either virtual or real), this action changes to the active screen indicated by num and screenAbs . If screenAbs is True , num specifies the index of the new screen; otherwise, num specifies an offset from the current screen to the new screen.

- If switchApp is False , it should switch to another screen on the same server. Otherwise it should switch to another X server or application which shares the same physical display.

- This action is optional; servers are free to ignore the action or any of its flags if they do not support the requested behavior. If the action is ignored, it behaves like SA_NoAction , otherwise neither key press nor release generate an event.

SA_SetControls

controls: KB_BOOLCTRLMASK

- Key press enables any boolean controls that are specified in controls and not already enabled at the time of the key press. Key release disables any controls that were enabled by the corresponding key press. This action can cause XkbControlsNotify events.

SA_LockControls

controls: KB_BOOLCTRLMASK

noLock: BOOL

noUnlock: BOOL

- If noLock is False , key press locks and enables any controls that are specified in controls and not already locked at the time of the key press.

  If noUnlock is False , key release unlocks and disables any controls that are specified in controls and were not enabled at the time of the corresponding key press.

SA_ActionMessage : pressMsg: BOOL

releaseMsg: BOOL

genEvent: BOOL

message: STRING

- if pressMsg is True , key press generates an XkbActionMessage event which reports the keycode, event type and the contents of message .

- If releaseMsg is True , key release generates an XkbActionMessage event which reports the keycode, event type and contents of message .

- If genEvent is True , both press and release generate key press and key release events, regardless of whether they also cause an XkbActionMessage .

SA_RedirectKey

newKey: KEYCODE

modsMask: KEYMASK

mods: KEYMASK

vmodsMask: CARD16

vmods: CARD16

- Key press causes a key press event for the key specified by newKey instead of for the actual key. The state reported in this event reports of the current effective modifiers changed as follow: Any real modifiers specified in modsMask are set to corresponding values from mods . Any real modifiers bound to the virtual modifiers specified in vmodsMask are either set or cleared, depending on the corresponding value in vmods . If the real and virtual modifier definitions specify conflicting values for a single modifier, the real modifier definition has priority.

- Key release causes a key release event for the key specified by newKey ; the state field for this event consists of the effective keyboard modifiers at the time of the release, changed as described above.

- The SA_RedirectKey action normally redirects to another key on the same device as the key or button which caused the event, unless that device does not belong to the input extension KEYCLASS, in which case this action causes an event on the core keyboard device.

SA_DeviceBtn

count: CARD8

button: BUTTON

device: CARD8

- The device field specifies the ID of an extension device; the button field specifies the index of a button on that device. If the button specified by this action is logically down, the key press and corresponding release are ignored and have no effect. If the device or button specified by this action are illegal, this action behaves like SA_NoAction .

- Otherwise, key press causes one or more input extension device button events instead of the usual key press event. If count is 0 , key press generates a single DeviceButtonPress event; if count is greater than 0 , key press generates count pairs of DeviceButtonPress and DeviceButtonRelease events.

- If count is 0 , key release generates an input extension DeviceButtonRelease which matches the event generated by the corresponding key press; if count is non-zero, key release does not cause a DeviceButtonRelease event. Key release never causes a key release event.

SA_LockDeviceBtn

button: BUTTON

device: CARD8

noLock: BOOL

noUnlock: BOOL

- The device field specifies the ID of an extension device; the button field specifies the index of a button on that device. If the device or button specified by this action are illegal, it behaves like SA_NoAction .

- Otherwise, if the specified button is not locked and if noLock is False , key press causes an input extension DeviceButtonPress event instead of a key press event and locks the button. If the button is already locked or if noLock is True , key press is ignored and has no effect.

- If the corresponding key press was ignored, and if noUnlock is False , key release generates an input extension DeviceButtonRelease event instead of a core protocol or input extension key release event and unlocks the specified button. If the corresponding key press locked a button, key release is ignored and has no effect.

SA_DeviceValuator

device : CARD8

val1What : SA_DVOP

val1 : CARD8

val1Value : INT8

val1Scale : 0...7

val2What : BOOL

val2 : CARD8

val2Value : INT8

val2Scale : 0...7

- The device field specifies the ID of an extension device; val1 and val2 specify valuators on that device. If device is illegal or if neither val1 nor val2 specifies a legal valuator, this action behaves like SA_NoAction .

- If valn specifies a legal valuator and valnWhat is not SA_IgnoreVal , the specified value is adjusted as specified by valnWhat :

- If valnWhat is SA_SetValMin , valn is set to its minimum legal value.

- If valnWhat is SA_SetValCenter , valn is centered (to (max-min)/2).

- If valnWhat is SA_SetValMax , valn is set to its maximum legal value.

- if valnWhat is SA_SetValRelative ,

  is added to valn .

- if valnWhat is SA_SetValAbsolute , valn is set to

  .

- Illegal values for SA_SetValRelative or SA_SetValAbsolute are clamped into range.

If StickyKeys are enabled, all SA_SetMods and SA_SetGroup actions act like SA_LatchMods and SA_LatchGroup respectively. If the LatchToLock AccessX option is set, either action behaves as if both the SA_ClearLocks and SA_LatchToLock flags are set.

Actions which cause an event from another key or from a button on another device immediately generate the specified event. These actions do not consider the behavior or actions (if any) that are bound to the key or button to which the event is redirected.

Core events generated by server actions contain the keyboard state that was in effect at the time the key event occurred; the reported state does not reflect any changes in state that occur as a result of the actions bound to the key event that caused them.

Events sent to clients that have not issued an XkbUseExtension request contain a compatibility state in place of the actual XKB keyboard state. See Effects of XKB on Core Protocol Events for a description of this compatibility mapping.

## Delivering a Key or Button Event to a Client

The window and client that receive core protocol and input extension key or button events are determined using the focus policy, window hierarchy and passive grabs as specified by the core protocol and the input extension, with the following changes:

- A passive grab triggers if the modifier state specified in the grab matches the grab compatibility state (described in Compatibility Components of Keyboard State). Clients can choose to use the XKB grab state instead by setting the GrabsUseXKBState per-client flag. This flag affects all passive grabs that are requested by the client which sets it but does not affect passive grabs that are set by any other client.

- The state field of events which trigger a passive grab reports the XKB or compatibility grab state in effect at the time the grab is triggered; the state field of the corresponding release event reports the corresponding grab state in effect when the key or button is released.

- If the LookupStateWhenGrabbed per-client flag is set, all key or button events that occur while a keyboard or pointer grab is active contain the XKB or compatibility lookup state, depending on the value of the GrabsUseXKBState per-client flag. If LookupStateWhenGrabbed is not set, they include the XKB or compatibility grab state, instead.

- Otherwise, the state field of events that do not trigger a passive grab report is derived from the XKB effective modifiers and group, as described in Computing A State Field from an XKB State.

- If a key release event is the result of an autorepeating key that is being held down, and the client to which the event is reported has requested detectable autorepeat (see Detectable Autorepeat), the event is not delivered to the client.

The following section explains the intent of the XKB interactions with core protocol grabs and the reason that the per-client flags are needed.

### XKB Interactions With Core Protocol Grabs

XKB provides the separate lookup and grab states to help work around some difficulties with the way the core protocol specifies passive grabs. Unfortunately, many clients work around those problems differently, and the way that XKB handles grabs and reports keyboard state can sometimes interact with those client workarounds in unexpected and unpleasant ways.

To provide more reasonable behavior for clients that are aware of XKB without causing problems for clients that are unaware of XKB, this extension provides two per-client flags that specify the way that XKB and the core protocol should interact.

- The largest problems arise from the fact that an XKB state field encodes an explicit keyboard group in bits 13-14 (as described in Computing A State Field from an XKB State), while pre-XKB clients use one of the eight keyboard modifiers to select an alternate keyboard group. To make existing clients behave reasonably, XKB normally uses the compatibility grab state instead of the XKB grab state to determine whether or not a passive grab is triggered. XKB-aware clients can set the GrabsUseXKBState per-client flag to indicate that they are specifying passive grabs using an XKB state.

- Some toolkits start an active grab when a passive grab is triggered, in order to have more control over the conditions under which the grab is terminated. Unfortunately, the fact that XKB reports a different state in events that trigger or terminate grabs means that this grab simulation can fail to terminate the grab under some conditions. To work around this problem, XKB normally reports the grab state in all events whenever a grab is active. Clients which do not use active grabs like this can set the LookupStateWhenGrabbed per-client flag in order to receive the same state component whether or not a grab is active.

  The GrabsUseXKBState per-client flag also applies to the state of events sent while a grab is active. If it is set, events during a grab contain the XKB lookup or grab state; by default, events during a grab contain the compatibility lookup or grab state.

The state used to trigger a passive grab is controlled by the setting of the GrabsUseXKBState per-client flag at the time the grab is registered. Changing this flag does not affect existing passive grabs.