You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- If the input devices emit only `KeyEvent`, use only `run_device!((matrix, dev) => EVENT_CHANNEL))` is enough, no `run_processor_chain` is needed. Because all `KeyEvent`s are automatically processed by `keyboard.run()`
36
+
-`EVENT_CHANNEL` are built-in, you can also use your own local channels
37
+
- The events are processed in a chained way, until the processor's `process()` returns `ProcessResult::Stop`. So the order of processors in the `run_processor_chain` matters
38
+
- For advanced use cases, developers can define custom events and procesors to fully control the input logic
39
+
- The keyboard is special -- it receives events only from `KEY_EVENT_CHANNEL` and processes `KeyEvent`s only. `KeyEvent` from ALL devices are handled by the `Keyboard` processor, then the other events are dispatched to binded processors
40
+
41
+
## Implementation new devices
42
+
RMK's input device framework is designed to provide a simple yet extensible way to handle both keys and sensors. Below is an overview of the framework:
To implement a new input device in RMK, you need to:
47
+
48
+
1. Create a struct for your device that implements the `InputDevice` trait
49
+
2. Define how it generates events by implementing the `read_event()` method
50
+
3. Use it with `run_devices!` to integrate into RMK's event system
51
+
52
+
## Input device trait
53
+
54
+
Input devices such as key matrices or sensors read physical devices and generate events. All input devices in RMK should implement the `InputDevice` trait:
55
+
56
+
```rust
57
+
pubtraitInputDevice {
58
+
/// Read the raw input event
59
+
asyncfnread_event(&mutself) ->Event;
60
+
}
61
+
```
62
+
63
+
This trait is used with the `run_devices!` macro to collect events from multiple input devices and send them to a specified channel:
64
+
65
+
```rust
66
+
// Send events from matrix to EVENT_CHANNEL
67
+
run_devices! (
68
+
(matrix) =>EVENT_CHANNEL,
69
+
)
70
+
```
71
+
72
+
> Why `run_devices!`?
73
+
>
74
+
> Currently, embassy-rs does not support generic tasks. The only option is to join all tasks together to handle multiple input devices concurrently. The `run_devices!` macro helps accomplish this efficiently.
75
+
76
+
## Runnable trait
77
+
78
+
For components that need to run continuously in a task, RMK provides the `Runnable` trait:
79
+
80
+
```rust
81
+
pubtraitRunnable {
82
+
asyncfnrun(&mutself);
83
+
}
84
+
```
12
85
13
-
- Keyboard itself
14
-
- Rotary encoder
15
-
- Touchpad
16
-
- Trackball
17
-
- Joystick
86
+
The `Keyboard` type implements this trait to process events and generate reports.
18
87
19
-
Except keyboard and rotary encoder, the others protocol/implementation depend on the actual device. A driver like interface is what we need.
88
+
89
+
## Event Types
90
+
91
+
RMK provides a default `Event` enum that is compatible with built-in `InputProcessor`s:
92
+
93
+
```rust
94
+
#[non_exhaustive]
95
+
#[derive(Serialize, Deserialize, Clone, Debug)]
96
+
pubenumEvent {
97
+
/// Keyboard event
98
+
Key(KeyEvent),
99
+
/// Rotary encoder, ec11 compatible models
100
+
RotaryEncoder(RotaryEncoderEvent),
101
+
/// Multi-touch touchpad
102
+
Touchpad(TouchpadEvent),
103
+
/// Joystick, suppose we have x,y,z axes for this joystick
104
+
Joystick([AxisEvent; 3]),
105
+
/// An AxisEvent in a stream of events. The receiver should keep receiving events until it receives [`Eos`] event.
106
+
AxisEventStream(AxisEvent),
107
+
/// End of the event sequence
108
+
///
109
+
/// This is used with [`AxisEventStream`] to indicate the end of the event sequence.
110
+
Eos,
111
+
}
112
+
```
113
+
114
+
The `Event` enum aims to cover raw outputs from common input devices. It also provides a stream-like axis event representation via `AxisEventStream` for devices with a variable number of axes. When using `AxisEventStream`, the `Eos` event must be sent to indicate the end of the sequence.
115
+
116
+
## Input Processor Trait
117
+
118
+
Input processors receive events from input devices, process them, and convert the results into HID reports for USB/BLE transmission. All input processors must implement the `InputProcessor` trait:
119
+
120
+
```rust
121
+
pubtraitInputProcessor {
122
+
/// Process the incoming events, convert them to HID report [`Report`],
123
+
/// then send the report to the USB/BLE.
124
+
///
125
+
/// Note there might be multiple HID reports are generated for one event,
126
+
/// so the "sending report" operation should be done in the `process` method.
127
+
/// The input processor implementor should be aware of this.
128
+
asyncfnprocess(&mutself, event:Event);
129
+
130
+
/// Send the processed report.
131
+
asyncfnsend_report(&self, report:Report) {
132
+
KEYBOARD_REPORT_CHANNEL.send(report).await;
133
+
}
134
+
}
135
+
```
136
+
137
+
The `process` method is responsible for processing input events and sending HID reports through the report channel. All processors share a common keymap state through `&'a RefCell<KeyMap<'a, ROW, COL, NUM_LAYER>>`.
20
138
21
139
### Rotary encoder
22
140
141
+
TODO:
23
142
The encoder list is represented separately in vial, different from normal matrix. But layers still have effect on encoder. The behavior of rotary encoder could be changed by vial.
24
143
25
144
# Input Devices
@@ -30,29 +149,33 @@ RMK supports various input devices beyond just key matrices. The input system co
30
149
31
150
Each input device must implement the `InputDevice` trait, which requires:
32
151
33
-
- An associated `EventType` that defines what kind of events this device generates
34
-
- A `run()` method containing the device's main logic
35
-
- A `send_event()` method to send events to processors
152
+
- A `read_event()` method to read raw input events
0 commit comments