summaryrefslogtreecommitdiff
path: root/specs/ch07.xml
diff options
context:
space:
mode:
Diffstat (limited to 'specs/ch07.xml')
-rw-r--r--specs/ch07.xml685
1 files changed, 685 insertions, 0 deletions
diff --git a/specs/ch07.xml b/specs/ch07.xml
new file mode 100644
index 0000000..8ba8f61
--- /dev/null
+++ b/specs/ch07.xml
@@ -0,0 +1,685 @@
+<chapter id='key_event_processing_in_the_client'>
+<title>Key Event Processing in the Client</title>
+
+<para>
+The XKB <emphasis>
+client map</emphasis>
+ for a keyboard is the collection of information a client needs to interpret
+key events that come from that keyboard. It contains a global list of <emphasis>
+key types</emphasis>
+, described in <ulink url="XKBproto.htm#50332257_45629">See Key Types</ulink>,
+and an array of <emphasis>
+key symbol map</emphasis>
+s, each of which describes the symbols bound to one particular key and the
+rules to be used to interpret those symbols.
+</para>
+
+<sect1 id='notation_and_terminology'>
+<title>Notation and Terminology</title>
+
+<para>
+XKB associates a two-dimensional array of symbols with each key. Symbols are
+addressed by keyboard group (see <ulink url="XKBproto.htm#50332257_13933">See
+Keyboard State</ulink>) and shift level, where level is defined as in the
+ISO9995 standard:
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term>Level</term>
+ <listitem>
+ <para>
+One of several states (normally 2 or 3) which govern which graphic
+character is produced when a graphic key is actuated. In certain cases the
+level may also affect function keys.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+
+<para>
+Note that shift level is derived from the modifier state, but not necessarily
+in the same way for all keys. For example, the <emphasis>
+Shift</emphasis>
+ modifier selects shift level 2 on most keys, but for keypad keys the modifier
+bound to <emphasis>
+Num_Lock</emphasis>
+ (i.e. the <emphasis>
+NumLock</emphasis>
+ virtual modifier) also selects shift level 2.gray symbols on a key
+</para>
+
+<para>
+We use the notation G<emphasis>
+n</emphasis>
+L<emphasis>
+n</emphasis>
+ to specify the position of a symbol on a key or in memory:
+</para>
+
+<mediaobject>
+ <imageobject> <imagedata fileref="XKBproto-6.gif"/>
+ </imageobject>
+ </mediaobject>
+
+
+<para>
+The gray characters indicate symbols that are implied or expected but are not
+actually engraved on the key.
+</para>
+
+<note><para>Unfortunately, the "natural" orientation of symbols on a key and
+the natural orientation in memory are reversed from one another, so keyboard
+group refers to a column on the key and a row in memory. There’s no real help
+for it, but we try to minimize confusion by using "group" and "level" (or
+"shift level") to refer to symbols regardless of context.</para></note>
+
+</sect1>
+<sect1 id='determining_the_keysym_associated_with_a_key_event'>
+<title>Determining the KeySym Associated with a Key Event</title>
+
+<para>
+To look up the symbol associated with an XKB key event, we need to know the
+group and shift level that correspond to the event.
+</para>
+
+
+<para>
+Group is reported in bits 13-14 of the state field of the key event, as
+described in <ulink url="XKBproto.htm#50332257_90933">See Computing A State
+Field from an XKB State</ulink>. The keyboard group reported in the event might
+be out-of-range for any particular key because the number of groups can vary
+from key to key. The XKB description of each key contains a <emphasis>
+group info</emphasis>
+ field which is interpreted identically to the global groups wrap control (see
+<ulink url="XKBproto.htm#50332257_67222">See Computing Effective Modifier and
+Group</ulink>) and which specifies the interpretation of groups that are
+out-of-range for that key.
+</para>
+
+
+<para>
+Once we have determined the group to be used for the event, we have to
+determine the shift level. The description of a key includes a <emphasis>
+key type</emphasis>
+ for each group of symbols bound to the key. Given the modifiers from the key
+event, this key type yields a shift level and a set of "leftover" modifiers, as
+described in <ulink url="XKBproto.htm#50332257_45629">See Key Types</ulink>
+below.
+</para>
+
+
+<para>
+Finally, we can use the effective group and the shift level returned by the
+type of that group to look up a symbol in a two-dimensional array of symbols
+associated with the key.
+</para>
+
+
+<sect2 id='key_types'>
+<title>Key Types</title>
+
+<para>
+Each entry of a key type’s <emphasis>
+map</emphasis>
+ field specifies the shift level that corresponds to some XKB modifier
+definition; any combination of modifiers that is not explicitly listed
+somewhere in the map yields shift level one. Map entries which specify unbound
+virtual modifiers (see <ulink url="XKBproto.htm#50332257_29579">See Inactive
+Modifier Definitions</ulink>) are not considered; each entry contains an
+automatically-updated <emphasis>
+active</emphasis>
+ field which indicates whether or not it should be used.
+</para>
+
+
+<para>
+Each key type includes a few fields that are derived from the contents of the
+map and which report some commonly used values so they don’t have to be
+constantly recalculated. The <emphasis>
+numLevels</emphasis>
+ field contains the highest shift level reported by any of its map entries; XKB
+uses <emphasis>
+numLevels</emphasis>
+ to insure that the array of symbols bound to a key is large enough (the number
+of levels reported by a key type is also referred to as its width). The
+<emphasis>
+modifiers</emphasis>
+ field reports all real modifiers considered by any of the map entries for the
+type. Both <emphasis>
+modifiers</emphasis>
+<emphasis>
+ </emphasis>
+and <emphasis>
+numLevels</emphasis>
+ are updated automatically by XKB and neither can be changed explicitly.
+</para>
+
+
+<para>
+Any modifiers specified in <emphasis>
+modifiers</emphasis>
+ are normally <emphasis>
+consumed</emphasis>
+ (see <ulink url="XKBproto.htm#50332257_25094">See Transforming the KeySym
+Associated with a Key Event</ulink>), which means that they are not considered
+during any of the later stages of event processing. For those rare occasions
+that a modifier <emphasis>
+should</emphasis>
+ be considered despite having been used to look up a symbol, key types include
+an optional <emphasis>
+preserve</emphasis>
+ field. If a <emphasis>
+preserve</emphasis>
+ list is present, each entry corresponds to one of the key type’s map entries
+and lists the modifiers that should <emphasis>
+not</emphasis>
+ be consumed if the matching map entry is used to determine shift level.
+</para>
+
+
+<para>
+For example, the following key type implements caps lock as defined by the core
+protocol (using the second symbol bound to the key):
+</para>
+
+<literallayout class='monospaced'>
+type "ALPHABETIC" {
+ modifiers = Shift+Lock;
+ map[Shift]= Level2;
+ map[Lock]= Level2;
+ map[Shift+Lock]= Level2;
+};
+</literallayout>
+
+<para>
+The problem with this kind of definition is that we could assign completely
+unrelated symbols to the two shift levels, and "Caps Lock" would choose the
+second symbol. Another definition for alphabetic keys uses system routines to
+capitalize the keysym:
+</para>
+
+<literallayout class='monospaced'>
+type "ALPHABETIC" {
+ modifiers= Shift;
+ map[Shift]= Level2;
+};
+</literallayout>
+
+<para>
+When caps lock is applied using this definition, we take the symbol from shift
+level one and capitalize it using system-specific capitalization rules. If
+shift and caps lock are both set, we take the symbol from shift level two and
+try to capitalize it, which usually has no effect.
+</para>
+
+
+<para>
+The following key type implements shift-cancels-caps lock behavior for
+alphabetic keys:
+</para>
+
+<literallayout class='monospaced'>
+type "ALPHABETIC" {
+ modifiers = Shift+Lock;
+ map[Shift] = Level2;
+ preserve[Lock]= Lock;
+};
+</literallayout>
+
+<para>
+Consider the four possible states that can affect alphabetic keys: no
+modifiers, shift alone, caps lock alone or shift and caps lock together. The
+map contains no explicit entry for <emphasis>
+None</emphasis>
+ (no modifiers), so if no modifiers are set, any group with this type returns
+the first keysym. The map entry for <emphasis>
+Shift</emphasis>
+ reports <emphasis>
+Level2</emphasis>
+, so any group with this type returns the second symbol when <emphasis>
+Shift</emphasis>
+ is set. There is no map entry for <emphasis>
+Lock</emphasis>
+ alone, but the type specifies that the <emphasis>
+Lock</emphasis>
+ modifier should be preserved in this case, so <emphasis>
+Lock</emphasis>
+ alone returns the first symbol in the group but first applies the
+capitalization transformation, yielding the capital form of the symbol. In the
+final case, there is no map entry for <emphasis>
+Shift+Lock</emphasis>
+, so it returns the first symbol in the group; there is no preserve entry, so
+the <emphasis>
+Lock</emphasis>
+ modifier is consumed and the symbol is not capitalized.
+</para>
+
+
+</sect2>
+<sect2 id='key_symbol_map'>
+<title>Key Symbol Map</title>
+
+<para>
+The <emphasis>
+key symbol map</emphasis>
+ for a key contains all of the information that a client needs to process
+events generated by that key. Each key symbol mapping reports:
+</para>
+
+<itemizedlist>
+<listitem>
+ <para>The number of groups of symbols bound to the key (<emphasis>
+numGroups</emphasis>
+).
+ </para>
+</listitem>
+<listitem>
+ <para>The treatment of out-of-range groups (<emphasis>
+groupInfo</emphasis>
+).
+ </para>
+</listitem>
+<listitem>
+ <para>The index of the key type to for each <emphasis>
+possible</emphasis>
+ group (<emphasis>
+kt_index[MaxKbdGroups]</emphasis>
+).
+ </para>
+</listitem>
+<listitem>
+ <para>The width of the widest type associated with the key (<emphasis>
+groupsWidth</emphasis>
+).
+ </para>
+</listitem>
+<listitem>
+ <para>The two-dimensional (numGroups <emphasis>
+×</emphasis>
+ groupsWidth) array of symbols bound to the key.
+ </para>
+</listitem>
+</itemizedlist>
+
+<para>
+It is legal for a key to have zero groups, in which case it also has zero
+symbols and all events from that key yield <emphasis>
+NoSymbol</emphasis>
+. The array of key types is of fixed width and is large enough to hold key
+types for the maximum legal number of groups (<emphasis>
+MaxKbdGroups</emphasis>
+, currently four); if a key has fewer than <emphasis>
+MaxKbdGroups</emphasis>
+ groups, the extra key types are reported but ignored. The <emphasis>
+groupsWidth</emphasis>
+ field cannot be explicitly changed; it is updated automatically whenever the
+symbols or set of types bound to a key are changed.
+</para>
+
+
+<para>
+If, when looking up a symbol, the effective keyboard group is out-of-range for
+the key, the <emphasis>
+groupInfo</emphasis>
+ field of the key symbol map specifies the rules for determining the
+corresponding legal group as follows:
+</para>
+
+<itemizedlist>
+<listitem>
+ <para>If the <emphasis>
+RedirectIntoRange</emphasis>
+ flag is set, the two least significant bits of <emphasis>
+groupInfo</emphasis>
+ specify the index of a group to which all illegal groups correspond. If the
+specified group is also out of range, all illegal groups map to <emphasis>
+Group1</emphasis>
+.
+ </para>
+</listitem>
+<listitem>
+ <para>If <emphasis>
+ClampIntoRange</emphasis>
+ flag is set, out-of-range groups correspond to the nearest legal group.
+Effective groups larger than the highest supported group are mapped to the
+highest supported group; effective groups less than <emphasis>
+Group1</emphasis>
+ are mapped to <emphasis>
+Group1</emphasis>
+. For example, a key with two groups of symbols uses <emphasis>
+Group2</emphasis>
+ type and symbols if the global effective group is either <emphasis>
+Group3</emphasis>
+ or <emphasis>
+Group4</emphasis>
+.
+ </para>
+</listitem>
+<listitem>
+ <para>If neither flag is set, group is wrapped into range using integer
+modulus. For example, a key with two groups of symbols for which groups wrap
+uses <emphasis>
+Group1</emphasis>
+ symbols if the global effective group is <emphasis>
+Group3</emphasis>
+ or <emphasis>
+Group2</emphasis>
+ symbols if the global effective group is <emphasis>
+Group4</emphasis>
+.
+ </para>
+</listitem>
+</itemizedlist>
+
+<para>
+The client map contains an array of key symbol mappings, with one entry for
+each key between the minimum and maximum legal keycodes, inclusive. All
+keycodes which fall in that range have key symbol mappings, whether or not any
+key actually yields that code.
+</para>
+
+
+</sect2>
+</sect1>
+<sect1 id='transforming_the_keysym_associated_with_a_key_event'>
+<title>Transforming the KeySym Associated with a Key Event</title>
+
+<para>
+Any modifiers that were not used to look up the keysym, or which were
+explicitly preserved, might indicate further transformations to be performed on
+the keysym or the character string that is derived from it. For example, If the
+<emphasis>
+Lock</emphasis>
+ modifier is set, the symbol and corresponding string should be capitalized
+according to the locale-sensitive capitalization rules specified by the system.
+If the <emphasis>
+Control</emphasis>
+ modifier is set, the keysym is not affected, but the corresponding character
+should be converted to a control character as described in <ulink
+url="dflttrns.htm#17949"></ulink>.
+</para>
+
+
+<para>
+This extension specifies the transformations to be applied when the <emphasis>
+Control</emphasis>
+ or <emphasis>
+Lock</emphasis>
+ modifiers are active but were not used to determine the keysym to be used:
+</para>
+
+<informaltable frame='none'>
+<tgroup cols='2'>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<thead>
+ <row rowsep='1'>
+ <entry>Modifier</entry>
+ <entry>Transformation</entry>
+ </row>
+</thead>
+<tbody>
+ <row rowsep='0'>
+ <entry><emphasis>
+Control</emphasis>
+ </entry>
+ <entry>Report the control character associated with the symbol. This
+extension defines the control characters associated with the ASCII alphabetic
+characters (both upper and lower case) and for a small set of punctuation
+characters (see <ulink url="dflttrns.htm#17949"></ulink>). Applications are
+free to associate control characters with any symbols that are not specified by
+this extension.</entry>
+ </row>
+ <row rowsep='0'>
+ <entry><emphasis>
+Lock</emphasis>
+ </entry>
+ <entry>Capitalize the symbol either according to capitalization rules
+appropriate to the application locale or using the capitalization rules defined
+by this extension (see <ulink url="dflttrns.htm#17949"></ulink>).</entry>
+ </row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+Interpretation of other modifiers is application dependent.
+</para>
+
+<note><para>This definition of capitalization is fundamentally different from
+the core protocol’s, which uses the lock modifier to select from the symbols
+bound to the key. Consider key 9 in the example keyboard on <ulink
+url="XKBproto.htm#50332257_ClientMapExample">See Consider a simple, if
+unlikely, keyboard with the following keys (gray characters indicate symbols
+that are implied or expected but are not actually engraved on the
+key):</ulink>; the core protocol provides no way to generate the capital form
+of either symbol bound to this key. XKB specifies that we first look up the
+symbol and then capitalize, so XKB yields the capital form of the two symbols
+when caps lock is active. </para></note>
+
+<para>
+XKB specifies the behavior of <emphasis>
+Lock</emphasis>
+ and <emphasis>
+Control</emphasis>
+, but interpretation of other modifiers is left to the application.
+</para>
+
+
+</sect1>
+<sect1 id='client_map_example'>
+<title>Client Map Example</title>
+
+<para>
+Consider a simple, if unlikely, keyboard with the following keys (gray
+characters indicate symbols that are implied or expected but are not actually
+engraved on the key):
+</para>
+
+<mediaobject>
+ <imageobject> <imagedata fileref="XKBproto-7.gif"/>
+ </imageobject>
+ </mediaobject>
+
+
+<para>
+The core protocol represents this keyboard as a simple array with one row per
+key and four columns (the widest key, key 10, determines the width of the
+entire array).
+</para>
+
+<informaltable frame='none'>
+<tgroup cols='5'>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<thead>
+ <row rowsep='1'>
+ <entry>Key</entry>
+ <entry>G1L1</entry>
+ <entry>G1L2</entry>
+ <entry>G2L1</entry>
+ <entry>G2L2</entry>
+ </row>
+</thead>
+<tbody>
+ <row rowsep='0'>
+ <entry>8</entry>
+ <entry>Q</entry>
+ <entry>NoSymbol</entry>
+ <entry>at</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>9</entry>
+ <entry>odiaeresis</entry>
+ <entry>egrave</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>10</entry>
+ <entry>A</entry>
+ <entry>NoSymbol</entry>
+ <entry>Æ</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>11</entry>
+ <entry>ssharp</entry>
+ <entry>question</entry>
+ <entry>backslash</entry>
+ <entry>questiondown</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>12</entry>
+ <entry>KP_End</entry>
+ <entry>KP_1</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>13</entry>
+ <entry>Num_Lock</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>14</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>15</entry>
+ <entry>Return</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ <entry>NoSymbol</entry>
+ </row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+The row to be used for a given key event is determined by keycode; the column
+to be used is determined by the symbols bound to the key, the state of the
+<emphasis>
+Shift</emphasis>
+ and <emphasis>
+Lock</emphasis>
+ Modifiers and the state of the modifiers bound to the <emphasis>
+Num_Lock</emphasis>
+ and <emphasis>
+Mode_switch</emphasis>
+ keys as specified by the core protocol.
+</para>
+
+
+<para>
+The XKB description of this keyboard consists of six key symbol maps, each of
+which specifies the types and symbols associated with each keyboard group for
+one key:
+</para>
+
+<informaltable frame='none'>
+<tgroup cols='4'>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<colspec align="left" colsep="0"/>
+<thead>
+ <row rowsep='1'>
+ <entry>Key</entry>
+ <entry>Group: Type</entry>
+ <entry>L1</entry>
+ <entry>L2</entry>
+ </row>
+</thead>
+<tbody>
+ <row rowsep='0'>
+ <entry>8</entry>
+ <entry>G1: ALPHABETIC</entry>
+ <entry>q</entry>
+ <entry>Q</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>G2: ONE_LEVEL</entry>
+ <entry>@</entry>
+ <entry>NoSymbol</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>9</entry>
+ <entry>G1: TWO_LEVEL</entry>
+ <entry>odiaeresis</entry>
+ <entry>egrave</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>10</entry>
+ <entry>G1: ALPHABETIC</entry>
+ <entry>a</entry>
+ <entry>A</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>G2: ALPHABETIC</entry>
+ <entry>ae</entry>
+ <entry>AE</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>11</entry>
+ <entry>G1: TWO_LEVEL</entry>
+ <entry>ssharp</entry>
+ <entry>question</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>G2: ONE_LEVEL</entry>
+ <entry>backslash</entry>
+ <entry>questiondown</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>12</entry>
+ <entry>G1: KEYPAD</entry>
+ <entry>KP_End</entry>
+ <entry>KP_1</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>13</entry>
+ <entry>G1: ONE_LEVEL</entry>
+ <entry>Num_Lock</entry>
+ <entry>&#x0020;</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>14</entry>
+ <entry>No Groups</entry>
+ <entry>&#x0020;</entry>
+ <entry>&#x0020;</entry>
+ </row>
+ <row rowsep='0'>
+ <entry>15</entry>
+ <entry>G1: ONE_LEVEL</entry>
+ <entry>Return</entry>
+ <entry>&#x0020;</entry>
+ </row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+The keycode reported in a key event determines the row to be used for that
+event; the effective keyboard group determines the list of symbols and key type
+to be used. The key type determines which symbol is chosen from the list.
+</para>
+
+
+<para>
+<ulink url="XKBproto.htm#50332257_24122">See Determining the KeySym Associated
+with a Key Event</ulink> details the procedure to map from a key event to a
+symbol and/or a string.
+</para>
+</sect1>
+</chapter>