Interactions Between XKB and the Core Protocol
In addition to providing a number of new requests, XKB replaces or extends
existing core protocol requests and events. Some aspects of the this extension,
such as the ability to lock any key or modifier, are visible even to clients
that are unaware of the XKB extension. Other capabilities, such as control of
keysym selection on a per-key basis, are available only to XKB-aware clients.
Though they do not have access to some advanced extension capabilities, the XKB
extension includes compatibility mechanisms to ensure that non-XKB clients
behave as expected and operate at least as well with an XKB-capable server as
they do today.
There are a few significant areas in which XKB state and mapping differences
might be visible to XKB-unaware clients:
The core protocol uses a modifier to choose between two keyboard
groups, while this extension provides explicit support for multiple groups.
The order of the symbols associated with any given key by XKB might not
match the ordering demanded by the core protocol.
To minimize problems that might result from these differences, XKB includes
ways to specify the correspondence between core protocol and XKB modifiers and
symbols.
This section describes the differences between the core X protocol’s notion
of a keyboard mapping and XKB and explains the ways they can interact.
Group Compatibility Map
As described in Keyboard
State, the current keyboard group is reported to XKB-aware clients in
bits 13-14 of the state field of many core protocol events. XKB-unaware clients
cannot interpret those bits, but they might use a keyboard modifier to
implement support for a single keyboard group. To ensure that pre-XKB clients
continue to work when XKB is present, XKB makes it possible to map an XKB state
field, which includes both keyboard group and modifier state into a pre-XKB
state field which contains only modifiers.
A keyboard description includes one
group compatibility map
per keyboard group (four in all). Each such map is a modifier definition (i.e.
specifies both real and virtual modifiers) which specifies the modifiers to be
set in the compatibility states when the corresponding keyboard group is
active. Here are a few examples to illustrate the application of the group
compatibility map:
GroupGroupCompat MapEffective Modifiers State for XKB ClientsCompatibility ModifiersState for non-XKB Clients1Group1=NoneShiftx00xxxxx00000001Shiftxxxxxxxx000000012Group2=Mod3Nonex01xxxxx00000000Mod3xxxxxxxx001000003Group3=Mod2Shiftx10xxxxx00000001Shift+Mod2xxxxxxxx000100014Group4=NoneControlx11xxxxx00000100Controlxxxxxxxx00000100
Note that non-XKB clients (i.e. clients that are linked with a version of the X
library that does not support XKB) cannot detect the fact that
Group4
is active in this example because the group compatibility map for
Group4
does not specify any modifiers.
Setting a Passive Grab for an XKB State
The fact that the
state
field of an event might look different when XKB is present can cause problems
with passive grabs. Existing clients specify the modifiers they wish to grab
using the rules defined by the core protocol, which use a normal modifier to
indicate keyboard group. If we used an XKB state field, the high bits of the
state field would be non-zero whenever the keyboard was in any group other than
Group1
, and none of the passive grabs set by clients could ever be triggered.
To avoid this behavior, the X server normally uses the compatibility grab state
to decide whether or not to activate a passive grab, even for XKB-aware
clients. The group compatibility map attempts to encode the keyboard group in
one or more modifiers of the compatibility state, so existing clients continue
to work exactly the way they do today. By default, there is no way to directly
specify a keyboard group in a
Grabbed
or
GrabButton
request, but groups can be specified indirectly by correctly adjusting the
group compatibility map.
Clients that wish to specify an XKB keyboard state, including a separate
keyboard group, can set the
GrabsUseXKBState
per-client flag which indicates that all subsequent key and button grabs from
the requesting clients are specified using an XKB state.
Whether the XKB or core state should be used to trigger a grab is determined by
the setting of the
GrabsUseXKBState
flag for the requesting client at the time the key or button is grabbed. There
is no way to change the state to be used for a grab that is already registered
or for grabs that are set by some other client.
Changing the Keyboard Mapping Using the Core Protocol
An XKB keyboard description includes a lot of information that is not present
in the core protocol description of a keyboard. Whenever a client remaps the
keyboard using core protocol requests, XKB examines the map to determine likely
default values for the components that cannot be specified using the core
protocol.
Some aspects of this automatic mapping are configurable, and make it fairly
easy to take advantage of many XKB features using existing tools like
xmodmap
, but much of the process of mapping a core keyboard description into an XKB
description is designed to preserve compatible behavior for pre-XKB clients and
cannot be redefined by the user. Clients or users that want behavior that
cannot be described using this mapping should use XKB functions directly.
Explicit Keyboard Mapping Components
This automatic remapping might accidentally replace definitions that were
explicitly requested by an application, so the XKB keyboard description defines
a set of
explicit components
for each key; any components that are listed in the explicit components for a
key are not changed by the automatic keyboard mapping. The explicit components
field for a key can contain any combination of the following values:
Bit in Explicit MaskProtects AgainstExplicitKeyType1Automatic determination of the key type associated with
Group1
(see Assigning Types To Groups of
Symbols for a Key)ExplicitKeyType2Automatic determination of the key type associated with
Group2
(see Assigning Types To Groups of
Symbols for a Key)ExplicitKeyType3Automatic determination of the key type associated with
Group3
(see Assigning Types To Groups of
Symbols for a Key).ExplicitKeyType4Automatic determination of the key type associated with
Group4
(see Assigning Types To Groups of
Symbols for a Key).ExplicitInterpretApplication of any of the fields of a symbol interpretation to the
key in question (see Assigning
Actions To Keys).ExplicitAutoRepeatAutomatic determination of autorepeat status for the key, as
specified in a symbol interpretation (see Assigning Actions To
Keys).ExplicitBehaviorAutomatic assignment of the
KB_Lock
behavior to the key, if the
LockingKey
flag is set in a symbol interpretation (see Assigning Actions To
Keys).ExplicitVModMapAutomatic determination of the virtual modifier map for the key
based on the actions assigned to the key and the symbol interpretations which
match the key (see Assigning
Actions To Keys).Assigning Symbols To Groups
The first step in applying the changes specified by a core protocol
ChangeKeyboardMapping
request to the XKB description of a keyboard is to determine the number of
groups that are defined for the key and the width of each group. The XKB
extension does not change key types in response to core protocol
SetModifierMapping
requests, but it does choose key actions as described in Assigning Actions To Keys.
Determining the number of symbols required for each group is straightforward.
If the key type for some group is not protected by the corresponding
ExplicitKeyType
component, that group has two symbols. If any of the explicit components for
the key include
ExplicitKeyType3
or
ExplicitKeyType4
, the width of the key type currently assigned to that group determines the
number of symbols required for the group in the core protocol keyboard
description. The explicit type components for
Group1
and
Group2
behave similarly, but for compatibility reasons the first two groups must have
at least two symbols in the core protocol symbol mapping. Even if an explicit
type assigned to either of the first two keyboard groups has fewer than two
symbols, XKB requires two symbols for it in the core keyboard description.
If the core protocol request contains fewer symbols than XKB needs, XKB adds
trailing
NoSymbol
keysyms to the request to pad it to the required length. If the core protocol
request includes more symbols than it needs, XKB truncates the list of keysyms
to the appropriate length.
Finally, XKB divides the symbols from the (possibly padded or truncated) list
of symbols specified by the core protocol request among the four keyboard
groups. In most cases, the symbols for each group are taken from the core
protocol definition in sequence (i.e. the first pair of symbols is assigned to
Group1
, the second pair of symbols is assigned to
Group2
, and so forth). If either
Group1
or
Group2
has an explicitly defined key type with a width other than two, it gets a
little more complicated.
Assigning Symbols to Groups One and Two with Explicitly Defined Key Types
The server assigns the first four symbols from the expanded or truncated map to
the symbol positions G1L1 , G1L2,
G2L1 and G2L2, respectively. If the key
type assigned to Group1 reports more than two shift levels,
the fifth and following symbols contain
the extra keysyms for
Group2
. If the key type assigned to
Group2
reports more than two shift levels, the extra symbols follow the symbols (if
any) for
Group1
in the core protocol list of symbols. Symbols for
Group3
and
Group4
are contiguous and follow the extra symbols, if any, for
Group1
and
Group2
.
For example, consider a key with a key type that returns three shift levels
bound to each group. The symbols bound to the core protocol are assigned in
sequence to the symbol positions:
G1L1, G1L2, G2L1, G2L2, G1L3, G2L3, G3L1, G3L2, G3L3, G4L1, G4L2, and G4L3
For a key with a width one key type on group one, a width two key type on group
two and a width three key type on group three, the symbols bound to the key by
the core protocol are assigned to the following key positions:
G1L1, (G1L2), G2L1, G2L2, G3L1, G3L2, G3L3
Note that the second and fourth symbols (positions
G1L2 and G2L2
) can never be generated if the key type associated with the group yields only
one symbol. XKB accepts and ignores them in order to maintain compatibility
with the core protocol.
Assigning Types To Groups of Symbols for a Key
Once the symbols specified by
ChangeKeyboardMapping
have been assigned to the four keyboard groups for a key, the X server assigns
a key type to each group on the key from a canonical list of key types. The
first four key types in any keyboard map are reserved for these standard key
types:
Key Type NameStandard Definition
ONE_LEVELDescribes keys that have exactly one symbol per group. Most special
or function keys (such as
Return
) are
ONE_LEVEL
keys. Any combination of modifiers yields level
0
. Index
0
in any key symbol map specifies key type
ONE_LEVEL
.
TWO_LEVELDescribes non-keypad and non-alphabetic keys that have exactly two
symbols per group. By default, the
TWO_LEVEL
type yields column
1
if the Shift modifier is set, column
0
otherwise. Index
1
in any key symbol map specifies key type
TWO_LEVEL
.
ALPHABETICDescribes alphabetic keys that have exactly two symbols per group.
The default definition of the
ALPHABETIC
type provides shift-cancels-caps behavior as described in Key Types. Index
2
in any key symbol map specifies key type
ALPHABETIC
.
KEYPADDescribes numeric keypad keys with two symbols per group. Yields
column
1
if either of the
Shift
modifier or the real modifier bound to the virtual modifier named
NumLock
are set. Yields column
0
if neither or both modifiers are set. Index
3
in any key symbol map specifies key type
KEYPAD
.
Users or applications may change these key types to get different default
behavior (to make shift cancel caps lock, for example) but they must always
have the specified number of symbols per group.
Before assigning key types to groups, the X server expands any alphanumeric
symbol definitions as follows:
If the second symbol of either group is
NoSymbol
and the first symbol of that group is an alphabetic keysym for which both
lowercase and uppercase forms are defined, the X server treats the key as if
the first element of the group were the lowercase form of the symbol and the
second element were the uppercase form of the symbol. For the purposes of this
expansion, XKB ignores the locale and uses the capitalization rules defined in
Default Symbol Transformations.
For each keyboard group that does not have an explicit type definition, XKB
chooses a key type from the canonical key types. If the second symbol assigned
to a group is
NoSymbol
(after alphabetic expansion), the server assigns key type
ONE_LEVEL
. If the group contains the lowercase and uppercase forms of a single glyph
(after alphanumeric expansion), the server assigns key type
ALPHABETIC
. If either of the symbols in a group is a numeric keypad keysym (
KP_*
), the server assigns key type
KEYPAD
. Otherwise, it assigns key type
TWO_LEVEL
.
Finally, XKB determines the number of groups of symbols that are actually
defined for the key. Trailing empty groups (i.e. groups that have
NoSymbol
in all symbol positions) are ignored.
There are two last special cases for compatibility with the core protocol: If,
after trailing empty groups are excluded, all of the groups of symbols bound to
the key have identical type and symbol bindings, XKB assigns only one group to
the key. If
Group2
is empty and either of
Group3
or
Group4
are not, and if neither
Group1
nor
Group2
have explicit key types, XKB copies the symbols and key type from
Group1
into
Group2
.
Assigning Actions To Keys
Once symbols have been divided into groups and key types chosen for the keys
affected by a
ChangeKeyboardMapping
request, XKB examines the symbols and modifier mapping for each changed key
and assigns server actions where appropriate. XKB also automatically assigns
server actions to changed keys if the client issues a core protocol
SetModifierMapping
request, and does so optionally in response to
XkbSetMap
and
XkbSetCompatMap
requests.
The compatibility map includes a list of
symbol interpretations
, which XKB compares to each symbol associated with any changed keys in turn,
unless the
ExplicitInterp
component is set for a key. Setting the
ExplicitInterp
component prevents the application of symbol interpretations to that key.
If the modifiers and keysym specified in a symbol interpretation match the
modifier mapping and a symbol bound to a changed key that is not protected by
ExplicitInterp
, the server applies the symbol interpretation to the symbol position. The
server considers all symbol interpretations which specify an explicit keysym
before considering any that do not. The server uses the first interpretation
which matches the given combination of keysym and modifier mapping; other
matching interpretations are ignored.
XKB uses four of the fields of a symbol interpretation to decide if it matches
one of the symbols bound to some changed key:
The
symbol
field is a keysym which matches if it has the value
NoSymbol
or is identical to the symbol in question.
The modifiers specified in the
mods
field are compared to the modifiers affected by the key in question as
indicated by
match
.
The
match
field can specify any of the comparisons:
NoneOf
,
AnyOfOrNone
,
AnyOf
,
AllOf
or
Exactly
.
The
levelOneOnly
setting, indicates that the interpretation in question should only use the
modifiers bound to this key by the modifier mapping if the symbol that matches
in level one of its group. Otherwise, if the symbol being considered is not in
shift level one of its group, the server behaves as if the modifier map for the
key were empty. Note that it is still possible for such an interpretation to
apply to a symbol in a shift level other than one if it matches a key without
modifiers; the
levelOneOnly
flag only controls the way that matches are determined and that the key
modifiers are applied when an interpretation does match.
Applying a symbol interpretation can affect several aspects of the XKB
definition of the key symbol mapping to which it is applied:
The
action
specified in the symbol interpretation is bound to the symbol position; any
key event which yields that symbol will also activate the new action.
If the matching symbol is in position G1L1, the autorepeat behavior of
the key is set from the
autorepeat
field of the symbol interpretation. The
ExplicitAutoRepeat
component protects the autorepeat status of a key from symbol interpretation
initiated changes.
If the symbol interpretation specifies an associated virtual modifier,
that virtual modifier is added to the virtual modifier map for the key. The
ExplicitVModMap
component guards the virtual modifier map for a key from automatic changes. If
the
levelOneOnly
flag is set for the interpretation, and the symbol in question is not in
position G1L1, the virtual modifier map is not updated.
If the matching symbol is in position G1L1, and the
locking key
field is set in the symbol interpretation, the behavior of the key is changed
to
KB_Lock
(see Key Behavior). The
ExplicitBehavior
component prevents this change.
If no interpretations match a given symbol or key, the server uses:
SA_NoAction
, autorepeat enabled, non-locking key. with no virtual modifiers.
If all of the actions computed for a key are
SA_NoAction
, the server assigns an length zero list of actions to the key.
If the core protocol modifier mapping is changed, the server regenerates
actions for the affected keys. The
XkbSetMap
and
XkbSetCompatMap
requests can also cause actions for some or all keyboard keys to be recomputed.
Updating Everything Else
Changes to the symbols or modifier mapping can affect the bindings of virtual
modifiers. If any virtual modifiers change, XKB updates all of its data
structures to reflect the change. Applying virtual modifier changes to the
keyboard mapping night result in changes to types, the group compatibility map,
indicator maps, internal modifiers or ignore locks modifiers.
Effects of XKB on Core Protocol Events
After applying server actions which modify the base, latched or locked modifier
or group state of the keyboard, the X server recomputes the effective group and
state. Several components of the keyboard state are reported to XKB-aware
clients depending on context (see
Keyboard State for a detailed description of each of the keyboard state
components):
The effective modifier state is reported in
XkbStateNotify
events and in response to
XkbGetState
requests.
The symbol lookup state is reported to XKB-aware clients in the state
field of core protocol and input extension key press and release events that do
not activate passive grabs. Unless the
LookupStateWhenGrabbed
per-client flag is set, the lookup state is only reported in these events when
no grabs are active.
The grab state is reported to XKB-aware clients in the state field of
all core protocol events that report keyboard state, except
KeyPress
and
KeyRelease
events that do not activate passive grabs.
The effective group is the sum of the base, latched and locked keyboard
groups. An out of range effective group is wrapped or truncated into range
according to the setting of the
groupsWrap
flag for the keyboard.
The server reports compatibility states to any clients that have not issued a
successful
XkbUseExtension
request. The server computes the compatibility symbol lookup state and the
compatibility effective grab state by applying the compatibility modifier map
to the corresponding computed XKB states.
The compatibility symbol lookup state is reported to non-XKB clients whenever
an XKB-aware client would receive the XKB lookup state. The compatibility grab
state is reported to XKB-unaware clients whenever an XKB client would receive
the XKB grab state.
If the
GrabsUseXKBState
per-client option is not set, even XKB-aware clients receive the compatibility
grab state in events that trigger or terminate passive grabs. If this flag is
not set, XKB clients also receive the compatibility grab or lookup state
whenever any keyboard grab is active.
If the
LookupStateWhenGrabbed
per-client option is set, clients receive either the XKB or compatibility
lookup state when the keyboard is grabbed, otherwise they receive either the
XKB or compatibility grab state. All non-XKB clients receive the compatibility
form of the appropriate state component; the form that is sent to an XKB-aware
client depends on the setting of the
GrabsUseXKBState
option for that client.
Effect of XKB on Core Protocol Requests
Whenever a client updates the keyboard mapping using a core protocol request,
the server saves the requested core protocol keyboard mapping and reports it to
any clients that issue
GetKeyboardMapping
or
GetModifierMapping
requests. Whenever a client updates the keyboard mapping using XKB requests,
the server discards the affected portion of the stored core keyboard
description and regenerates it based on the XKB description of the keyboard.
The symbols associated with the XKB keyboard description appear in the order:
G1L1 G1L2 G2L1 G2L2 G1L3-n G2L3-n G3L* G4L*
If the type associated with
Group1
is width one, the second symbol is
NoSymbol
; if the type associated with
Group2
is width one, the fourth symbol is
NoSymbol
.
If a key has only one group but the keyboard has several, the symbols for
Group1
are repeated for each group. For example, given a keyboard with three groups
and a key with one group that contains the symbols {
a A
}, the core protocol description would contain the six symbols: {
a
A
a
A
a
A
}. As a slightly more complicated example, an XKB key which had a single width
three group with the symbols {
a
b
c
} would show up in the generated core protocol keyboard description with the
symbols {
a
b
a
b
c
c
a
b
c
} for a keyboard with three groups.
The generated modifier mapping for a key contains all of the modifiers affected
by all of the actions associated with the key plus all of the modifiers
associated with any virtual modifiers bound to the key by the virtual modifier
mapping. If any of the actions associated with a key affect any component of
the keyboard group, any modifiers specified in any entry of the group
compatibility map (see Group
Compatibility Map) are reported in the modifier mask. The
SA_ISOLock
action can theoretically affect any modifier, but the modifier map of an
SA_ISOLock
key contains only the modifiers or group state that it sets by default.
The server notifies interested clients of keyboard map changes in one of two
ways. It sends
XkbMapNotify
to clients that have explicitly selected them and core protocol
MappingNotify
events to clients that have not. Once a client requests
XkbMapNotify
events, the server stops sending it
MappingNotify
events to inform it of keyboard changes.
Sending Events to Clients
XKB normally assumes that events sent to clients using the core protocol
SendEvent
request contain a core protocol state, if applicable. If the client which will
receive the event is not XKB-capable, XKB attempts to convert the core state to
an XKB state as follows: if any of the modifiers bound to
Group2
in the group compatibility map are set in the event state, XKB clears them in
the resulting event but sets the effective group in the event state to
Group2
.
If the
PCF_SendEventUsesXKBState
per-client flag is set at the time of the SendEvent request, XKB instead
assumes that the event reported in the event is an XKB state. If the receiving
client is not XKB-aware, the extension converts the XKB state (which contains
the effective state in bits 13-14) to a core state by applying the group
compatibility map just as it would for actual key events.