Most of this documentation is currently Windows oriented as that is the only implemented build at this time.
Build System
All builds are to implemented as io steps with no arguments or return types except the bundle and output path.
Builds are expected to be per major target (i.e., Windows, MacOS, ChromeOS, iOS).
A given build must implement the following trait:
#[async_trait(?Send)]
pub trait BuildSteps {
fn populate_steps(&mut self);
fn count(&self) -> usize;
async fn build_full(&self);
}
And, subsequently, every step in the build must implement this trait:
#[async_trait(?Send)]
pub trait BuildStep {
async fn build(&self, bundle: Arc<KbdgenBundle>, output_path: &Path);
}
Target Specific information
Windows
Useful Sites
Windows Keyboard Layout info: https://kbdlayout.info/
KLC Generation
See the .klc file example below for an overview.
It is currently assumed that Windows only has the core platform (primary
).
.klc files must be encoded in UTF-16 and must have Windows style CRLF or MSKLC
will refuse to read them.
The .klc file has multiple sections, and the important ones are LAYOUT, LIGATURE, and DEADKEY.
For the LAYOUT section, .klc expects rows for each set of keys across all supported
layers (i.e., default
, shift
, etc.), in the following format:
scancode | virtual_key | default | shift | ctrl | alt | alt + shift
(note that the format of the columns beyond virtual_key
is actually variable and
described in the SHIFTSTATE section above, but we only support
the format presented here)
If a given key has no key on a layer, it is represented with -1
.
Only ASCII keys can be represented as-is. All other keys must be converted to Unicode hex.
The creation of .klc files is performed as follows:
-
a .klc file is created per
language-tag
, i.e., perlayout
file -
various metadata required by .klc is generated
-
the keymap for the
layouts
are expected to be in the ISO keyboard format: https://en.wikipedia.org/wiki/ISO/IEC_9995#ISO/IEC_9995-1 A variable calledcursor
is an incrementing integer that keeps track of which key we’re on -
the generation occurs in two steps. The first step, for every key, creates a
WindowsLayerSet
, which lists the set of the key on every layer, and notes any missing characters (nulls) and converts them toNone
. This step also converts any Unicode escapes into Unicode characters -
the
WindowsLayerSet
is used to calculate the status ofcaps_mode
, which is one of the expected .klc columns and roughly corresponds to whether a given key is related to theshift
layer,alt
layer, or both -
the second step, the final .klc key is created, including any available information on its dead key or ligature status. Dead keys must be formatted such as
@
, and ligatures as%%
-
both steps validate to make sure the incoming characters are within BMP
-
SGCap rows are added
-
space and decimal rows are added
Finally, after all this, PahkatClient is used to download the MS KLC installer and run on the resulting .klc files. This step only works on Windows.
Nomenclature
BMP - Basic Multilingual Plane. The true encoding Windows .klc actually expects: https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
This means characters > 0xFFFF
cannot be represented in .klc at all. Not to be confused with keys,
as there are keys that require multiple UTF-16 codepoints to represent (see ligatures),
but no character can be > 0xFFFF
.
Ligatures - ligatures are a Windows-specific term for keys that require 2 or 3 UTF-16 codepoints to represent. This is required for certain languages.
SGCap - "Some keyboards do not associate the CapsLock and Shift keys together for all keystrokes; instead, pressing the CapsLock key defines an additional two shift states for specific keys. Therefore, some languages cannot by typed without the CapsLock key. The "SG" in the name orginiates from the first keyboard layout to use the functionality, the Swiss German keyboard layout."
(Copied from: https://kbdlayout.info/features/SGCAPS)
While alt caps is mentioned as a potential layer, it does not seem to be used. Currently, we accept the keys but do not write them anywhere.
KLC Example
KBD kbdse-FI "Davvisámegiella (Suopma)"
COPYRIGHT "(c) 2017 Divvun/Giellatekno/UiT"
COMPANY "UiT Norgga árktalaš universitehta"
LOCALENAME "se-Latn-FI"
LOCALEID "00000c3b"
VERSION 1.0
SHIFTSTATE
0 // 4
1 // 5 Shift
2 // 6 Ctrl
6 // 7 Alt
7 // 8 Alt + Shift
LAYOUT
29 OEM_3 4 00a7 00bd -1 | -1
02 1 4 1 ! -1 -1 -1
03 2 4 2 " -1 @ -1
04 3 4 3 # -1 00a3 -1
05 4 4 4 00a4 -1 $ -1
06 5 4 5 % -1 20ac -1
07 6 4 6 & -1 -1 -1
08 7 4 7 / -1 { -1
09 8 4 8 ( -1 [ -1
0a 9 4 9 ) -1 ] -1
0b 0 4 0 = -1 } -1
0c OEM_MINUS 4 + ? -1 \ -1
0d OEM_PLUS 4 @00b4 @` -1 -1 -1
10 Q 1 00e1 00c1 -1 q Q
11 W 1 0161 0160 -1 w W
12 E 5 e E -1 20ac -1
13 R 5 r R -1 -1 -1
14 T 1 t T -1 0167 0166
15 Y 5 y Y -1 -1 -1
16 U 5 u U -1 -1 -1
17 I 1 i I -1 00ef 00cf
18 O 1 o O -1 00f5 00d5
19 P 5 p P -1 -1 -1
1a OEM_4 1 00e5 00c5 -1 @00a8 @^
1b OEM_6 1 014b 014a -1 @~ @02c7
1e A 1 a A -1 00e2 00c2
1f S 5 s S -1 -1 -1
20 D 5 d D -1 -1 -1
21 F 5 f F -1 -1 -1
22 G 1 g G -1 01e7 01e6
23 H 1 h H -1 01e5 01e4
24 J 5 j J -1 -1 -1
25 K 1 k K -1 01e9 01e8
26 L 5 l L -1 -1 -1
27 OEM_1 1 00f6 00d6 -1 00f8 00d8
28 OEM_7 1 00e4 00c4 -1 00e6 00c6
2b OEM_5 1 0111 0110 -1 ' *
56 OEM_102 1 017e 017d -1 01ef 01ee
2c Z 1 z Z -1 0292 01b7
2d X 1 010d 010c -1 x X
2e C 5 c C -1 -1 -1
2f V 5 v V -1 -1 -1
30 B 5 b B -1 -1 -1
31 N 5 n N -1 -1 -1
32 M 5 m M -1 00b5 -1
33 OEM_COMMA 4 , ; -1 < -1
34 OEM_PERIOD 4 . : -1 > -1
35 OEM_2 4 - _ -1 -1 -1
39 SPACE 0 0020 0020 0020 -1 -1
53 DECIMAL 0 . . -1 -1 -1
DEADKEY 00b4
0061 00e1
0041 00c1
00e5 01fb
00c5 01fa
00e6 01fd
00c6 01fc
0063 0107
0043 0106
0065 00e9
0045 00c9
0067 01f5
0047 01f4
0069 00ed
0049 00cd
006b 1e31
004b 1e30
006c 013a
004c 0139
006d 1e3f
004d 1e3e
006e 0144
004e 0143
006f 00f3
004f 00d3
00f8 01ff
00d8 01fe
0070 1e55
0050 1e54
0072 0155
0052 0154
0073 015b
0053 015a
0075 00fa
0055 00da
0076 01d8
0056 01d7
0077 1e83
0057 1e82
0079 00fd
0059 00dd
007a 017a
005a 0179
0020 00b4
DEADKEY 0060
0061 00e0
0041 00c0
0065 00e8
0045 00c8
0069 00ec
0049 00cc
006e 01f9
004e 01f8
006f 00f2
004f 00d2
0075 00f9
0055 00d9
0076 01dc
0056 01db
0077 1e81
0057 1e80
0079 1ef3
0059 1ef2
0020 0060
DEADKEY 00a8
0061 00e4
0041 00c4
0065 00eb
0045 00cb
0068 1e27
0048 1e26
0069 00ef
0049 00cf
006f 00f6
004f 00d6
0074 1e97
0075 00fc
0055 00dc
0077 1e85
0057 1e84
0078 1e8d
0058 1e8c
0079 00ff
0059 0178
0020 00a8
DEADKEY 005e
0061 00e2
0041 00c2
0063 0109
0043 0108
0065 00ea
0045 00ca
0067 011d
0047 011c
0068 0125
0048 0124
0069 00ee
0049 00ce
006a 0135
004a 0134
006f 00f4
004f 00d4
0073 015d
0053 015c
0075 00fb
0055 00db
0077 0175
0057 0174
0079 0177
0059 0176
0020 005e
DEADKEY 007e
0061 00e3
0041 00c3
0069 0129
0049 0128
006e 00f1
004e 00d1
006f 00f5
004f 00d5
0075 0169
0055 0168
0020 007e
DEADKEY 02c7
0061 01ce
0041 01cd
0063 010d
0043 010c
0064 010f
0044 010e
0065 011b
0045 011a
0067 01e7
0047 01e6
0068 021f
0048 021e
0069 01d0
0049 01cf
006a 01f0
006b 01e9
004b 01e8
006c 013e
004c 013d
006e 0148
004e 0147
006f 01d2
004f 01d1
0072 0159
0052 0158
0073 0161
0053 0160
0074 0165
0054 0164
0075 01d4
0055 01d3
0076 01da
0056 01d9
007a 017e
005a 017d
0292 01ef
01b7 01ee
0020 02c7
KEYNAME
01 Esc
0e Backspace
0f Tab
1c Enter
1d Ctrl
2a Shift
36 "Right Shift"
37 "Num *"
38 Alt
39 Space
3a "Caps Lock"
3b F1
3c F2
3d F3
3e F4
3f F5
40 F6
41 F7
42 F8
43 F9
44 F10
45 Pause
46 "Scroll Lock"
47 "Num 7"
48 "Num 8"
49 "Num 9"
4a "Num -"
4b "Num 4"
4c "Num 5"
4d "Num 6"
4e "Num +"
4f "Num 1"
50 "Num 2"
51 "Num 3"
52 "Num 0"
53 "Num Del"
54 "Sys Req"
57 F11
58 F12
7c F13
7d F14
7e F15
7f F16
80 F17
81 F18
82 F19
83 F20
84 F21
85 F22
86 F23
87 F24
KEYNAME_EXT
1c "Num Enter"
1d "Right Ctrl"
35 "Num /"
37 "Prnt Scrn"
38 "Right Alt"
45 "Num Lock"
46 Break
47 Home
48 Up
49 "Page Up"
4b Left
4d Right
4f End
50 Down
51 "Page Down"
52 Insert
53 Delete
54 (00)
56 Help
5b "Left Windows"
5c "Right Windows"
5d Application
DESCRIPTIONS
0c3b Davvisámegiella (Suopma)
LANGUAGENAMES
0c3b Davvisámegiella (Suopma)
ENDKBD