diff --git a/firmware2/src/main.rs b/firmware2/src/main.rs index f6ad207..05d8f5b 100644 --- a/firmware2/src/main.rs +++ b/firmware2/src/main.rs @@ -31,7 +31,7 @@ use embassy_executor::Spawner; use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex}; use embassy_sync::channel::Channel; use embassy_sync::signal::Signal; -use embassy_time::{Duration, Timer}; +use embassy_time::{Duration, Instant, Timer}; use esp_alloc::{HeapRegion, MemoryCapability}; use esp_hal::clock::CpuClock; use esp_hal::dma::{BurstConfig, DmaDescriptor, DmaTxBuf, ExternalBurstConfig}; @@ -56,6 +56,7 @@ use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub}; use rmk::config::{BehaviorConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig}; use rmk::controller::{Controller, EventController}; use rmk::debounce::default_debouncer::DefaultDebouncer; +use rmk::descriptor::KeyboardReport; use rmk::embassy_futures::yield_now; use rmk::event::{ControllerEvent, KeyboardEvent}; use rmk::hid::Report; @@ -70,6 +71,7 @@ use slint::platform::software_renderer::Rgb565Pixel; use slint::ComponentHandle; use static_cell::StaticCell; use ui::AppWindow; +use xkbcommon::xkb::{self, KeyDirection}; use {esp_alloc as _, esp_backtrace as _}; use crate::matrix::IoeMatrix; @@ -110,7 +112,8 @@ cfg_if! { } } -const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS +// const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS +const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS pub static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); @@ -393,16 +396,13 @@ async fn main(_spawner: Spawner) { let hid_report_proxy_task = async {}; let hid_report_proxy_task = { - use xkbcommon::xkb::{self, Keymap}; + use xkbcommon::xkb; static KEYBOARD_REPORT_PROXY: Channel = Channel::new(); { *rmk::channel::KEYBOARD_REPORT_SENDER.write().await = &KEYBOARD_REPORT_PROXY; } - info!("HID Report Proxy Task: Waiting 1 sec..."); - Timer::after_secs(1).await; - info!("HID Report Proxy Task: Done waiting."); const KEYMAP_STRING: &str = include_str!("../keymaps/cz.xkb"); let keymap_string_buffer = unsafe { let allocation = PSRAM_ALLOCATOR.alloc_caps( @@ -415,17 +415,77 @@ async fn main(_spawner: Spawner) { Box::from_raw_in(slice as *mut str, &PSRAM_ALLOCATOR) }; - info!("HID Report Proxy Task: test"); let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); - info!("HID Report Proxy Task: foo"); - let keymap = Keymap::new_from_string(&context, keymap_string_buffer, xkb::KEYMAP_FORMAT_TEXT_V1, xkb::KEYMAP_COMPILE_NO_FLAGS).unwrap(); - info!("HID Report Proxy Task: bar"); + info!("Parsing XKB keymap..."); + let instant_start = Instant::now(); + let keymap = xkb::Keymap::new_from_string(&context, keymap_string_buffer, xkb::KEYMAP_FORMAT_TEXT_V1, xkb::KEYMAP_COMPILE_NO_FLAGS).unwrap(); + let duration = Instant::now().duration_since(instant_start); + info!("XKB keymap parsed successfully! Took {seconds}.{millis:03} seconds.", seconds = duration.as_secs(), millis = duration.as_millis() % 1_000); + let mut state = xkb::State::new(&keymap); + let mut previous_state = KeyboardReport::default(); - async { + async move { loop { let report = KEYBOARD_REPORT_PROXY.receive().await; - info!("Intercepted HID report: {report:?}"); + if let Report::KeyboardReport(report) = &report { + // TODO: Process modifiers + + 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; + + // 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) + } + + if *keycode_old == 0 && keycode_new == 0 { + 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 || ((keycode_new != 0) && *keycode_old != keycode_new) { + let keycode_new_xkb = into_xkb_keycode(keycode_new); + let string = state.key_get_utf8(keycode_new_xkb); + + warn!("Pressed: 0x{:02x} ({})", keycode_new, keycode_new); + warn!("Print: {string}"); + + state.update_key(keycode_new_xkb, KeyDirection::Down); + } + + // state.update_key(keycode, direction); + *keycode_old = keycode_new; + } + } + rmk::channel::KEYBOARD_REPORT_RECEIVER.send(report).await; } }