Virtual Modifiers
The core protocol specifies that
certain keysyms, when bound to modifiers, affect the rules of keycode to keysym
interpretation for all keys; for example, when
Num_Lock
is bound to some modifier, that modifier is used to choose shifted or
unshifted state for the numeric keypad keys. The core protocol does not provide
a convenient way to determine the mapping of modifier bits, in particular
Mod1
through
Mod5
, to keysyms such as
Num_Lock
and
Mode_switch
. Clients must retrieve and search the modifier map to determine the keycodes
bound to each modifier, and then retrieve and search the keyboard mapping to
determine the keysyms bound to the keycodes. They must repeat this process for
all modifiers whenever any part of the modifier mapping is changed.
XKB provides a set of sixteen named virtual modifiers, each of which can be
bound to any set of the eight "real" modifiers (
Shift
,
Lock
,
Control
and
Mod1
-
Mod5
as reported in the keyboard state). This makes it easier for applications and
keyboard layout designers to specify to the function a modifier key or data
structure should fulfill without having to worry about which modifier is bound
to a particular keysym.
The use of a single, server-driven mechanism for reporting changes to all data
structures makes it easier for clients to stay synchronized. For example, the
core protocol specifies a special interpretation for the modifier bound to the
Num_Lock
key. Whenever any keys or modifiers are rebound, every application has to
check the keyboard mapping to make sure that the binding for
Num_Lock
has not changed. If
Num_Lock
is remapped when XKB is in use, the keyboard description is automatically
updated to reflect the new binding, and clients are notified immediately and
explicitly if there is a change they need to consider.
The separation of function from physical modifier bindings also makes it easier
to specify more clearly the intent of a binding. X servers do not all assign
modifiers the same way — for example,
Num_Lock
might be bound to
Mod2
for one vendor and to
Mod4
for another. This makes it cumbersome to automatically remap the keyboard to a
desired configuration without some kind of prior knowledge about the keyboard
layout and bindings. With XKB, applications simply use virtual modifiers to
specify the behavior they want, without regard for the actual physical bindings
in effect.
XKB puts most aspects of the keyboard under user or program control, so it is
even more important to clearly and uniformly refer to modifiers by function.
Modifier Definitions
Use an
XKB modifier definition
to specify the modifiers affected by any XKB control or data structure. An XKB
modifier definition consists of a set of real modifiers, a set of virtual
modifiers, and an effective mask. The mask is derived from the real and virtual
modifiers and cannot be explicitly changed — it contains all of the real
modifiers specified in the definition
plus
any real modifiers that are bound to the virtual modifiers specified in the
definition. For example, this modifier definition specifies the numeric lock
modifier if the
Num_Lock
keysym is not bound to any real modifier:
{ real_mods= None, virtual_mods= NumLock, mask= None }
If we assign
Mod2
to the
Num_Lock
key, the definition changes to:
{ real_mods= None, virtual_mods= NumLock, mask= Mod2 }
Using this kind of modifier definition makes it easy to specify the desired
behavior in such a way that XKB can automatically update all of the data
structures that make up a keymap to reflect user or application specified
changes in any one aspect of the keymap.
The use of modifier definitions also makes it possible to unambiguously specify
the reason that a modifier is of interest. On a system for which the
Alt
and
Meta
keysyms are bound to the same modifier, the following definitions behave
identically:
{ real_mods= None, virtual_mods= Alt, mask= Mod1 }
{ real_mods= None, virtual_mods= Meta, mask= Mod1 }
If we rebind one of the modifiers, the modifier definitions automatically
reflect the change:
{ real_mods= None, virtual_mods= Alt, mask= Mod1 }
{ real_mods= None, virtual_mods= Meta, mask= Mod4 }
Without the level of indirection provided by virtual modifier maps and modifier
definitions, we would have no way to tell which of the two definitions is
concerned with
Alt
and which is concerned with
Meta.
Inactive Modifier Definitions
Some XKB structures ignore modifier
definitions in which the virtual modifiers are unbound. Consider this
example:
if ( state matches { Shift } ) Do OneThing;
if ( state matches { Shift+NumLock } ) Do Another;
If the
NumLock
virtual modifier is not bound to any real modifiers, these effective masks for
these two cases are identical (i.e. they contain only
Shift
). When it is essential to distinguish between
OneThing
and Another, XKB considers only those modifier definitions for which all
virtual modifiers are bound.
Virtual Modifier Mapping
XKB maintains a
virtual modifier mapping
, which lists the virtual modifiers associated with each key. The real
modifiers bound to a virtual modifier always include all of the modifiers bound
to any of the keys that specify that virtual modifier in their virtual modifier
mapping.
For example, if
Mod3
is bound to the
Num_Lock
key by the core protocol modifier mapping, and the
NumLock
virtual modifier is bound to they
Num_Lock
key by the virtual modifier mapping,
Mod3
is added to the set of modifiers associated with the
NumLock
virtual modifier.
The virtual modifier mapping is normally updated automatically whenever actions
are assigned to keys (see Changing
the Keyboard Mapping Using the Core Protocol for details) and few
applications should need to change the virtual modifier mapping explicitly.