More host string sending improvements, add compiled czech coders'

layout, send site password to host
This commit is contained in:
Jakub Hlusička 2026-02-12 02:39:31 +01:00
parent a09da0c8a7
commit ab506de76a
7 changed files with 1982 additions and 12 deletions

View file

@ -24,6 +24,9 @@
"ESP_LOG": "warn", "ESP_LOG": "warn",
"ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES": "20", "ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES": "20",
"SLINT_FONT_SIZES": "8,11,10,12,13,14,15,16,18,20,22,24,32", "SLINT_FONT_SIZES": "8,11,10,12,13,14,15,16,18,20,22,24,32",
"ACID_KEYMAP_PATH": "../keymaps/cz_coder.xkb",
"ACID_COMPOSE_PATH": "../compose/cs_CZ Compose.txt",
"ACID_COMPOSE_LOCALE": "cs_CZ.UTF-8",
}, },
"extraArgs": ["-Zbuild-std=core,alloc"], "extraArgs": ["-Zbuild-std=core,alloc"],
// Enable device support and a wide set of features on the esp-rtos crate. // Enable device support and a wide set of features on the esp-rtos crate.

View file

@ -29,6 +29,9 @@ ESP_LOG = "warn"
ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES = "20" ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES = "20"
# This is overkill, but we can afford it. # This is overkill, but we can afford it.
SLINT_FONT_SIZES = "8,11,10,12,13,14,15,16,18,20,22,24,32" SLINT_FONT_SIZES = "8,11,10,12,13,14,15,16,18,20,22,24,32"
ACID_KEYMAP_PATH = "../keymaps/cz_coder.xkb"
ACID_COMPOSE_PATH = "../compose/cs_CZ Compose.txt"
ACID_COMPOSE_LOCALE = "cs_CZ.UTF-8"
# Xtensa only: # Xtensa only:
# Needed for nightly, until llvm upstream has support for Rust Xtensa. # Needed for nightly, until llvm upstream has support for Rust Xtensa.

View file

