KeyboardGen (shortened kbdgen
) is a tool for generating keyboard
layouts from .kbdgen bundles and associated resources.
CLI
Core kbdgen
functionality will be within the subcommand target
, that then allows to select
among the various linguistic targets: Windows, MacOS, .svg, etc.
Example usage:
cargo run — target --bundle-path C:\Projects\Divvun\keyboards\keyboard-sme\sme.kbdgen --output-path C:\KbdgenBuilds\sme_mac macos generate
The first argument is the location of the given .kbdgen bundle (see below for information on bundles) that the keyboard should be built from.
The second argument is the output path.
And the third argument is the desired target.
Bundle
\.kbdgen bundles are folders with the .kbdgen extension which describe keyboards for a language or language family. They’re expected to contain 3 pieces:
*project.yaml *layouts folder *targets folder *resources
You can see an example of a .kbdgen bundle here: https://github.com/giellalt/keyboard-sme
Layouts
A layout is a file that describes keyboard layouts, including associated keymaps, dead keys, and transforms, as well as any configuration information, for all supported targets.
With the new kbdgen
, the layout format has been changed as described below.
Layouts are described in .yaml files, with one layout
file per
language tag
(i.e., se-FI
(Northern Sami (Finland)))
The layout
may be described for multiple targets
(windows, macOS, etc.),
i.e., groupings of platforms
.
A given target
may support one or more platforms
(iPad-9in
, iPad-12in
).
Within a platform
are the supported keyboard layers
, i.e.,
default
, shift
, caps
(for caps lock), etc.
Layouts also have associated deadKeys
information, which is for keys that do not
themselves result in a key printed, but will print a key in combination with some
other key. For deadKeys
, there must be a corresponding transforms
entry for the
' ' key, and referrs to deadKey
usage with a space
(i.e., a termination).
There’s also the space
category.
Deadkeys
deadKeys
can be nested:
'a':
'b': ['c']
'a':
'b':
'c': ['d']
Or with a more authentic example:
transforms:
'-':
' ': '-'
a: ā
e: ē
'´':
' ': '-´'
a: ā́
e: ḗ
Layers
Layers are expected to be whitespace separated strings listing the keymap of
characters in correspondence with appropriate format for the expected
platform
-layer
combination.
Newlines are permitted for readability, but the keys must be in the correct order, and having more keys than expected will result in an error.
Special keys are supported, and must be contained within \s{}
.
Unrepresentable unicode characters must be contained within u{}
.
Additional Info
displayNames
, at the top of the layout
file, are the name of the
given keyboard in each of the relevant languages. This is often used in parts of
UI or for naming.
Each target
may have an associated config
describing some target
-specific
settings.
Additionally, various keyboards may require these:
longpress
- used for mobile keyboards, the set of keys that become available
if a key is pressed for a long time.
transforms
- used in combination with deadKeys
, describes the final character
that should be printed once a series of keys is pressed.
keyNames
- descriptions of named keys (space
and return
) in the language in
question.
Targets
Target files are .yaml files that are specific to the given target and hold additional per target configuration.
For a given build to succeed for a target, the target file must be present.
Target Specific information
Windows
Generating a Windows keyboard layout in the current implementation of kbdgen
mainly
concerns the generation of .klc files, and then subsequent building of those files
on a Windows system.
KLC is Windows’s format for keyboard layouts, meaning Keyboard Layout Creator, which is also the tool that can be used to view and modify .klc files. The tool can be downloaded from Microsoft: https://www.microsoft.com/en-us/download/details.aspx?id=102134
Installing MSKLC requires enabling .NET Framework 3.5 in Windows Programs and Features.
\.klc is a format that has specific requirements for how a keyboard is described and must be encoded as UTF-16, with Windows style CRLF, or the file will be perceived as invalid.
For details on the .klc format, please see the developer documentation.
Target configuration
A Windows target file does not have to be specified. ??
Keyboard layouts
windows:
config:
locale: se-Latn-FI
primary:
layers:
default: |
§ 1 2 3 4 5 6 7 8 9 0 + ´
á š e r t y u i o p å ŋ
a s d f g h j k l ö ä đ
ž z č c v b n m , . -
shift: |
½ ! " # ¤ % & / ( ) = ? `
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M ; : _
caps: |
§ 1 2 3 4 5 6 7 8 9 0 + ´
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M , . -
caps+shift: |
½ ! " # ¤ % & / ( ) = ? `
á š e r t y u i o p å ŋ
a s d f g h j k l ö ä đ
ž z č c v b n m ; : _
alt: |
| \u{0} @ £ $ € \u{0} { [ ] } \ \u{0}
q w € \u{0} ŧ \u{0} \u{0} ï õ \u{0} ¨ ~
â \u{0} \u{0} \u{0} ǧ ǥ \u{0} ǩ \u{0} ø æ '
ǯ ʒ x \u{0} \u{0} \u{0} \u{0} µ < > \u{0}
alt+shift: |
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
Q W \u{0} \u{0} Ŧ \u{0} \u{0} Ï Õ \u{0} ^ ˇ
 \u{0} \u{0} \u{0} Ǧ Ǥ \u{0} Ǩ \u{0} Ø Æ *
