Added sticky key support

This commit is contained in:
Christoffer Martinsson 2024-02-19 22:16:56 +01:00
parent 60309e3c7a
commit e332b0dc5e
2 changed files with 77 additions and 49 deletions

View File

@ -161,11 +161,15 @@ fn main() -> ! {
let mut status_led_count_down = timer.count_down(); let mut status_led_count_down = timer.count_down();
status_led_count_down.start(250.millis()); status_led_count_down.start(250.millis());
let mut start_count_down = timer.count_down();
start_count_down.start(5000.millis());
// Create variables to track caps lock and fn mode // Create variables to track caps lock and fn mode
let mut caps_lock_active: bool = false; let mut caps_lock_active: bool = false;
let mut fn_mode: u8; let mut fn_mode: u8;
let mut gui_lock_state: u8 = 0; let mut sticky_state: u8 = 0;
let mut gui_lock_trigger_index: u8 = 0; let mut sticky_key: Keyboard = Keyboard::NoEventIndicated;
let mut started: bool = false;
// Initialize button matrix // Initialize button matrix
button_matrix.init_pins(); button_matrix.init_pins();
@ -185,7 +189,11 @@ fn main() -> ! {
loop { loop {
if status_led_count_down.wait().is_ok() { if status_led_count_down.wait().is_ok() {
update_status_led(&mut status_led, &caps_lock_active, &gui_lock_state); update_status_led(&mut status_led, &caps_lock_active, &sticky_state, &started);
}
if start_count_down.wait().is_ok() && !started {
started = true;
} }
if usb_hid_report_count_down.wait().is_ok() { if usb_hid_report_count_down.wait().is_ok() {
@ -193,19 +201,16 @@ fn main() -> ! {
fn_mode = get_fn_mode(pressed_keys); fn_mode = get_fn_mode(pressed_keys);
if !caps_lock_active { if !caps_lock_active && sticky_state != 2 {
update_status_led(&mut status_led, &caps_lock_active, &gui_lock_state); update_status_led(&mut status_led, &caps_lock_active, &sticky_state, &started);
} }
for (index, key) in pressed_keys.iter().enumerate() { for (index, key) in pressed_keys.iter().enumerate() {
buttons[index].pressed = *key; buttons[index].pressed = *key;
} }
let keyboard_report = get_keyboard_report( let keyboard_report =
&mut buttons, get_keyboard_report(&mut buttons, fn_mode, &mut sticky_state, &mut sticky_key);
fn_mode,
&mut gui_lock_state,
&mut gui_lock_trigger_index,
);
match keyboard.device().write_report(keyboard_report) { match keyboard.device().write_report(keyboard_report) {
Err(UsbHidError::WouldBlock) => {} Err(UsbHidError::WouldBlock) => {}
@ -248,8 +253,8 @@ fn main() -> ! {
/// Update status LED colour based on function layer and capslock /// Update status LED colour based on function layer and capslock
/// ///
/// Normal = green (NORMAL) /// Normal = Off (OFF)
/// GUI lock = blue (GUI LOCK) /// STICKY lock = blue/falshing blue (ACTIVITY)
/// Capslock active = flashing red (WARNING) /// Capslock active = flashing red (WARNING)
/// Error = steady red (ERROR) /// Error = steady red (ERROR)
/// ///
@ -259,7 +264,8 @@ fn main() -> ! {
fn update_status_led<P, SM, I>( fn update_status_led<P, SM, I>(
status_led: &mut Ws2812StatusLed<P, SM, I>, status_led: &mut Ws2812StatusLed<P, SM, I>,
caps_lock_active: &bool, caps_lock_active: &bool,
gui_lock_state: &u8, sticky_state: &u8,
started: &bool,
) where ) where
P: PIOExt + FunctionConfig, P: PIOExt + FunctionConfig,
I: PinId, I: PinId,
@ -268,10 +274,14 @@ fn update_status_led<P, SM, I>(
{ {
if *caps_lock_active { if *caps_lock_active {
status_led.update(StatusMode::Warning); status_led.update(StatusMode::Warning);
} else if *gui_lock_state != 0 { } else if *sticky_state == 1 {
status_led.update(StatusMode::Activity); status_led.update(StatusMode::Activity);
} else { } else if *sticky_state == 2 {
status_led.update(StatusMode::ActivityFlash);
} else if !(*started) {
status_led.update(StatusMode::Normal); status_led.update(StatusMode::Normal);
} else {
status_led.update(StatusMode::Off);
} }
} }
@ -302,27 +312,37 @@ fn get_fn_mode(pressed_keys: [bool; NUMBER_OF_KEYS]) -> u8 {
/// ///
/// * `matrix_keys` - Array of pressed keys /// * `matrix_keys` - Array of pressed keys
/// * `fn_mode` - Current function layer /// * `fn_mode` - Current function layer
/// * `gui_lock` - Is GUI lock active /// * `sticky_state` - Is STICKY lock active
/// * `gui_lock_index` - Index of the key pressed after GUI lock was activated /// * `sticky_key` - the key pressed after STICKY lock was activated
fn get_keyboard_report( fn get_keyboard_report(
matrix_keys: &mut [KeyboardButton; NUMBER_OF_KEYS], matrix_keys: &mut [KeyboardButton; NUMBER_OF_KEYS],
fn_mode: u8, fn_mode: u8,
gui_lock_state: &mut u8, sticky_state: &mut u8,
gui_lock_trigger_index: &mut u8, sticky_key: &mut Keyboard,
) -> [Keyboard; NUMBER_OF_KEYS] { ) -> [Keyboard; NUMBER_OF_KEYS] {
let mut keyboard_report: [Keyboard; NUMBER_OF_KEYS] = let mut keyboard_report: [Keyboard; NUMBER_OF_KEYS] =
[Keyboard::NoEventIndicated; NUMBER_OF_KEYS]; [Keyboard::NoEventIndicated; NUMBER_OF_KEYS];
// Filter report based on Fn mode and pressed keys // Filter report based on Fn mode and pressed keys
for (index, key) in matrix_keys.iter_mut().enumerate() { for (index, key) in matrix_keys.iter_mut().enumerate() {
// Check if GUI lock button is pressed // Check if STICKY button is pressed (SET STICKY)
if key.pressed != key.previous_pressed if key.pressed != key.previous_pressed
&& key.pressed && key.pressed
&& index as u8 == layout::GUI_LOCK_BUTTON[0] && index as u8 == layout::STICKY_BUTTON[0]
&& fn_mode == layout::GUI_LOCK_BUTTON[1] && fn_mode == layout::STICKY_BUTTON[1]
&& *gui_lock_state == 0 && *sticky_state == 0
{ {
*gui_lock_state = 1; *sticky_state = 1;
}
// Check if STICKY button is pressed (CLEAR STICKY)
else if key.pressed != key.previous_pressed
&& key.pressed
&& index as u8 == layout::STICKY_BUTTON[0]
&& fn_mode == layout::STICKY_BUTTON[1]
&& *sticky_state != 0
{
*sticky_state = 0;
*sticky_key = Keyboard::NoEventIndicated;
} }
// Set fn mode for the pressed button // Set fn mode for the pressed button
@ -336,22 +356,11 @@ fn get_keyboard_report(
continue; continue;
} }
/// Index of GUI key in keyboard report // If STICKY lock is active, hold index key pressed until STICKY lock key is pressed
/// Index 36, 37, 38, 45, 46, 47 are not used by any other keys // again
const GUI_REPORT_INDEX: usize = 47; if *sticky_state == 1 && key.pressed {
*sticky_key = layout::MAP[key.fn_mode as usize][index];
// If GUI lock is active, set LeftGUI key to pressed *sticky_state = 2;
// when next button is pressed. Keep LeftGUI pressed
// until next button is released
if *gui_lock_state == 1 && key.pressed {
*gui_lock_trigger_index = index as u8;
*gui_lock_state = 2;
keyboard_report[GUI_REPORT_INDEX] = Keyboard::LeftGUI;
} else if *gui_lock_state == 2 && *gui_lock_trigger_index == index as u8 && key.pressed {
keyboard_report[GUI_REPORT_INDEX] = Keyboard::LeftGUI;
*gui_lock_state = 3;
} else if *gui_lock_state == 3 && *gui_lock_trigger_index == index as u8 && !key.pressed {
*gui_lock_state = 0;
} }
// Add defined HID key to the report // Add defined HID key to the report
@ -359,5 +368,12 @@ fn get_keyboard_report(
keyboard_report[index] = layout::MAP[key.fn_mode as usize][index]; keyboard_report[index] = layout::MAP[key.fn_mode as usize][index];
} }
} }
/// Index of STICKY key in keyboard report
/// Index 36, 37, 38, 45, 46, 47 are not used by any other keys
const STICKY_REPORT_INDEX: usize = 46;
// Add sticky key to the report
keyboard_report[STICKY_REPORT_INDEX] = *sticky_key;
keyboard_report keyboard_report
} }

View File

@ -26,10 +26,12 @@ pub enum StatusMode {
Off = 0, Off = 0,
Normal = 1, Normal = 1,
Activity = 2, Activity = 2,
Other = 3, ActivityFlash = 3,
Warning = 4, Other = 4,
Error = 5, OtherFlash = 5,
Bootloader = 6, Warning = 6,
Error = 7,
Bootloader = 8,
} }
#[warn(dead_code)] #[warn(dead_code)]
@ -100,22 +102,32 @@ where
/// ///
/// Make sure to call this function regularly to keep the LED flashing /// Make sure to call this function regularly to keep the LED flashing
pub fn update(&mut self, mode: StatusMode) { pub fn update(&mut self, mode: StatusMode) {
let colors: [RGB8; 7] = [ let colors: [RGB8; 9] = [
(0, 0, 0).into(), // Off (0, 0, 0).into(), // Off
(10, 7, 0).into(), // Green (10, 7, 0).into(), // Green
(10, 4, 10).into(), // Blue (10, 4, 10).into(), // Blue
(10, 4, 10).into(), // Blue
(5, 10, 0).into(), // Orange
(5, 10, 0).into(), // Orange (5, 10, 0).into(), // Orange
(2, 20, 0).into(), // Red (2, 20, 0).into(), // Red
(2, 20, 0).into(), // Red (2, 20, 0).into(), // Red
(0, 10, 10).into(), // Purple (0, 10, 10).into(), // Purple
]; ];
if mode == StatusMode::Warning && !self.state { if (mode == StatusMode::ActivityFlash
|| mode == StatusMode::OtherFlash
|| mode == StatusMode::Warning)
&& !self.state
{
self.ws2812_direct self.ws2812_direct
.write([colors[mode as usize]].iter().copied()) .write([colors[mode as usize]].iter().copied())
.unwrap(); .unwrap();
self.state = true; self.state = true;
} else if mode == StatusMode::Warning || mode == StatusMode::Off { } else if mode == StatusMode::ActivityFlash
|| mode == StatusMode::OtherFlash
|| mode == StatusMode::Warning
|| mode == StatusMode::Off
{
self.ws2812_direct self.ws2812_direct
.write([colors[0]].iter().copied()) .write([colors[0]].iter().copied())
.unwrap(); .unwrap();