Input Device
RMK's input device system provides a unified interface for hardware components that generate input events.
Input devices are hardware components that provide input to the keyboard firmware, such as key matrix, rotary encoders, joysticks, pointing devices, ADC sensors, and more.
Overview
Input devices read from hardware peripherals and publish events. These events are then consumed by Processors or the keyboard core. For details about events, see the Event documentation.
InputDevice Trait
The InputDevice trait defines the interface for input devices:
You don't need to implement this trait manually. Use the #[input_device] macro to generate the implementation automatically.
Defining Input Devices
Use the #[input_device] macro on a struct to define an input device:
Parameters:
publish = EventType(required): The event type this device publishes.
How it works:
#[input_device]implements bothInputDeviceandRunnabletraits automatically.- You only need to implement a
read_<event_name>_event()method that returns the event. The macro will automatically publish the returned event to the corresponding event channel. - The method name is derived from the event type name by converting it to snake_case and stripping the
Eventsuffix:publish = BatteryAdcEvent→async fn read_battery_adc_event(&mut self) -> BatteryAdcEventpublish = KeyboardEvent→async fn read_keyboard_event(&mut self) -> KeyboardEvent
Single-event Device Example
A device that reads charging state from a GPIO pin:
Multi-event Device Example
A device that produces multiple event types using a wrapper enum (see Multi-event Enums):
Running Input Devices
All input devices implement the Runnable trait. Use the run_all! macro to run all runnables — input devices, processors, and the rest of the firmware (keyboard, storage, transports) — concurrently:
See examples/use_rust/nrf52840_ble for a complete main.rs using these devices.
Configuration
RMK provides keyboard.toml configuration support for some built-in input devices (such as rotary encoders, joysticks, PMW3610 and PMW3360/PMW3389 sensors, and IQS5xx trackpads), so you can use them without writing any Rust code. See the Input Device Configuration documentation for details.
Combining with Processor
#[input_device] can be combined with #[processor] on the same struct. This allows a single struct to both produce events and subscribe to other events:
When combining input device and processor, be careful not to create event loops:
- Direct loop: Subscribing to an event you publish yourself (RMK rejects this case at compile time)
- Indirect loop: Device A subscribes to X and publishes Y, Device B subscribes to Y and publishes X — this forms a cycle
- Longer chains: A→B→C→A loops are also possible (A publishes B, B publishes C, C publishes A)
Event loops cause infinite cycles and hang your firmware.