From c75cff2a2c04ac6a85b5a84536d9281e1376bba4 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 9 May 2025 15:04:50 +0800 Subject: [PATCH 1/2] Allow keyboard remapping Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/command.rs | 1 + framework_lib/src/chromium_ec/commands.rs | 25 +++++++++++++++++++++++ framework_lib/src/chromium_ec/mod.rs | 14 +++++++++++++ 3 files changed, 40 insertions(+) diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index c6c68385..e009a9ec 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -62,6 +62,7 @@ pub enum EcCommands { /// Change charge limit ChargeLimitControl = 0x3E03, DisablePs2Emulation = 0x3E08, + UpdateKeyboardMatrix = 0x3E0C, /// Get/Set Fingerprint LED brightness FpLedLevelControl = 0x3E0E, /// Get information about the current chassis open/close status diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 2e72c947..4a8fd2bf 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -927,6 +927,31 @@ impl EcRequest for EcRequestFlashNotify { } } +#[repr(C, packed)] +pub struct KeyboardMatrixMap { + pub row: u8, + pub col: u8, + pub scanset: u16, +} +#[repr(C, packed)] +pub struct EcRequestUpdateKeyboardMatrix { + pub num_items: u32, + pub write: u32, + pub scan_update: [KeyboardMatrixMap; 1], +} +#[repr(C, packed)] +pub struct EcResponseUpdateKeyboardMatrix { + pub num_items: u32, + pub write: u32, + pub scan_update: [KeyboardMatrixMap; 32], +} + +impl EcRequest for EcRequestUpdateKeyboardMatrix { + fn command_id() -> EcCommands { + EcCommands::UpdateKeyboardMatrix + } +} + #[repr(C, packed)] pub struct EcRequestChassisOpenCheck {} diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 9ba22117..9bd367a0 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -390,6 +390,20 @@ impl CrosEc { .map(|res| res.sensor_count) } + pub fn remap_caps_to_ctrl(&self) -> EcResult<()> { + self.remap_key(6, 15, 0x0014) + } + + pub fn remap_key(&self, row: u8, col: u8, scanset: u16) -> EcResult<()> { + let _current_matrix = EcRequestUpdateKeyboardMatrix { + num_items: 1, + write: 1, + scan_update: [KeyboardMatrixMap { row, col, scanset }], + } + .send_command(self)?; + Ok(()) + } + /// Get current status of Framework Laptop's microphone and camera privacy switches /// [true = device enabled/connected, false = device disabled] pub fn get_privacy_info(&self) -> EcResult<(bool, bool)> { From 51776de85c1543c399889be1130f5b2881d58958 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 9 May 2025 23:50:06 +0800 Subject: [PATCH 2/2] Add --remap-key command Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 36 +++++++++++++++++++++++ framework_lib/src/commandline/clap_std.rs | 14 +++++++++ framework_lib/src/commandline/mod.rs | 17 ++++++----- framework_lib/src/commandline/uefi.rs | 1 + 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 2098d223..c36da6e2 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -382,3 +382,39 @@ sudo framework_tool --rgbkbd 2 0xFF0000 > sudo framework_tool --stylus-battery Stylus Battery Strength: 77% ``` + +## Remap keyboard + +Note that the keyboard matrix on Framework 12 and Framework 13 are +different. +The scancodes are the same. + +- Left-Ctrl 0x0014 +- Left-Alt 0x0014 +- Tab 0x0058 + +### Framework 12 + +``` +# Remap capslock key as left-ctrl +> framework_tool --remap-key 6 15 0x0014 + +# Swap left-ctrl and alt +> framework_tool --remap-key 1 14 0x0011 +> framework_tool --remap-key 6 13 0x0014 +``` + +### Framework 13 + +``` +# Remap capslock key as left-ctrl +> framework_tool --remap-key 4 4 0x0014 + +# Swap left-ctrl and alt +> framework_tool --remap-key 1 12 0x0011 +> framework_tool --remap-key 1 3 0x0014 +``` + +### Framework 16 + +It's not controlled by the EC, use https://keyboard.frame.work. diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 4b17646c..aabd5468 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -181,6 +181,11 @@ struct ClapCli { #[arg(long)] kblight: Option>, + /// Set keyboard backlight percentage or get, if no value provided + #[arg(long, value_parser=maybe_hex::)] + #[clap(num_args = 3)] + remap_key: Vec, + /// Set the color of to . Multiple colors for adjacent keys can be set at once. /// [ ...] /// Example: 0 0xFF000 0x00FF00 0x0000FF @@ -338,6 +343,14 @@ pub fn parse(args: &[String]) -> Cli { 1 => Some((args.charge_rate_limit[0], None)), _ => None, }; + let remap_key = match args.remap_key.len() { + 3 => Some(( + args.remap_key[0] as u8, + args.remap_key[1] as u8, + args.remap_key[2], + )), + _ => None, + }; Cli { verbosity: args.verbosity.log_level_filter(), @@ -397,6 +410,7 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: args.fp_led_level, fp_brightness: args.fp_brightness, kblight: args.kblight, + remap_key, rgbkbd: args.rgbkbd, ps2_enable: args.ps2_enable, tablet_mode: args.tablet_mode, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index ce11646d..0b9aa39d 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -181,6 +181,7 @@ pub struct Cli { pub fp_led_level: Option>, pub fp_brightness: Option>, pub kblight: Option>, + pub remap_key: Option<(u8, u8, u16)>, pub rgbkbd: Vec, pub ps2_enable: Option, pub tablet_mode: Option, @@ -809,6 +810,15 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else if let Some(Some(kblight)) = args.kblight { assert!(kblight <= 100); ec.set_keyboard_backlight(kblight); + } else if let Some(None) = args.kblight { + print!("Keyboard backlight: "); + if let Some(percentage) = print_err(ec.get_keyboard_backlight()) { + println!("{}%", percentage); + } else { + println!("Unable to tell"); + } + } else if let Some((row, col, scanset)) = args.remap_key { + print_err(ec.remap_key(row, col, scanset)); } else if !args.rgbkbd.is_empty() { if args.rgbkbd.len() < 2 { println!( @@ -826,13 +836,6 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } } else if let Some(enable) = args.ps2_enable { print_err(ec.ps2_emulation_enable(enable)); - } else if let Some(None) = args.kblight { - print!("Keyboard backlight: "); - if let Some(percentage) = print_err(ec.get_keyboard_backlight()) { - println!("{}%", percentage); - } else { - println!("Unable to tell"); - } } else if let Some(tablet_arg) = &args.tablet_mode { let mode = match tablet_arg { TabletModeArg::Auto => TabletModeOverride::Default, diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 63924450..097c006f 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -94,6 +94,7 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: None, fp_brightness: None, kblight: None, + remap_key: None, rgbkbd: vec![], ps2_enable: None, tablet_mode: None,