diff --git a/firmware2/src/main.rs b/firmware2/src/main.rs index 72d7b17..a117add 100644 --- a/firmware2/src/main.rs +++ b/firmware2/src/main.rs @@ -20,6 +20,7 @@ use core::cell::RefCell; use core::slice; use alloc::boxed::Box; +use alloc::string::String; use alloc::vec; use cfg_if::cfg_if; use embassy_executor::Spawner; @@ -61,7 +62,7 @@ use slint::ComponentHandle; use slint::platform::software_renderer::Rgb565Pixel; use static_cell::StaticCell; use ui::AppWindow; -use xkbcommon::xkb::{self, KeyDirection, ModIndex}; +use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, Status}; use {esp_alloc as _, esp_backtrace as _}; use crate::matrix::IoeMatrix; @@ -461,74 +462,124 @@ async fn main(_spawner: Spawner) { let report = KEYBOARD_REPORT_PROXY.receive().await; if let Report::KeyboardReport(report) = &report { - warn!("MODIFIERS = {:02x}", report.modifier); - const RMK_ALT: u8 = 0xE2; - // TODO: Process modifiers + const KEYCODES_LEN_MODIFIERS: usize = 8; + const KEYCODES_LEN_REGULAR: usize = 6; + const KEYCODES_LEN: usize = KEYCODES_LEN_MODIFIERS + KEYCODES_LEN_REGULAR; - for (keycode_old, &keycode_new) in - core::iter::zip(&mut previous_state.keycodes, &report.keycodes) - { - fn into_xkb_keycode(rmk_keycode: u8) -> xkb::Keycode { - // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/hid/hid-input.c?id=refs/tags/v6.18#n27 - const UNK: u8 = 240; - #[rustfmt::skip] - const HID_KEYBOARD: [u8; 256] = [ - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, - 105, 108, 103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113, - 115, 114, UNK, UNK, UNK, 121, UNK, 89, 93, 124, 92, 94, 95, UNK, UNK, UNK, - 122, 123, 90, 91, 85, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 111, UNK, UNK, UNK, - UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, - UNK, UNK, UNK, UNK, UNK, UNK, 179, 180, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, - UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, - UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 111, UNK, UNK, UNK, UNK, UNK, UNK, UNK, - 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113, - 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140, UNK, UNK, UNK, UNK, - ]; - // https://cgit.freedesktop.org/xorg/driver/xf86-input-evdev/tree/src/evdev.c#n73 - const MIN_KEYCODE: u8 = 8; + let mut pressed_keys = rmk::heapless::Vec::::new(); + let mut released_keys = rmk::heapless::Vec::::new(); - // TODO: The combination of these two operations should be precomputed - // in a const expr into a single look-up table. - xkb::Keycode::new( - (HID_KEYBOARD[rmk_keycode as usize] + MIN_KEYCODE) as u32, - ) + let pressed_mods_bits = !previous_state.modifier & report.modifier; + let released_mods_bits = previous_state.modifier & !report.modifier; + + for index in 0..KEYCODES_LEN_MODIFIERS { + const USB_HID_LEFT_CTRL: u8 = 0xE0; + let mod_bit = 1_u8 << index; + let mod_keycode = USB_HID_LEFT_CTRL + index as u8; + + if pressed_mods_bits & mod_bit != 0 { + pressed_keys.push(mod_keycode).unwrap(); } - if *keycode_old == 0 && keycode_new == 0 { + if released_mods_bits & mod_bit != 0 { + released_keys.push(mod_keycode).unwrap(); + } + } + + // TODO: This currently depends on pressed keys not changing position in the array. + // Should be made independent of that. + for (&keycode_old, &keycode_new) in + core::iter::zip(&previous_state.keycodes, &report.keycodes) + { + if keycode_old == keycode_new { continue; } - if keycode_new == 0 || ((*keycode_old != 0) && *keycode_old != keycode_new) - { - warn!("Release: 0x{:02x} ({})", *keycode_old, *keycode_old); - state.update_key(into_xkb_keycode(*keycode_old), KeyDirection::Up); + if keycode_old != 0 { + released_keys.push(keycode_old).unwrap(); } - if *keycode_old == 0 || ((keycode_new != 0) && *keycode_old != keycode_new) - { - let keycode_new_xkb = into_xkb_keycode(keycode_new); - let syms = state.key_get_syms(keycode_new_xkb); + if keycode_new != 0 { + pressed_keys.push(keycode_new).unwrap(); + } + } - for sym in syms { - compose_state.feed(*sym); + previous_state = report.clone(); + + fn into_xkb_keycode(rmk_keycode: u8) -> xkb::Keycode { + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/hid/hid-input.c?id=refs/tags/v6.18#n27 + const UNK: u8 = 240; + #[rustfmt::skip] + const HID_KEYBOARD: [u8; 256] = [ + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, + 105, 108, 103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113, + 115, 114, UNK, UNK, UNK, 121, UNK, 89, 93, 124, 92, 94, 95, UNK, UNK, UNK, + 122, 123, 90, 91, 85, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 111, UNK, UNK, UNK, + UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, + UNK, UNK, UNK, UNK, UNK, UNK, 179, 180, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, + UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, + UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 111, UNK, UNK, UNK, UNK, UNK, UNK, UNK, + 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113, + 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140, UNK, UNK, UNK, UNK, + ]; + // https://cgit.freedesktop.org/xorg/driver/xf86-input-evdev/tree/src/evdev.c#n73 + const MIN_KEYCODE: u8 = 8; + + // TODO: The combination of these two operations should be precomputed + // in a const expr into a single look-up table. + xkb::Keycode::new((HID_KEYBOARD[rmk_keycode as usize] + MIN_KEYCODE) as u32) + } + + for keycode in released_keys { + warn!("Release: 0x{:02x} ({})", keycode, keycode); + state.update_key(into_xkb_keycode(keycode), KeyDirection::Up); + } + + for keycode in pressed_keys { + warn!("Pressed: 0x{:02x} ({})", keycode, keycode); + let keycode_xkb = into_xkb_keycode(keycode); + let sym = state.key_get_one_sym(keycode_xkb); + + let result: Option<(Keysym, Option)> = match compose_state.feed(sym) + { + FeedResult::Ignored => { + let string = state.key_get_utf8(keycode_xkb); + Some((sym, Some(string))) } + FeedResult::Accepted => { + let status = compose_state.status(); + warn!("Compose status: {status:?}"); + match status { + Status::Nothing => { + let string = state.key_get_utf8(keycode_xkb); + Some((sym, Some(string))) + } + Status::Composing => None, + Status::Composed => { + let sym = compose_state.keysym().unwrap_or_default(); + let string = compose_state.utf8().unwrap_or_default(); + Some((sym, Some(string))) + } + Status::Cancelled => None, + } + } + }; - let string = compose_state.utf8(); + if let Some((sym, string)) = result { + // Change `Some("")` into `None`. + let string = string.filter(|string| !string.is_empty()); - warn!("Pressed: 0x{:02x} ({})", keycode_new, keycode_new); - warn!("Syms: {syms:?}"); - warn!("String: {string:?}"); + warn!("Sym: {sym:?}"); + warn!("String: {:?}", string.as_ref()); - state.update_key(keycode_new_xkb, KeyDirection::Down); + state.update_key(keycode_xkb, KeyDirection::Down); } - - *keycode_old = keycode_new; } }