Processor
RMK's processor system provides a unified interface for components that consume events and react to them, such as displays, LEDs, and other output peripherals.
Overview
Processors subscribe to events and react accordingly. Events are published by Input Devices or other processors. For details about events, see the Event documentation.
Processors can operate in three modes:
- Event-driven - React to events as they arrive
- Polling - Perform periodic updates at specified intervals (in addition to handling events)
- Deadline - Fire a callback at a deadline the processor computes from its own state (in addition to handling events)
Defining Processors
Use the #[processor] macro to define custom processors:
Parameters:
subscribe = [Event1, Event2, ...](required): Event types to subscribe to (see Built-in Events)poll_interval = <ms>(optional): Enable polling with fixed interval, requirespoll()method
How it works:
#[processor]implementsProcessorandRunnabletraits automatically- Event handlers are automatically routed based on method naming:
on_<event_name>_event() - Method names follow snake_case conversion of event type names
Registering Processors
If you use the Rust API directly, no registration is needed — every processor implements Runnable, so just pass it to run_all! alongside your other tasks (see Input Device).
For keyboard.toml users, processors are registered in the #[rmk_keyboard] module using the #[register_processor] attribute:
Available registration modes:
#[register_processor(event)]: Event-driven mode, reacts to subscribed events#[register_processor(poll)]: Polling mode, requirespoll_intervalparameter in#[processor]macro
Multi-event Subscription
Processors can subscribe to multiple event types and handle them with separate methods:
Polling Processor
For processors that need periodic updates (e.g., display refresh, LED animations), use the poll_interval parameter:
Deadline Processor
For timeouts that move — a layer that deactivates some time after the last mouse motion, for example — a fixed poll_interval doesn't fit. Implement DeadlineProcessor instead: deadline() returns the next Instant to fire at, or None when nothing is armed, and on_deadline() runs when that instant passes without an event in between. deadline_loop() drives it, re-reading deadline() after every event.
The Runnable that #[processor] generates only runs the event loop, so mark the struct with #[::rmk::macros::runnable_generated] to suppress it and write Runnable yourself:
Example: LED Indicator Processor
A complete example of a processor that controls an LED based on keyboard indicators:
RMK ships this functionality as the built-in rmk::processor::builtin::led_indicator::KeyboardIndicatorProcessor, so you only need a custom processor like this for behavior the built-in doesn't cover.
Related Documentation
- Event - Event concepts, built-in events, and custom event definition
- Input Device - How to create input devices that publish events