Fork me on GitHub

This documentation is currently under active development.

Please follow the warnings or errors that the kbdgen tool provides, and if something is missing from the documentation, please open an issue on GitHub.

1. Introduction to kbdgen 1.0.7

1.1. What is kbdgen?

kbdgen is a tool for generating keyboards from layout descriptor files defined using YAML.

It requires Python 3.4 or higher.

1.2. Supported targets

kbdgen supports both mobile and desktop keyboards, including a web-based visual layout for development and debugging your layouts.

android

Android target, can be built on any OS

ios

iOS target, can be built only on macOS

osx

macOS target, can be built only on macOS

svg

SVG target, for debugging and development using HTML and SVG, can be built on any OS

win

Windows 8.1+ target, can be built on Unix-like operating systems (requires wine)

x11

X11 target, can be built on any OS

1.3. Anatomy of a kbdgen project

A kbdgen project is ordinarily structured with a central project.yaml file defining the project descriptor, with several other YAML files describing each layout in the same directory, listed in the layouts property of the project descriptor.

Resources for each layout will differ per target, and there is no specified or required directory structure for storing these resources. When required, properties for resource paths are relative to the project descriptor file.

For more information on the project and layout descriptors, see the documentation and examples provided in the "Projects" and "Layouts" chapters.

1.4. Usage

kbdgen is a command line application. Running kbdgen --help will provide you with the flags supported.

In general, to begin with you will likely want to just run kbdgen -t <target> -o <output-dir> <path/to/project.yaml>.

Try with the svg target to get a feel for how it works.

2. Installation

Each target may have separate requirements for generating and building the output that kbdgen provides. Please check the Installation section of your desired target before proceeding.

2.1. From Source

2.1.1. Unix-like (Linux, macOS, etc)

You will need Python 3.4 or higher installed to continue. Use your operating system’s package manager to install the python3 package or equivalent. You will also need to install poetry, a Python package management tool.

poetry install

You will also need to install imagemagick or icon generation (and therefore the build) will fail for several targets. On macOS, this can be installed with MacPorts or Homebrew. (brew install imagemagick or port install imagemagick).

2.1.2. Windows

Ensure Python 3.4 or higher is installed on your system and Python’s executables are available in your %PATH%. You will also need to install poetry, a Python package management tool. Using the Command Prompt, run the following commands:

poetry install

It is left an exercise for the reader to work out how to install imagemagick on Windows and add it to the %PATH%.

3. Projects

3.1. Example project descriptor file

Below shows a typical and basic project.yaml that describes a project localised into Norwegian Bokmål and English, with target-specific configuration for iOS and Android.

Example of a basic project descriptor file
# An internal identifier for the project
internalName: project

# Strings for describing the project, using ISO 639-1 or 639-3 tags.
locales:
  en:
    name: "Keyboard Project"
    description: "A test keyboard"
  nb:
    name: "Tastatur"
    description: "Et testtastatur"

# Author and email properties
author: Example Person
email: person@place.example

# Optional organisation and copyright properties
organisation: Example Corp
copyright: Copyright © 2017 Example Corp

# Layouts supported by this project, without .yaml suffix
layouts: [layout1, layout2]

# Target-specific configurations at project level (may also include osx, win, etc)
targets:
  android:
    version: "1.0"
    build: "1"
    packageId: com.example.keyboards
  ios:
    version: "1.0"
    build: "1"
    packageId: com.example.keyboards

3.2. Supported properties

For target-specific properties, please see the specific chapter for your desired target.
Property Type Required Description Example

internalName

string

Yes

The internal identifier for the project. May be used for generating filenames or internal metadata for a project.

Must meet the requirements of the regex: /^[a-z0-9_-]+$/.

internalName: keyboards

locales.<lang>.name

string

Yes, at least for en

The name string for the project. For mobile keyboards, this is the title of the app.

<lang> is any ISO 639-1 or 639-3 code. If a language has both, prefer the 639-1 variant for better support.

