NAME
UI::KeyboardLayout - Module for designing keyboard layouts
SYNOPSIS
#!/usr/bin/perl -wC31
use UI::KeyboardLayout;
use strict;
UI::KeyboardLayout::->set_NamesList("$ENV{HOME}/Downloads/NamesList-6.1.0d8.txt");
my $i = do {local $/; open $in, '<', 'MultiUni.kbdd' or die; <$in>};
# Init from in-memory copy of the configfile
my $k = UI::KeyboardLayout:: -> new_from_configfile($i)
-> fill_win_template( 1, [qw(faces CyrillicPhonetic)] );
print $k;
open my $f, '<', "$ENV{HOME}/Downloads/NamesList-6.1.0d8.txt" or die;
my $k = UI::KeyboardLayout::->new();
my ($d,$c,$names) = $k->parse_NameList($f);
close $f or die;
$k->print_decompositions($d);
$k->print_compositions ($c);
AUTHORS
Ilya Zakharevich, ilyaz@cpan.org
DESCRIPTION
[To be continued]
Keyboards: on ease of access
Let's start with trivialities: different people have different needs with respect to keyboard layouts. For a moment, ignore the question of the repertoir of characters available via keyboard; then the most crucial distinction corresponds to a certain scale. In absense of a better word, we use a provisional name "the required typing speed".
One example of people on the "quick" (or "rabid"?) pole of this scale are people who type a lot of text which is either "already prepared", or for which the "quality of prose" is not crucial. Quite often, these people may type in access of 100 words per minute. For them, the most important questions are of physical exhaustion from typing. The position of most frequent letters relative to the "rest" finger position, whether frequently typed together letters are on different hands (or at least not on the same/adjacent fingers), the distance fingers must travel when typing common words, how many keypresses are needed to reach a letter/symbol which is not "on the face fo the keyboard" - their primary concerns are of this kind.
On the other, "deliberate", pole these concerns cease to be crucial. On this pole are people who type while they "create" the text, and what takes most of their focus is this "creation" process. They may "polish their prose", or the text they write may be overburdened by special symbols - anyway, what they concentrate on is not typing itself.
For them, the details of the keyboard layout are important mostly in the relation to how much they distract the writer from the other things the writer is focused on. The primary question is now not "how easy it is to type this", but "how easy it is to recall how to type this". The focus transfers from the mechanics of finger movements to the psycho/neuro/science of memory.
These questions are again multifaceted: there are symbols one encounters every minute; after you recall once how to access them, most probably you won't need to recall them again - until you have a long interval when you do not type. The situation is quite different with symbols you need once per week - most probably, each time you will need to call them again and again. If such rarely used symbols/letters are frequenct (since many of them appear), it is important to have an easy way to find how to type them; on the other hand, probably there is very little need for this way to be easily memorizable. And for symbols which you need once per day, one needs both an easy way to find how to type them, and the way to type them should better be easily memorizable.
Now add to this the fact that for different people (so: different usage scenarios) this division into "all the time/every minute/every day/every week" categories is going to be different. And one should not forget important scenario of going to vacation: when you return, you need to "reboot" your typing skills from the dormant state.
On the other hand, note that the questions discussed above are more or less orthogonal: if the logic of recollection requires ω to be related in some way to the W-key, then it does not matter where the W-key is on the keyboard - the same logic is applicable to the QWERTY base layoubt, or BÉPO one, or Colemak, or Dvorak. This module concerns itself only with the questions of "consistency" and the related question of "the ease of recall"; we care only about which symbols relate to which "base keys", and do not care about where the base key sit on the physical keyboard.
NOTE: the version 0.00 of this module supports only the standard US layout of the base keys.
Now consider the question of the character repertoir: a person may need ways to type "continuously" in several languages; in addition to this, there may be a need to occasionally type "standalone" characters or symbols outside the repertoir of these languages. Moreover, these languages may use different scripts (such as Polish/Bulgarian/Greek/Arabic/Japanese), or may share a "bulk" of their characters, and differ only in some "exceptional letters". To add insult to injury, these "exceptional letters" may be rare in the language (such as ÿ in French or à in Swedish) or may have a significant letter frequency (such as é in French) or be somewhere in between (such as ñ in Spanish).
And the non-language symbols do not need to be the math symbols (although often they are). An Engish-language discussion of etimology at coffee table may lead to a need to write down a word in polytonic greek, or old norse; next moment one would need to write a phonetic transcription in IPA/APA symbols. A discussion of keyboard layout may involve writing down symbols for non-character keys of the keyboard. A typography freak would optimize a document by fine-tuned whitespaces. Almost everybody needs arrows symbols, and many people would use box drawing characters if they had a simple access to them.
Essentially, this means that as far as it does not impacts other accessibility goals, it makes sense to have unified memorizable access to as many symbols/characters as possible. (An example of impacting other aspects: MicroSoft's (and IBM's) "US International" keyboards steal characters `~'"^: typing them produces "unexpected results" - they are deadkeys. This significantly simplifies entering characters with accents, but makes it harder to enter non-accented characters.)
One of the most known principles of design of human-machine interaction is that "simple common tasks should be simple to perform, and complicated tasks should be possible to perform". I strongly disagree with this principle - IMO, it lacks a very important component: "a gradual increase in complexity". When a certain action is easy to perform, and another similar action is still "possible to perform", but on a very elevated level of complexity, this leads to a significant psychological barrier sitting between these tasks. Even when switching from the former task to the latter has significant benefits, this barrier leads to self-censorship. People will ignore the benefits even if they exceed the penalty of "the elevated level of complexity" mentioned above. And IMO self-censorship is the worst type of censorship.
So I would add another clause to the law above: "and moderately complicated tasks should remain moderately hard to perform". What does it tell us in the situation of keyboard layout? One can separate several levels of complexity.
- Basic:
-
There should be some "base keyboards": keyboard layouts used for continuous typing in a certain language or script. Access from one base keyboard to letters of another should be as simple as possible.
- By parts:
-
If a symbol can be thought of as a combination of certain symbols accessible on the base keyboard, one should be able to "compose" the symbol: enter it by typing a certain "composition prefix" key then the combination (as far as the combination is unambiguously associated to one symbol).
The "thoughts" above should be either obvious (as in "combining a and e should give æ") or governed by simple mneumonic rules; the rules should cover as wide a range as possible (as in "Greek/Coptic/Hebrew/Russian letters are combined as G/C/H/R and the corresponding Latin letter; the correspondence is phonetic, or, in presence of conflicts, visual").
- Quick access:
-
As many non-basic letters as possible (of those expected to appear often) should be available via shortcuts. Same should be applicable to starting sequences of composition rules (such as "instead of typing StartCompose and ' one can type AltGr-').
- Smart access
-
Certain non-basic characters may be accessible by shortcuts which are not based on composition rules. However, these shortcuts should be deducible by using simple mneumonic rules (such as "to get a vowel with `-accent, type AltGr-key with key sitting below the vowel key").
- Superdeath:
-
If anything else fails, the user should be able to enter a character by its Unicode number (preferably in the most frequently referenced format: hexadecimal.
Here are the finer points elaborating on these levels of complexity:
It looks reasonable to allow "fuzzy mneumonic rules": the rules which specify several possible variants where to look for the shortcut (up to 3-4 variants). If/when one forgets the keying of the shortcut, but remembers such a rule, a short experiment with these positions allows one to reconstruct the lost memory.
-
The "base keyboards" (those used for continuous typing in a certain language or script) should be identical to some "standard" widely used keyboards. These keyboards should differ from each other in position of keys used by the scripts only. If a script B has more letters than a script A, then a lot of "punctuation" on the layout A will be replaced by letters in the layout B. This missing punctuation should be made available by pressing a modifier (AltGr? compare with MicroSoft's Vietnamese keyboard's top row).
-
If more than one base keyboard is used, there must be a quick access: if one needs to enter one letter from layout B when in layout A, one should not be forced to switch to B, type the letter, then switch back to A. It must be available on "
Quick_Access_Key letter
". -
One should consider what the
Quick_Access_Key
does when the layouts A and B are identical on a particular key. One can go with the "Occam's razor" approach and makeQuick_Access_Key
the do-nothing identity map. Alternatively, one can make it access some symbols useful both for script A and script B. It is a judgement call.Note that there is a gray area when layouts A and B are not identical, but a key
K
produces punctuation in layout A, and a letter in layout B. Then when in layout B, this punctuation is available onAltGr-key
, so, in principle,Quick_Access_Key
would duplicate the functionality ofAltGr
. Compare with "there is more than one way to do it" below; remember that OS (or misbehaving applications) may make some keypresses "unavailable". I feel that in these situations, having duplication is a significant advantage over "having some extra symbols available". -
Paired symbols (such as such as ≤≥, «», ‹›, “�, ‘’ should be put on paired keyboard's keys: <> or [] or ().
-
"Directional symbols" (such as arrows) should be put either on numeric keypad or on a 3×3 subgrid on the letter-part of the keyboard (such as QWE/ASD/ZXC). (Compare with [broken?] implementation in Neo2.)
-
for symbols that are naturally thought of as sitting in a table, one can create intuitive mapping of quite large tables to the keyboard. Split each key in halves by a horizontal line, think of
Shift-key
as sitting in the top half. Then ignoring`~
key and most of punctuation on the right hand side, keyboard becomes an 8×10 grid. Taking into accountAltGr
, one can map up to 8×10×2 (or, in some cases, 8×20!) table to a keyboard.Example: Think of IPA consonants.
-
Cheatsheets are useful. And there are people who are ready to dedicate a piece of their memory to where on a layout is a particularly useful to them symbol. So even if there is no logical position for a certain symbol, but there is an empty slot on layout, one should not hesitate in using this slot.
However, this will be distractive to people who do not want to dedicate their memory to "special cases". So it makes sense to have three kinds of cheatsheets for layouts: one with special cases ignored (useful for most people), one with all general cases ignored (useful for checks "is this symbol available in some place I do not know about" and for memorization), and one with all the bells and whistles.
-
"There is more than one way to do it" is not a defect, it is an asset. If it is a reasonable expectation to find a symbol X on keypress K', and the same holds for keypress K'' and they both do not conflict with other "being intuitive" goals, go with both variants. Same for 3 variants, 4 - now you get my point.
Example: The standard Russian phonetic layout has � on the
^
-key; on the other hand, � is a variant of Е; so it makes sense to have � available onAltGr-Е
as well. Same for Ъ and Ь.
Explanation of keyboard layout terms used in the docs
The aim of this module is to make keyboard layout design as simple as possible. It turns out that even very elaborate designs can be made quickly and the process is not very error-prone. It looks like certain venues not tried before are now made possible; at least I'm not aware of other attempts in this direction. One can make layouts which can be "explained" very concisely, while they contain thousand(s) of accessible letters.
Unfortunately, being on unchartered territories, in my explanations I'm forced to use home-grown terms. So be patient with me... The terms are keyboard group, keyboard, face and layer.
In what follows, the words letter and character are used interchangeably. A key means a physical key on a keyboard clicked (possibly together with one of modifiers Shift
, AltGr
- or, rarely Control
. AltGr
is either marked as such, or is just the "right" Alt
key; at least on Windows it can be replaced by Control-Alt
. A dead key is a key click which does not produce any letter, but modifies what the next keypress would do.
A plain layer is a part of keyboard layout accessible by using only non-dead keyes (possibly in combination with Shift
); likewise, additional layers are parts of layout accessible by combining the non-dead keys with Shift
(if needed) and with a particular combination of other modifiers (AltGr
or Control
). So there may be up to 2 additional layers: the AltGr
-layer and Control
-layer.
On the simplest layouts, such as "US" or "Russian", there is no dead keys - but this is only feasible for languages which use very few characters with diacritic marks. However, note that most layouts do not use Control
-layer - it is stated that this might be subject to problems with system interaction.
The primary face consists of the plain and additional layers of a keyboard; it is the part of layout accessible without switching "sticky state" and without using dead keys. There may be up to 3 layouts (Primary, AltGr, Control) per face (on Windows). A secondary face is a face exposed after pressing a dead key.
A keyboard is a collection of faces: the primary face, plus one face per a defined deadkey. Finally, a keyboard group is a collection of keyboards (switchable by CapsLock and/or keyboard change hotkeys like Shift-Alt
) designed to work smoothly together.
EXAMPLE: Start with a very elaborate (and not yet implemented, but feasible with this module) example. A keyboard group may consist of phonetically matched Latin and Cyrillic keyboards, and visually matched Greek and Math keyboards. Several deadkeys may be shared by all 4 of these keyboards; in particular, there would be 4 deadkeys allowing access to primary faces of these 4 keyboards from other keyboards of the group. Also, there may be specialised deadkey tuned for particular need of entering Latin script, Cyrillic script, Greek script, and Math.
Suppose that there are 8 specialized Latin deadkeys (for example, name them
grave/tilde/hat/breve/ring_above/macron/acute/diaeresis
although in practice each one of them may do more than the name suggests). Then Latin keyboard will have the following 13 faces:
Primary/Latin-Primary/Cyrillic-Primary/Greek-Primary/Math-Primary
grave/tilde/hat/breve/ring_above/macron/acute/diaeresis
NOTE: Here Latin-Primary is the face one gets when one presses the Access-Latin deadkey when in Latin mode; it may be convenient to define it to be the same as Primary - or maybe not. For example, if one defines it to be Greek-Primary, then this deadkey has a convenient semantic of flipping between Latin and Greek modes for the next typed character: when in Latin, Latin-DEADKEY a
would enter α, when in Greek, the same keypresses [now meaning "Latin-DEADKEY α"] would enter "a".
Assume that the layout does not use the Control
modifier. Then each of these faces would consists of two layers: the plain one, and the AltGr
- one. For example, pressing AltGr
with a key on Greek face could add diaeresis to a vowel, or use a modified ("final" or "symbol") "glyph" for a consonant (as in σ/ς θ/ϑ). Or, on Latin face, AltGr-a
may produce æ. Or, on a Cyrillic keyboard, AltGr-� (ya) may produce ѣ (yat').
Likewise, the Greek keyboard may define special deadkeys to access polytonic greek vowels. (On the other hand, maybe this is not a very good idea - it may be more useful to make polytonic Greek accessible from all keyboards in a keyboard group. Then one is able to type a polytonic Greek letter without switching to the Greek keyboard.)
With such a keyboard group, to type one Greek word in a Cyrillic text one would switch to the Greek keyboard, then back to Cyrillic; but when all one need to type now is only one Greek letter, it may be easier to use the "Greek-DEADKEY letter" combination, and save switching back to the Cyrillic keyboard. (Of course, for this to work the letter should be on the primary face of the Greek keyboard.)
=====================================================
Looks too complicated? Try to think about it in a different way: there are many faces in a group of keyboards; break them into 3 "onion rings":
- CORE faces
-
one can "switch to a such a face" and type continuously using this face without pressing dead keys. In other words, these faces can be made "active".
When another face is active, the letters in these faces are still accessible by pressing one particular dead key before each of these letters. This dead key does not depend on which core face is currently "active". (This is the same as for univerally accessible faces.)
- Universally accessible faces
-
one cannot "switch to them", however, letters in these faces are accessible by pressing one particular dead key before this letter. This dead key does not depend on which core face is currently "active".
- satellite faces
-
one cannot "switch to them", and letters in these faces are accessible from one particular core face only. One must press a dead key before every letter in such faces.
For example, when entering a mix of Latin/Cyrillic scripts and math, it makes sense to make the base-Latin and base-Cyrillic faces into the core; it is convenient when (several) Math faces and a Greek face can be made universally accessible. On the other hand, faces containing diacretized Latin letters and diacretized Cyrillic letters should better be made satellite; this avoids a proliferation of dead keys which would make typing slower.
Access to diacritic marks
The logic: dead keys are either 8-bit characters with high bit set, or if none with the needed glyph, they are "spacing modifier letters" or "spacing clones of diacritics". And if you type something after them, you can get other modifier letters and combining characters: here is the logic of this:
- The second press
-
The principal combining mark.
- Surrogate for the diacritic
-
(either
"
or'
): corresponding "prime shape"-modifier character - SPACE
-
The modifier character itself.
- NBSP
-
Modifier letter (the first one if diacritic is 8-bit, the second one otherwise.
CAVEATS
Non-US keycaps: the key "a" still uses (VK_)A, but its scancode is now different. E.g., French's A is on 0x10, which is US's Q. Our table of scancodes is currently hardwired. Some pictures and tables are available on
http://bepo.fr/wiki/Pilote_Windows
FILES
SEE ALSO
On diacritics:
http://www.phon.ucl.ac.uk/home/wells/dia/diacritics-revised.htm#two
http://en.wikipedia.org/wiki/Tonos#Unicode
http://en.wikipedia.org/wiki/Early_Cyrillic_alphabet#Numerals.2C_diacritics_and_punctuation
http://en.wikipedia.org/wiki/Vietnamese_alphabet#Tone_marks
http://en.wikipedia.org/wiki/User:TEB728/temp (Chars of languages)
http://www.evertype.com/alphabets/index.html
Accents in different Languages:
http://fonty.pl/porady,12,inne_diakrytyki.htm#07
On typography marks
http://wiki.neo-layout.org/wiki/Striche
http://www.matthias-kammerer.de/SonsTypo3.htm
http://en.wikipedia.org/wiki/Soft_hyphen
On keyboard layouts:
http://en.wikipedia.org/wiki/Keyboard_layout
http://en.wikipedia.org/wiki/Keyboard_layout#US-International
Discussion of layout changes:
https://www.libreoffice.org/bugzilla/show_bug.cgi?id=5981
http://msdn.microsoft.com/en-us/goglobal/bb964651
http://eurkey.steffen.bruentjen.eu/layout.html
http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Birman%27s_keyboard_layout.svg
http://bepo.fr/wiki/Accueil
http://cgit.freedesktop.org/xkeyboard-config/tree/symbols/ru#n598
http://eklhad.net/linux/app/halfqwerty.xkb (One-handed layout)
http://www.doink.ch/an-x11-keyboard-layout-for-scholars-of-old-germanic/ (and references there)
http://www.neo-layout.org/
https://commons.wikimedia.org/wiki/File:Neo2_keyboard_layout.svg
Images in (download of)
http://www.mzuther.de/en/contents/osd-neo2
Neo2 sources:
http://wiki.neo-layout.org/browser/windows/kbdneo2/Quelldateien
Shift keys at center, nice graphic:
http://www.tinkerwithabandon.com/twa/keyboarding.html
Physical keyboard:
http://www.konyin.com/?page=product.Multilingual%20Keyboard%20for%20UNITED%20STATES
Portable keyboard layout
http://www.autohotkey.com/forum/viewtopic.php?t=28447
One-handed
http://www.autohotkey.com/forum/topic1326.html
Typing on numeric keypad
http://goron.de/~johns/one-hand/#documentation
On screen keyboard indicator
http://www.autohotkey.com/docs/scripts/KeyboardOnScreen.htm
By author of MSKLC Michael S. Kaplan (do not forget to follow links)
http://blogs.msdn.com/b/michkap/archive/2006/03/26/560595.aspx
http://blogs.msdn.com/b/michkap/archive/2006/04/22/581107.aspx
Chaining dead keys:
http://blogs.msdn.com/b/michkap/archive/2011/04/16/10154700.aspx
Mapping VK to VSC etc:
http://blogs.msdn.com/b/michkap/archive/2006/08/29/729476.aspx
[Link] Remapping CapsLock to mean Backspace in a keyboard layout
(if repeat, every second Press counts ;-)
http://colemak.com/forum/viewtopic.php?id=870
Scancodes from kbd.h get in the way
http://blogs.msdn.com/b/michkap/archive/2006/08/30/726087.aspx
What happens if you start with .klc with other VK_ mappings:
http://blogs.msdn.com/b/michkap/archive/2010/11/03/10085336.aspx
Keyboards with Ctrl-Shift states:
http://blogs.msdn.com/b/michkap/archive/2010/10/08/10073124.aspx
On assigning Ctrl-values
http://blogs.msdn.com/b/michkap/archive/2008/11/04/9037027.aspx
On hotkeys for switching layouts:
http://blogs.msdn.com/b/michkap/archive/2008/07/16/8736898.aspx
Text services
http://blogs.msdn.com/b/michkap/archive/2008/06/30/8669123.aspx
Low-level access in MSKLC
http://levicki.net/articles/tips/2006/09/29/HOWTO_Build_keyboard_layouts_for_Windows_x64.php
http://blogs.msdn.com/b/michkap/archive/2011/04/09/10151666.aspx
On font linking
http://blogs.msdn.com/b/michkap/archive/2006/01/22/515864.aspx
Unicode in console
http://blogs.msdn.com/michkap/archive/2005/12/15/504092.aspx
Adding formerly "invisible" keys to the keyboard
http://blogs.msdn.com/b/michkap/archive/2006/09/26/771554.aspx
Redefining NumKeypad keys
http://blogs.msdn.com/b/michkap/archive/2007/07/04/3690200.aspx
BUT!!!
http://blogs.msdn.com/b/michkap/archive/2010/04/05/9988581.aspx
And backspace/return/etc
http://blogs.msdn.com/b/michkap/archive/2008/10/27/9018025.aspx
kbdutool.exe, run with the /S ==> .c files
Doing one's own WM_DEADKEY processing'
http://blogs.msdn.com/b/michkap/archive/2006/09/10/748775.aspx
Dead keys do not work on SG-Caps
http://blogs.msdn.com/b/michkap/archive/2008/02/09/7564967.aspx
VK_OEM_8 Kana modifier - Using instead of AltGr http://www.kbdedit.com/manual/ex13_replacing_altgr_with_kana.html Limitations of using KANA toggle http://www.kbdedit.com/manual/ex12_trilang_ser_cyr_lat_gre.html
Ctrl2cap
http://technet.microsoft.com/en-us/sysinternals/bb897578
Low level scancode mapping
http://www.annoyances.org/exec/forum/winxp/r1017256194
http://web.archive.org/web/20030211001441/http://www.microsoft.com/hwdev/tech/input/w2kscan-map.asp
http://msdn.microsoft.com/en-us/windows/hardware/gg463447
http://www.annoyances.org/exec/forum/winxp/1034644655
???
http://netj.org/2004/07/windows_keymap
the free remapkey.exe utility that's in Microsoft NT / 2000 resource kit.
CapsLock as on typewriter:
http://www.annoyances.org/exec/forum/winxp/1071197341
Problems on X11:
http://wiki.linuxquestions.org/wiki/Configuring_keyboards (current???)
http://wiki.linuxquestions.org/wiki/Accented_Characters (current???)
http://wiki.linuxquestions.org/wiki/Altering_or_Creating_Keyboard_Maps (current???)
https://help.ubuntu.com/community/ComposeKey (documents almost 1/2 of the needed stuff)
http://www.gentoo.org/doc/en/utf-8.xml (2005++ ???)
http://en.gentoo-wiki.com/wiki/X.Org/Input_drivers (2009++ HAS: How to make CapsLock change layouts)
http://www.freebsd.org/cgi/man.cgi?query=setxkbmap&sektion=1&manpath=X11R7.4
http://people.uleth.ca/~daniel.odonnell/Blog/custom-keyboard-in-linuxx11
http://shtrom.ssji.net/skb/xorg-ligatures.html (of 2008???)
http://tldp.org/HOWTO/Danish-HOWTO-2.html (of 2005???)
http://www.tux.org/~balsa/linux/deadkeys/index.html (of 1999???)
EIGHT_LEVEL FOUR_LEVEL_ALPHABETIC FOUR_LEVEL_SEMIALPHABETIC PC_SYSRQ : see
http://cafbit.com/resource/mackeyboard/mackeyboard.xkb
./xkb in /etc/X11 /usr/local/X11 /usr/share/local/X11 but what dead_diaresis means is defined here:
Apparently, may be in /usr/X11R6/lib/X11/locale/en_US.UTF-8/Compose /usr/share/X11/locale/en_US.UTF-8/Compose
http://wiki.maemo.org/Remapping_keyboard
Note: have XIM input method in GTK disables Control-Shift-u way of entering HEX unicode.
Note: the problems with handling deadkeys via .Compose are that: .Compose is handled by applications, while keymaps by server (since they may be on different machines, things can easily get out of sync); .Compose knows nothing about the current "Keyboard group" or of the state of CapsLock etc (therefore emulating "group switch" via composing is impossible).
JS code to add "insert these chars": google for editpage_specialchars_cyrilic, or
http://en.wikipedia.org/wiki/User:TEB728/monobook.jsx
Summary tables for Cyrillic
http://ru.wikipedia.org/wiki/%D0%9A%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%D0%B8%D1%86%D0%B0#.D0.A1.D0.BE.D0.B2.D1.80.D0.B5.D0.BC.D0.B5.D0.BD.D0.BD.D1.8B.D0.B5_.D0.BA.D0.B8.D1.80.D0.B8.D0.BB.D0.BB.D0.B8.D1.87.D0.B5.D1.81.D0.BA.D0.B8.D0.B5_.D0.B0.D0.BB.D1.84.D0.B0.D0.B2.D0.B8.D1.82.D1.8B_.D1.81.D0.BB.D0.B0.D0.B2.D1.8F.D0.BD.D1.81.D0.BA.D0.B8.D1.85_.D1.8F.D0.B7.D1.8B.D0.BA.D0.BE.D0.B2
http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B7%D0%B8%D1%86%D0%B8%D0%B8_%D0%B1%D1%83%D0%BA%D0%B2_%D0%BA%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%D0%B8%D1%86%D1%8B_%D0%B2_%D0%B0%D0%BB%D1%84%D0%B0%D0%B2%D0%B8%D1%82%D0%B0%D1%85
http://en.wikipedia.org/wiki/List_of_Cyrillic_letters
http://en.wikipedia.org/wiki/Cyrillic_alphabets#Summary_table
http://en.wiktionary.org/wiki/Appendix:Cyrillic_script
Extra chars (see also the ordering table on page 8)
http://std.dkuug.dk/jtc1/sc2/wg2/docs/n3194.pdf
IPA
http://upload.wikimedia.org/wikipedia/commons/f/f5/IPA_chart_2005_png.svg
Table with Unicode points marked:
http://www.staff.uni-marburg.de/~luedersb/IPA_CHART2005-UNICODE.pdf
(except for "Lateral flap" and "Epiglottal" column/row.
(Extended) IPA explained by consortium:
http://www.unicode.org/charts/PDF/U0250.pdf
IPA keyboard
http://www.rejc2.co.uk/ipakeyboard/
http://en.wikipedia.org/wiki/International_Phonetic_Alphabet_chart_for_English_dialects#cite_ref-r_11-0
Is this discussing KBDNLS_TYPE_TOGGLE on VK_KANA???
http://mychro.mydns.jp/~mychro/mt/2010/05/vk-f.html
LIMITATIONS
Currently only output for Windows keyboard layout drivers (via MSKLC) is available.
Currently only the keyboards with US-mapping of hardware keys to "the etched symbols" are supported (think of German physical keyboards where Y/Z keycaps are swapped: Z is etched between T and U, and Y is to the left of X, or French which swaps A and Q, or French or Russian physical keyboards which have more alphabetical keys than 26).
Currently no LIGATURES or chained deadkeys are supported.
UNICODE TABLE GOTCHAS
LESS-THAN
, FULL MOON
, GREATER-THAN
, EQUALS
GREEK RHO
, MALE
are defined with SYMBOL
or SIGN
at end, but (may) drop it when combined with modifiers via WITH
. Likewise for SUBSET OF
, SUPERSET OF
, CONTAINS AS MEMBER
, PARALLEL TO
, EQUIVALENT TO
, IDENTICAL TO
.
Sometimes opposite happens, and SIGN
appears out of blue sky; compare:
2A18 INTEGRAL WITH TIMES SIGN
2A19 INTEGRAL WITH INTERSECTION
ENG
is a combination of n
with HOOK
, but it is not marked as such in its name.
Sometimes a name of diacretic (after WITH
) acquires an ACCENT
at end (see U+0476
).
Oftentimes the part to the left of WITH
is not resolvable: sometimes it is underspecified (e.g, just TRIANGLE
), sometimes it is overspecified (e.g., in LEFT VERTICAL BAR WITH QUILL
), sometime it should be understood as a word (e.g, in END WITH LEFTWARDS ARROW ABOVE
). Sometimes it just does not exist (e.g., LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE
- there is LATIN LETTER INVERTED GLOTTAL STOP
, but not the reversed variant). Sometimes it is a defined synonym (VERTICAL BAR
).
Sometimes it has something appended (N-ARY UNION OPERATOR WITH DOT
).
Sometimes WITH
is just a clarification (RIGHTWARDS HARPOON WITH BARB DOWNWARDS
).
1 AND
1 ANTENNA
1 ARABIC MATHEMATICAL OPERATOR HAH
1 ARABIC MATHEMATICAL OPERATOR MEEM
1 ARABIC ROUNDED HIGH STOP
1 ARABIC SMALL HIGH LIGATURE ALEF
1 ARABIC SMALL HIGH LIGATURE QAF
1 ARABIC SMALL HIGH LIGATURE SAD
1 BACK
1 BLACK SUN
1 BRIDE
1 BROKEN CIRCLE
1 CIRCLED HORIZONTAL BAR
1 CIRCLED MULTIPLICATION SIGN
1 CLOSED INTERSECTION
1 CLOSED LOCK
1 COMBINING LEFTWARDS HARPOON
1 COMBINING RIGHTWARDS HARPOON
1 CONGRUENT
1 COUPLE
1 DIAMOND SHAPE
1 END
1 EQUIVALENT
1 FISH CAKE
1 FROWNING FACE
1 GLOBE
1 GRINNING CAT FACE
1 HEAVY OVAL
1 HELMET
1 HORIZONTAL MALE
1 IDENTICAL
1 INFINITY NEGATED
1 INTEGRAL AVERAGE
1 INTERSECTION BESIDE AND JOINED
1 KISSING CAT FACE
1 LATIN CAPITAL LETTER REVERSED C
1 LATIN CAPITAL LETTER SMALL Q
1 LATIN LETTER REVERSED GLOTTAL STOP
1 LATIN LETTER TWO
1 LATIN SMALL CAPITAL LETTER I
1 LATIN SMALL CAPITAL LETTER U
1 LATIN SMALL LETTER LAMBDA
1 LATIN SMALL LETTER REVERSED R
1 LATIN SMALL LETTER TC DIGRAPH
1 LATIN SMALL LETTER TH
1 LEFT VERTICAL BAR
1 LOWER RIGHT CORNER
1 MEASURED RIGHT ANGLE
1 MONEY
1 MUSICAL SYMBOL
1 NIGHT
1 NOTCHED LEFT SEMICIRCLE
1 ON
1 OR
1 PAGE
1 RIGHT ANGLE VARIANT
1 RIGHT DOUBLE ARROW
1 RIGHT VERTICAL BAR
1 RUNNING SHIRT
1 SEMIDIRECT PRODUCT
1 SIX POINTED STAR
1 SMALL VEE
1 SOON
1 SQUARED UP
1 SUMMATION
1 SUPERSET BESIDE AND JOINED BY DASH
1 TOP
1 TOP ARC CLOCKWISE ARROW
1 TRIPLE VERTICAL BAR
1 UNION BESIDE AND JOINED
1 UPPER LEFT CORNER
1 VERTICAL BAR
1 VERTICAL MALE
1 WHITE SUN
2 CLOSED MAILBOX
2 CLOSED UNION
2 DENTISTRY SYMBOL LIGHT VERTICAL
2 DOWN-POINTING TRIANGLE
2 HEART
2 LEFT ARROW
2 LINE INTEGRATION
2 N-ARY UNION OPERATOR
2 OPEN MAILBOX
2 PARALLEL
2 RIGHT ARROW
2 SMALL CONTAINS
2 SMILING CAT FACE
2 TIMES
2 TRIPLE HORIZONTAL BAR
2 UP-POINTING TRIANGLE
2 VERTICAL KANA REPEAT
3 CHART
3 CONTAINS
3 TRIANGLE
4 BANKNOTE
4 DIAMOND
4 PERSON
5 LEFTWARDS TWO-HEADED ARROW
5 RIGHTWARDS TWO-HEADED ARROW
8 DOWNWARDS HARPOON
8 UPWARDS HARPOON
9 SMILING FACE
11 CIRCLE
11 FACE
11 LEFTWARDS HARPOON
11 RIGHTWARDS HARPOON
15 SQUARE
perl -wlane "next unless /^Unresolved: <(.*?)>/; $s{$1}++; END{print qq($s{$_}\t$_) for keys %s}" oxx-us2 | sort -n > oxx-us2-sorted-kw
SQUARE WITH
specify fill - not combining. FACE
is not combining, same for HARPOON
s.
Only CIRCLE WITH HORIZONTAL BAR
is combining. Triangle is combining only with underbar and dot above.
TRIANGLE
means WHITE UP-POINTING TRIANGLE
. DIAMOND
- WHITE DIAMOND
(so do many others.) TIMES
means MULTIPLICATION SIGN
; but CIRCLED MULTIPLICATION SIGN
means CIRCLED TIMES
- go figure! CIRCLED HORIZONTAL BAR WITH NOTCH
is not a decomposition (it is "something circled").
Another way of compositing is OVER
(but not UNDER
!) and FROM BAR
. See also ABOVE
, BELOW
- but only BELOW LONG DASH
. Avoid WITH/AND
after these.
TWO HEADED
should replace TWO-HEADED
. LEFT ARROW
means LEFTWARDS ARROW
, same for RIGHT
. DIAMOND SHAPE
means DIAMOND
- actually just a bug - http://www.reddit.com/r/programming/comments/fv8ao/unicode_600_standard_published/? LINE INTEGRATION
means CONTOUR INTEGRAL
. INTEGRAL AVERAGE
means INTEGRAL
. SUMMATION
means N-ARY SUMMATION
. INFINITY NEGATED
means INFINITY
.
HEART
means WHITE HEART SUIT
. TRIPLE HORIZONTAL BAR
looks genuinely missing...
SEMIDIRECT PRODUCT
means one of two, left or right???
Set $ENV{UI_KEYBOARDLAYOUT_UNRESOLVED}
to enable warnings. Then do
perl -wlane "next unless /^Unresolved: <(.*?)>/; $s{$1}++; END{print qq($s{$_}\t$_) for keys %s}" oxx | sort -n > oxx-sorted-kw
COPYRIGHT
Copyright (c) 2011-2012 Ilya Zakharevich <ilyaz@cpan.org>
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.0 or, at your option, any later version of Perl 5 you may have available.
The distributed examples may have their own copyrights.
TODO
UniPolyK-MultiSymple
Interaction of FromToFlipShift with SelectRX not intuitive. This works: Diacritic[<sub>](SelectRX[[0-9]](FlipShift(Latin)))
ByPairs[], in fact, does not allow spaces??? Actually, even Id() does not allow spaces!!!
DefinedTo cannot be put on Cyrillic 3a9 (yo to superscript disappears - due to duplication???).
... so we do it differently now, but: LinkLayer was not aggressively resolving all the occurences of a character on a layer before we started to combine it with Diacritic_if_undef... - and Cyrillic 3a9 is not helped...
via_parent() is broken - cannot replace for Diacritic_if_undef.
Currently, we map ephigraphic letters to capital letters - is it intuitive???
dotted circle ◌ 25CC
DeadKey_Map200A= FlipLayers #DeadKey_Map200A_0= Id(Russian-AltGr) #DeadKey_Map200A_1= Id(Russian) performs differently from the commented variant: it adds links to auto-filled keys...
Why ¨ on THIN SPACE inserts OGONEK after making ¨ multifaceted???
When splitting a name on OVER/BELOW/ABOVE, we need both sides as modifiers???
Ỳ currently unreachable (appears only in Latin-8 Celtic, is not on Wikipedia)
Somebody is putting an extra element at the end of arrays for layers??? - Probably SPACE...
Need to treat upside-down as a pseudo-decomposition.
We decompose reversed-smallcaps in one step - probably better add yet another two-steps variant...
When creating a <pseudo-stuff> treat SYMBOL/SIGN/FINAL FORM/ISOLATED FORM/INITIAL FORM/MEDIAL FORM; note that SIGN may be stripped: LESS-THAN SIGN becomes LESS-THAN WITH DOT
We do not do canonical-merging of diacritics; so one needs to specify VARIA in addition to GRAVE ACCENT.
We use a smartish algorithm to assign multiple diacritics to the same deadkey. A REALLY smart algorithm would use information about when a particular precombined form was introduced in Unicode...
Inspector tool for NamesList.txt: grep " WITH .* " ! | grep -E -v "(ACUTE|GRAVE|ABOVE|BELOW|TILDE|DIAERESIS|DOT|HOOK|LEG|MACRON|BREVE|CARON|STROKE|TAIL|TONOS|BAR|DOTS|ACCENT|HALF RING|VARIA|OXIA|PERISPOMENI|YPOGEGRAMMENI|PROSGEGRAMMENI|OVERLAY|(TIP|BARB|CORNER) ([A-Z]+WARDS|UP|DOWN|RIGHT|LEFT))$" | grep -E -v "((ISOLATED|MEDIAL|FINAL|INITIAL) FORM|SIGN|SYMBOL)$" |less grep " WITH " ! | grep -E -v "(ACUTE|GRAVE|ABOVE|BELOW|TILDE|DIAERESIS|CIRCUMFLEX|CEDILLA|OGONEK|DOT|HOOK|LEG|MACRON|BREVE|CARON|STROKE|TAIL|TONOS|BAR|CURL|BELT|HORN|DOTS|LOOP|ACCENT|RING|TICK|HALF RING|COMMA|FLOURISH|TITLO|UPTURN|DESCENDER|VRACHY|QUILL|BASE|ARC|CHECK|STRIKETHROUGH|NOTCH|CIRCLE|VARIA|OXIA|PSILI|DASIA|DIALYTIKA|PERISPOMENI|YPOGEGRAMMENI|PROSGEGRAMMENI|OVERLAY|(TIP|BARB|CORNER) ([A-Z]+WARDS|UP|DOWN|RIGHT|LEFT))$" | grep -E -v "((ISOLATED|MEDIAL|FINAL|INITIAL) FORM|SIGN|SYMBOL)$" |less
AltGrMap should be made CapsLock aware (impossible: smart capslock works only on the first layer, so the dead char must be on the first layer). [May work for Shift-Space - but it has a bag of problems...]
Alas, CapsLock'ing a composition cannot be made stepwise. Hence one must calculate it directly. (Oups, Windows CapsLock is not configurable on AltGr-layer. One may need to convert it to VK_KANA???)
WarnConflicts[exceptions] and NoConflicts translation map parsing rules.
Need a way to map to a different face, not a different layer.
Vietnamese: to put second accent over ă, ơ (o/horn), put them over ae/oe; - including another ˘ which would "cancel the implied one", so will get o-horn itself. - Except for acute accent which should replaced by ¨, and hook must be replaced by ˆ. (Over ae/oe there is only macron and diaeresis over ae.)
Or: for the purpose of taking a second accent, AltGr-A behaves as Ä‚ (or Â?), AltGr-O behaves as Ô (or O-horn Æ ?). Then Ã… and O/ behave as the other one... And Ëš puts the dot *below*, macron puts a hook. Exception: ¨ acts as ´ on the unaltered AE.
While Å takes acute accent, one can always input it via putting ˚ on �.
If Ê is on the keyboard (and macron puts a hook), then the only problem is how to enter a hook alone (double circumflex is not precombined), dot below (???), and accents on u-horn ư.
Mogrification rules for double accents: AE Å OE O/ Ù mogrify into hatted/horned versions; macron mogrifies into a hook; second hat modifies a hat into a horn. The only problem: one won't be able to enter double grave on U - use the OTHER combination of ¨ and `... And how to enter dot below on non-accented aue? Put ¨ on umlaut? What about Ë?
When linking two layers, consider prefer_first as a suggestion only: if the prefered slot results in no link, try the second one.
Translation map "functions" for flipping AltGr-register (cannot one use FromTo[] between explicit layers???).
To allow . or , on VK_DECIMAL: maybe make CapsLock-dependent?
http://blogs.msdn.com/b/michkap/archive/2006/09/13/752377.aspx
How to write this diacritic recipe: insert hacheck on AltGr-variant, but only if the breve on the base layer variant does not insert hacheck (so inserts breve)???
GOTCHAS (Windows)
- Several similar MSKLC created keyboards may confuse the system
-
Apparently, the system may get majorly confused when the
description
of the project gets changed without changing the DLL (=project) name.(Tested only with Win7 and the name in the DESCRIPTIONS section coinciding with the name on the KBD line - both in *.klc file.)
The symptoms: I know how one can get 4 different lists of keyboards:
Click on the keyboard icon in the
Language Bar
- usually shown on the toolbar; positioned to the right of the language code EN/RU etc (keyboard icon is not shown if only one keyboard is associated to the current language).-
Go to the
Input Language
settings (e.g., right-click on the Language bar, Settings, General. -
on this
General
page, pressAdd
button, go to the language in question. -
Check the .klc files for recently installed Input Languages.
-
In MS Keyboard Layout Creator, go to
File/Load Existing Keyboard
list.
It looks like the first 4 get in sync if one deletes all related keyboards, then installs the necessary subset. I do not know how to fix 5 - MSKLC continues to show the old name for this project.
- Too long description (or funny characters in description?)
-
If the name in the
DESCRIPTIONS
section is too long, the name shown in the list2
above may be empty.(Checked only on Win7 and when the name in the DESCRIPTIONS section coincides with the name on the
KBD
line - both in *.klc file.)(Fixed by shortening the name [but see "Several similar MSKLC created keyboards may confuse the system" above!], so maybe it was not the length but some particular character (
+
?) which was confusing the system. (I saw a report on MSKLC bug when description had apostroph character'
.) - MSKLC ruins names of dead key when reading a .klc
-
When reading a .klc file, MS Keyboard Layout Creator may ruin the names of dead keys. Symptom: open the dialogue for a dead key mapping (click the key, check that
Dead key view
has checkmark, click on the...
button near theDead key?
checkbox); then the name (the first entry field) contains some junk. (Looks like a long ASCII stringU+0030 U+0030 U+0061 U+0039
.)
Workaround: if all one needs is to compile a .klc, one can run KBDUTOOL directly.
Workaround: correct ALL these names manually in MSKLC. If the names are the Unicode name for the dead character, just click the
Default
button near the entry field. Do this for ALL the dead keys in all the registers (includingSPACE
!). IfCapsLock
is not made "semantically meaningful", there are 6 views of the keyboard (PLAIN, Ctrl, Ctrl+Shift, Shift, AltGr, AltGr+Shift
) - check them all for grayed out keys (=deadkeys).Check for success:
File/"Save Source File As
, use a temporary name. Inspect near the end of the generated .klc file. If OK, you can go to the Project/Build menu. (Likewise, this way lets you find which deadkey's names need to be fixed.)!!! This is time-consuming !!! Make sure that other things are OK before you do this (by
Project/Validate
,Project/Test
).BTW: It might be that this is cosmetic only. I do not know any bad effect - but I did not try to use any tool with visual feedback on the currently active sub-layout of keyboard.
- Double bug in KBDUTOOL with dead characters above 0x0fff
-
This line in .klc file is treated correctly by MSKLC's builtin keyboard tester:
39 SPACE 0 0020 00a0@ 0020 2009@ 200a@ // ,  , ,  ,   // SPACE, NO-BREAK SPACE, SPACE, THIN SPACE, HAIR SPACE
However, via kbdutool it produces the following two bugs:
static ALLOC_SECTION_LDATA MODIFIERS CharModifiers = { &aVkToBits[0], 7, { // Modification# // Keys Pressed // ============= // ============= 0, // 1, // Shift 2, // Control SHFT_INVALID, // Shift + Control SHFT_INVALID, // Menu SHFT_INVALID, // Shift + Menu 3, // Control + Menu 4 // Shift + Control + Menu } }; ..................................... {VK_SPACE ,0 ,' ' ,WCH_DEAD ,' ' ,WCH_LGTR ,WCH_LGTR }, {0xff ,0 ,WCH_NONE ,0x00a0 ,WCH_NONE ,WCH_NONE ,WCH_NONE }, ..................................... static ALLOC_SECTION_LDATA LIGATURE2 aLigature[] = { {VK_SPACE ,6 ,0x2009 ,0x2009 }, {VK_SPACE ,7 ,0x200a ,0x200a },
Essentially,
2009@ 200a@
produceLIGATURES
(= multiple 16-bit chars) instead of deadkeys. Moreover, these ligatures are put on non-existing "modifications" 6, 7 (the maximal modification defined is 4; so the code uses theShift + Control + Menu
flags instead of "modification number" in the ligatures table. - Default keyboard of an application
-
Apparently, there is no way to choose a default keyboard for a certain language. The configuration UI allows moving keyboards up and down in the list, but, apparently, this order is not related to which keyboard is selected when an application starts.
AltGr
-keypresses going nowhere-
Some
AltGr
-keypresses do not result in the corresponding letter on keyboard being inserted. It looks like they are stolen by some system-wide hotkeys. See:http://www.kbdedit.com/manual/ex13_replacing_altgr_with_kana.html
If these keypresses would perform some action, one might be able to deduce how to disable the hotkeys. So the real problem comes when the keypress is silently dropped.
I found out one scenario how this might happen, and how to fix this particular situation. (Unfortunately, it is not fixed what I see, when
AltGr-s
[but notAltGr-S
] is stolen. Installing a shortcut, one can associate a hotkey to the shortcut. Unfortunately, the UI allows (and encourages!) hotkeys of the form <Control-Alt-letter> (which are equivalent toAltGr-letter
) - instead of safe combinations likeControl-Alt-F4
orAlt-Shift-letter
(which do not go to keyboard drivers, so cannot generate characters). If/when an application linked to by this shortcut is gone, the hotkey remains, but now it does nothing (no warning or dialogue comes).If the shortcut is installed in one of "standard places", one can find it. Save this to K:\findhotkey.vbs (replace K: by the suitable drive letter here and below)
on error resume next set WshShell = WScript.CreateObject("WScript.Shell") Dim A Dim Ag Set Ag=Wscript.Arguments If Ag.Count > 0 then For x = 0 to Ag.Count -1 A = A & Ag(x) Next End If Set FSO = CreateObject("Scripting.FileSystemObject") f=FSO.GetFile(A) set lnk = WshShell.CreateShortcut(A) If lnk.hotkey <> "" then msgbox A & vbcrlf & lnk.hotkey End If
Save this to K:\findhotkey.cmd
set findhotkey=k:\findhotkey for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %UserProfile%\desktop for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %AllUsersProfile%\desktop for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %UserProfile%\Start Menu for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %AllUsersProfile%\Start Menu for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %APPDATA% for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A" cd /d %HOMEDRIVE%%HOMEPATH% for /r %%A in (*.lnk) do %findhotkey%.vbs "%%A" for /r %%A in (*.pif) do %findhotkey%.vbs "%%A" for /r %%A in (*.url) do %findhotkey%.vbs "%%A"
(In most situations, only the section after the last
cd /d
is important; in my configuration all the "interesting" stuff is in%APPDATA%
. Running this should find all shortcuts which define hot keys.Run the cmd file. Repeat in the "All users"/"Public" directory. It should show a dialogue for every shortcut with a hotkey it finds. (But, as I said, it did not fix my problem:
AltGr-s
works in MSKLC test window, and nowhere else I tried...)
13 POD Errors
The following errors were encountered while parsing the POD:
- Around line 106:
Non-ASCII character seen before =encoding in 'ω'. Assuming CP1252
- Around line 219:
Expected '=item 2'
- Around line 229:
Expected '=item 3'
- Around line 236:
Expected '=item 4'
- Around line 253:
Expected '=item 5'
- Around line 258:
Expected '=item 6'
- Around line 264:
Expected '=item 7'
- Around line 275:
Expected '=item 8'
- Around line 289:
Expected '=item 9'
- Around line 964:
Expected '=item 2'
- Around line 969:
Expected '=item 3'
- Around line 974:
Expected '=item 4'
- Around line 978:
Expected '=item 5'