1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
|
<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 <link linkend='Key_Types'>Key Types</link>,
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 <link linkend='Keyboard_State'>
Keyboard State</link>) 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 format="SVG" fileref="XKBproto-6.svg"/>
</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 <link linkend='Computing_A_State_Field_from_an_XKB_State'>Computing A State
Field from an XKB State</link>. 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
<link linkend='Computing_Effective_Modifier_and_Group'>Computing Effective Modifier and
Group</link>) 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 <link linkend='Key_Types'>Key Types</link>
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 <link linkend='Inactive_Modifier_Definitions'>Inactive
Modifier Definitions</link>) 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 <link linkend='Transforming_the_KeySym_Associated_with_a_Key_Event'>Transforming the KeySym
Associated with a Key Event</link>), 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 <link
linkend="default_symbol_transformations">Default Symbol Transformations</link>.
</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='topbot'>
<?dbfo keep-together="always" ?>
<tgroup cols='2' align='left' colsep='0' rowsep='0'>
<colspec colname='c1' colwidth='1.0*'/>
<colspec colname='c2' colwidth='3.0*'/>
<thead>
<row rowsep='1'>
<entry>Modifier</entry>
<entry>Transformation</entry>
</row>
</thead>
<tbody>
<row>
<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
<link linkend="default_symbol_transformations">Default Symbol Transformations</link>).
Applications are
free to associate control characters with any symbols that are not specified by
this extension.</entry>
</row>
<row>
<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 <link linkend="default_symbol_transformations">Default Symbol Transformations</link>).</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
<link linkend='Client_Map_Example'>client map example</link>;
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 format="SVG" fileref="XKBproto-7.svg"/>
</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='topbot'>
<?dbfo keep-together="always" ?>
<tgroup cols='5' align='left' colsep='0' rowsep='0'>
<colspec colname='c1' colwidth='1.0*'/>
<colspec colname='c2' colwidth='2.0*'/>
<colspec colname='c3' colwidth='2.0*'/>
<colspec colname='c4' colwidth='2.0*'/>
<colspec colname='c5' colwidth='2.0*'/>
<thead>
<row rowsep='1'>
<entry>Key</entry>
<entry>G1L1</entry>
<entry>G1L2</entry>
<entry>G2L1</entry>
<entry>G2L2</entry>
</row>
</thead>
<tbody>
<row>
<entry>8</entry>
<entry>Q</entry>
<entry>NoSymbol</entry>
<entry>at</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>9</entry>
<entry>odiaeresis</entry>
<entry>egrave</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>10</entry>
<entry>A</entry>
<entry>NoSymbol</entry>
<entry>Æ</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>11</entry>
<entry>ssharp</entry>
<entry>question</entry>
<entry>backslash</entry>
<entry>questiondown</entry>
</row>
<row>
<entry>12</entry>
<entry>KP_End</entry>
<entry>KP_1</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>13</entry>
<entry>Num_Lock</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>14</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
<entry>NoSymbol</entry>
</row>
<row>
<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='topbot'>
<?dbfo keep-together="always" ?>
<tgroup cols='4' align='left' colsep='0' rowsep='0'>
<colspec colname='c1' colwidth='1.0*'/>
<colspec colname='c2' colwidth='1.0*'/>
<colspec colname='c3' colwidth='1.0*'/>
<colspec colname='c4' colwidth='1.0*'/>
<thead>
<row rowsep='1'>
<entry>Key</entry>
<entry>Group: Type</entry>
<entry>L1</entry>
<entry>L2</entry>
</row>
</thead>
<tbody>
<row>
<entry>8</entry>
<entry>G1: ALPHABETIC</entry>
<entry>q</entry>
<entry>Q</entry>
</row>
<row>
<entry>G2: ONE_LEVEL</entry>
<entry>@</entry>
<entry>NoSymbol</entry>
</row>
<row>
<entry>9</entry>
<entry>G1: TWO_LEVEL</entry>
<entry>odiaeresis</entry>
<entry>egrave</entry>
</row>
<row>
<entry>10</entry>
<entry>G1: ALPHABETIC</entry>
<entry>a</entry>
<entry>A</entry>
</row>
<row>
<entry>G2: ALPHABETIC</entry>
<entry>ae</entry>
<entry>AE</entry>
</row>
<row>
<entry>11</entry>
<entry>G1: TWO_LEVEL</entry>
<entry>ssharp</entry>
<entry>question</entry>
</row>
<row>
<entry>G2: ONE_LEVEL</entry>
<entry>backslash</entry>
<entry>questiondown</entry>
</row>
<row>
<entry>12</entry>
<entry>G1: KEYPAD</entry>
<entry>KP_End</entry>
<entry>KP_1</entry>
</row>
<row>
<entry>13</entry>
<entry>G1: ONE_LEVEL</entry>
<entry>Num_Lock</entry>
<entry> </entry>
</row>
<row>
<entry>14</entry>
<entry>No Groups</entry>
<entry> </entry>
<entry> </entry>
</row>
<row>
<entry>15</entry>
<entry>G1: ONE_LEVEL</entry>
<entry>Return</entry>
<entry> </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>
<link linkend='Determining_the_KeySym_Associated_with_a_Key_Event'>Determining the KeySym Associated
with a Key Event</link> details the procedure to map from a key event to a
symbol and/or a string.
</para>
</sect1>
</chapter>
|