Ǯ Ʒ X \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
ctrl: |
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
deadKeys:
default: [´]
shift: ['`']
caps: [´]
caps+shift: ['`']
alt: ['~', ¨]
alt+shift: [^, ˇ]
Config
The config
section is used by Pahkat for spellchecking, the fields:
-
locale
- defines the language locale -
id
- defines the id
Layers
Each layer is split by line, typically to 3 lines of the keyboard. Keys in the format of \u{} are written in Unicode to avoid display issues. In particular, \u{0} is an absent key. Note that KLC cannot support keys outside the Basic Multilingual Plane, even if Unicode supports them.
ChromeOS
ChromeOS generation mainly involves adding keyboard layout information to a JavaScript file.
Target configuration
A file for the desired target has to be specified, and in this case for ChromeOS, it could look like this:
appId: dnihbfekindancgddjehgonciaopmkbe
build: 11
version: 1.0.0
The fields define what follows:
-
appId
- the id of the app -
version
- current app version -
build
- current app build
Keyboard layouts
The ChromeOS keyboard was modeled after the Windows one and so shares a lot of similarities.
chromeOS:
config:
locale: fi
primary:
layers:
default: |
§ 1 2 3 4 5 6 7 8 9 0 + ´
á š e r t y u i o p å ŋ
a s d f g h j k l ö ä đ
ž z č c v b n m , . -
shift: |
½ ! " # ¤ % & / ( ) = ? `
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M ; : _
caps: |
§ 1 2 3 4 5 6 7 8 9 0 + ´
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M , . -
caps+shift: |
½ ! " # ¤ % & / ( ) = ? `
á š e r t y u i o p å ŋ
a s d f g h j k l ö ä đ
ž z č c v b n m ; : _
alt: |
| \u{0} @ £ $ € \u{0} { [ ] } \ \u{0}
q w € \u{0} ŧ \u{0} \u{0} ï õ \u{0} ¨ ~
â \u{0} \u{0} \u{0} ǧ ǥ \u{0} ǩ \u{0} ø æ '
ǯ ʒ x \u{0} \u{0} \u{0} \u{0} µ < > \u{0}
alt+shift: |
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
Q W \u{0} \u{0} Ŧ \u{0} \u{0} Ï Õ \u{0} ^ ˇ
 \u{0} \u{0} \u{0} Ǧ Ǥ \u{0} Ǩ \u{0} Ø Æ *
