add multiple momentary layers

This commit is contained in:
2025-12-28 20:59:08 +01:00
parent 150c52f620
commit 5012c6d494
3 changed files with 172 additions and 50 deletions

View File

@@ -36,7 +36,7 @@ pub fn init_display(bus: I2c<'static, embassy_rp::peripherals::I2C0, embassy_rp:
/// Temp function which updates the display with currently pressed keys /// Temp function which updates the display with currently pressed keys
pub fn update_display( pub fn update_display(
display: &mut Option<Display>, display: &mut Option<Display>,
pressed_keys: &[(usize, usize, crate::keymap::KeyCode)], pressed_keys: &[(usize, usize, crate::keymap::Action)],
) -> Option<()> { ) -> Option<()> {
if let Some(display) = display { if let Some(display) = display {
display.clear(BinaryColor::Off).ok()?; display.clear(BinaryColor::Off).ok()?;
@@ -54,7 +54,7 @@ pub fn update_display(
let mut y_pos = 0; let mut y_pos = 0;
for (row_idx, col_idx, keycode) in pressed_keys.iter().take(3) { for (row_idx, col_idx, keycode) in pressed_keys.iter().take(3) {
let mut msg = heapless::String::<32>::new(); let mut msg = heapless::String::<32>::new();
write!(&mut msg, "R{}C{}: 0x{:02X}", row_idx, col_idx, keycode.as_u8()).ok(); write!(&mut msg, "R{}C{}: 0x{:?}", row_idx, col_idx, keycode).ok();
Text::with_baseline(&msg, Point::new(0, y_pos), text_style, Baseline::Top) Text::with_baseline(&msg, Point::new(0, y_pos), text_style, Baseline::Top)
.draw(display) .draw(display)

View File

@@ -2,11 +2,27 @@
/// Reference: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf /// Reference: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
/// Section 10: Keyboard/Keypad Page (0x07) /// Section 10: Keyboard/Keypad Page (0x07)
#[allow(dead_code)] static N_LAYERS: usize = 4;
static COLS: usize = 12;
static ROWS: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Key(HidKey), // normal key press
Layer(LayerOperation), // layer modifier key press
None, // do nothing
Trans, // fall back to the default keymap
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayerOperation {
MO(usize) // momentary (hold to switch to the layer)
}
#[allow(dead_code)]
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyCode { pub enum HidKey {
No = 0x00, No = 0x00,
// Letters // Letters
@@ -108,65 +124,142 @@ pub enum KeyCode {
RightMeta = 0xE7, RightMeta = 0xE7,
} }
impl KeyCode { impl HidKey {
pub const fn as_u8(self) -> u8 { pub const fn as_u8(self) -> u8 {
self as u8 self as u8
} }
pub const fn is_modifier(self) -> bool { pub const fn is_modifier(self) -> bool {
matches!(self, matches!(self,
KeyCode::LeftCtrl | KeyCode::LeftShift | KeyCode::LeftAlt | KeyCode::LeftMeta | HidKey::LeftCtrl | HidKey::LeftShift | HidKey::LeftAlt | HidKey::LeftMeta |
KeyCode::RightCtrl | KeyCode::RightShift | KeyCode::RightAlt | KeyCode::RightMeta HidKey::RightCtrl | HidKey::RightShift | HidKey::RightAlt | HidKey::RightMeta
) )
} }
pub const fn modifier_bit(self) -> u8 { pub const fn modifier_bit(self) -> u8 {
match self { match self {
KeyCode::LeftCtrl => 0x01, HidKey::LeftCtrl => 0x01,
KeyCode::LeftShift => 0x02, HidKey::LeftShift => 0x02,
KeyCode::LeftAlt => 0x04, HidKey::LeftAlt => 0x04,
KeyCode::LeftMeta => 0x08, HidKey::LeftMeta => 0x08,
KeyCode::RightCtrl => 0x10, HidKey::RightCtrl => 0x10,
KeyCode::RightShift => 0x20, HidKey::RightShift => 0x20,
KeyCode::RightAlt => 0x40, // AltGr HidKey::RightAlt => 0x40, // AltGr
KeyCode::RightMeta => 0x80, HidKey::RightMeta => 0x80,
_ => 0, _ => 0,
} }
} }
} }
/// Keymap for my 4x12 ortholinear keyboard /// Keymap for my 4x12 ortholinear keyboard
/// Each position [row][col] maps to a USB HID scancode /// Each position [row][col] on each layer maps to an action
pub const KEYMAP: [[KeyCode; 12]; 4] = [ pub const KEYMAPS: [[[Action; COLS]; ROWS]; N_LAYERS] = [
[ [
KeyCode::Escape, KeyCode::Q, KeyCode::W, KeyCode::E, // base layer
KeyCode::R, KeyCode::T, KeyCode::Y, KeyCode::U, [
KeyCode::I, KeyCode::O, KeyCode::P, KeyCode::Backspace, Action::Key(HidKey::Escape), Action::Key(HidKey::Q), Action::Key(HidKey::W), Action::Key(HidKey::E),
Action::Key(HidKey::R), Action::Key(HidKey::T), Action::Key(HidKey::Y), Action::Key(HidKey::U),
Action::Key(HidKey::I), Action::Key(HidKey::O), Action::Key(HidKey::P), Action::Key(HidKey::Backspace),
], ],
[ [
KeyCode::Tab, KeyCode::A, KeyCode::S, KeyCode::D, Action::Key(HidKey::Tab), Action::Key(HidKey::A), Action::Key(HidKey::S), Action::Key(HidKey::D),
KeyCode::F, KeyCode::G, KeyCode::H, KeyCode::J, Action::Key(HidKey::F), Action::Key(HidKey::G), Action::Key(HidKey::H), Action::Key(HidKey::J),
KeyCode::K, KeyCode::L, KeyCode::Semicolon, KeyCode::Enter, Action::Key(HidKey::K), Action::Key(HidKey::L), Action::Key(HidKey::Semicolon), Action::Key(HidKey::Enter),
], ],
[ [
KeyCode::LeftShift, KeyCode::Z, KeyCode::X, KeyCode::C, Action::Key(HidKey::LeftShift), Action::Key(HidKey::Z), Action::Key(HidKey::X), Action::Key(HidKey::C),
KeyCode::V, KeyCode::B, KeyCode::N, KeyCode::M, Action::Key(HidKey::V), Action::Key(HidKey::B), Action::Key(HidKey::N), Action::Key(HidKey::M),
KeyCode::Comma, KeyCode::Dot, KeyCode::Up, KeyCode::Slash, Action::Key(HidKey::Comma), Action::Key(HidKey::Dot), Action::Key(HidKey::Up), Action::Key(HidKey::Slash),
], ],
[ [
KeyCode::LeftCtrl, KeyCode::No, KeyCode::LeftMeta, KeyCode::LeftAlt, Action::Key(HidKey::LeftCtrl), Action::Layer(LayerOperation::MO(3)), Action::Key(HidKey::LeftMeta), Action::Key(HidKey::LeftAlt),
KeyCode::No, KeyCode::Space, KeyCode::No, KeyCode::No, Action::Layer(LayerOperation::MO(1)), Action::Key(HidKey::Space), Action::Key(HidKey::No), Action::Layer(LayerOperation::MO(2)),
KeyCode::RightAlt, KeyCode::Left, KeyCode::Down, KeyCode::Right, Action::Key(HidKey::RightAlt), Action::Key(HidKey::Left), Action::Key(HidKey::Down), Action::Key(HidKey::Right),
],
],
// layer 1 (numbers mostly)
[
[
Action::Key(HidKey::Grave), Action::Key(HidKey::Kb1), Action::Key(HidKey::Kb2), Action::Key(HidKey::Kb3),
Action::Key(HidKey::Kb4), Action::Key(HidKey::Kb5), Action::Key(HidKey::Kb6), Action::Key(HidKey::Kb7),
Action::Key(HidKey::Kb8), Action::Key(HidKey::Kb9), Action::Key(HidKey::Kb0), Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Key(HidKey::RightShift),
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
],
],
// layer 2 (additional keys missing from the kb)
[
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Key(HidKey::LeftBracket), Action::Key(HidKey::RightBracket), Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Key(HidKey::Minus), Action::Key(HidKey::Equal), Action::Key(HidKey::Quote), Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Key(HidKey::RightShift),
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
],
],
// layer 3 (fn key layer, with f* keys and home/end/pgup/pgdown)
[
[
Action::Key(HidKey::F1), Action::Key(HidKey::F2), Action::Key(HidKey::F3), Action::Key(HidKey::F4),
Action::Key(HidKey::F5), Action::Key(HidKey::F6), Action::Key(HidKey::F7), Action::Key(HidKey::F8),
Action::Key(HidKey::F9), Action::Key(HidKey::F10), Action::Key(HidKey::F11), Action::Key(HidKey::F12),
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Key(HidKey::PageUp), Action::Trans,
],
[
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Trans, Action::Trans, Action::Trans,
Action::Trans, Action::Key(HidKey::Home), Action::Key(HidKey::PageDown), Action::Key(HidKey::End),
],
], ],
]; ];
/// Get keycode from given row and column /// Get action from given row and column
pub fn get_keycode(row: usize, col: usize) -> Option<KeyCode> { pub fn get_action(row: usize, col: usize, layer: usize) -> Action {
if row < 4 && col < 12 { if row < ROWS && col < COLS && layer < N_LAYERS {
let keycode = KEYMAP[row][col]; let action = KEYMAPS[layer][row][col];
if keycode != KeyCode::No {
return Some(keycode); // handle transparent keys, in this case it should fall down to the first layer without transparent key
if matches!(action, Action::Trans) && layer > 0 {
return get_action(row, col, layer - 1);
}
action
} else {
Action::None
} }
} }
None
}

View File

@@ -17,9 +17,9 @@ use embassy_rp::{
}; };
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use usbd_hid::descriptor::KeyboardReport; use usbd_hid::descriptor::KeyboardReport;
use {defmt_rtt as _, panic_probe as _}; use crate::keymap::{Action, LayerOperation, get_action};
use keymap::get_keycode; use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
I2C0_IRQ => I2cInterruptHandler<embassy_rp::peripherals::I2C0>; I2C0_IRQ => I2cInterruptHandler<embassy_rp::peripherals::I2C0>;
@@ -68,18 +68,45 @@ async fn main(_spawner: Spawner) -> () {
let in_fut = async { let in_fut = async {
let mut previous_keycodes: [u8; 6] = [0; 6]; let mut previous_keycodes: [u8; 6] = [0; 6];
let mut previous_modifier: u8 = 0; let mut previous_modifier: u8 = 0;
let mut active_layer: usize = 0;
loop { loop {
let scan_result = matrix.scan().await; let scan_result = matrix.scan().await;
// Collect all pressed keys and their scancodes // first pass to check if the layer keys are active
let mut pressed_keys: heapless::Vec<(usize, usize, keymap::KeyCode), 48> = heapless::Vec::new(); let mut layer_active = false;
for (row_idx, row) in scan_result.iter().enumerate() { for (row_idx, row) in scan_result.iter().enumerate() {
for (col_idx, &is_pressed) in row.iter().enumerate() { for (col_idx, &is_pressed) in row.iter().enumerate() {
if is_pressed { if is_pressed {
if let Some(keycode) = get_keycode(row_idx, col_idx) { // try to find if any of the pressed keys on the 0th layer is a layer modify key
let _ = pressed_keys.push((row_idx, col_idx, keycode)); let action = get_action(row_idx, col_idx, 0);
if let Action::Layer(LayerOperation::MO(layer)) = action {
layer_active = true;
active_layer = layer;
break;
}
}
}
// break the loop early if layer key is pressed
if layer_active {
break;
}
}
if !layer_active {
active_layer = 0;
}
// Collect all pressed keys and their scancodes
let mut pressed_keys: heapless::Vec<(usize, usize, keymap::Action), 48> = heapless::Vec::new();
for (row_idx, row) in scan_result.iter().enumerate() {
for (col_idx, &is_pressed) in row.iter().enumerate() {
if is_pressed {
let action = get_action(row_idx, col_idx, active_layer);
if !matches!(action, Action::None | Action::Layer(_)) {
let _ = pressed_keys.push((row_idx, col_idx, action));
} }
} }
} }
@@ -90,16 +117,18 @@ async fn main(_spawner: Spawner) -> () {
let mut keycodes = [0u8; 6]; let mut keycodes = [0u8; 6];
let mut keycode_index = 0; let mut keycode_index = 0;
for (_, _, keycode) in pressed_keys.iter() { for (_, _, action) in pressed_keys.iter() {
if keycode.is_modifier() { if let Action::Key(hid_key) = action {
if hid_key.is_modifier() {
// Add to modifier byte // Add to modifier byte
modifier |= keycode.modifier_bit(); modifier |= hid_key.modifier_bit();
} else if keycode_index < 6 { } else if keycode_index < 6 {
// Add to keycodes array (max 6 regular keys) // Add to keycodes array (max 6 regular keys)
keycodes[keycode_index] = keycode.as_u8(); keycodes[keycode_index] = hid_key.as_u8();
keycode_index += 1; keycode_index += 1;
} }
} }
}
// Update display // Update display
display::update_display(&mut display, &pressed_keys); display::update_display(&mut display, &pressed_keys);