Compose key handling
This commit is contained in:
parent
1f21d29bd2
commit
97f330c7b9
|
|
@ -20,6 +20,7 @@ use core::cell::RefCell;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
|
@ -61,7 +62,7 @@ use slint::ComponentHandle;
|
||||||
use slint::platform::software_renderer::Rgb565Pixel;
|
use slint::platform::software_renderer::Rgb565Pixel;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use ui::AppWindow;
|
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 {esp_alloc as _, esp_backtrace as _};
|
||||||
|
|
||||||
use crate::matrix::IoeMatrix;
|
use crate::matrix::IoeMatrix;
|
||||||
|
|
@ -461,74 +462,124 @@ async fn main(_spawner: Spawner) {
|
||||||
let report = KEYBOARD_REPORT_PROXY.receive().await;
|
let report = KEYBOARD_REPORT_PROXY.receive().await;
|
||||||
|
|
||||||
if let Report::KeyboardReport(report) = &report {
|
if let Report::KeyboardReport(report) = &report {
|
||||||
warn!("MODIFIERS = {:02x}", report.modifier);
|
const KEYCODES_LEN_MODIFIERS: usize = 8;
|
||||||
const RMK_ALT: u8 = 0xE2;
|
const KEYCODES_LEN_REGULAR: usize = 6;
|
||||||
// TODO: Process modifiers
|
const KEYCODES_LEN: usize = KEYCODES_LEN_MODIFIERS + KEYCODES_LEN_REGULAR;
|
||||||
|
|
||||||
for (keycode_old, &keycode_new) in
|
let mut pressed_keys = rmk::heapless::Vec::<u8, KEYCODES_LEN>::new();
|
||||||
core::iter::zip(&mut previous_state.keycodes, &report.keycodes)
|
let mut released_keys = rmk::heapless::Vec::<u8, KEYCODES_LEN>::new();
|
||||||
{
|
|
||||||
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
|
let pressed_mods_bits = !previous_state.modifier & report.modifier;
|
||||||
// in a const expr into a single look-up table.
|
let released_mods_bits = previous_state.modifier & !report.modifier;
|
||||||
xkb::Keycode::new(
|
|
||||||
(HID_KEYBOARD[rmk_keycode as usize] + MIN_KEYCODE) as u32,
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if keycode_new == 0 || ((*keycode_old != 0) && *keycode_old != keycode_new)
|
if keycode_old != 0 {
|
||||||
{
|
released_keys.push(keycode_old).unwrap();
|
||||||
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)
|
if keycode_new != 0 {
|
||||||
{
|
pressed_keys.push(keycode_new).unwrap();
|
||||||
let keycode_new_xkb = into_xkb_keycode(keycode_new);
|
}
|
||||||
let syms = state.key_get_syms(keycode_new_xkb);
|
}
|
||||||
|
|
||||||
for sym in syms {
|
previous_state = report.clone();
|
||||||
compose_state.feed(*sym);
|
|
||||||
|
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<String>)> = 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!("Sym: {sym:?}");
|
||||||
warn!("Syms: {syms:?}");
|
warn!("String: {:?}", string.as_ref());
|
||||||
warn!("String: {string:?}");
|
|
||||||
|
|
||||||
state.update_key(keycode_new_xkb, KeyDirection::Down);
|
state.update_key(keycode_xkb, KeyDirection::Down);
|
||||||
}
|
}
|
||||||
|
|
||||||
*keycode_old = keycode_new;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue