diff --git a/justfile b/justfile index 7797f0c38..f4de382b2 100644 --- a/justfile +++ b/justfile @@ -26,7 +26,7 @@ sha256sums output_dir: cd {{output_dir}}; sha256sum * > sha256sums test: - cargo test --verbose -p kanata -p kanata-parser -p kanata-keyberon -- --nocapture + cargo test -p kanata -p kanata-parser -p kanata-keyberon -- --nocapture cargo clippy --all fmt: diff --git a/keyberon/src/action/switch.rs b/keyberon/src/action/switch.rs index 6a00d370a..c5750b41b 100644 --- a/keyberon/src/action/switch.rs +++ b/keyberon/src/action/switch.rs @@ -1094,16 +1094,13 @@ fn bool_evaluation_test_not_0() { OpCode::new_key(KeyCode::F), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied(), - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied(), + )); } #[test] @@ -1115,16 +1112,13 @@ fn bool_evaluation_test_not_1() { OpCode::new_key(KeyCode::B), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1136,16 +1130,13 @@ fn bool_evaluation_test_not_2() { OpCode::new_key(KeyCode::Y), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - true, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1156,16 +1147,13 @@ fn bool_evaluation_test_not_3() { OpCode::new_key(KeyCode::D), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1183,16 +1171,13 @@ fn bool_evaluation_test_not_4() { OpCode::new_key(KeyCode::F), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1204,16 +1189,13 @@ fn bool_evaluation_test_not_5() { OpCode::new_key(KeyCode::D), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - true, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1226,16 +1208,13 @@ fn bool_evaluation_test_not_6() { OpCode::new_key(KeyCode::D), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1247,16 +1226,13 @@ fn bool_evaluation_test_or_equivalency_not_6() { OpCode::new_key(KeyCode::D), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1268,16 +1244,13 @@ fn bool_evaluation_test_not_7() { OpCode::new_key(KeyCode::E), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1289,16 +1262,13 @@ fn bool_evaluation_test_or_equivalency_not_7() { OpCode::new_key(KeyCode::E), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1310,16 +1280,13 @@ fn bool_evaluation_test_not_8() { OpCode::new_key(KeyCode::A), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - false, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(!evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] @@ -1331,16 +1298,13 @@ fn bool_evaluation_test_not_9() { OpCode::new_key(KeyCode::C), ]; let keycodes = [KeyCode::A, KeyCode::B, KeyCode::D, KeyCode::F]; - assert_eq!( - true, - evaluate_boolean( - opcodes.as_slice(), - keycodes.iter().copied(), - [].iter().copied(), - [].iter().copied(), - [].iter().copied() - ) - ); + assert!(evaluate_boolean( + opcodes.as_slice(), + keycodes.iter().copied(), + [].iter().copied(), + [].iter().copied(), + [].iter().copied() + )); } #[test] diff --git a/keyberon/src/chord.rs b/keyberon/src/chord.rs index 4340e1885..620385199 100644 --- a/keyberon/src/chord.rs +++ b/keyberon/src/chord.rs @@ -310,7 +310,6 @@ impl<'a, T> ChordsV2<'a, T> { return; }; let Some(possible_chords) = self.chords.mapping.get(starting_press) else { - dbg!("no chord activations"); no_chord_activations!(self, "no chords for key"); return; }; @@ -403,7 +402,6 @@ impl<'a, T> ChordsV2<'a, T> { .iter() .all(|pk| accumulated_presses.contains(pk)) { - dbg!("got exact chord match"); let ach = get_active_chord(cch, since, coord, relevant_release_found); let overflow = self.active_chords.push(ach); assert!(overflow.is_ok(), "active chords has room"); @@ -448,7 +446,7 @@ impl<'a, T> ChordsV2<'a, T> { } _ => {} } - self.ticks_until_next_state_change = dbg!(min_timeout.saturating_sub(since)); + self.ticks_until_next_state_change = min_timeout.saturating_sub(since); prev_count = count_possible; } if self.ticks_until_next_state_change == 0 || relevant_release_found { @@ -553,6 +551,6 @@ fn get_active_chord<'a, T>( } else { ActiveChordStatus::Unread }, - delay: dbg!(since), + delay: since, } } diff --git a/keyberon/src/key_code.rs b/keyberon/src/key_code.rs index 84412edc6..24ee730b0 100644 --- a/keyberon/src/key_code.rs +++ b/keyberon/src/key_code.rs @@ -817,6 +817,10 @@ pub enum KeyCode { K742, K743, K744, + MWU, + MWD, + MWL, + MWR, KeyMax, } diff --git a/keyberon/src/layout.rs b/keyberon/src/layout.rs index 6f0f23c81..bd8c4abb5 100644 --- a/keyberon/src/layout.rs +++ b/keyberon/src/layout.rs @@ -1631,7 +1631,7 @@ impl<'a, const C: usize, const R: usize, T: 'a + Copy + std::fmt::Debug> Layout< let waiting: WaitingState = WaitingState { coord, timeout: if self.quick_tap_hold_timeout { - dbg!(timeout.saturating_sub(delay)) + timeout.saturating_sub(delay) } else { *timeout }, @@ -2050,7 +2050,7 @@ mod test { ]], [[Trans, MultipleKeyCodes(&[LCtrl, Enter].as_slice())]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); layout.event(Press(0, 1)); @@ -2102,7 +2102,7 @@ mod test { ]], [[Trans, MultipleKeyCodes(&[LCtrl, Enter].as_slice())]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); layout.event(Press(0, 1)); @@ -2151,7 +2151,7 @@ mod test { tap_hold_interval: 0, }), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); layout.event(Press(0, 0)); @@ -2193,7 +2193,7 @@ mod test { }), k(Enter), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Press another key before timeout assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -2251,7 +2251,7 @@ mod test { }), k(Enter), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Press and release another key before timeout assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -2306,7 +2306,7 @@ mod test { tap_hold_interval: 0, }), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.quick_tap_hold_timeout = true; // Press and release another key before timeout @@ -2344,7 +2344,7 @@ mod test { [[MultipleActions(&[l(1), k(LShift)].as_slice()), k(F)]], [[Trans, k(E)]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); layout.event(Press(0, 0)); @@ -2364,7 +2364,7 @@ mod test { #[test] fn custom() { static LAYERS: Layers<1, 1, i32> = &[[[Action::Custom(42)]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); @@ -2391,7 +2391,7 @@ mod test { [[l(0), k(B)]], [[k(C), k(D)]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_eq!(0, layout.current_layer()); assert_keys(&[], layout.keycodes()); @@ -2494,7 +2494,7 @@ mod test { tap_hold_interval: 0, }), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[], layout.keycodes()); @@ -2568,7 +2568,7 @@ mod test { }), k(Enter), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // press and release the HT key, expect tap action assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -2631,7 +2631,7 @@ mod test { tap_hold_interval: 200, }), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // press and release the HT key, expect tap action assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -2743,7 +2743,7 @@ mod test { config: HoldTapConfig::Default, tap_hold_interval: 200, })]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // press and hold the HT key, expect hold action assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -2795,7 +2795,7 @@ mod test { tap_hold_interval: 200, }), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // press HT1, press HT2, release HT1 after hold timeout, release HT2, press HT2 layout.event(Press(0, 0)); @@ -2836,7 +2836,7 @@ mod test { k(A), k(B), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.oneshot.on_press_release_delay = 1; // Test: @@ -2948,7 +2948,7 @@ mod test { k(A), k(B), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.oneshot.on_press_release_delay = 1; // Test: @@ -3102,7 +3102,7 @@ mod test { k(A), k(B), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Test: // 1. press one-shot @@ -3259,7 +3259,7 @@ mod test { ]], [[k(A), k(B), k(C), k(D)]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.oneshot.on_press_release_delay = 1; layout.event(Press(0, 0)); @@ -3315,7 +3315,7 @@ mod test { ]], [[k(A), k(B), k(C)]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.oneshot.on_press_release_delay = 1; layout.event(Press(0, 0)); @@ -3383,7 +3383,7 @@ mod test { ], [k(B), k(C)], ]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Test: tap-dance first key, timeout layout.event(Press(0, 0)); @@ -3508,7 +3508,7 @@ mod test { ], [k(B), k(C)], ]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Test: tap-dance-eager first key layout.event(Press(0, 0)); @@ -3597,7 +3597,7 @@ mod test { ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 1)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -3652,7 +3652,7 @@ mod test { Chords(&GROUP), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 2)); // timeout on non-terminal chord for _ in 0..50 { @@ -3781,7 +3781,7 @@ mod test { Chords(&GROUP), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 2)); // timeout on non-terminal chord for _ in 0..50 { @@ -3833,7 +3833,7 @@ mod test { }; static LAYERS: Layers<2, 1> = &[[[Chords(&GROUP), Chords(&GROUP)]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.quick_tap_hold_timeout = true; layout.event(Press(0, 0)); layout.event(Press(0, 1)); @@ -3867,7 +3867,7 @@ mod test { }), k(Space), ]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -3908,7 +3908,7 @@ mod test { Layer(1), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // Press a key layout.event(Press(0, 0)); @@ -3998,7 +3998,7 @@ mod test { #[test] fn test_clear_multiple_keycodes() { static LAYERS: Layers<2, 1> = &[[[k(A), MultipleKeyCodes(&[LCtrl, Enter].as_slice())]]]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 1)); assert_eq!(CustomEvent::NoEvent, layout.tick()); assert_keys(&[LCtrl, Enter], layout.keycodes()); @@ -4018,7 +4018,7 @@ mod test { [[NoOp, NoOp, Layer(3), Trans]], [[NoOp, NoOp, NoOp, Trans]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); // change to layer 2 layout.event(Press(0, 0)); @@ -4049,7 +4049,7 @@ mod test { [[Layer(1), Trans]], [[NoOp, MultipleActions(&[Trans].as_slice())]], ]; - let mut layout = Layout::new_with_trans_action_settings(&DEFSRC_LAYER, &LAYERS, true, true); + let mut layout = Layout::new_with_trans_action_settings(&DEFSRC_LAYER, LAYERS, true, true); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4080,7 +4080,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4127,7 +4127,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4164,7 +4164,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4203,7 +4203,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4228,7 +4228,7 @@ mod test { [[NoOp, Layer(2), k(B)]], [[NoOp, NoOp, MultipleActions(&[Trans, k(X)].as_slice())]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4258,7 +4258,7 @@ mod test { [[NoOp, Layer(2), k(C), k(D)]], [[NoOp, NoOp, Chords(&GROUP), Chords(&GROUP)]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4293,7 +4293,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4322,7 +4322,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4387,7 +4387,7 @@ mod test { }), ]], ]; - let mut layout = Layout::new(&LAYERS); + let mut layout = Layout::new(LAYERS); layout.event(Press(0, 0)); assert_eq!(CustomEvent::NoEvent, layout.tick()); @@ -4428,7 +4428,7 @@ mod test { for &do_layer_switch in &[false, true] { let mut layout = Layout::new_with_trans_action_settings( &DEFSRC_LAYER, - &LAYERS, + LAYERS, trans_v2, delegate_to_1st, ); diff --git a/parser/src/cfg/is_a_button.rs b/parser/src/cfg/is_a_button.rs new file mode 100644 index 000000000..a5a753454 --- /dev/null +++ b/parser/src/cfg/is_a_button.rs @@ -0,0 +1,178 @@ +pub(crate) fn is_a_button(osc: u16) -> bool { + if cfg!(target_os = "windows") { + matches!(osc, 1..=6 | 256..) + } else { + osc >= 256 + } +} + +#[test] +fn mouse_inputs_most_care_about_are_considered_buttons() { + use crate::keys::{OsCode, OsCode::*}; + const MOUSE_INPUTS: &[OsCode] = &[ + MouseWheelUp, + MouseWheelDown, + MouseWheelLeft, + MouseWheelRight, + BTN_LEFT, + BTN_RIGHT, + BTN_MIDDLE, + BTN_SIDE, + BTN_EXTRA, + BTN_FORWARD, + BTN_BACK, + ]; + for input in MOUSE_INPUTS.iter().copied() { + println!("{input}"); + assert!(is_a_button(input.into())); + } +} + +#[test] +fn standard_keys_are_not_considered_buttons() { + use crate::keys::{OsCode, OsCode::*}; + const KEY_INPUTS: &[OsCode] = &[ + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_SEMICOLON, + KEY_SLASH, + KEY_GRAVE, + KEY_LEFTBRACE, + KEY_BACKSLASH, + KEY_RIGHTBRACE, + KEY_APOSTROPHE, + KEY_MINUS, + KEY_DOT, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_ESC, + KEY_TAB, + KEY_ENTER, + KEY_LEFTCTRL, + KEY_LEFTSHIFT, + KEY_COMMA, + KEY_RIGHTSHIFT, + KEY_KPASTERISK, + KEY_LEFTALT, + KEY_SPACE, + KEY_CAPSLOCK, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_NUMLOCK, + KEY_SCROLLLOCK, + KEY_KP0, + KEY_KP1, + KEY_KP2, + KEY_KP3, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPMINUS, + KEY_KPPLUS, + KEY_KPDOT, + KEY_KPENTER, + KEY_RIGHTCTRL, + KEY_KPSLASH, + KEY_RIGHTALT, + KEY_HOME, + KEY_UP, + KEY_PAGEUP, + KEY_LEFT, + KEY_RIGHT, + KEY_END, + KEY_DOWN, + KEY_PAGEDOWN, + KEY_INSERT, + KEY_DELETE, + KEY_MUTE, + KEY_VOLUMEDOWN, + KEY_VOLUMEUP, + KEY_PAUSE, + KEY_LEFTMETA, + KEY_RIGHTMETA, + KEY_COMPOSE, + KEY_BACK, + KEY_FORWARD, + KEY_NEXTSONG, + KEY_PLAYPAUSE, + KEY_PREVIOUSSONG, + KEY_STOP, + KEY_HOMEPAGE, + KEY_MAIL, + KEY_MEDIA, + KEY_REFRESH, + KEY_F13, + KEY_F14, + KEY_F15, + KEY_F16, + KEY_F17, + KEY_F18, + KEY_F19, + KEY_F20, + KEY_F21, + KEY_F22, + KEY_F23, + KEY_F24, + KEY_HANGEUL, + KEY_HANJA, + KEY_252, + KEY_102ND, + KEY_PLAY, + KEY_PRINT, + KEY_SEARCH, + KEY_RO, + KEY_HENKAN, + KEY_MUHENKAN, + ]; + for input in KEY_INPUTS.iter().copied() { + println!("{input}"); + assert!(!is_a_button(input.into())); + } +} diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index 778051a37..352eb7f54 100755 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -78,6 +78,9 @@ pub use fake_key::{FAKE_KEY_ROW, NORMAL_KEY_ROW}; mod os_dependent; use os_dependent::*; +mod is_a_button; +use is_a_button::*; + use crate::trie::Trie; use anyhow::anyhow; use std::cell::Cell; @@ -2936,8 +2939,8 @@ fn parse_layers( } } } - for layer_action in layers_cfg[layer_level][0].iter_mut() { - if *layer_action == Action::Trans && s.block_unmapped_keys { + for (osc, layer_action) in layers_cfg[layer_level][0].iter_mut().enumerate() { + if s.block_unmapped_keys && *layer_action == Action::Trans && !is_a_button(osc as u16) { *layer_action = Action::NoOp; } } diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 2cbd015bb..d42fd88f7 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -5,6 +5,8 @@ use kanata_keyberon::action::BooleanOperator::*; use std::sync::{Mutex, MutexGuard}; +mod ambiguous; + static CFG_PARSE_LOCK: Mutex<()> = Mutex::new(()); fn lock(lk: &Mutex) -> MutexGuard { @@ -17,7 +19,7 @@ fn lock(lk: &Mutex) -> MutexGuard { fn parse_cfg(cfg: &str) -> Result { let _lk = lock(&CFG_PARSE_LOCK); let mut s = ParserState::default(); - Ok(parse_cfg_raw_string( + parse_cfg_raw_string( cfg, &mut s, &PathBuf::from("test"), @@ -26,7 +28,7 @@ fn parse_cfg(cfg: &str) -> Result { }, DEF_LOCAL_KEYS, Err("env vars not implemented".into()), - )?) + ) } #[test] diff --git a/parser/src/cfg/tests/ambiguous.rs b/parser/src/cfg/tests/ambiguous.rs new file mode 100644 index 000000000..330ab84f5 --- /dev/null +++ b/parser/src/cfg/tests/ambiguous.rs @@ -0,0 +1,32 @@ +use super::*; + +#[test] +fn parse_double_dollar_var() { + let source = r#" +(defsrc) +(deflayer base) +(defvar $$num 100 + $num 99 + num not-a-number-or-key) +(defalias test + (movemouse-accel-up $$num $$$num $$num $$$num)) +"#; + parse_cfg(source) + .map_err(|e| eprintln!("{:?}", miette::Error::from(e))) + .expect("parses"); +} + +#[test] +fn parse_double_at_alias() { + let source = r#" +(defsrc) +(deflayer base) + ;; alias cannot be used in macro, @alias can +(defalias @alias 0 + alias (tap-hold 9 9 a b) + test (macro @@alias)) +"#; + parse_cfg(source) + .map_err(|e| eprintln!("{:?}", miette::Error::from(e))) + .expect("parses"); +} diff --git a/parser/src/keys/linux.rs b/parser/src/keys/linux.rs index 43ae238a0..dbec816f0 100644 --- a/parser/src/keys/linux.rs +++ b/parser/src/keys/linux.rs @@ -753,6 +753,10 @@ impl OsCode { 742 => Some(OsCode::BTN_TRIGGER_HAPPY39), 743 => Some(OsCode::BTN_TRIGGER_HAPPY40), 744 => Some(OsCode::BTN_MAX), + 745 => Some(OsCode::MouseWheelUp), + 746 => Some(OsCode::MouseWheelDown), + 747 => Some(OsCode::MouseWheelLeft), + 748 => Some(OsCode::MouseWheelRight), 767 => Some(OsCode::KEY_MAX), _ => None, } diff --git a/parser/src/keys/macos.rs b/parser/src/keys/macos.rs index b747dc321..3abdfc8e5 100644 --- a/parser/src/keys/macos.rs +++ b/parser/src/keys/macos.rs @@ -2011,6 +2011,10 @@ impl OsCode { 742 => Some(OsCode::BTN_TRIGGER_HAPPY39), 743 => Some(OsCode::BTN_TRIGGER_HAPPY40), 744 => Some(OsCode::BTN_MAX), + 745 => Some(OsCode::MouseWheelUp), + 746 => Some(OsCode::MouseWheelDown), + 747 => Some(OsCode::MouseWheelLeft), + 748 => Some(OsCode::MouseWheelRight), 767 => Some(OsCode::KEY_MAX), _ => None, } diff --git a/parser/src/keys/mappings.rs b/parser/src/keys/mappings.rs index b45e3f81c..904420836 100644 --- a/parser/src/keys/mappings.rs +++ b/parser/src/keys/mappings.rs @@ -851,6 +851,10 @@ fn haphazard_osc_to_kc_mappings(osc: OsCode) -> KeyCode { OsCode::BTN_TRIGGER_HAPPY38 => KeyCode::K741, OsCode::BTN_TRIGGER_HAPPY39 => KeyCode::K742, OsCode::BTN_TRIGGER_HAPPY40 => KeyCode::K743, + OsCode::MouseWheelUp => KeyCode::MWU, + OsCode::MouseWheelDown => KeyCode::MWD, + OsCode::MouseWheelLeft => KeyCode::MWL, + OsCode::MouseWheelRight => KeyCode::MWR, OsCode::BTN_MAX => KeyCode::K744, _ => KeyCode::No, } @@ -1351,6 +1355,10 @@ fn haphazard_kc_to_osc_mappings(kc: KeyCode) -> OsCode { KeyCode::K742 => OsCode::BTN_TRIGGER_HAPPY39, KeyCode::K743 => OsCode::BTN_TRIGGER_HAPPY40, KeyCode::K744 => OsCode::BTN_MAX, + KeyCode::MWU => OsCode::MouseWheelUp, + KeyCode::MWD => OsCode::MouseWheelDown, + KeyCode::MWL => OsCode::MouseWheelLeft, + KeyCode::MWR => OsCode::MouseWheelRight, _ => OsCode::KEY_UNKNOWN, } } diff --git a/parser/src/keys/mod.rs b/parser/src/keys/mod.rs index 3991c1645..492098dd2 100644 --- a/parser/src/keys/mod.rs +++ b/parser/src/keys/mod.rs @@ -305,13 +305,9 @@ pub fn str_to_oscode(s: &str) -> Option { "mfwd" | "mouseforward" | "🖰5" => OsCode::BTN_EXTRA, // NOTE: these are linux and interception-only due to missing implementation for LLHOOK - #[cfg(any(target_os = "linux", target_os = "unknown", feature = "interception_driver"))] "mwu" | "mousewheelup" => OsCode::MouseWheelUp, - #[cfg(any(target_os = "linux", target_os = "unknown", feature = "interception_driver"))] "mwd" | "mousewheeldown" => OsCode::MouseWheelDown, - #[cfg(any(target_os = "linux", target_os = "unknown", feature = "interception_driver"))] "mwl" | "mousewheelleft" => OsCode::MouseWheelLeft, - #[cfg(any(target_os = "linux", target_os = "unknown", feature = "interception_driver"))] "mwr" | "mousewheelright" => OsCode::MouseWheelRight, "hmpg" | "homepage" => OsCode::KEY_HOMEPAGE, diff --git a/parser/src/keys/windows.rs b/parser/src/keys/windows.rs index b7b3bec1a..652267254 100644 --- a/parser/src/keys/windows.rs +++ b/parser/src/keys/windows.rs @@ -425,11 +425,11 @@ impl OsCode { 269 => Some(OsCode::KEY_269), 270 => Some(OsCode::KEY_270), 271 => Some(OsCode::KEY_271), - 272 => Some(OsCode::BTN_LEFT), - 273 => Some(OsCode::BTN_RIGHT), - 274 => Some(OsCode::BTN_MIDDLE), - 275 => Some(OsCode::BTN_SIDE), - 276 => Some(OsCode::BTN_EXTRA), + 1 => Some(OsCode::BTN_LEFT), + 2 => Some(OsCode::BTN_RIGHT), + 4 => Some(OsCode::BTN_MIDDLE), + 5 => Some(OsCode::BTN_SIDE), + 6 => Some(OsCode::BTN_EXTRA), 277 => Some(OsCode::BTN_FORWARD), 278 => Some(OsCode::BTN_BACK), 279 => Some(OsCode::BTN_TASK), @@ -898,6 +898,10 @@ impl OsCode { 742 => Some(OsCode::BTN_TRIGGER_HAPPY39), 743 => Some(OsCode::BTN_TRIGGER_HAPPY40), 744 => Some(OsCode::BTN_MAX), + 745 => Some(OsCode::MouseWheelUp), + 746 => Some(OsCode::MouseWheelDown), + 747 => Some(OsCode::MouseWheelLeft), + 748 => Some(OsCode::MouseWheelRight), 767 => Some(OsCode::KEY_MAX), _ => None, } diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index 02ed69f60..98f52e7db 100755 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -48,6 +48,9 @@ mod macos; #[cfg(target_os = "macos")] use macos::*; +mod output_logic; +use output_logic::*; + #[cfg(target_os = "unknown")] mod unknown; #[cfg(target_os = "unknown")] @@ -185,51 +188,6 @@ pub struct Kanata { tcp_server_address: Option, } -// Functions to send keys except those that fall in the ignorable range. -// -// POTENTIAL PROBLEM - G-keys: -// Some keys are ignored because they are *probably* unused, -// or otherwise are probably in an unergonomic, far away key position, -// so if you're using kanata, you can now stop using those keys and -// do something better! -// -// I should probably let people turn this off if they really want to, -// but I don't like how that would require extra code. -// I'll defer to YAGNI and add docs, and let people report problems if -// they want a fix 🐝. -// -// The keys ignored are intentionally the upper numbers of KEY_MACROX. -// The Linux input-event-codes.h file mentions G1-G18 and S1-S30 -// as keys that might use these codes. -// -// Logitech still makes devices with G-keys -// but the S-keys are apparently from the -// "Microsoft SideWinder X6 Keyboard" -// which appears to no longer be in production. -// -// Thus based on my reading, 18 is the highest macro key -// that can be assumed to be used by devices still in production. -const KEY_IGNORE_MIN: u16 = 0x2a4; // KEY_MACRO21 -const KEY_IGNORE_MAX: u16 = 0x2ad; // KEY_MACRO30 -fn write_key(kb: &mut KbdOut, osc: OsCode, val: KeyValue) -> Result<(), std::io::Error> { - match u16::from(osc) { - KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), - _ => kb.write_key(osc, val), - } -} -fn press_key(kb: &mut KbdOut, osc: OsCode) -> Result<(), std::io::Error> { - match u16::from(osc) { - KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), - _ => kb.press_key(osc), - } -} -fn release_key(kb: &mut KbdOut, osc: OsCode) -> Result<(), std::io::Error> { - match u16::from(osc) { - KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), - _ => kb.release_key(osc), - } -} - #[derive(PartialEq, Clone, Copy)] pub enum Axis { Vertical, diff --git a/src/kanata/output_logic.rs b/src/kanata/output_logic.rs new file mode 100644 index 000000000..c22b62f24 --- /dev/null +++ b/src/kanata/output_logic.rs @@ -0,0 +1,93 @@ +use super::*; + +// Functions to send keys except those that fall in the ignorable range. +// And also have been repurposed to have additional logic to send mouse events, out of convenience. +// +// POTENTIAL PROBLEM - G-keys: +// Some keys are ignored because they are *probably* unused, +// or otherwise are probably in an unergonomic, far away key position, +// so if you're using kanata, you can now stop using those keys and +// do something better! +// +// I should probably let people turn this off if they really want to, +// but I don't like how that would require extra code. +// I'll defer to YAGNI and add docs, and let people report problems if +// they want a fix 🐝. +// +// The keys ignored are intentionally the upper numbers of KEY_MACROX. +// The Linux input-event-codes.h file mentions G1-G18 and S1-S30 +// as keys that might use these codes. +// +// Logitech still makes devices with G-keys +// but the S-keys are apparently from the +// "Microsoft SideWinder X6 Keyboard" +// which appears to no longer be in production. +// +// Thus based on my reading, 18 is the highest macro key +// that can be assumed to be used by devices still in production. +pub(super) const KEY_IGNORE_MIN: u16 = 0x2a4; // KEY_MACRO21 +pub(super) const KEY_IGNORE_MAX: u16 = 0x2ad; // KEY_MACRO30 +pub(super) fn write_key(kb: &mut KbdOut, osc: OsCode, val: KeyValue) -> Result<(), std::io::Error> { + match u16::from(osc) { + KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), + _ => kb.write_key(osc, val), + } +} +pub(super) fn press_key(kb: &mut KbdOut, osc: OsCode) -> Result<(), std::io::Error> { + use OsCode::*; + match u16::from(osc) { + KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), + _ => match osc { + BTN_LEFT | BTN_RIGHT | BTN_MIDDLE | BTN_SIDE | BTN_EXTRA => { + let btn = osc_to_btn(osc); + kb.click_btn(btn) + } + MouseWheelUp | MouseWheelDown | MouseWheelLeft | MouseWheelRight => { + let direction = osc_to_wheel_direction(osc); + kb.scroll(direction, HI_RES_SCROLL_UNITS_IN_LO_RES) + } + _ => kb.press_key(osc), + }, + } +} +pub(super) fn release_key(kb: &mut KbdOut, osc: OsCode) -> Result<(), std::io::Error> { + use OsCode::*; + match u16::from(osc) { + KEY_IGNORE_MIN..=KEY_IGNORE_MAX => Ok(()), + _ => match osc { + BTN_LEFT | BTN_RIGHT | BTN_MIDDLE | BTN_SIDE | BTN_EXTRA => { + let btn = osc_to_btn(osc); + kb.release_btn(btn) + } + MouseWheelUp | MouseWheelDown | MouseWheelLeft | MouseWheelRight => { + // no-op: these are handled as scroll events in the press but scroll has no notion + // of release. + Ok(()) + } + _ => kb.release_key(osc), + }, + } +} +fn osc_to_btn(osc: OsCode) -> Btn { + use Btn::*; + use OsCode::*; + match osc { + BTN_LEFT => Left, + BTN_RIGHT => Right, + BTN_MIDDLE => Mid, + BTN_EXTRA => Forward, + BTN_SIDE => Backward, + _ => unreachable!("called osc_to_btn with bad value {osc}"), + } +} +fn osc_to_wheel_direction(osc: OsCode) -> MWheelDirection { + use MWheelDirection::*; + use OsCode::*; + match osc { + MouseWheelUp => Up, + MouseWheelDown => Down, + MouseWheelLeft => Left, + MouseWheelRight => Right, + _ => unreachable!("called osc_to_wheel_direction with bad value {osc}"), + } +} diff --git a/src/oskbd/simulated.rs b/src/oskbd/simulated.rs index 42d9f7820..4913056f1 100644 --- a/src/oskbd/simulated.rs +++ b/src/oskbd/simulated.rs @@ -408,6 +408,7 @@ impl KbdOut { Ok(()) } pub fn scroll(&mut self, direction: MWheelDirection, distance: u16) -> Result<(), io::Error> { + self.log.scroll(direction, distance); self.outputs .push(format!("scroll:{direction:?},{distance:?}")); Ok(()) diff --git a/src/tests/sim_tests/block_keys_tests.rs b/src/tests/sim_tests/block_keys_tests.rs new file mode 100644 index 000000000..24f41bac4 --- /dev/null +++ b/src/tests/sim_tests/block_keys_tests.rs @@ -0,0 +1,35 @@ +use super::*; + +#[test] +fn block_does_not_block_buttons() { + let result = simulate( + "(defcfg process-unmapped-keys yes + block-unmapped-keys yes) + (defsrc) + (deflayer base)", + "d:mlft d:mrgt d:mmid d:mbck d:mfwd t:10 d:f1 + u:mlft u:mrgt u:mmid u:mbck u:mfwd t:10 u:f1", + ); + assert_eq!( + "out🖰:↓Left\nt:1ms\nout🖰:↓Right\nt:1ms\nout🖰:↓Mid\nt:1ms\nout🖰:↓Backward\n\ + t:1ms\nout🖰:↓Forward\nt:7ms\nout🖰:↑Left\nt:1ms\nout🖰:↑Right\nt:1ms\nout🖰:↑Mid\n\ + t:1ms\nout🖰:↑Backward\nt:1ms\nout🖰:↑Forward", + result + ); +} + +#[test] +fn block_does_not_block_wheel() { + let result = simulate( + "(defcfg process-unmapped-keys yes + block-unmapped-keys yes) + (defsrc) + (deflayer base)", + "d:mwu d:mwd d:mwl d:mwr t:10 d:f1 + u:mwu u:mwd u:mwl u:mwr t:10 u:f1", + ); + assert_eq!( + "scroll:Up,120\nt:1ms\nscroll:Down,120\nt:1ms\nscroll:Left,120\nt:1ms\nscroll:Right,120", + result + ); +} diff --git a/src/tests/sim_tests/mod.rs b/src/tests/sim_tests/mod.rs index 5c8242d4a..dd5f3ad4a 100644 --- a/src/tests/sim_tests/mod.rs +++ b/src/tests/sim_tests/mod.rs @@ -10,6 +10,7 @@ use kanata_state_machine::{ str_to_oscode, Kanata, }; +mod block_keys_tests; mod chord_sim_tests; mod layer_sim_tests; mod seq_sim_tests;