The basic concept of the design of this keymap is:
- to put the most often used keys under the strongest fingers
- to use only a few number of layers
- to be as free as possible and not stick to any conventions
The layers of this keymap are the following:
- Base layer (Colemak-PST which is Colemak-DH with some personal key swaps)
- "Down" layer which handles the digit keys and the rest of the symbols
- Function layer which takes care of F1 through F12
- Lights layer handling the cool underglow LEDs
Throughout the implementation of the keymap we assume that the attached PC has the German keyboard layout defined.
Umlauts can be found by double-tapping the 'normal' keys a, o, and u, respectively. The € sign is under the e.
The ß is created by double-tapping v. I decided not to put it under the s key in order to still be able to tap ss in a fast manner.
Most of the symbols are either directly reachable (like @, &, /, or . and ,) or only need either Shift (like | or ~) or Down (like ', ", or the opening brackets) in order to be reached. Only a few symbols are left that need both Shift and Down but these are almost only the closing brackets which in turn show some symmetry to the opening brackets.
There are no "dead" symbols anymore: ^, ´, and ` are implemented to be automatically tapped twice if the user taps them once in order to directly show them. In turn, no 'é' and other characters that rely on these symbols are possible to be typed anymore.
The combination of symbols (normal, "shifted", and "downed" typing) often does not follow any standard. Instead it is based on what I find useful for an efficient typing.
Implementing this was quite a pain: You have to know and take into account the original combination of normal, "shifted", and "altgr"ed typing. If you e.g. want a key to be available directly when the key is pressed but originally this symbol is reachable via Shift, then you have to register (= press down) Shift first, register the "partner" key (= the key that is necessary to be pressed in order to get the actually wanted symbol to appear in combination with Shift), and then unregister (= release) Shift again. The same is true for symbols that are reachable via AltGr.
All of this led to an implementation of various macros that handle the different cases of "normal", "shifted", and "altgr"ed typing. (To be found in shift-handling.h
.)
The digits 1, 2, 3, etc. go from right to left because that felt better for me.
The function keys are reachable via the same keys as the digits, e.g. F1 is on the same key as 1. Only the Fn key needs to be previously held or tapped.
Due to the fact that I use some key combinations very often, I paid special attention to their location:
- Ctrl-x, Ctrl-c, and Ctrl-v lie directly next to each other, and the Ctrl key is also on the left hand keymap in order to be able to access the key combination with only one hand.
- Ctrl-Shift-something is easily reachable by tapping and holding the right Ctrl key twice. (Implemented as tap dance.)
- Similarly, Ctrl-Alt-something is easily reachable by tapping and holding the right Ctrl key three times. (Implemented as tap dance.)
- Alt and Tab are very close to each other in order to switch the application windows fast.
- Right Ctrl is available to get out of the Linux virtual machine easily.
- Alt-some digit to directly select a browser tab or a file in VSCode can be reached via double-tapping and holding the Down key and typing the respective digit key. (Implemented as tap dance.)
- etc.
The left rotary knob is defined to control the volume.
Using it together with the Down key the brightness is controlled.
The right encoder sends PgUp or PgDn on every turn.
In combination with the Down key the encoder jumps to the next and the previous tab (e.g. in a browser, a terminal, or in VSCode).
The leader key in the bottom right corner of the keyboard can be used for a lot of fancy key combinations. Currently, some short messages for the closing greeting at the end of emails are defined for Lead-M-some digit where some digit is of course again just the respective key like T for 1, S for 2, etc. So no holding of the Down key is necessary. Also the Lead key is tapped, not held.
To be implemented: The OLEDs display the current layer at the top of the active layers stack, the Kyria logo, and the lock status (caps lock, num lock, scroll lock).
The source code is structured in a way that the handling of special functions can be found in different source files:
keymap.c
: The main file that includes the other.h
files and contains the definition of the keymap layers. It also defines theprocess_record_user()
function which handles the press and release events for each key and the global functionmatrix_scan_user()
but only as the hull to call the respective functions of the sub areas.leader-key.c
: Handling of the 'leader key'.oled.c
: Definition of messages on the displays (not yet implemented).rotary-encoder.c
: Everything that has to do with the rotary knob.shift-handling.h
: Definition of various C macros that take care of the redefinition of keys for "normal" and "shifted" pressing.tapdance.c
: Handling the "tap dance", i.e. multiply typing and holding keys and getting different results from that.
In order for the .c
files to be linked into the resulting firmware, they need
to be mentioned in rules.mk
in the way SRC += tapdance.c
.
Memory is a costly good, so optimization during the compilation and the linking is highly recommended. Is is helpful to set the right definitions in the file rules.mk
. These determine which modules are finally included in the resulting firmware.
There is a small script ./bin/build-firmware.sh
available to build the firmware and copy the resulting .hex
file into the bin
directory. This way also the latest version of the firmware is stored in the Git repo. You can simply call the script from anywhere.
I use VSCode in combination with clang (version 12) to write and format the C code. The clang settings are as follows:
{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 2, TabWidth: 2, BreakBeforeBraces: Attach, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 120, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false, AlignConsecutiveMacros: AcrossEmptyLines }
We use the long keycode names (like KC_ENTER and KC_LSHIFT) whenever we can. Only in the matrix definition of the keymap we use the short names (like KC_ENT and KC_LSFT) because they fit better into the keyboard optics.
I used and still use the keyboard layout editor for painting the keyboard layout (see the image at the top of this page). This web-based application has various flaws:
- It is not updated anymore.
- Thus, it does not use TLS (
http
instead ofhttps
)! - It is buggy when it comes to saving the results.
The definition of the layout is done in a JSON
file which can be saved (downloaded) and (up)loaded. Unfortunately, the storage of the keymap is buggy. Therefore I need to handle two variants of the keymap. These two - and the resulting image - can be found in the resources
directory.