It must be defined for at least the en locale, and preferably also for each well-supported locale that you expect to support.

locales:
  en:
    name: My Keyboard Project

locales.<lang>.description

string

Yes, at least for en

The description of the project.

<lang> is any ISO 639-1 or 639-3 code. If a language has both, prefer the 639-1 variant for better support.

It must be defined for at least the en locale, and preferably also for each well-supported locale that you expect to support.

locales:
  en:
    description: A keyboard supporting zero languages.

author

string

Yes

The author

author: Brendan Molloy

email

string

Yes

The author’s email address

email: brendan@bbqsrc.net

organisation

string

Yes

The associated organisation. Put author here too if no organisation.

organisation: Divvun

copyright

string

Yes

The copyright string to be used where and if necessary.

copyright: Copyright © 2017 Divvun

layouts

string array

Yes

Specify the layouts to be included in this project.

The layout names are the names of the YAML files without the .yaml suffix.

layouts: [sma, sme, smj]

targets.<target>

property map

Target dependent

For defining target-specific project-level properties, such as code signing certificates, build and version numbers, and other resources to be included at a project level.

See the documentation for each target for more information.

targets:
  android:
    version: "1.0"
    build: "1"
    packageId: com.example.keyboards

3.3. Best practices

These best practices are a work-in-progress. If you have a suggestion, please submit an issue on GitHub.

4. Layouts

4.1. Structure of a layout descriptor file

Layout descriptors, like project descriptors, are defined using YAML.

At the highest level, a layout consists of several modes which define how the layout should behave when different layers are enabled. There are distinct modes for mobile and desktop keyboards, and the same layout file may incorporate both modes if the user desires.

Layouts support a supportedTargets property so that a layout may be defined to only function with certain targets. This allows the keyboard developer to separate Windows layouts from Mac layouts, or separate mobile from desktop layouts, depending on the relevant use case for the developer.

Keys and transform outputs may be multi-codepoint. Simply type the output you expect in the descriptor and it will be generated correctly, as layout modes are space-delimited only.

If you wish to input a unicode codepoint that causes distortion to the layout descriptor, you may use \u{x} notation, which is just the U+xxxx codepoint written as \u{xxxx}. The Examples section shows this in use several times.

It is of fundamental importance that the internalName for each layout is unique. While the kbdgen generator should have an error in the case of user error, it has previously caused undefined behaviour.

4.2. Mobile layouts

Mobile layouts consist of the modes mobile-default and mobile-shift. These modes are currently used with the android and ios targets.

Mobile layouts support the longpress property, which defines a space-delimited set of characters to be able to be selected by the user when they long press the defined key.

The styles property defines the behaviour of the special keys depending on the size and shape of the device. At the moment this property is required. You may simply copy and paste this boilerplate into your projects.

The strings property defines the strings to be shown on the spacebar and return keys. While these are not strictly required, it is highly recommended that you set these before deploying into production for the best user experience, particularly on iOS.

4.3. Desktop layouts

A desktop layout consists of keys for each mode, dead key definitions (using deadKeys) and a transforms map (transforms) for defining key sequences to output specific glyphs. Transforms may be infinitely nested in this format, it is up to the platform to determine how many levels of nesting are considered reasonable.

4.3.1. Modes

Modes are defined as a space-delimited and newline-delimited set of characters for use as keys on a keyboard. The expected keyboard layout is the ISO standard keyboard (not the ANSI US keyboard, which has one less key).

keyboard
Figure 1. The ISO standard keyboard layout showing potential variations in colour

kbdgen supports E00–E12, D01–D12, C01–C12, and B00–10 as per traditional European ISO standard keyboards. In practice, for ANSI keyboards, C12 moves to D13, and B00 is simply dropped altogether. B11 is not used on any modern keyboard, and E13 is largely ignored.

If you forget to add the | symbol after the mode key, you will encounter some fun parsing errors. Don’t forget the pipe!

