MCPcopy Index your code
hub / github.com/TyberiusPrime/KeyToKey

github.com/TyberiusPrime/KeyToKey @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
213 symbols 929 edges 20 files 48 documented · 23%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

KeyToKey

KeyToKey (K2K) is a Rust libary for building keyboard firmwares.

Basically, a keyboard firmware a) reads key-presses, b) translates them c) and outputs the results to a computer.

KeyToKey's role is in b - it takes a stream of events, such as key presses, releases and timeouts, and translates them using a series of handler trait objects into reports that can easily be converted to the format USB expects.

This is inspired by the QMK mechanical keyboard firmware, which probably is the most feature complete keyboard firmware to date. Alas it's C, and an amazing ball of ifdefs that usually needs more flash than the micros it's targeting offer.

The trait object oriented approach chosen here allows composition of arbitrarily complex keyboard layouts - and unit testing them without hardware.

To get started, maybe check out the reference firmware.

KeyToKey operates on key codes that are u32 representing unicode key points. (The USB keycodes are nested in the first 'private area' of the unicode code set, and the rest of the private area is free to be used by the keyboard implementor.)

A basic keyboard uses two handlers - a handlers::UnicodeKeyboard, which sends the OS-specific magic 'enter-an-arbitrary-unicode-keypoint' for any key code outside of the private areas, and a handlers::USBKeyboard which handles all the usual 'tell the computer which buttons are pressed' functionality including modifiers.

USBKeyboard does not limit the number of simultanious keys, but the downstream translation into USB might restrict to the usual 6 key rollover.

Basic features * works as a regular USB keyboard * arbirtrary unicode input in linux and windows

Advanced Features working * Layers (which can rewrite key codes, conditionally rewrite them based on shift status or send arbitrary strings, again dependeant on shift) * RewriteLayers (which can only rewrite key codes, but are much more memory efficient) * PressReleaseMacros (callbacks on key press / key release) * StickyMacros (Tap once to activate, again to deactivate){ * OneShots (Press -> activate, deactivates after next any-not-one-shot key press - useful for modifiers or temporarily activated layers) * SpaceCadet (Do one thing on press-and-hold, a different thing on tap. For example a shift key that also outputs a '(')) * Sequences (e.g. t e h -> the which don't intercept the keycodes, but then send a set of backspace presses, and then your action)

Advanced features planned * Leader sequences (e.g. hit leader h e a r t to enter a heart emoji, or an arbitrary string) * TapDance (count the number of taps on a key, pass the final count to a callback) * AutoShift - Short tap: lower case, longer tap: uppercase. Removes key repeat though. * send keys later (e.g. for a macro that sends a key after a delay)

K2K strives to seperate the triggers (when does something happen) from the actual actions. Currently actions may be arbitrary (USB) KeyCodes being registered, &str being send or callbacks (implemented via traits)

Other rust firmwares / keyboard libraries

  • https://gitlab.com/polymer-kb/firmware/polymer

Extension points exported contracts — how you extend this code

AcceptsKeycode (Interface)
Trait for things that can be converted to a u32 keycode ie. various integers and (usb) KeyCodes themselves [6 implementers]
src/key_codes.rs
ProcessKeys (Interface)
Handlers are defined by this trait they process the events, set their status to either Handled or Ignored (if more data [18 …
src/handlers/mod.rs
USBKeyOut (Interface)
the handlers use this trait to generate their output [1 implementers]
src/lib.rs
Checks (Interface)
(no doc) [1 implementers]
src/test_helpers.rs
KeyCodeInfo (Interface)
(no doc) [1 implementers]
src/key_codes.rs
Action (Interface)
A callback used when one single action is needed examples: Leader invocations. Notably implemented on &str, so you can [9 …
src/handlers/mod.rs
OnOff (Interface)
A trait for callbacks when an on/off action is needed Used by PressReleaseMacros, StickyMacros, OneShots see PressRele [6 …
src/handlers/mod.rs
NonLayerAction (Interface)
an Action For example by a leader sequence or a tap dance. Contrast with LayerAction which is a superset of Action Not [1 …
src/handlers/mod.rs

Core symbols most depended-on inside this repo

handle_keys
called by 191
src/lib.rs
to_u32
called by 127
src/key_codes.rs
add_handler
called by 117
src/lib.rs
add_keypress
called by 104
src/lib.rs
add_keyrelease
called by 89
src/lib.rs
enable_handler
called by 29
src/lib.rs
set_modifier
called by 21
src/lib.rs
iter_unhandled_mut
called by 16
src/key_stream.rs

Shape

Method 90
Function 70
Class 32
Enum 12
Interface 9

Languages

Rust100%

Modules by API surface

src/lib.rs30 symbols
src/premade.rs29 symbols
src/test_helpers.rs26 symbols
src/handlers/layer.rs16 symbols
src/key_codes.rs12 symbols
src/handlers/usbkeyboard.rs10 symbols
src/handlers/sequence.rs9 symbols
src/handlers/oneshot.rs9 symbols
src/handlers/unicodekeyboard.rs8 symbols
src/handlers/tapdance.rs8 symbols
src/handlers/spacecadet.rs8 symbols
src/handlers/rewrite_layer.rs8 symbols

For agents

$ claude mcp add KeyToKey \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact