Tracking issue for input device support
RMK should support other input devices, like touchpad, encoder, joystick, etc.
roadmap:
- [x] #192
- [x] #229
- [x] #230
- [ ] #231
- [ ] #232
- [ ] #233
Related issue: #29 #69
Since the generic task limitation(https://github.com/embassy-rs/embassy/issues/2454), the only way for defining a generic input device task is to use macro. There are two options:
- Use a proc-macro like:
#[input_device]
struct RotaryEncoder {}
impl InputDevice for RotaryEncoder {...}
which could be expanded as:
struct RotaryEncoder {}
impl InputDevice for RotaryEncoder {...}
#[embassy_executor::task]
async fn rotaryencoder_task(device: RotaryEncoder) -> ! {
device.run().await
}
- Use a decl macro
struct RotaryEncoder {}
impl InputDevice for RotaryEncoder {...}
impl_input_device!(RotaryEncoder, task_name);
expanded code:
struct RotaryEncoder {}
impl InputDevice for RotaryEncoder {...}
#[embassy_executor::task]
async fn task_name(device: RotaryEncoder) -> ! {
device.run().await
}
- option 1: simple and easy to use, but it's hard to make the task name customizable; better diagnosis if users misuse it.
- option 2: the task name can be customized, but need calling
impl_input_devicefor each device; might be hard to debug if users misuse it
Now I'm going to option 2 first, Any ideas are welcome:)
Okay, after some testing I found neither work with generic tasks. So I have to give up embassy task. The only option seems to be join all input device's run together:
// Implement the input device for RotaryEncoder
struct RotaryEncoder {}
impl InputDevice for RotaryEncoder {...}
in user space:
let e1 = RotaryEncoder {};
let e2 = RotaryEncoder {};
join(run_rmk(), run_devices!(e1, e2)).await
I have an idea to make the input device/processor more flexible and avoid the unstable feature #[feature(generic_const_exprs)]
https://github.com/drindr/rmk/blob/3710603d4df71b5f27456617e48c41994b79effd/rmk/src/input_device/mod.rs#L103-L143
I have an idea to make the input device/processor more flexible and avoid the unstable feature
#[feature(generic_const_exprs)]https://github.com/drindr/rmk/blob/3710603d4df71b5f27456617e48c41994b79effd/rmk/src/input_device/mod.rs#L103-L143
The main difference is to use a trait for receiver/sender instead of channels, am I right?
BTW in #250 I also changed a little bit on input processors
I'm thinking about removing receiver/sender, adding something like DeviceBuilder to bind the input device and corresponding processors. In current implementation, all the input device and processors are linked separately by channels, it's not easy for end users to configure them
End with something like:
run_devices!{
(matrix, encoder, touchpad) => EVENT_CHANNEL
}
run_processor_chain! {
EVENT_CHANNEL => [touchpad_processor, encoder_processor]
}
The channel can be customized, but I'm not sure that should we make channel customized? or just use built-in channels for all devices
End with something like:
run_devices!{ (matrix, encoder, touchpad) => EVENT_CHANNEL }
run_processor_chain! { EVENT_CHANNEL => [touchpad_processor, encoder_processor] }
The channel can be customized, but I'm not sure that should we make channel customized? or just use built-in channels for all devices
I think it would be useful when a local processor is required, especially for split. For instance,
- the boot/bootloader switch on the peripheral should be processed on the itself. (a small keymap should be placed in the peripheral. Or just triggered by the master?)
- the peripheral changes the master. (I'm not sure if someone have such a requirement)
End with something like: run_devices!{ (matrix, encoder, touchpad) => EVENT_CHANNEL } run_processor_chain! { EVENT_CHANNEL => [touchpad_processor, encoder_processor] } The channel can be customized, but I'm not sure that should we make channel customized? or just use built-in channels for all devices
I think it would be useful when a local processor is required, especially for split. For instance,
- the boot/bootloader switch on the peripheral should be processed on the itself. (a small keymap should be placed in the peripheral. Or just triggered by the master?)
- the peripheral changes the master. (I'm not sure if someone have such a requirement)
It runs on the peripheral side, we could have it as a proxy/filter of peripheral events, before the peripheral sends events out. Luckily it has nothing conflict with current implementation:D