Desktop layouts consist of several modes due to the complexity of desktop keyboards:

  • iso-default

  • iso-shift

  • iso-caps

  • iso-caps+shift

  • iso-alt

  • iso-alt+shift

  • iso-caps+alt

  • iso-ctrl

There are also a few target-specific modes for macOS due to the addition of the Command key on macOS keyboards:

  • osx-cmd

  • osx-cmd+shift

  • osx-cmd+alt

  • osx-cmd+alt+shift

It is possible that further modes may be supported in the future if necessary.

4.4. Supported properties

For target-specific properties, please see the specific chapter for your desired target.
Property Type Required Description Example

internalName

string

Yes

The internal identifier for the layout. May be used for generating filenames or internal metadata for a layout.

Must meet the requirements of the regex: /^[a-z0-9_-]+$/. A good choice is to use the locale code.

This SHOULD NOT change between versions! If you change this, targets such as Android will display unexpected behaviour when you update your keyboards.

internalName: sma

displayNames.<lang>

string

Yes, at least for en.

The name of the layout.

<lang> is any ISO 639-1 or 639-3 code. If a language has both, prefer the 639-1 variant for better support.

It must be defined for at least the en locale, and preferably also for each well-supported locale that you expect to support.

displayNames:
  en: Southern Sámi

locale

string

Yes

The locale for the layout.

Locale is any ISO 639-1 or 639-3 code. If a language has both, prefer the 639-1 variant for better support.

For platforms that do not support the correct locale code for this layout, target-specific overrides may be defined. Please check the relevant target documentation for more information.

locale: sma

targets.<target>

string map

No

A map of target-specific customisation properties.

<target> is the code for the target.

Only necessary if you need to set a target-specific property.

targets:
  win:
    locale: sma-Latn-NO

modes.<mode>

layout-formatted string

Yes (see description)

For mobile targets, both mobile-default and mobile-shift modes are required.

For desktop targets, in general only the iso-default and iso-shift modes are strictly required. Some targets require other modes, and the tool will inform you if they are missing.

The value of this key should be similar to that provided in the example.

NOTE: Do not forget the | symbol after the <mode> key or you will receive unexpected parsing errors.

modes:
  mobile-default: |
    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 ï

deadKeys.<mode>

string array

No

Defines the dead keys on the given <mode>, which is the key for the mode from the modes property.

It is recommended that the keys of this array are wrapped in quotes to make diaeresis and other hard to see glyphs maintainable for future developers, including yourself.

deadKeys:
  iso-default: ["`"]

transforms

nested string maps

No

Defines the output of a sequence of key strokes.

Always includes deadkeys but some targets support key sequencing (replacing glyphs based on input pattern) — this behaviour is target dependent.

This map may be repeatedly nested until a terminal is reached. If a sequence is short-circuited, the " " is used as the fallback output in all cases.

