Get Compose keys working with proper shifting

This commit is contained in:
2024-06-23 14:43:19 +02:00
parent 5a38ef7f78
commit a066b3c5dc
4 changed files with 109 additions and 52 deletions

View File

@ -40,14 +40,14 @@ pub enum Button {
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, MsgPack, MsgUnpack, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, MsgPack, MsgUnpack,
)] )]
pub enum CompShift { pub enum CompShift {
/// Do not shift the key. /// Do not shift the key. [Key::A] becomes 'a'.
#[default] #[default]
Lower, Lower,
/// Shift the key. /// Shift the key. [Key::A] becomes 'A'.
Upper, Upper,
/// Shift the key if shift is being held down. /// Shift the key if shift is being held down. [Key::A] becomes 'a' or 'A' depending.
Variable, Variable,
} }

View File

@ -1,7 +1,7 @@
use core::future::pending; use core::future::pending;
use crate::{ use crate::{
button::Button, button::{Button, CompShift, Modifier},
event::{button, switch, Half}, event::{button, switch, Half},
keys::Key, keys::Key,
}; };
@ -28,6 +28,7 @@ pub async fn keypress_handler(
output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>, output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>,
) -> ! { ) -> ! {
type SwitchIndex = usize; type SwitchIndex = usize;
#[derive(Debug)] #[derive(Debug)]
struct PressEvent { struct PressEvent {
source_button: SwitchIndex, source_button: SwitchIndex,
@ -36,51 +37,88 @@ pub async fn keypress_handler(
time: Instant, time: Instant,
} }
#[derive(Default)]
struct ShiftHeld {
left: bool,
right: bool,
}
impl ShiftHeld {
pub fn either(&self) -> bool {
self.left || self.right
}
}
async fn slow_press( async fn slow_press(
output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>, output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>,
shift_held: &mut ShiftHeld,
button: &Button, button: &Button,
) { ) {
let event = match button { let do_compose = |keys: &[(CompShift, Key)]| {
&Button::Mod(m) | &Button::ModTap(_, m) => button::Event::PressMod(m), for &(comp_shift, key) in keys {
&Button::Key(k) => button::Event::PressKey(k), match comp_shift {
&Button::Compose2(csa, a, csb, b) => { // Release any pressed shift keys
let events = [ CompShift::Lower => {
button::Event::PressKey(COMPOSE_KEY), if shift_held.left {
button::Event::ReleaseKey(COMPOSE_KEY), output.publish_immediate(button::Event::ReleaseMod(Modifier::LShift));
button::Event::Wait, }
button::Event::PressKey(a), if shift_held.right {
button::Event::ReleaseKey(a), output.publish_immediate(button::Event::ReleaseMod(Modifier::RShift));
button::Event::Wait, }
button::Event::PressKey(b), }
button::Event::ReleaseKey(b),
button::Event::Wait,
];
for event in events { // Press shift if not already pressed
output.publish_immediate(event); CompShift::Upper if !shift_held.either() => {
output.publish_immediate(button::Event::PressMod(Modifier::LShift));
}
_ => {}
}
output.publish_immediate(button::Event::PressKey(key));
output.publish_immediate(button::Event::ReleaseKey(key));
output.publish_immediate(button::Event::Wait);
match comp_shift {
// Re-press any shift keys we released
CompShift::Lower => {
if shift_held.left {
output.publish_immediate(button::Event::PressMod(Modifier::LShift));
}
if shift_held.right {
output.publish_immediate(button::Event::PressMod(Modifier::RShift));
}
}
// Release the shift keys we pressed
CompShift::Upper if !shift_held.either() => {
output.publish_immediate(button::Event::ReleaseMod(Modifier::LShift));
}
_ => {}
}
}
};
let event = match button {
&Button::Mod(m) | &Button::ModTap(_, m) => {
match m {
Modifier::LShift => shift_held.left = true,
Modifier::RShift => shift_held.right = true,
_ => {}
} }
button::Event::PressMod(m)
}
&Button::Key(k) => button::Event::PressKey(k),
&Button::Compose2(csa, a, csb, b) => {
do_compose(&[(CompShift::Variable, COMPOSE_KEY), (csa, a), (csb, b)]);
return; return;
} }
&Button::Compose3(csa, a, csb, b, csc, c) => { &Button::Compose3(csa, a, csb, b, csc, c) => {
let events = [ do_compose(&[
button::Event::PressKey(COMPOSE_KEY), (CompShift::Variable, COMPOSE_KEY),
button::Event::ReleaseKey(COMPOSE_KEY), (csa, a),
button::Event::Wait, (csb, b),
button::Event::PressKey(a), (csc, c),
button::Event::ReleaseKey(a), ]);
button::Event::Wait,
button::Event::PressKey(b),
button::Event::ReleaseKey(b),
button::Event::Wait,
button::Event::PressKey(c),
button::Event::ReleaseKey(c),
];
for event in events {
output.publish_immediate(event);
}
return; return;
} }
_ => return, _ => return,
@ -90,10 +128,19 @@ pub async fn keypress_handler(
async fn slow_release( async fn slow_release(
output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>, output: &mut Pub<'_, impl PubSubBehavior<button::Event>, button::Event>,
shift_held: &mut ShiftHeld,
button: &Button, button: &Button,
) { ) {
let event = match button { let event = match button {
&Button::Mod(m) | &Button::ModTap(_, m) => button::Event::ReleaseMod(m), &Button::Mod(m) | &Button::ModTap(_, m) => {
match m {
Modifier::LShift => shift_held.left = false,
Modifier::RShift => shift_held.right = false,
_ => {}
}
button::Event::ReleaseMod(m)
}
&Button::Key(k) => button::Event::ReleaseKey(k), &Button::Key(k) => button::Event::ReleaseKey(k),
_ => return, _ => return,
}; };
@ -104,6 +151,10 @@ pub async fn keypress_handler(
let mut queue = Deque::<PressEvent, { 2 * SWITCH_COUNT }>::new(); let mut queue = Deque::<PressEvent, { 2 * SWITCH_COUNT }>::new();
let queue = &mut queue; let queue = &mut queue;
// tracks whether a shift-key is being held down.
// required to properly play compose macros.
let mut shift_held = ShiftHeld::default();
loop { loop {
// create a future that waits for the next ModTap to time out // create a future that waits for the next ModTap to time out
let modtap_timeout = async { let modtap_timeout = async {
@ -134,7 +185,7 @@ pub async fn keypress_handler(
continue; continue;
}; };
debug!("modtap resolved as mod: {:?}", event.button); debug!("modtap resolved as mod: {:?}", event.button);
slow_press(output, &event.button).await; slow_press(output, &mut shift_held, &event.button).await;
loop { loop {
let Some(event) = queue.pop_front() else { break }; let Some(event) = queue.pop_front() else { break };
@ -145,7 +196,7 @@ pub async fn keypress_handler(
queue.push_front(event).expect("we just popped, the queue can't be full"); queue.push_front(event).expect("we just popped, the queue can't be full");
break; break;
} }
slow_press(output, &event.button).await; slow_press(output, &mut shift_held, &event.button).await;
} }
continue; continue;
@ -194,7 +245,7 @@ pub async fn keypress_handler(
if queue.is_empty() { if queue.is_empty() {
debug!("sending key now"); debug!("sending key now");
// otherwise, send immediately // otherwise, send immediately
slow_press(output, &button).await; slow_press(output, &mut shift_held, &button).await;
} else { } else {
debug!("adding key to queue"); debug!("adding key to queue");
// if events in queue, also add to queue // if events in queue, also add to queue
@ -222,16 +273,16 @@ pub async fn keypress_handler(
for _ in 0..position_in_queue { for _ in 0..position_in_queue {
let prev_event = queue.pop_front().unwrap(); let prev_event = queue.pop_front().unwrap();
debug!("pressing earlier event {:?}", prev_event); debug!("pressing earlier event {:?}", prev_event);
slow_press(output, &prev_event.button).await; slow_press(output, &mut shift_held, &prev_event.button).await;
} }
let _ = queue.pop_front(); let _ = queue.pop_front();
debug!("pressing modtap as key"); debug!("pressing modtap as key");
slow_press(output, &Button::Key(k)).await; slow_press(output, &mut shift_held, &Button::Key(k)).await;
slow_release(output, &Button::Key(k)).await; slow_release(output, &mut shift_held, &Button::Key(k)).await;
} else { } else {
// If the ModTap wasn't in the queue, it has already been resolved as a Mod. // If the ModTap wasn't in the queue, it has already been resolved as a Mod.
debug!("modtap wasn't in queue, releasing"); debug!("modtap wasn't in queue, releasing");
slow_release(output, &button).await; slow_release(output, &mut shift_held, &button).await;
}; };
} }
Button::Mod(..) Button::Mod(..)
@ -247,11 +298,11 @@ pub async fn keypress_handler(
for _ in 0..=position_in_queue { for _ in 0..=position_in_queue {
let prev_event = queue.pop_front().unwrap(); let prev_event = queue.pop_front().unwrap();
debug!("pressing {prev_event:?}"); debug!("pressing {prev_event:?}");
slow_press(output, &prev_event.button).await; slow_press(output, &mut shift_held, &prev_event.button).await;
} }
} }
debug!("releasing key {button:?}"); debug!("releasing key {button:?}");
slow_release(output, &button).await; slow_release(output, &mut shift_held, &button).await;
} }
_ => {} _ => {}
} }

View File

@ -116,9 +116,14 @@ impl RequestHandler for Handler {
} }
type HidStream = HidReaderWriter<'static, Driver<'static, USB>, 256, 256>; type HidStream = HidReaderWriter<'static, Driver<'static, USB>, 256, 256>;
/// Capacity of the [button::Event] buffer in [event_listener_task]. A too small capacity may cause
/// events to be dropped.
pub const BUTTON_EVENT_BUF_LEN: usize = 32;
#[embassy_executor::task] #[embassy_executor::task]
async fn event_listener_task(mut events: KbEvents, ctx: &'static Context) -> ! { async fn event_listener_task(mut events: KbEvents, ctx: &'static Context) -> ! {
let button_events = PubSubChannel::<NoopRawMutex, button::Event, 10, 1, 1>::new(); let button_events =
PubSubChannel::<NoopRawMutex, button::Event, BUTTON_EVENT_BUF_LEN, 1, 1>::new();
let mut button_pub = button_events.publisher().unwrap(); let mut button_pub = button_events.publisher().unwrap();
let mut button_sub = button_events.subscriber().unwrap(); let mut button_sub = button_events.subscriber().unwrap();
@ -128,6 +133,7 @@ async fn event_listener_task(mut events: KbEvents, ctx: &'static Context) -> ! {
) )
.await; .await;
// match hack because rust isn't smart enough.
match r { match r {
Either::First(never) | Either::Second(never) => match never {}, Either::First(never) | Either::Second(never) => match never {},
} }

View File

@ -39,7 +39,7 @@
Key(D0), Key(D0),
// Row 2 // Row 2
Compose2(Lower, Apostrophe, Variable, A), // ä Compose2(Upper, Apostrophe, Variable, A), // ä
ModTap(D4, RCtrl), ModTap(D4, RCtrl),
ModTap(D5, RShift), ModTap(D5, RShift),
ModTap(D6, RMod), ModTap(D6, RMod),
@ -47,7 +47,7 @@
Mod(RAlt), Mod(RAlt),
// Row 3 // Row 3
Compose2(Lower, Apostrophe, Variable, O), // ö Compose2(Upper, Apostrophe, Variable, O), // ö
Key(D1), Key(D1),
Key(D2), Key(D2),
Key(D3), Key(D3),