Skip to content

Commit 1420d6f

Browse files
Merge pull request #145 from FrameworkComputer/kb-remap
Allow keyboard remapping
2 parents 9a1d630 + 51776de commit 1420d6f

File tree

7 files changed

+101
-7
lines changed

7 files changed

+101
-7
lines changed

EXAMPLES.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,39 @@ sudo framework_tool --rgbkbd 2 0xFF0000
403403
> sudo framework_tool --stylus-battery
404404
Stylus Battery Strength: 77%
405405
```
406+
407+
## Remap keyboard
408+
409+
Note that the keyboard matrix on Framework 12 and Framework 13 are
410+
different.
411+
The scancodes are the same.
412+
413+
- Left-Ctrl 0x0014
414+
- Left-Alt 0x0014
415+
- Tab 0x0058
416+
417+
### Framework 12
418+
419+
```
420+
# Remap capslock key as left-ctrl
421+
> framework_tool --remap-key 6 15 0x0014
422+
423+
# Swap left-ctrl and alt
424+
> framework_tool --remap-key 1 14 0x0011
425+
> framework_tool --remap-key 6 13 0x0014
426+
```
427+
428+
### Framework 13
429+
430+
```
431+
# Remap capslock key as left-ctrl
432+
> framework_tool --remap-key 4 4 0x0014
433+
434+
# Swap left-ctrl and alt
435+
> framework_tool --remap-key 1 12 0x0011
436+
> framework_tool --remap-key 1 3 0x0014
437+
```
438+
439+
### Framework 16
440+
441+
It's not controlled by the EC, use https://keyboard.frame.work.

framework_lib/src/chromium_ec/command.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub enum EcCommands {
6262
/// Change charge limit
6363
ChargeLimitControl = 0x3E03,
6464
DisablePs2Emulation = 0x3E08,
65+
UpdateKeyboardMatrix = 0x3E0C,
6566
/// Get/Set Fingerprint LED brightness
6667
FpLedLevelControl = 0x3E0E,
6768
/// Get information about the current chassis open/close status

framework_lib/src/chromium_ec/commands.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,31 @@ impl EcRequest<EcResponseFlashNotify> for EcRequestFlashNotify {
927927
}
928928
}
929929

930+
#[repr(C, packed)]
931+
pub struct KeyboardMatrixMap {
932+
pub row: u8,
933+
pub col: u8,
934+
pub scanset: u16,
935+
}
936+
#[repr(C, packed)]
937+
pub struct EcRequestUpdateKeyboardMatrix {
938+
pub num_items: u32,
939+
pub write: u32,
940+
pub scan_update: [KeyboardMatrixMap; 1],
941+
}
942+
#[repr(C, packed)]
943+
pub struct EcResponseUpdateKeyboardMatrix {
944+
pub num_items: u32,
945+
pub write: u32,
946+
pub scan_update: [KeyboardMatrixMap; 32],
947+
}
948+
949+
impl EcRequest<EcResponseUpdateKeyboardMatrix> for EcRequestUpdateKeyboardMatrix {
950+
fn command_id() -> EcCommands {
951+
EcCommands::UpdateKeyboardMatrix
952+
}
953+
}
954+
930955
#[repr(C, packed)]
931956
pub struct EcRequestChassisOpenCheck {}
932957

framework_lib/src/chromium_ec/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,20 @@ impl CrosEc {
390390
.map(|res| res.sensor_count)
391391
}
392392

393+
pub fn remap_caps_to_ctrl(&self) -> EcResult<()> {
394+
self.remap_key(6, 15, 0x0014)
395+
}
396+
397+
pub fn remap_key(&self, row: u8, col: u8, scanset: u16) -> EcResult<()> {
398+
let _current_matrix = EcRequestUpdateKeyboardMatrix {
399+
num_items: 1,
400+
write: 1,
401+
scan_update: [KeyboardMatrixMap { row, col, scanset }],
402+
}
403+
.send_command(self)?;
404+
Ok(())
405+
}
406+
393407
/// Get current status of Framework Laptop's microphone and camera privacy switches
394408
/// [true = device enabled/connected, false = device disabled]
395409
pub fn get_privacy_info(&self) -> EcResult<(bool, bool)> {

framework_lib/src/commandline/clap_std.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ struct ClapCli {
181181
#[arg(long)]
182182
kblight: Option<Option<u8>>,
183183

184+
/// Set keyboard backlight percentage or get, if no value provided
185+
#[arg(long, value_parser=maybe_hex::<u16>)]
186+
#[clap(num_args = 3)]
187+
remap_key: Vec<u16>,
188+
184189
/// Set the color of <key> to <RGB>. Multiple colors for adjacent keys can be set at once.
185190
/// <key> <RGB> [<RGB> ...]
186191
/// Example: 0 0xFF000 0x00FF00 0x0000FF
@@ -338,6 +343,14 @@ pub fn parse(args: &[String]) -> Cli {
338343
1 => Some((args.charge_rate_limit[0], None)),
339344
_ => None,
340345
};
346+
let remap_key = match args.remap_key.len() {
347+
3 => Some((
348+
args.remap_key[0] as u8,
349+
args.remap_key[1] as u8,
350+
args.remap_key[2],
351+
)),
352+
_ => None,
353+
};
341354

342355
Cli {
343356
verbosity: args.verbosity.log_level_filter(),
@@ -397,6 +410,7 @@ pub fn parse(args: &[String]) -> Cli {
397410
fp_led_level: args.fp_led_level,
398411
fp_brightness: args.fp_brightness,
399412
kblight: args.kblight,
413+
remap_key,
400414
rgbkbd: args.rgbkbd,
401415
ps2_enable: args.ps2_enable,
402416
tablet_mode: args.tablet_mode,

framework_lib/src/commandline/mod.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub struct Cli {
181181
pub fp_led_level: Option<Option<FpBrightnessArg>>,
182182
pub fp_brightness: Option<Option<u8>>,
183183
pub kblight: Option<Option<u8>>,
184+
pub remap_key: Option<(u8, u8, u16)>,
184185
pub rgbkbd: Vec<u64>,
185186
pub ps2_enable: Option<bool>,
186187
pub tablet_mode: Option<TabletModeArg>,
@@ -840,6 +841,15 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
840841
} else if let Some(Some(kblight)) = args.kblight {
841842
assert!(kblight <= 100);
842843
ec.set_keyboard_backlight(kblight);
844+
} else if let Some(None) = args.kblight {
845+
print!("Keyboard backlight: ");
846+
if let Some(percentage) = print_err(ec.get_keyboard_backlight()) {
847+
println!("{}%", percentage);
848+
} else {
849+
println!("Unable to tell");
850+
}
851+
} else if let Some((row, col, scanset)) = args.remap_key {
852+
print_err(ec.remap_key(row, col, scanset));
843853
} else if !args.rgbkbd.is_empty() {
844854
if args.rgbkbd.len() < 2 {
845855
println!(
@@ -857,13 +867,6 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
857867
}
858868
} else if let Some(enable) = args.ps2_enable {
859869
print_err(ec.ps2_emulation_enable(enable));
860-
} else if let Some(None) = args.kblight {
861-
print!("Keyboard backlight: ");
862-
if let Some(percentage) = print_err(ec.get_keyboard_backlight()) {
863-
println!("{}%", percentage);
864-
} else {
865-
println!("Unable to tell");
866-
}
867870
} else if let Some(tablet_arg) = &args.tablet_mode {
868871
let mode = match tablet_arg {
869872
TabletModeArg::Auto => TabletModeOverride::Default,

framework_lib/src/commandline/uefi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub fn parse(args: &[String]) -> Cli {
9494
fp_led_level: None,
9595
fp_brightness: None,
9696
kblight: None,
97+
remap_key: None,
9798
rgbkbd: vec![],
9899
ps2_enable: None,
99100
tablet_mode: None,

0 commit comments

Comments
 (0)