transforms:
  a:
    ' ': a
    `: à

special.<key>

string

No

These properties are used for setting key outputs for keys outside of the input key area, such as spacebar.

Currently the only supported <key> is space.

special:
  space:
    iso-caps: \u{A0}

strings.<key>

string

No

These properties are only used on mobile targets.

They are used for specifying strings to be shown on the space and return keys on mobile targets.

strings:
  space: space
  return: return

decimal

string

No (defaults to ".")

Specify the decimal separator for the given locale. Required for the numpad keys on some targets.

decimal: ","

supportedTargets

string array

No (defaults to all targets)

A list of the supported targets of this layout. Unlisted targets will result in no generation being attempted for that target.

This is useful for having different definitions for the same layout, such as a separate Windows and macOS variant.

supportedTargets: [osx, x11, svg]

styles

mobile styles map

No (Yes for mobile)

This boilerplate is currently required for mobile targets. It is targeted for deprecation.

Just copy and paste it verbatim into your mobile layouts for a happy life.

styles:
  tablet:
    actions:
      backspace: [1, right, fill]
      enter: [2, right, fill]
      shift: [3, both, fill]
  phone:
    actions:
      shift: [3, left, fill]
      backspace: [3, right, fill]

4.5. Examples

4.5.1. Mobile layout example

internalName: sma

displayNames:
  sma: Åarjelsaemien gïele
  en: South Sami
  fi: Eteläsaame
  nb: Sørsamisk
  se: Lullisámegiella
  sv: Sydsamiska

locale: sma

supportedTargets: [ios, android]

modes:
  mobile-default: |
    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 ï
  mobile-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 Ï

longpress:
  A: Ä Á À Â Ã Ạ
  E: Ë É È Ê Ẽ Ẹ
  I: Ï Í Ì Î Ĩ Ị
  O: Ø Ö Ó Ò Ô Õ Ọ
  U: Ü Ú Ù Û Ũ Ụ
  Y: Ÿ Ý Ỳ Ŷ
  Æ: Ä
  Ö: Ø

  C: Č Ç
  D: Đ
  G: Ǧ Ǥ Ǧ
  K: Ǩ
  N: Ŋ
  S: Š
  T: Ŧ
  Z: Ž Ʒ Ǯ

  a: ä á à â ã ạ
  e: ë é è ê ẽ ẹ
  i: ï í ì î ĩ ị
  o: ø ö ó ò ô õ ọ
  u: ü ú ù û ũ ụ
  y: ÿ ý ỳ ŷ
  æ: ä
  ö: ø

  c: č ç
  d: đ
  g: ǧ ǥ ǧ
  k: ǩ
  n: ŋ
  s: š
  t: ŧ
  z: ž ʒ ǯ

styles:
  tablet:
    actions:
      backspace: [1, right, fill]
      enter: [2, right, fill]
      shift: [3, both, fill]
  phone:
    actions:
      shift: [3, left, fill]
      backspace: [3, right, fill]

strings:
  space: gaskoe
  return: return

4.5.2. Windows desktop layout example

internalName: sma_NO-windows

displayNames:
  sma: Åarjelsaemien gïele (Nöörje)
  en: South Sami (Norway)
  fi: Eteläsaame (Norja)
  nb: Sørsamisk (Norge)
  se: Lullisámegiella (Norga)
  sv: Sydsamiska (Norge)

locale: sma

supportedTargets: [win, x11, svg]

targets:
  win:
    locale: sma-Latn-NO

modes:
  iso-default: |
    | 1 2 3 4 5 6 7 8 9 0 + \
    ï 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 , . -
  iso-shift: |
    § ! " # ¤ % & / ( ) = ? `
    Ï 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 ; : _
  iso-caps: |
    | 1 2 3 4 5 6 7 8 9 0 + \
    Ï 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 , . -
  iso-caps+shift: |
    § ! " # ¤ % & / ( ) = ? `
    ï 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 ; : _
  iso-alt: |
    \u{0} \u{0} @ £ $ € \u{0} { [ ] } \u{0} ´
    q â € \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}
  iso-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 Â \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:
  iso-default: ['¨']
  iso-shift: ['^', '`']
  iso-caps: ['¨']
  iso-caps+shift: ['^', '`']
  iso-alt: ['~', '´']

transforms:
  "`":
    " ": "`"
    a: à
    A: À
    e: è
    E: È
  ´:
    " ": ´
    a: á
    A: Á
    å: ǻ
    Å: Ǻ
  ^:
    " ": ^
    a: â
    A: Â
    c: ĉ
    C: Ĉ
  ¨:
    " ": ¨
    a: ä
    A: Ä
    e: ë
    E: Ë
  "~":
    " ": "~"
    a: ã
    A: Ã
    i: ĩ
    I: Ĩ

4.5.3. macOS desktop layout example

internalName: sma_NO-mac

displayNames:
  sma: Åarjelsaemien gïele (Nöörje)
  en: South Sami (Norway)
  fi: Eteläsaame (Norja)
  nb: Sørsamisk (Norge)
  'no': Sørsamisk (Norge)
  nn: Sørsamisk (Noreg)
  da: Sydsamisk (Norge)
  se: Lullisámegiella (Norga)
  sv: Sydsamiska (Norge)

