Get Compose keys working with proper shifting
This commit is contained in:
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user