add multiple momentary layers
This commit is contained in:
@@ -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)
|
||||
|
||||
161
src/keymap.rs
161
src/keymap.rs
@@ -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
|
||||
}
|
||||
|
||||
57
src/main.rs
57
src/main.rs
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user