locale: sma

supportedTargets: [osx, x11, svg]

modes:
  iso-default: |
    < 1 2 3 4 5 6 7 8 9 0 + ´
    ï 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 , . -
  iso-shift: |
    > ! " # $ % & / ( ) = ? `
    Ï 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 ; : _
  iso-caps: |
    < 1 2 3 4 5 6 7 8 9 0 + ´
    Ï 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 , . -
  iso-alt: |
    ≤ © ™ £ € ‸ § | [ ] ˝ ± \u{301}
    q , é ˇ þ ˘ ˀ ʼ œ ˙ ˚ \u{308}
    ¯ ß ð ƒ . ˛ \u{A0}\u{330} ˜ - ø ä '
    ' ÷ ˍ ¸ ‹ › ‘ ’ ‚ … –
  iso-alt+shift: |
    ≥ ¡ ® ¥ ¢ \u{32D} ¶ \ { } \u{30B} ¿ \u{300}
    Q \u{326} É \u{30C} Þ \u{306} \u{309} \u{31B} Œ \u{307} \u{30A} \u{302}
    \u{304} № Ð ʔ \u{323} \u{328} \u{330} \u{303} \u{335} Ø Ä "
    § ⁄ \u{331} \u{327} « » “ ” „ · —
  iso-caps+alt: |
    ≤ © ™ £ € ‸ § | [ ] ˝ ± \u{301}
    Q , É ˇ Þ ˘ ˀ ʼ Œ ˙ ˚ \u{308}
    ¯ SS Ð ƒ . ˛ \u{A0}\u{330} ˜ - Ø Ä '
    ' ÷ ˍ ¸ ‹ › ‘ ’ ‚ … –
  iso-ctrl: |
    ` 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{1D} ~
    \u{1} \u{13} \u{4} \u{6} \u{7} \u{8} \u{A} \u{B} \u{C} ; ' \u{1C}
    0 \u{1A} \u{18} \u{3} \u{16} \u{2} \u{E} \u{D} , . /
  osx-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 , . -
  osx-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 ; : _
  osx-cmd+alt: |
    € © ™ £ € ∞ § | [ ] ≈ ± `
    • Ω é \u{0} † µ ü ı œ π ˙ ~
     ß ∂ ƒ ¸ ˛ √ ª fi ö ä '
    ≤ ÷ ≈ ç ‹ › ‘ ’ ‚ … –
  osx-cmd+alt+shift: |
    Ÿ ¡ ® ¥ ¢ ‰ ¶ \ { } ≠ ¿ \u{0}
    ° ˝ É \u{0} ‡ ˜ Ü ˆ Œ ∏ ˚ ^
    ◊ ∑ ∆ ∫ ¯ ˘ ¬ º fl Ö Ä \u{0}
    ≥ ⁄ \u{0} Ç « » “ ” „ · —

deadKeys:
  iso-default: ['¨', '´']
  iso-shift: ['`', 'ˆ']
  iso-caps: ['¨', '´']
  iso-alt: [',', '-', '.', '¯', '¸', 'ʼ', 'ˀ', 'ˇ', 'ˍ', '˘', '˙', '˚', '˛', '˜', '˝', '‸', '\u{A0}\u{330}']
  iso-alt+shift: ['ʔ', '№']
  iso-caps+alt: [',', '-', '.', '¯', '¸', 'ʼ', 'ˀ', 'ˇ', 'ˍ', '˘', '˙', '˚', '˛', '˜', '˝', '‸']
  osx-cmd+alt: ['¸', '˙']

transforms:
  \u{A0}\u{330}:
    " ": \u{A0}\u{330}
    e: 
    E: 
    i: 
    I: 
    u: 
    U: 
  "-":
    " ": "-"
    b: ƀ
    d: đ
    D: Đ
    g: ǥ
  ",":
    " ": ","
    s: ș
    S: Ș
    t: ț
    T: Ț
  .:
    " ": .
    a: 
    A: 
    b: 
    B: 
  :
    " ": 
    d: 
    D: 
    e: 
    E: 
  "`":
    " ": "`"
    a: à
    A: À
    e: è
    E: È
  ´:
    " ": ´
    a: á
    A: Á
    å: ǻ
    Å: Ǻ
  ˜:
    " ": "~"
    a: ã
    A: Ã
    y: 
    Y: 
  ¯:
    " ": ¯
    a: ā
    l: l\u{323}\u{304}
    L: L\u{323}\u{304}
    æ: ǣ
    Æ: Ǣ
  ʼ:
    " ": ʼ
    o: ơ
    O: Ơ
    u: ư
    U: Ư

special:
  space:
    iso-caps: \u{A0}
    iso-alt: \u{A0}
    iso-alt+shift: \u{A0}
    iso-caps+alt: \u{A0}
    osx-cmd+alt: \u{A0}

4.6. Best practices

These best practices are a work-in-progress. If you have a suggestion, please submit an issue on GitHub.

As you can see from the examples, in some cases, macOS and Windows keyboards diverge significantly enough that two separate layouts are defined. While it is still possible to generate a macOS and Windows keyboard from the same source, consider user expectations when decided whether or not to split the layouts into separate files.

4.7. Generating layouts from CLDR with cldr2kbdgen

kbdgen includes a tool called cldr2kbdgen, which will convert a CLDR keyboard XML descriptor into a fully functional kbdgen layout.

You can acquire a CLDR keyboard repository from the Unicode website. Choose the latest from the Data column, then select the cldr-keyboards-x.y.z.zip file.

If converting a macOS keyboard and the E00 (top left) and B00 (bottom left) keys are flipped, this is a known issue with some CLDR definitions. Add the --osx flag to the cldr2kbdgen command and it will auto-flip them back.

Usage is straightforward: cldr2kbdgen <cldr-xml> <path/to/layout.yaml>

5. Targets

5.1. Android

The Android target uses a fork of the Android Open Source Project’s LatinIME codebase to generate a custom keyboard for Android with the look and feel of the native keyboard.

The target will automatically download the giella-ime dependency and cache it for future builds. The cache will automatically be invalidated upon an update to the repository.

5.1.2. Installation and environment configuration

In general, kbdgen will do its best to inform you if versions of things are incorrect, however, It is highly recommended to use the approach described below. Android builds do not tolerate incorrect versions of things and will give you a hard time.
You will need about 2.6 GB of free space to install the Android SDK dependencies.
Installing the Android development environment
  1. Create a directory to host your Android SDK.

  2. Export ANDROID_HOME to point to this directory.

  3. Unzip the Android SDK CLI tools into $ANDROID_HOME (so you have $ANDROID_HOME/tools).

  4. Run yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses to accept the licenses.

  5. Run $ANDROID_HOME/tools/bin/sdkmanager tools "build-tools;25.0.3" "extras;android;m2repository" ndk-bundle "platforms;android-25" to install the required dependencies. This may take a long time, and will not show any progress of any kind.

  6. Run cargo install cargo-ndk to add the NDK plugin to cargo.

  7. Run the following to install all the required Rust targets for cross-compilation:

rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
The minimum supported NDK version is r19c (19.2.x).

You should save the ANDROID_HOME export into your .profile so the variable is set when your shell loads.

5.1.3. Project-level configuration and properties

As described in the Projects chapter, some targets may require project-level properties in order to generate the target.

Table 1. Android project properties
Property Required Description Example

packageId

Yes

The reverse-domain notation ID for the package

packageId: com.example.mypackageid

icon

No (but recommended)

Path to the icon file to be converted into the various sizes required by Android, relative to project root.

icon: icons/icon.png

keyStore

No (Yes for release builds)

Path to the Android keystore (see "Generating keystores" section for more information)

keyStore: my.keystore

keyAlias

No (Yes for release builds)

The key to use within the provided keystore

