Improvements to sending strings to host
This commit is contained in:
parent
3b364c64c2
commit
a09da0c8a7
|
|
@ -13,15 +13,15 @@ use embassy_sync::channel::Channel;
|
|||
use embassy_time::Instant;
|
||||
use esp_alloc::{EspHeap, MemoryCapability};
|
||||
use itertools::Itertools;
|
||||
use log::{debug, info, warn};
|
||||
use log::{debug, error, info, warn};
|
||||
use rmk::descriptor::KeyboardReport;
|
||||
use rmk::futures::FutureExt;
|
||||
use rmk::hid::Report;
|
||||
use rmk::types::action::{Action, KeyAction};
|
||||
use rmk::{a, join_all, k, layer};
|
||||
use rmk::{a, heapless, join_all, k, layer};
|
||||
use slint::platform::Key;
|
||||
use static_cell::StaticCell;
|
||||
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModMask, Status};
|
||||
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModIndex, ModMask, Status};
|
||||
|
||||
use crate::matrix::{MATRIX_COLS, MATRIX_ROWS};
|
||||
use crate::util::DurationExt;
|
||||
|
|
@ -133,27 +133,130 @@ pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
|
|||
}
|
||||
}
|
||||
|
||||
const KEYCODES_LEN_MODIFIERS: usize = 8;
|
||||
const USB_HID_LEFT_CTRL: u8 = 0xE0;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ModifierDescriptor {
|
||||
name: &'static str,
|
||||
hid_flag: Option<u8>,
|
||||
keycode: Option<u8>,
|
||||
}
|
||||
|
||||
impl ModifierDescriptor {
|
||||
const fn new(name: &'static str, hid_index: Option<u8>) -> Self {
|
||||
Self {
|
||||
name,
|
||||
hid_flag: if let Some(hid_index) = hid_index {
|
||||
Some(1_u8 << hid_index)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
keycode: if let Some(hid_index) = hid_index {
|
||||
Some(USB_HID_LEFT_CTRL + hid_index)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_strings_to_host<A: Allocator>(
|
||||
keymap: Arc<xkb::Keymap, A>,
|
||||
compose_table: Arc<xkb::compose::Table, A>,
|
||||
) {
|
||||
/// Names of modifiers in the conventional order.
|
||||
const XKB_REAL_MODIFIER_DESCRIPTORS: [ModifierDescriptor; KEYCODES_LEN_MODIFIERS] = [
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_SHIFT, Some(1)),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_CAPS, None),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_CTRL, Some(0)),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_ALT, Some(2)),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_NUM, None),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_MOD3, None),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_LOGO, Some(3)),
|
||||
ModifierDescriptor::new(xkb::MOD_NAME_ISO_LEVEL3_SHIFT, Some(6)),
|
||||
];
|
||||
|
||||
let modifier_xkb_index_to_descriptor = keymap
|
||||
.mods()
|
||||
.enumerate()
|
||||
.map(|(index, modifier)| {
|
||||
let descriptor = XKB_REAL_MODIFIER_DESCRIPTORS
|
||||
.iter()
|
||||
.find(|descriptor| descriptor.name == modifier);
|
||||
debug!("Modifier #{index} {descriptor:02x?}");
|
||||
descriptor
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
info!("modifier_xkb_index_to_hid_flag: {modifier_xkb_index_to_descriptor:02x?}");
|
||||
|
||||
loop {
|
||||
let string = OUTPUT_STRING_CHANNEL.receive().await;
|
||||
let keycodes = string_to_hid_keycodes(&keymap, &compose_table, &string);
|
||||
let string_keycodes = string_to_hid_keycodes(&keymap, &compose_table, &string);
|
||||
|
||||
warn!("keycodes for {string:?}: {keycodes:02x?}");
|
||||
warn!("keycodes for {string:?}: {string_keycodes:02x?}");
|
||||
|
||||
if let Ok(string_keycodes) = string_keycodes {
|
||||
for keycode in string_keycodes {
|
||||
let mut keycodes_vec = heapless::Vec::<u8, 6>::new();
|
||||
let modifier = {
|
||||
let mut modifier = 0;
|
||||
let mut remaining_mask = keycode.mod_mask;
|
||||
let mut index = 0;
|
||||
|
||||
while remaining_mask != 0 {
|
||||
if remaining_mask & 1 != 0 {
|
||||
if let Some(mod_descriptor) = modifier_xkb_index_to_descriptor[index] {
|
||||
if let Some(hid_flag) = mod_descriptor.hid_flag {
|
||||
modifier |= hid_flag;
|
||||
}
|
||||
|
||||
if let Some(keycode) = mod_descriptor.keycode {
|
||||
let _ = keycodes_vec.push(keycode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remaining_mask >>= 1;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
modifier
|
||||
};
|
||||
|
||||
if keycodes_vec.len() + 1 > keycodes_vec.capacity() {
|
||||
warn!("Failed to send key because the keycode buffer is full.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(keycodes) = keycodes {
|
||||
for keycode_chunk in keycodes.chunks(6) {
|
||||
rmk::channel::KEYBOARD_REPORT_RECEIVER
|
||||
.send(Report::KeyboardReport(KeyboardReport {
|
||||
modifier: Default::default(), // TODO
|
||||
reserved: Default::default(), // TODO
|
||||
modifier,
|
||||
reserved: Default::default(),
|
||||
leds: Default::default(),
|
||||
keycodes: {
|
||||
// Send multiple keycodes at the same time.
|
||||
let mut keycodes = [0; _];
|
||||
keycodes[0..keycode_chunk.len()].copy_from_slice(keycode_chunk);
|
||||
keycodes[..keycodes_vec.len()].copy_from_slice(&keycodes_vec);
|
||||
keycodes
|
||||
},
|
||||
}))
|
||||
.await;
|
||||
|
||||
keycodes_vec.push(keycode.keycode);
|
||||
warn!(
|
||||
"Sending HID keycode 0x{:02x} with modifier 0x{:02x} (xkb mask 0x{:02x}) as keycode sequence {keycodes_vec:02x?}",
|
||||
keycode.keycode, modifier, keycode.mod_mask
|
||||
);
|
||||
|
||||
rmk::channel::KEYBOARD_REPORT_RECEIVER
|
||||
.send(Report::KeyboardReport(KeyboardReport {
|
||||
modifier,
|
||||
reserved: Default::default(),
|
||||
leds: Default::default(),
|
||||
keycodes: {
|
||||
let mut keycodes = [0; _];
|
||||
keycodes[..keycodes_vec.len()].copy_from_slice(&keycodes_vec);
|
||||
keycodes
|
||||
},
|
||||
}))
|
||||
|
|
@ -180,8 +283,9 @@ async fn send_keycodes_to_slint<A: Allocator>(
|
|||
loop {
|
||||
let report = KEYBOARD_REPORT_PROXY.receive().await;
|
||||
|
||||
info!("Intercepted HID keyboard report: {report:#02x?}");
|
||||
|
||||
if let Report::KeyboardReport(report) = &report {
|
||||
const KEYCODES_LEN_MODIFIERS: usize = 8;
|
||||
const KEYCODES_LEN_REGULAR: usize = 6;
|
||||
const KEYCODES_LEN: usize = KEYCODES_LEN_MODIFIERS + KEYCODES_LEN_REGULAR;
|
||||
|
||||
|
|
@ -192,7 +296,6 @@ async fn send_keycodes_to_slint<A: Allocator>(
|
|||
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;
|
||||
|
||||
|
|
@ -325,26 +428,35 @@ fn lookup_keysym_entries(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HidKeycodeWithMods {
|
||||
keycode: u8,
|
||||
mod_mask: ModMask,
|
||||
}
|
||||
|
||||
pub fn string_to_hid_keycodes(
|
||||
keymap: &xkb::Keymap,
|
||||
compose_table: &xkb::compose::Table,
|
||||
string: &str,
|
||||
) -> Result<Vec<u8, &'static EspHeap>, char> {
|
||||
) -> Result<Vec<HidKeycodeWithMods, &'static EspHeap>, char> {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct KeycodeChoice {
|
||||
mod_mask: ModMask,
|
||||
hid_keycode: u8,
|
||||
xkb_keycode: xkb::Keycode,
|
||||
}
|
||||
|
||||
let mut hid_keycodes = Vec::new_in(&PSRAM_ALLOCATOR);
|
||||
|
||||
for character in string.chars() {
|
||||
let keysym = xkbcommon::xkb::utf32_to_keysym(character as u32);
|
||||
let mut found_keycode = None;
|
||||
let mut chosen_keycode = None;
|
||||
|
||||
keymap.key_for_each(|keymap, keycode| {
|
||||
if found_keycode.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
for layout_index in 0..keymap.num_layouts_for_key(keycode) {
|
||||
for level_index in 0..keymap.num_levels_for_key(keycode, layout_index) {
|
||||
keymap.key_for_each(|keymap, xkb_keycode| {
|
||||
for layout_index in 0..keymap.num_layouts_for_key(xkb_keycode) {
|
||||
for level_index in 0..keymap.num_levels_for_key(xkb_keycode, layout_index) {
|
||||
let [current_keysym] =
|
||||
keymap.key_get_syms_by_level(keycode, layout_index, level_index)
|
||||
keymap.key_get_syms_by_level(xkb_keycode, layout_index, level_index)
|
||||
else {
|
||||
// Multi-keysym levels are currently not handled.
|
||||
continue;
|
||||
|
|
@ -353,25 +465,60 @@ pub fn string_to_hid_keycodes(
|
|||
if current_keysym == &keysym {
|
||||
let mut masks: [ModMask; 32 /* TODO: Re-evaluate the appropriate size */] = Default::default();
|
||||
let masks_len = keymap.key_get_mods_for_level(
|
||||
keycode,
|
||||
xkb_keycode,
|
||||
layout_index,
|
||||
level_index,
|
||||
&mut masks,
|
||||
);
|
||||
let masks = &mut masks[0..masks_len];
|
||||
warn!("string_to_hid_keycodes: char = {character:?}, sym = {keysym:?}, code = {keycode:?}, layout = {layout_index:?}, level = {level_index:?}, masks = {masks:?}");
|
||||
found_keycode = Some(keycode);
|
||||
let hid_keycode = xkb_to_hid_keycode(xkb_keycode);
|
||||
|
||||
info!("Candidate for {character:?} ({keysym:?}) considered: XKB = 0x{xkb_keycode:02x?}, HID = 0x{hid_keycode:02x?}, layout = {layout_index:?}, level = {level_index:?}, masks = 0x{masks:02x?}", xkb_keycode = xkb_keycode.raw());
|
||||
|
||||
let Some(hid_keycode) = hid_keycode else {
|
||||
warn!("Could not translate XKB {xkb_keycode:?} to an HID keycode, skipping candidate.");
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(&simplest_mod_mask) = masks.iter().min() else {
|
||||
error!("No mod mask found for this key.");
|
||||
continue;
|
||||
};
|
||||
|
||||
let keycode_choice = KeycodeChoice {
|
||||
mod_mask: simplest_mod_mask,
|
||||
hid_keycode,
|
||||
xkb_keycode,
|
||||
};
|
||||
|
||||
if let Some(found_keycode) = &mut chosen_keycode {
|
||||
*found_keycode = core::cmp::min(*found_keycode, keycode_choice);
|
||||
} else {
|
||||
chosen_keycode = Some(keycode_choice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let Some(found_keycode) = found_keycode else {
|
||||
let Some(KeycodeChoice {
|
||||
mod_mask,
|
||||
hid_keycode,
|
||||
xkb_keycode,
|
||||
}) = chosen_keycode
|
||||
else {
|
||||
return Err(character);
|
||||
};
|
||||
let hid_keycode = xkb_to_hid_keycode(found_keycode);
|
||||
|
||||
hid_keycodes.push(hid_keycode);
|
||||
warn!(
|
||||
"Candidate for {character:?} ({keysym:?}) chosen: XKB = 0x{xkb_keycode:02x?}, HID = 0x{hid_keycode:02x?}, mod_mask = 0x{mod_mask:02x?}",
|
||||
xkb_keycode = xkb_keycode.raw()
|
||||
);
|
||||
|
||||
hid_keycodes.push(HidKeycodeWithMods {
|
||||
keycode: hid_keycode,
|
||||
mod_mask,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(hid_keycodes)
|
||||
|
|
@ -428,7 +575,7 @@ pub const fn hid_to_xkb_keycode(hid_keycode: u8) -> xkb::Keycode {
|
|||
xkb::Keycode::new(HID_TO_XKB[hid_keycode as usize] as u32)
|
||||
}
|
||||
|
||||
pub const fn xkb_to_hid_keycode(xkb_keycode: xkb::Keycode) -> u8 {
|
||||
pub const fn xkb_to_hid_keycode(xkb_keycode: xkb::Keycode) -> Option<u8> {
|
||||
const XKB_TO_HID: [u8; 256] = {
|
||||
let mut xkb_to_hid = [0_u8; _];
|
||||
let mut hid: u8 = 0;
|
||||
|
|
@ -445,7 +592,11 @@ pub const fn xkb_to_hid_keycode(xkb_keycode: xkb::Keycode) -> u8 {
|
|||
xkb_to_hid
|
||||
};
|
||||
|
||||
XKB_TO_HID[xkb_keycode.raw() as usize]
|
||||
if (xkb_keycode.raw() as usize) < XKB_TO_HID.len() {
|
||||
Some(XKB_TO_HID[xkb_keycode.raw() as usize])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TryFromKeysym: Sized {
|
||||
|
|
|
|||
Loading…
Reference in a new issue