ANY contributions are welcome! Here is a simple step-by-step guide for developers:
Before you start, you may want to read the [Under the Hood] section to understand how RMK works. GitHub Issues is also a good place for questions.
Check out the active PRs to make sure that what you want to add isn't already being implemented by others.
Write your code!
Open a PR to merge your code into the main repo. Make sure all CIs pass.
If you're not familiar with RMK, the following is a simple introduction to the source code of RMK.
There are four crates in the RMK project: rmk, rmk-config, rmk-types and rmk-macro.
rmk: The main crate that contains the core firmware logic, including matrix scanning, key processing, USB/BLE communication, and all the runtime services.rmk-macro: A proc-macro helper for RMK that reads the keyboard.toml config file, converts the TOML config to RMK config, and generates the boilerplate code.rmk-config: Contains the configuration data structures and parsing logic shared between rmk-macro and rmk, defining how keyboard configurations are represented in memory.rmk-types: Provides common type definitions used across all RMK crates, such as keyboard actions, key events, and other shared data structures.So, if you want to contribute new features to RMK, look into the rmk core crate. If you want to add support for a new chip, both rmk and rmk-macro should be updated so that users can use keyboard.toml to configure keyboards with your new chip. If you want to add new configurations, look into both rmk-macro/config and rmk/config.
The rmk crate is the main crate. It provides several entry APIs to start the keyboard firmware. All the entry APIs are similar; they:
Generally, there are 4-5 running tasks at the same time, depending on the user's config. Communication between tasks is done via channels. There are several built-in channels:
FLASH_CHANNEL: a multi-sender, single-receiver channel. Many tasks send FlashOperationMessage, such as the BLE task (which saves bond info) and the vial task (which saves keys), etc.KEY_EVENT_CHANNEL: a multi-sender, single-receiver channel. The sender can be a matrix task that scans the key matrix or a split peripheral manager that receives key events from split peripherals. The receiver, i.e., the keyboard task, receives the key event and processes the key.EVENT_CHANNEL: a multi-sender, single-receiver channel. It's used for all events from input devices except KeyboardEvent.KEYBOARD_REPORT_CHANNEL: a single-sender, single-receiver channel. The keyboard task sends keyboard reports to the channel after the key event is processed, and the USB/BLE task receives the keyboard report and sends the key to the host.An important part of keyboard firmware is how it performs matrix scanning and how it processes the scanning result to generate keys.
In RMK, this work is done by Matrix and Keyboard respectively. The Matrix scans the key matrix and sends a KeyboardEvent if there's a key change in the matrix. Then the Keyboard receives the KeyboardEvent and processes it into an actual keyboard report. Finally, the keyboard report is sent to the USB/BLE tasks and forwarded to the host via USB/BLE.