Build keyboard firmware by declaring keymaps in Nickel, powered by Rust.
A 'smart keyboard' is a keyboard with additional bells and whistles, such as alternate key functionality (layers, tap-hold keys, chords, etc.), or RGB effects, etc. -- e.g. QMK, ZMK are popular smart keyboard firmware frameworks.
This project provides a library which handles the keymap behaviour part of this.
-
Nickel allows for concise expression of keymaps, as semicolon's fak showed. (e.g. simple example keymap, a more sophisticated example keymap). Nickel is a configuration language along the lines of "JSON + functions"; its emphasis on correctness and modular configurations make it a powerful configuration language.
-
This project supports the cheap and powerful CH32X035, a 32-bit RISC-V MCU. -- In the same way that semicolon's fak enabled low-budget keyboard designs with the CH552, this project enables keyboard designs using CH32X035.
-
The smart keymap library can be built as a static native library, which makes it easy to integrate into USB HID keyboard examples written in C.
-
As Rust crate, the project also supports using Rust to write keyboard firmware, similar to what keyberon supports.
-
This project also draws inspiration from ideas explored in semickolon's kirei, which emphasised "keys as the main abstraction of keymap behaviour".
The main idea is write a keymap in Nickel (keymap.ncl
),
and build keyboard firmware which uses smart-keymap
with this custom keymap.
See the RP2040 firmware example below
Documentation for features which have been implemented can be found at: https://rgoulter.com/smart-keymap/features.html
Some sample ncl keymaps can be found under tests/ncl/. In particular:
- 48-key basic keymap,
- 36-key rgoulter keymap.
- used as a 48-key keymap.
Published documentation for the Rust crate can be found at https://rgoulter.com/smart-keymap/doc/smart_keymap/index.html.
Some keyboard firmware which uses smart-keymap
:
The firmware under rp2040-rtic-smart-keyboard
has been adapted from the rgoulter/keyboard-labs firmware/keyberon code.
In particular, the firmware under rp2040-rtic-smart-keyboard
has an example for the
Pico42.
DevEnv is used to provide the toolchain dependencies.
Use devenv shell
to enter a shell which has all the tooling installed.
A DevContainer is defined for the project, which can be used to easily get started using e.g. VSCode, GitHub Codespaces, etc..
Using a keymap.ncl
(or the keymap.rs
generated from its definition),
the keyboard firmware can be built with a command such as:
env SMART_KEYMAP_CUSTOM_KEYMAP="$(pwd)/tests/ncl/keymap-42key-dvorak-simple-with-tap_hold/keymap.ncl" \
cargo build \
--release \
--target=thumbv6m-none-eabi \
--package=rp2040-rtic-smart-keyboard
The firmware can be deployed to an RP2040 board (in bootloader mode)
by using cargo run
instead of cargo build
.
The pico42
example can be built / run by adding --example pico42
.
A custom board.ncl
file can be built by setting the SMART_KEYBOARD_CUSTOM_BOARD
variable to its path, and building the rp2040-rtic-smart-keyboard
package's binary.
e.g. with 42key-dvorak/keymap.ncl,
let K = import "keys.ncl" in
# Define tap_hold keys
# by merging a `K.hold` modifier
# with a key.
let A_A = K.A & K.hold K.LeftAlt in
let G_O = K.O & K.hold K.LeftGUI in
let C_E = K.E & K.hold K.LeftCtrl in
let S_U = K.U & K.hold K.LeftShift in
let S_H = K.H & K.hold K.RightShift in
let C_T = K.T & K.hold K.RightCtrl in
let G_N = K.N & K.hold K.RightGUI in
let A_S = K.S & K.hold K.RightAlt in
{
keys = [
K.Quote, K.Comma, K.Dot, K.P, K.Y, K.F, K.G, K.C, K.R, K.L,
A_A, G_O, C_E, S_U, K.I, K.D, S_H, C_T, G_N, A_S,
K.Semicolon, K.Q, K.J, K.K, K.X, K.B, K.M, K.W, K.V, K.Z,
K.LeftCtrl, K.LeftGUI, K.LeftAlt, K.Tab, K.Escape, K.Space, K.Backspace, K.Return, K.Delete, K.RightAlt, K.RightGUI, K.RightCtrl,
],
}
and board-pico42.ncl (for the Pico42).
{
gpio_pins,
usb
= {
vid = 0xCAFE,
pid = 0x0005,
manufacturer = "rgoulter keyboard-labs",
product = "Pico42"
},
matrix
=
let p = gpio_pins in
{
cols = [p.GP0, p.GP1, p.GP2, p.GP3, p.GP4, p.GP5, p.GP6, p.GP7, p.GP8, p.GP9, p.GP10, p.GP11],
rows = [p.GP14, p.GP15, p.GP16, p.GP17],
key_count = 42,
},
keymap_index_for_key = fun { column_index, row_index } =>
let NO = null in
let keymap_indices = [
[ 0, 1, 2, 3, 4, NO, NO, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, NO, NO, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, NO, NO, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41],
]
in
let row = std.array.at row_index keymap_indices in
std.array.at column_index row |> match {
idx if idx != null => 'Key idx,
_ => 'NoKey,
},
}
the keyboard firmware can be built & flashed to the RP2040 bootloader with:
env \
SMART_KEYMAP_CUSTOM_KEYMAP="$(pwd)/tests/ncl/keymap-42key-dvorak-simple-with-tap_hold/keymap.ncl" \
SMART_KEYBOARD_CUSTOM_BOARD="$(pwd)/rp2040-rtic-smart-keyboard/examples/board-pico42.ncl" \
cargo run \
--release \
--target=thumbv6m-none-eabi \
--package=rp2040-rtic-smart-keyboard
The example USB HID keyboard software from the EVT has been adapted to work with smart_keymap lib.
See firmware/ch32x035-usb-device-compositekm-c for more details.