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., per layout 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 called cursor 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 to None. This step also converts any Unicode escapes into Unicode characters

  • the WindowsLayerSet is used to calculate the status of caps_mode, which is one of the expected .klc columns and roughly corresponds to whether a given key is related to the shift 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."

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

Chrome OS

MacOS

XML Generation

iOS