@ -61,7 +61,7 @@ On Windows, use PuTTY with a baudrate of 115200.
To generate an English (US) keymap, the following command may be used: To generate an English (US) keymap, the following command may be used:
`xkbcli compile-keymap --include [path-to-xkb-directory] --layout us >my_compose.txt` `xkbcli compile-keymap --include [path-to-xkb-directory] --layout us >my_keymap.xkb`
Substitute `us` for any other 2-letter country code. Substitute `us` for any other 2-letter country code.
@ -80,7 +80,18 @@ Use libxkbcommon's `xkbcli` to compile a standalone compose file:
Compose files to replace `[path-to-Compose-file]` with may be found in: Compose files to replace `[path-to-Compose-file]` with may be found in:
* the `/usr/share/X11/locale` directory on X11-based Linux distributions; * the `/usr/share/X11/locale` directory on X11-based Linux distributions;
* the [`libx11` git repository](https://gitlab.freedesktop.org/xorg/lib/libx11/-/tree/master). There's an button to download it as a ZIP archive. * the [`libx11` git repository](https://gitlab.freedesktop.org/xorg/lib/libx11/-/tree/master/nls). There's a button to download it as a ZIP archive.
### Setup in GNOME
#### Making all xkb layouts available
By default, GNOME displays only the most common keyboard layouts (`xkb_symbols`). Other keyboard layouts can be made visible via:
```sh
gsettings set org.gnome.desktop.input-sources show-all-sources true
```
In order to use completely custom layouts, [this article](https://web.archive.org/web/20260212010717/https://staticf0x.github.io/2021/custom-keyboard-layout-in-x11-and-wayland.html) may be helpful.
# esp32s3 BLE example # esp32s3 BLE example

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
use core::alloc::Layout; use core::alloc::Layout;
use core::fmt::Debug; use core::fmt::Debug;
use core::ops::Index;
use core::slice; use core::slice;
use alloc::alloc::Allocator; use alloc::alloc::Allocator;
@ -24,7 +25,7 @@ use static_cell::StaticCell;
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModIndex, ModMask, Status}; use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModIndex, ModMask, Status};
use crate::matrix::{MATRIX_COLS, MATRIX_ROWS}; use crate::matrix::{MATRIX_COLS, MATRIX_ROWS};
use crate::util::DurationExt; use crate::util::{DurationExt, get_file_name};
use crate::vial::CustomKeycodes; use crate::vial::CustomKeycodes;
use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR}; use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR};
@ -67,9 +68,17 @@ pub const fn get_default_keymap() -> [[[KeyAction; MATRIX_COLS]; MATRIX_ROWS]; N
} }
pub fn create_hid_report_interceptor() -> impl Future<Output = ()> { pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
const KEYMAP_STRING: &str = include_str!("../keymaps/cz.xkb"); // TODO: Use `include_dir` or similar to support multiple keymaps.
const COMPOSE_MAP_STRING: &str = include_str!("../compose/cs_CZ Compose.txt"); const KEYMAP_NAME: &str = get_file_name(env!("ACID_KEYMAP_PATH"));
const COMPOSE_MAP_LOCALE: &str = "cs_CZ.UTF-8"; const KEYMAP_STRING: &str = include_str!(env!("ACID_KEYMAP_PATH"));
const COMPOSE_MAP_NAME: &str = get_file_name(env!("ACID_COMPOSE_PATH"));
const COMPOSE_MAP_STRING: &str = include_str!(env!("ACID_COMPOSE_PATH"));
// E.g. `cs_CZ.UTF-8`
const COMPOSE_MAP_LOCALE: &str = env!("ACID_COMPOSE_LOCALE");
info!(
"Keymap: {KEYMAP_NAME:?}, compose: {COMPOSE_MAP_NAME:?}, compose locale: {COMPOSE_MAP_LOCALE:?}"
);
let keymap_string_buffer = unsafe { let keymap_string_buffer = unsafe {
let allocation = PSRAM_ALLOCATOR.alloc_caps( let allocation = PSRAM_ALLOCATOR.alloc_caps(
@ -230,6 +239,7 @@ async fn send_strings_to_host<A: Allocator>(
continue; continue;
} }
// TODO: Check whether this is necessary, otherwise remove.
rmk::channel::KEYBOARD_REPORT_RECEIVER rmk::channel::KEYBOARD_REPORT_RECEIVER
.send(Report::KeyboardReport(KeyboardReport { .send(Report::KeyboardReport(KeyboardReport {
modifier, modifier,
@ -243,7 +253,9 @@ async fn send_strings_to_host<A: Allocator>(
})) }))
.await; .await;
keycodes_vec.push(keycode.keycode); keycodes_vec
.push(keycode.keycode)
.expect("no space for the main keycode");
warn!( warn!(
"Sending HID keycode 0x{:02x} with modifier 0x{:02x} (xkb mask 0x{:02x}) as keycode sequence {keycodes_vec:02x?}", "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 keycode.keycode, modifier, keycode.mod_mask
@ -480,6 +492,11 @@ pub fn string_to_hid_keycodes(
continue; continue;
}; };
if (0x65..USB_HID_LEFT_CTRL).contains(&hid_keycode) {
warn!("Skipping candidate because is in a poorly supported range of HID keycodes.");
continue;
}
let Some(&simplest_mod_mask) = masks.iter().min() else { let Some(&simplest_mod_mask) = masks.iter().min() else {
error!("No mod mask found for this key."); error!("No mod mask found for this key.");
continue; continue;

View file

@ -17,7 +17,7 @@ use hex::FromHexError;
use i_slint_core::model::{ModelChangeListener, ModelChangeListenerContainer}; use i_slint_core::model::{ModelChangeListener, ModelChangeListenerContainer};
use log::{error, info, warn}; use log::{error, info, warn};
use password_hash::Key; use password_hash::Key;
use rmk::futures::TryFutureExt; use rmk::futures::{FutureExt, TryFutureExt};
use slint::{ use slint::{
Model, ModelExt, ModelNotify, ModelRc, ModelTracker, SharedString, StandardListViewItem, Model, ModelExt, ModelNotify, ModelRc, ModelTracker, SharedString, StandardListViewItem,
VecModel, VecModel,
@ -765,14 +765,14 @@ impl AppViewTrait for StateUserSites {
warn!("Site password: {site_password:?}"); warn!("Site password: {site_password:?}");
for character in site_password.chars() {
let keysym = xkbcommon::xkb::utf32_to_keysym(character as u32);
}
slint::spawn_local({ slint::spawn_local({
let username = user_sites.username.clone(); let username = user_sites.username.clone();
let db = state.db.clone(); let db = state.db.clone();
async move { async move {
// Send password to the host.
OUTPUT_STRING_CHANNEL.send(site_password).await;
// Update the stored site.
let mut write = db.write_transaction().await; let mut write = db.write_transaction().await;
let key = DbKey::new(DbPathSpectreUserSite { let key = DbKey::new(DbPathSpectreUserSite {
user_sites: DbPathSpectreUserSites { user_sites: DbPathSpectreUserSites {

View file

@ -24,3 +24,25 @@ impl DurationExt for Duration {
FormattedDuration(self) FormattedDuration(self)
} }
} }
pub const fn get_file_name(path: &str) -> &str {
let path = path.as_bytes();
let mut start_index = path.len() as isize;
loop {
start_index -= 1;
if start_index < 0
|| path[start_index as usize] == b'/'
|| path[start_index as usize] == b'\\'
{
start_index += 1;
break;
}
}
match str::from_utf8(path.split_at(start_index as usize).1) {
Ok(substring) => substring,
Err(_) => panic!("Failed to extract the file name from a path."),
}
}