Ǯ Ʒ X \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
ctrl: |
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
\u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0} \u{0}
Config
The config
section is used by Pahkat for spellchecking, the fields:
-
locale
- defines the language locale -
xkbLayout
- defines the layout ??
Layers
Each layer is split by line,
typically to 3 lines of the keyboard. Keys in the format of \u{}
are written in Unicode to avoid display issues.
iOS
Target configuration
A file for the desired target has to be specified, and in this case for iOS, it could look like this:
codeSignId: "Apple Distribution: The University of Tromso (2K5J2584NX)"
teamId: 2K5J2584NX
packageId: no.uit.giella.keyboards.Sami
bundleName: Divvun Keyboards
sentryDsn: https://94b33a64dc8e4471a7c8cb2f40ce37dc@sentry.io/1227106
aboutDir: ../aboutFiles
version: 3.2.1
build: 278
The fields define what follows:
-
codeSignId
- the id for codesigning -
teamId
- team id -
packageId
- package id -
bundleName
- name of the bundle -
sentryDsn
- url to sentry -
aboutDir
- a path to files each containing a localized description about the app -
version
- current app version -
build
- current app build
Keyboard layouts
iOS is one of the few keyboard layouts that handle more than one platform.
Additionally, it also requires the symbols
layers.
iOS:
config:
spellerPackageKey: https://pahkat.uit.no/main/packages/speller-sme?platform=mobile
spellerPath: se.bhfst
primary:
layers:
default: |
á š e r t y u i o p ŋ
a s d f g h j k l đ ŧ
\s{shift:1.25} \s{spacer:0.25} ž z č c v b n m \s{spacer:0.25} \s{backspace:1.25}
shift: |
Á Š E R T Y U I O P Ŋ
A S D F G H J K L Đ Ŧ
\s{shift:1.25} \s{spacer:0.25} Ž Z Č C V B N M \s{spacer:0.25} \s{backspace:1.25}
symbols-1: |
1 2 3 4 5 6 7 8 9 0
- / : ; ( ) kr & @ "
\s{shiftSymbols} \s{spacer:0.25} . , ? ! ' \s{spacer:0.25} \s{backspace}
symbols-2: |
[ ] { } # % ^ * + =
_ \ | ~ < > € $ £ •
\s{shiftSymbols} \s{spacer:0.25} . , ? ! ' \s{spacer:0.25} \s{backspace}
iPad-9in:
layers:
default: |
\s{"`":0.75} á š e r t y u i o p ŋ \s{backspace:1.25}
\s{shift} a s d f g h j k l đ ŧ \s{shift}
\s{spacer:0.5} ž z č c v b n m , . \s{spacer:0.5} \s{return:2}
shift: |
\s{"@":0.75} Á Š E R T Y U I O P Ŋ \s{backspace:1.25}
\s{shift} A S D F G H J K L Đ Ŧ \s{shift}
\s{spacer:0.5} Ž Z Č C V B N M ! ? \s{spacer:0.5} \s{return:2}
alt: |
\s{"@":0.75} 1 2 3 4 5 6 7 8 9 0 å \s{backspace:1.25}
\s{shift} % # kr & * ( ) ' " ø æ \s{shift}
\s{spacer:0.5} q w x - = / ; : ! ? \s{spacer:0.5} \s{return:2}
alt+shift: |
\s{"@":0.75} 1 2 3 4 5 6 7 8 9 0 Å \s{backspace:1.25}
\s{shift} % # kr & * ( ) ' " Ø Æ \s{shift}
\s{spacer:0.5} Q W X - = / ; : ! ? \s{spacer:0.5} \s{return:2}
symbols-1: |
\s{spacer:0.75} 1 2 3 4 5 6 7 8 9 0 ` \s{backspace:1.25}
\s{shiftSymbols} @ # kr & * ( ) ' " + • \s{shiftSymbols}
\s{spacer:1.5} % _ - = / ; : , . \s{spacer:0.5} \s{return:2}
symbols-2: |
\s{spacer:0.75} 1 2 3 4 5 6 7 8 9 0 ´ \s{backspace:1.25}
\s{shiftSymbols} € $ £ ^ [ ] { } — ° … \s{shiftSymbols}
\s{spacer:1.5} § | ~ ≠ \ < > ! ? \s{spacer:0.5} \s{return:2}
iPad-12in:
layers:
...
Longpress
A longpress section like this is also needed for alternative keys but isn’t specifically exclusive to iOS but rather defined independently in the layout file and shared between Android and iOS
longpress:
A: Å Æ Ä À Â Ã Ā Ạ
Á: Q
E: Ë É È Ê Ẽ Ē Ẹ Ė Ǝ
I: Ï Í Ì Î Ĩ Ī Ị I
...
Config
The config
section is used by Pahkat for spellchecking, the fields:
-
spellerPackageKey
- defines the url for the spellchecking files of the layout we want to generate -
spellerPath
- defines which spellchecker file to use. -
space
- name of space key -
r#return
- name of return key
Platforms
Three platforms are supported, all of which have to be defined, primary
, iPad-9in
, iPad-12in
.
iPad-9in:
layers:
default: |
...
Layers
iOS supports some standard keyboard layers in addition to symbols-1
and symbols-2
.
Each layer is split by line, typically to 3 lines of the keyboard.
Special keys need to be preceeded by \s
,
and is sometimes followed by a number after :
representing the desired width of the key (keywidth is 1
by default, centered):
-
\s{spacer:0.5}
- not a key, just a spacer -
\s{shift}
- Shift -
\s{backspace:1.25}
- Delete -
\s{return:2}
- Enter -
\s{"@":0.75}
- a given key, but with a custom width -
\s{shiftSymbols}
- switch between symbols-1 and symbols-2 layers
MacOS
Target configuration
A MacOS target file does not have to be specified. ??
Keyboard layouts
macOS:
primary:
layers:
default: |
' 1 2 3 4 5 6 7 8 9 0 + ´
á š e r t y u i o p å ŋ
a s d f g h j k l ö ä đ
ž z č c v b n m , . -
shift: |
§ ! " # $ % & / ( ) = ? `
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M ; : _
caps: |
' 1 2 3 4 5 6 7 8 9 0 + ´
Á Š E R T Y U I O P Å Ŋ
A S D F G H J K L Ö Ä Đ
Ž Z Č C V B N M , . -
alt: |
' © ™ £ € ˆ § | [ ] ˝ ± \u{301}
q w é ˇ ŧ þ ˀ ʼ œ ˙ ˚ ¨
¯ ß ð ƒ . ˛ ˘ ˜ - ø æ @
< ÷ x ¸ ‹ › ‘ ’ ‚ … –
alt+shift: |
§ ¡ ® ¥ ¢ \u{302} ¶ \ { } \u{30B} ¿ \u{300}
Q W É \u{30C} Ŧ Þ \u{309} \u{31B} Œ \u{307} \u{30A} \u{308}
\u{304} № Ð ʔ \u{323} \u{328} \u{306} \u{303} \u{335} Ø Æ *
> ⁄ X \u{327} « » “ ” „ · —
alt+caps: |
' © ™ £ € ˆ § | [ ] ˝ ± \u{301}
Q W É ˇ Ŧ Þ ˀ ʼ Œ ˙ ˚ ¨
¯ SS Ð ƒ . ˛ ˘ ˜ - Ø Æ @
< ÷ X ¸ ‹ › ‘ ’ ‚ … –
ctrl: |
0 1 2 3 4 5 6 7 8 9 0 \u{1F} =
\u{11} \u{17} \u{5} \u{12} \u{14} \u{19} \u{15} \u{9} \u{F} \u{10} \u{1B} \u{1D}
\u{1} \u{13} \u{4} \u{6} \u{7} \u{8} \u{A} \u{B} \u{C} ; ' \u{1C}
` \u{1A} \u{18} \u{3} \u{16} \u{2} \u{E} \u{D} , . /
cmd: |
§ 1 2 3 4 5 6 7 8 9 0 + ´
q w e r t y u i o p å ¨
a s d f g h j k l ö ä '
< z x c v b n m , . -
cmd+shift: |
° ! " # € % & / ( ) = ? `
Q W E R T Y U I O P Å ˆ
A S D F G H J K L Ö Ä *
> Z X C V B N M ; : _
cmd+alt: |
€ © ™ £ € § \u{0} | [ ] ≈ ± `
• , é \u{0} ŧ µ ü ı œ þ ˙ ˜
¯ ß ð ƒ \u{0} ħ ˝ ª ł ø æ '
≤ ÷ đ ¸ ‹ › ‘ ’ ‚ … –
deadKeys:
default: [´]
shift: ['`']
caps: [´]
alt: ['-', ., ¨, ¯, ¸, ƒ, ʼ, ˀ, ˆ, ˇ, ˘, ˙, ˚, ˛, ˜, ˝]
alt+shift: [ʔ, №]
alt+caps: ['-', ., ¨, ¯, ¸, ƒ, ʼ, ˀ, ˆ, ˇ, ˘, ˙, ˚, ˛, ˜, ˝]
cmd+alt: [',', ¯, ¸, ƒ, ˙, ˜, ˝]
space:
caps: '\u{A0}'
alt: '\u{A0}'
alt+shift: '\u{A0}'
alt+caps: '\u{A0}'
cmd+alt: '\u{A0}'
Layers
Each layer is split by line,
typically to 3 lines of the keyboard. Keys in the format of \u{}
are written in Unicode to avoid display issues. In
particular, \u{0}
is an absent key.
Dead keys
Dead keys
Space
Space
Android
Target configuration
A file for the desired target has to be specified, and in this case for Android, it could look like this:
packageId: no.uit.giella.keyboards.Sami
keyAlias: sami_keyboard
sentryDsn: https://8f857d788e764bd2a13aaafdf0018c92@sentry.io/1341912
version: 3.2.0
build: 113
The fields define what follows:
-
packageId
- the id of the package -
keyAlias
- name -
sentryDsn
- url to sentry -
version
- current app version -
build
- current app build -
key_store
- store ?? -
key_alias
- alias ?? -
play_store_account
- play store email ?? -
play_store_p12
- play store ?? -
store_password
- password ?? -
key_password
- password ??
Keyboard layouts
Android layouts tend to be quite simple:
android:
config:
spellerPackageKey: https://pahkat.uit.no/main/packages/speller-sme?platform=mobile
spellerPath: se.bhfst
primary:
layers:
default: |
á š e r t y u i o p ŋ
a s d f g h j k l đ ŧ
\s{shift} ž z č c v b n m \s{backspace}
shift: |
Á Š E R T Y U I O P Ŋ
A S D F G H J K L Đ Ŧ
\s{shift} Ž Z Č C V B N M \s{backspace}
Longpress
A longpress section like this is also needed for alternative keys but isn’t specifically exclusive to Android but rather defined independently in the layout file and shared between Android and iOS
longpress:
A: Å Æ Ä À Â Ã Ā Ạ
Á: Q
E: Ë É È Ê Ẽ Ē Ẹ Ė Ǝ
I: Ï Í Ì Î Ĩ Ī Ị I
...
Config
The config
section is used by Pahkat for spellchecking, the fields:
-
spellerPackageKey
- defines the url for the spellchecking files of the layout we want to generate -
spellerPath
- defines which spellchecker file to use.
Layers
Just two layers are standard, default
and shift
. Each layer is split by line,
typically to 3 lines of the keyboard. Special keys need to be preceeded by \s
:
-
\s{shift}
- Shift -
\s{backspace}
- Delete -
\s{return}
- Enter