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
pub fn update_display(
display: &mut Option<Display>,
pressed_keys: &[(usize, usize, crate::keymap::KeyCode)],
pressed_keys: &[(usize, usize, crate::keymap::Action)],
) -> Option<()> {
if let Some(display) = display {
display.clear(BinaryColor::Off).ok()?;
@@ -54,7 +54,7 @@ pub fn update_display(
let mut y_pos = 0;
for (row_idx, col_idx, keycode) in pressed_keys.iter().take(3) {
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)
.draw(display)

View File

@@ -2,11 +2,27 @@
/// Reference: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
/// 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)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyCode {
pub enum HidKey {
No = 0x00,
// Letters
@@ -108,65 +124,142 @@ pub enum KeyCode {
RightMeta = 0xE7,
}
impl KeyCode {
impl HidKey {
pub const fn as_u8(self) -> u8 {
self as u8
}
pub const fn is_modifier(self) -> bool {
matches!(self,
KeyCode::LeftCtrl | KeyCode::LeftShift | KeyCode::LeftAlt | KeyCode::LeftMeta |
KeyCode::RightCtrl | KeyCode::RightShift | KeyCode::RightAlt | KeyCode::RightMeta
HidKey::LeftCtrl | HidKey::LeftShift | HidKey::LeftAlt | HidKey::LeftMeta |
HidKey::RightCtrl | HidKey::RightShift | HidKey::RightAlt | HidKey::RightMeta
)
}
pub const fn modifier_bit(self) -> u8 {
match self {
KeyCode::LeftCtrl => 0x01,
KeyCode::LeftShift => 0x02,
KeyCode::LeftAlt => 0x04,
KeyCode::LeftMeta => 0x08,
KeyCode::RightCtrl => 0x10,
KeyCode::RightShift => 0x20,
KeyCode::RightAlt => 0x40, // AltGr
KeyCode::RightMeta => 0x80,
HidKey::LeftCtrl => 0x01,
HidKey::LeftShift => 0x02,
HidKey::LeftAlt => 0x04,
HidKey::LeftMeta => 0x08,
HidKey::RightCtrl => 0x10,
HidKey::RightShift => 0x20,
HidKey::RightAlt => 0x40, // AltGr
HidKey::RightMeta => 0x80,
_ => 0,
}
}
}
/// Keymap for my 4x12 ortholinear keyboard
/// Each position [row][col] maps to a USB HID scancode
pub const KEYMAP: [[KeyCode; 12]; 4] = [
/// Each position [row][col] on each layer maps to an action
pub const KEYMAPS: [[[Action; COLS]; ROWS]; N_LAYERS] = [
[
KeyCode::Escape, KeyCode::Q, KeyCode::W, KeyCode::E,
KeyCode::R, KeyCode::T, KeyCode::Y, KeyCode::U,
KeyCode::I, KeyCode::O, KeyCode::P, KeyCode::Backspace,
// base layer
[
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),
],
[
Action::Key(HidKey::Tab), Action::Key(HidKey::A), Action::Key(HidKey::S), Action::Key(HidKey::D),
Action::Key(HidKey::F), Action::Key(HidKey::G), Action::Key(HidKey::H), Action::Key(HidKey::J),
Action::Key(HidKey::K), Action::Key(HidKey::L), Action::Key(HidKey::Semicolon), Action::Key(HidKey::Enter),
],
[
Action::Key(HidKey::LeftShift), Action::Key(HidKey::Z), Action::Key(HidKey::X), Action::Key(HidKey::C),
Action::Key(HidKey::V), Action::Key(HidKey::B), Action::Key(HidKey::N), Action::Key(HidKey::M),
Action::Key(HidKey::Comma), Action::Key(HidKey::Dot), Action::Key(HidKey::Up), Action::Key(HidKey::Slash),
],
[
Action::Key(HidKey::LeftCtrl), Action::Layer(LayerOperation::MO(3)), Action::Key(HidKey::LeftMeta), Action::Key(HidKey::LeftAlt),
Action::Layer(LayerOperation::MO(1)), Action::Key(HidKey::Space), Action::Key(HidKey::No), Action::Layer(LayerOperation::MO(2)),
Action::Key(HidKey::RightAlt), Action::Key(HidKey::Left), Action::Key(HidKey::Down), Action::Key(HidKey::Right),
],
],
// layer 1 (numbers mostly)
[
KeyCode::Tab, KeyCode::A, KeyCode::S, KeyCode::D,
KeyCode::F, KeyCode::G, KeyCode::H, KeyCode::J,
KeyCode::K, KeyCode::L, KeyCode::Semicolon, KeyCode::Enter,
[
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)
[
KeyCode::LeftShift, KeyCode::Z, KeyCode::X, KeyCode::C,
KeyCode::V, KeyCode::B, KeyCode::N, KeyCode::M,
KeyCode::Comma, KeyCode::Dot, KeyCode::Up, KeyCode::Slash,
[
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)
[
KeyCode::LeftCtrl, KeyCode::No, KeyCode::LeftMeta, KeyCode::LeftAlt,
KeyCode::No, KeyCode::Space, KeyCode::No, KeyCode::No,
KeyCode::RightAlt, KeyCode::Left, KeyCode::Down, KeyCode::Right,
[
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
pub fn get_keycode(row: usize, col: usize) -> Option<KeyCode> {
if row < 4 && col < 12 {
let keycode = KEYMAP[row][col];
if keycode != KeyCode::No {
return Some(keycode);
/// Get action from given row and column
pub fn get_action(row: usize, col: usize, layer: usize) -> Action {
if row < ROWS && col < COLS && layer < N_LAYERS {
let action = KEYMAPS[layer][row][col];
// 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 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 {
I2C0_IRQ => I2cInterruptHandler<embassy_rp::peripherals::I2C0>;
@@ -68,18 +68,45 @@ async fn main(_spawner: Spawner) -> () {
let in_fut = async {
let mut previous_keycodes: [u8; 6] = [0; 6];
let mut previous_modifier: u8 = 0;
let mut active_layer: usize = 0;
loop {
let scan_result = matrix.scan().await;
// Collect all pressed keys and their scancodes
let mut pressed_keys: heapless::Vec<(usize, usize, keymap::KeyCode), 48> = heapless::Vec::new();
// first pass to check if the layer keys are active
let mut layer_active = false;
for (row_idx, row) in scan_result.iter().enumerate() {
for (col_idx, &is_pressed) in row.iter().enumerate() {
if is_pressed {
if let Some(keycode) = get_keycode(row_idx, col_idx) {
let _ = pressed_keys.push((row_idx, col_idx, keycode));
// try to find if any of the pressed keys on the 0th layer is a layer modify key
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,14 +117,16 @@ async fn main(_spawner: Spawner) -> () {
let mut keycodes = [0u8; 6];
let mut keycode_index = 0;
for (_, _, keycode) in pressed_keys.iter() {
if keycode.is_modifier() {
// Add to modifier byte
modifier |= keycode.modifier_bit();
} else if keycode_index < 6 {
// Add to keycodes array (max 6 regular keys)
keycodes[keycode_index] = keycode.as_u8();
keycode_index += 1;
for (_, _, action) in pressed_keys.iter() {
if let Action::Key(hid_key) = action {
if hid_key.is_modifier() {
// Add to modifier byte
modifier |= hid_key.modifier_bit();
} else if keycode_index < 6 {
// Add to keycodes array (max 6 regular keys)
keycodes[keycode_index] = hid_key.as_u8();
keycode_index += 1;
}
}
}