keyAlias: myprojectkey
A full example of the targets section for Android
targets:
  android:
    packageId: com.example.amazing.keyboards
    icon: icon.png
    keyStore: path/to/my/keystore
    keyAlias: alias_specified_during_generation

5.1.4. Layout-level configuration and properties

Table 2. Android layout properties
Property Required Description Example

minimumSdk

No

The API level that is the minimum supported for a keyboard. Useful for limiting access to a keyboard where it is known several glyphs are missing on older devices.

See the Android documentation for API versions compared to OS version.

NOTE: The lowest API supported by this keyboard is API 16, but it may work on older variants.

minimumSdk: 16

showNumberHints

No (defaults to true)

Defines whether or not the number hints are shown on the top row of keys.

When set to false, no number hints will be shown and any long press keys defined will be shown in their place.

showNumberHints: true

5.1.5. Testing

Testing on a device

Different versions of Android have different requirements for enabling Developer Mode. Use a search engine to find out how to enable USB debugging for your specific device before continuing.

Connecting an Android device for debugging
  1. Connect your Android device to your system

  2. Run $ANDROID_HOME/platform-tools/adb install -r <path to apk>

If you receive an error about the package already being installed or signatures not matching, uninstall the package from the device first.

5.1.6. Generating keystores

Use ASCII characters only for your password if you value your sanity.

Make sure you’ve read the "Signing Your Applications" page from the Android Developers website.

It is recommended that you use 4096-bit keys, and name the keystore and alias your key with the internal name of your project.

For example, if my project name was "sami_keyboard", and I wanted the key to last for 10000 days, I would run the following command:

keytool -genkey -v -keystore sami_keyboard.keystore -alias sami_keyboard -keyalg RSA -keysize 4096 -validity 10000

Make sure you keep your key safe! Don’t publish it to git or svn.

The warning straight from the Android website says:

Warning: Keep your keystore and private key in a safe and secure place, and ensure that you have secure backups of them. If you publish an app to Google Play and then lose the key with which you signed your app, you will not be able to publish any updates to your app, since you must always sign all versions of your app with the same key.

5.2. iOS

The iOS target uses a fork of the tasty-imitation-keyboard project to generate a custom keyboard for iOS with the look and feel of the native keyboard.

The target will automatically download the giellakbd-ios dependency and cache it for future builds. The cache will automatically be invalidated upon an update to the repository.

5.2.1. Requirements

You will need:

  • Xcode

  • Rust

Run the following:

rustup target add aarch64-apple-ios
rustup target add armv7-apple-ios
rustup target add i386-apple-ios
rustup target add x86_64-apple-ios
cargo install cargo-lipo

5.2.2. Project-level configuration and properties

This section is incomplete. Please check the examples/ directory in the kbdgen git repository for guidance.

As described in the Projects chapter, some targets may require project-level properties in order to generate the target.

Table 3. iOS project properties
Property Required Description Example

5.2.3. Layout-level configuration and properties

This section is incomplete. Please check the examples/ directory in the kbdgen git repository for guidance.
Table 4. iOS layout properties
Property Required Description Example
Example
targets:
  ios:
    bundleName: "Sami Keyboards"
    packageId: com.example.keyboards.sami
    icon: any.png
    aboutDir: path/to/about/files # Should contain {locale}.txt files

5.2.4. Testing

Testing in a simulator

The simulator does not always fully replicate the behaviour that a user will experience when using keyboards on a real device.

This is especially the case regarding when and where a keyboard can be used in the simulator.

The best app for testing keyboards in the simulator is the Calendar app. It offers a consistent experience and does not often cause obscure and unreproducable issues when compared with other simulator apps.

To begin testing in the simulator is straightforward. Open the path provided by kbdgen after a completed build in Xcode, choose a simulator device from the dropdown in the main toolbar, and press the "Play" button.

Follow the instructions in the provided hosting app to enable the keyboards.

5.3. macOS

This section is incomplete.

The osx target generates a .pkg file, optionally codesigned, that installs a series of .keylayout files for each layout provided in the project.

To sign the package, specify the -R flag while building.

5.3.1. Requirements

