From 707c994a76ad236a0954ae63e94298c49284582f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Hlusi=C4=8Dka?= Date: Fri, 13 Feb 2026 02:50:32 +0100 Subject: [PATCH] Use fork keys --- firmware/acid-firmware/src/config.rs | 154 ++++++++++++++++++ firmware/acid-firmware/src/main.rs | 21 ++- firmware/acid-firmware/src/matrix.rs | 6 +- .../acid-firmware/src/{keymap.rs => proxy.rs} | 41 +---- firmware/acid-firmware/src/ui/backend.rs | 2 +- firmware/acid-firmware/src/ui/mod.rs | 2 +- firmware/acid-firmware/vial.json | 30 ++++ 7 files changed, 202 insertions(+), 54 deletions(-) create mode 100644 firmware/acid-firmware/src/config.rs rename firmware/acid-firmware/src/{keymap.rs => proxy.rs} (92%) diff --git a/firmware/acid-firmware/src/config.rs b/firmware/acid-firmware/src/config.rs new file mode 100644 index 0000000..579d29a --- /dev/null +++ b/firmware/acid-firmware/src/config.rs @@ -0,0 +1,154 @@ +use core::alloc::Layout; +use core::fmt::Debug; +use core::ops::Index; +use core::slice; + +use alloc::alloc::Allocator; +use alloc::boxed::Box; +use alloc::collections::btree_map::{BTreeMap, Entry}; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; +use embassy_time::Instant; +use esp_alloc::{EspHeap, MemoryCapability}; +use itertools::Itertools; +use log::{debug, error, info, warn}; +use rmk::config::{BehaviorConfig, ForksConfig, PositionalConfig}; +use rmk::descriptor::KeyboardReport; +use rmk::fork::{Fork, StateBits}; +use rmk::futures::FutureExt; +use rmk::hid::Report; +use rmk::types::action::{Action, KeyAction}; +use rmk::types::modifier::ModifierCombination; +use rmk::{a, heapless, join_all, k, layer}; +use slint::platform::Key; +use static_cell::StaticCell; +use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModIndex, ModMask, Status}; + +use crate::util::{DurationExt, get_file_name}; +use crate::vial::CustomKeycodes; +use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR}; + +pub const NUM_LAYER: usize = 8; +pub const MATRIX_ROWS: usize = 5; +pub const MATRIX_COLS: usize = 12; +pub const MATRIX_AREA: usize = MATRIX_ROWS * MATRIX_COLS; + +const T: KeyAction = a!(Transparent); + +#[rustfmt::skip] +pub const fn get_default_keymap() -> [[[KeyAction; MATRIX_COLS]; MATRIX_ROWS]; NUM_LAYER] { + [ + layer!([ + [k!(Escape), k!(Kc1), k!(Kc2), k!(Kc3), k!(Kc4), k!(Kc5), k!(Kc6), k!(Kc7), k!(Kc8), k!(Kc9), k!(Kc0), k!(Backspace)], + [k!(Tab), k!(Q), k!(W), k!(E), k!(R), k!(T), k!(Z), k!(U), k!(I), k!(O), k!(P), k!(Delete)], + [k!(LCtrl), k!(A), k!(S), k!(D), k!(F), k!(G), k!(H), k!(J), k!(K), k!(L), k!(Comma), k!(Enter)], + [k!(LShift), k!(Y), k!(X), k!(C), k!(V), k!(B), k!(N), k!(M), a!(No), a!(No), k!(Up), KeyAction::Single(Action::User(CustomKeycodes::FOCUS_LCD as u8))], + [a!(No), a!(No), k!(LGui), k!(LAlt), KeyAction::Single(Action::TriLayerLower), k!(Space), k!(Space), KeyAction::Single(Action::TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)] + // [a!(No), a!(No), k!(LGui), k!(LAlt), k!(TriLayerLower), k!(Space), k!(Space), k!(TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)] + ]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]), + ] +} + +fn fork_by_shift( + trigger: CustomKeycodes, + negative_output: KeyAction, + positive_output: KeyAction, + keep_shift: bool, +) -> Fork { + Fork::new( + KeyAction::Single(Action::User(trigger as u8)), + negative_output, + positive_output, + StateBits::new_from( + ModifierCombination::new() + .with_left_shift(true) + .with_right_shift(true), + Default::default(), + Default::default(), + ), + StateBits::default(), + ModifierCombination::new() + .with_left_shift(keep_shift) + .with_right_shift(keep_shift), + false, + ) +} + +pub fn get_behavior_config() -> BehaviorConfig { + BehaviorConfig { + fork: ForksConfig { + forks: { + let mut forks = heapless::Vec::new(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_ACUTE_ABOVERING_CS, + rmk::k!(Equal), + rmk::k!(Grave), // Shift is kept + true, + )) + .unwrap(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_CARON_DIAERESIS_CS, + rmk::shifted!(Equal), + rmk::wm!(Minus, ModifierCombination::new().with_right_alt(true)), + false, + )) + .unwrap(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_ACUTE_ABOVERING_CSP, + rmk::wm!(Equal, ModifierCombination::new().with_right_alt(true)), + rmk::wm!(Grave, ModifierCombination::new().with_right_alt(true)), // Shift is kept + true, + )) + .unwrap(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_CARON_DIAERESIS_CSP, + rmk::wm!( + Equal, + ModifierCombination::new() + .with_left_shift(true) + .with_right_alt(true) + ), + rmk::wm!(Backslash, ModifierCombination::new().with_right_alt(true)), + false, + )) + .unwrap(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_9_FORWARDSLASH_EN_CSP, + rmk::k!(Kc9), + rmk::k!(Slash), + false, + )) + .unwrap(); + forks + .push(fork_by_shift( + CustomKeycodes::FORK_0_BACKWARDSLASH_EN_CSP, + rmk::k!(Kc0), + rmk::k!(Backslash), + false, + )) + .unwrap(); + forks + }, + }, + ..Default::default() + } +} + +pub fn get_positional_config() -> PositionalConfig { + PositionalConfig::default() +} diff --git a/firmware/acid-firmware/src/main.rs b/firmware/acid-firmware/src/main.rs index 0b2da20..04ca73e 100644 --- a/firmware/acid-firmware/src/main.rs +++ b/firmware/acid-firmware/src/main.rs @@ -61,26 +61,30 @@ use itertools::Itertools; use log::{error, info, warn}; use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub}; use rmk::config::{ - BehaviorConfig, DeviceConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig, + BehaviorConfig, DeviceConfig, ForksConfig, PositionalConfig, RmkConfig, StorageConfig, + VialConfig, }; use rmk::controller::{Controller, EventController}; use rmk::debounce::default_debouncer::DefaultDebouncer; use rmk::event::ControllerEvent; +use rmk::fork::{Fork, StateBits}; use rmk::hid::Report; use rmk::input_device::Runnable; -use rmk::join_all; use rmk::keyboard::Keyboard; use rmk::storage::async_flash_wrapper; use rmk::types::action::{Action, KeyAction}; +use rmk::types::keycode::KeyCode; +use rmk::types::modifier::ModifierCombination; +use rmk::{heapless, join_all}; use rmk::{initialize_keymap_and_storage, run_devices, run_rmk}; use slint::platform::software_renderer::Rgb565Pixel; use static_cell::StaticCell; use {esp_alloc as _, esp_backtrace as _}; -use crate::keymap::create_hid_report_interceptor; use crate::logging::LOG_LEVEL_FILTER; use crate::matrix::IoeMatrix; use crate::peripherals::st7701s::St7701s; +use crate::proxy::create_hid_report_interceptor; use crate::ui::backend::{FramebufferPtr, SlintBackend}; use crate::vial::{ CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID, VIAL_KEYBOARD_NAME, VIAL_PRODUCT_ID, @@ -89,13 +93,14 @@ use crate::vial::{ mutually_exclusive_features::none_or_one_of!["usb-log", "alt-log", "rtt-log"]; +mod config; mod crypto; mod db; mod ffi; -mod keymap; mod logging; mod matrix; mod peripherals; +mod proxy; mod ui; mod util; mod vial; @@ -425,15 +430,15 @@ async fn main(_spawner: Spawner) { // Initialze keyboard stuffs // Initialize the storage and keymap - let mut default_keymap = keymap::get_default_keymap(); - let mut behavior_config = BehaviorConfig::default(); - let mut per_key_config = PositionalConfig::default(); + let mut default_keymap = config::get_default_keymap(); + let mut behavior_config = config::get_behavior_config(); + let mut positional_config = config::get_positional_config(); let (keymap, mut storage) = initialize_keymap_and_storage( &mut default_keymap, flash_part_rmk, &storage_config, &mut behavior_config, - &mut per_key_config, + &mut positional_config, ) .await; diff --git a/firmware/acid-firmware/src/matrix.rs b/firmware/acid-firmware/src/matrix.rs index a0704e7..c93ae75 100644 --- a/firmware/acid-firmware/src/matrix.rs +++ b/firmware/acid-firmware/src/matrix.rs @@ -13,6 +13,8 @@ use rmk::{ matrix::{KeyState, MatrixTrait}, }; +use crate::config::{MATRIX_AREA, MATRIX_COLS, MATRIX_ROWS}; + pub struct RaiiGuard { on_drop: Option, } @@ -33,10 +35,6 @@ impl Drop for RaiiGuard { } } -pub const MATRIX_ROWS: usize = 5; -pub const MATRIX_COLS: usize = 12; -pub const MATRIX_AREA: usize = MATRIX_ROWS * MATRIX_COLS; - /// IO Expander Matrix pub struct IoeMatrix where diff --git a/firmware/acid-firmware/src/keymap.rs b/firmware/acid-firmware/src/proxy.rs similarity index 92% rename from firmware/acid-firmware/src/keymap.rs rename to firmware/acid-firmware/src/proxy.rs index 112479c..61393d6 100644 --- a/firmware/acid-firmware/src/keymap.rs +++ b/firmware/acid-firmware/src/proxy.rs @@ -24,13 +24,11 @@ use slint::platform::Key; use static_cell::StaticCell; use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, ModIndex, ModMask, Status}; -use crate::matrix::{MATRIX_COLS, MATRIX_ROWS}; +use crate::config::{MATRIX_COLS, MATRIX_ROWS}; use crate::util::{DurationExt, get_file_name}; use crate::vial::CustomKeycodes; use crate::{KEYBOARD_REPORT_PROXY, PSRAM_ALLOCATOR}; -pub const NUM_LAYER: usize = 4; - pub static KEY_MESSAGE_CHANNEL: Channel = Channel::new(); pub static OUTPUT_STRING_CHANNEL: Channel = Channel::new(); @@ -53,43 +51,6 @@ impl Debug for KeyMessage { } } -const T: KeyAction = a!(Transparent); - -#[rustfmt::skip] -pub const fn get_default_keymap() -> [[[KeyAction; MATRIX_COLS]; MATRIX_ROWS]; NUM_LAYER] { - [ - layer!([ - [k!(Escape), k!(Kc1), k!(Kc2), k!(Kc3), k!(Kc4), k!(Kc5), k!(Kc6), k!(Kc7), k!(Kc8), k!(Kc9), k!(Kc0), k!(Backspace)], - [k!(Tab), k!(Q), k!(W), k!(E), k!(R), k!(T), k!(Z), k!(U), k!(I), k!(O), k!(P), k!(Delete)], - [k!(LCtrl), k!(A), k!(S), k!(D), k!(F), k!(G), k!(H), k!(J), k!(K), k!(L), k!(Comma), k!(Enter)], - [k!(LShift), k!(Y), k!(X), k!(C), k!(V), k!(B), k!(N), k!(M), a!(No), a!(No), k!(Up), KeyAction::Single(Action::User(CustomKeycodes::FOCUS_LCD as u8))], - [a!(No), a!(No), k!(LGui), k!(LAlt), KeyAction::Single(Action::TriLayerLower), k!(Space), k!(Space), KeyAction::Single(Action::TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)] - // [a!(No), a!(No), k!(LGui), k!(LAlt), k!(TriLayerLower), k!(Space), k!(Space), k!(TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)] - ]), - layer!([ - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T] - ]), - layer!([ - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T] - ]), - layer!([ - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T], - [T, T, T, T, T, T, T, T, T, T, T, T] - ]), - ] -} - pub fn create_hid_report_interceptor() -> impl Future { // TODO: Use `include_dir` or similar to support multiple keymaps. const KEYMAP_NAME: &str = get_file_name(env!("ACID_KEYMAP_PATH")); diff --git a/firmware/acid-firmware/src/ui/backend.rs b/firmware/acid-firmware/src/ui/backend.rs index a78e26f..434d118 100644 --- a/firmware/acid-firmware/src/ui/backend.rs +++ b/firmware/acid-firmware/src/ui/backend.rs @@ -20,7 +20,7 @@ use slint::{ }; use xkbcommon::xkb::{self, Keysym}; -use crate::keymap::{KEY_MESSAGE_CHANNEL, TryFromKeysym}; +use crate::proxy::{KEY_MESSAGE_CHANNEL, TryFromKeysym}; use super::window_adapter::SoftwareWindowAdapter; diff --git a/firmware/acid-firmware/src/ui/mod.rs b/firmware/acid-firmware/src/ui/mod.rs index f38d093..64b52ea 100644 --- a/firmware/acid-firmware/src/ui/mod.rs +++ b/firmware/acid-firmware/src/ui/mod.rs @@ -36,7 +36,7 @@ use crate::{ PartitionAcid, ReadTransactionExt, }, ffi::{alloc::__spre_free, crypto::ACTIVE_ENCRYPTED_USER_KEY}, - keymap::OUTPUT_STRING_CHANNEL, + proxy::OUTPUT_STRING_CHANNEL, ui::{ backend::SlintBackend, messages::{ diff --git a/firmware/acid-firmware/vial.json b/firmware/acid-firmware/vial.json index 623aae0..af853ba 100644 --- a/firmware/acid-firmware/vial.json +++ b/firmware/acid-firmware/vial.json @@ -47,6 +47,36 @@ "name": "FOCUS_LCD", "title": "Focus LCD", "shortName": "Focus\nLCD" + }, + { + "name": "FORK_ACUTE_ABOVERING_CS", + "title": "Shift fork between ´ and ° on the CS layout", + "shortName": "(CS)\n°\n´" + }, + { + "name": "FORK_CARON_DIAERESIS_CS", + "title": "Shift fork between ˇ and ¨on the CS layout", + "shortName": "(CS)\n¨\nˇ" + }, + { + "name": "FORK_ACUTE_ABOVERING_CSP", + "title": "Shift fork between ´ and ° on the CSP layout", + "shortName": "(CSP)\n°\n´" + }, + { + "name": "FORK_CARON_DIAERESIS_CSP", + "title": "Shift fork between ˇ and ¨on the CSP layout", + "shortName": "(CSP)\n¨\nˇ" + }, + { + "name": "FORK_9_FORWARDSLASH_EN_CSP", + "title": "Shift fork between 9 and / on the EN or the CSP layout", + "shortName": "(EN/CSP)\n/\n9" + }, + { + "name": "FORK_0_BACKWARDSLASH_EN_CSP", + "title": "Shift fork between 0 and \\ on the EN or the CSP layout", + "shortName": "(EN/CSP)\n\\\n0" } ], "layouts": {