This target can only be generated on a macOS system.

You need to install:

  • ImageMagick

5.3.2. Project-level configuration and properties

targets:
  osx:
    bundleName: "Brendan's Keyboards"
    packageId: so.brendan.keyboards.sami
    codeSignId: "macOS Installer Certificate ID (find in your Keychain)"
    icon: any.png
    version: "1.0.0" # should follow x.y.z format
    resources: path/to/resources # optional
    welcome: welcome.txt # or .html or .rtf; optional
    readme: readme.txt # or .html or .rtf; optional
    license: license.txt # or .html or .rtf; optional
    conclusion: conclusion.txt # or .html or .rtf; optional
    background: background.png # or .jpg; optional

icon will be converted into an .icns file.

codeSignId must be for a macOS installer distribution certificate, generated by the Team Agent.

Resources can be localised. Place readme, welcome, license and conclusion files into zz.lproj directories inside the resources directory, where zz represents a supported language code. Place the background image into the root of the resources directory.

5.3.3. Layout-level configuration and properties

The macOS target supports a few custom modes to facilitate the differences between macOS keyboards and others. Particularly, the cmd key is macOS specific.

Therefore, macOS specific modes are supported with the osx- prefix.

It is important to supply at least an osx-cmd mode otherwise the cmd key will have no function whatsoever.

If you wish to use your iso-default mode as the osx-cmd mode (which is the sanest default), you can use YAML referencing:

iso-default: | &default
  my keyboard here
osx-cmd: *default

5.4. SVG

This target exists for the purpose of visualising and debugging keyboard layouts during development. An HTML index file is generated, including all SVGs necessary to demonstrate the project.

The SVGs show each mode, and the corresponding ISO key code for the mapping. This is especially useful for correcting missing key errors.

5.5. Windows

5.5.1. Preparing build environment

Building the Windows target on Unix-like operating systems

You will need to install:

  • wine

  • winetricks

You will need to use wine in 32-bit mode. If you are concerned or unsure, just set WINEARCH="win32" in your environment before beginning.

Run wine at least once to generate a wine prefix.

Run winetricks -q dotnet20 to install .NET Framework 2.0, required by the keyboard layout creator tools.

Download and install the following dependencies into your wine prefix:

Now when you generate the release version of the win target, an installer will be generated that is fully compatible with Windows systems.

5.5.2. Limitations

  • Windows does not support Unicode glyphbombs ("grapheme clusters") in deadkeys, but does support them as ordinary keys.

  • Using iso-caps and iso-caps+shift with Windows is limited to single codepoints, as the glyphbomb limitation also applies here.

  • Windows keyboard identifiers must be unique, are 8 characters long and begin with kbd. The next 5 characters are generated from the next 5 alphanumeric characters of the keyboard’s internalName. For example, if the internalName of a keyboard is se-1-foo, the internal keyboard name for Windows will be kbdse1fo.

  • If a keyboard is generated with erroneous data, MSKLC does not provide any useful error information and merely complains that there was an error and the file cannot be opened. Please report these files as bugs on GitHub for investigation.

5.5.3. Mappings between modes in layout files and Windows keyboards

Mappings from kbdgen modes to Windows keyboards
iso-default

Base keyboard

iso-shift

Shift pressed

iso-alt

AltGr (or Ctrl+Alt if keyboard missing AltGr) pressed

iso-alt+shift

AltGr plus shift

iso-caps+alt

AltGr plus caps lock

iso-ctrl

Ctrl pressed (mostly will not work due to OS-level key combinations overriding this layer)

Special cased mappings
iso-caps

Caps lock enabled

iso-caps+shift

Caps lock and shift pressed

If both of the above modes are found, the limitation regarding single codepoints described in the Limitations section applies.

Any other modes are ignored by this target.

5.6. X11

The X11 output should be considered experimental. It requires modifying global X11 files, and might eat your cat.

The x11 target outputs an X11-compatible xkb file. It has no special configuration and outputs the generated file to the x11/ directory.