From fe6b2e3c412db9b804c38fc5ac4ba697ed831f7b Mon Sep 17 00:00:00 2001 From: C J Silverio Date: Thu, 18 Jan 2024 23:14:20 -0800 Subject: [PATCH] One step closer to being acceptable. Also, we now do absolutely nothing if an incoming key does not map to any hotkey at all, which is the behavior in the main branch. And also correct behavior. --- src/controller/control.rs | 89 ++++++++++-------- src/controller/keys.rs | 179 +++++++++++++++++++------------------ src/controller/settings.rs | 9 +- 3 files changed, 151 insertions(+), 126 deletions(-) diff --git a/src/controller/control.rs b/src/controller/control.rs index f32c7eb0..2efc5678 100644 --- a/src/controller/control.rs +++ b/src/controller/control.rs @@ -314,6 +314,10 @@ impl Controller { /// Returns an enum indicating what we did in response, so that the C++ layer can /// start a tick timer for cycle delay. pub fn handle_key_event(&mut self, key: u32, button: &ButtonEvent) -> KeyEventResponse { + if matches!(Hotkey::from(key), Hotkey::None) { + return KeyEventResponse::default(); + } + // This call starts and stops long-press timers as well. // It returns nothing if the handler should take no further action. let Some(tracked) = self.create_or_update_tracked(key, button, false) else { @@ -332,20 +336,19 @@ impl Controller { } let options = settings(); - // if the hud is NOT visible, we show it briefly before acting. - if showBriefly() { + let requested_action = tracked.action(); + // if the hud is NOT visible, we show it briefly before cycling. + if !matches!(requested_action, Action::RefreshLayout | Action::ShowHide) && showBriefly() { return KeyEventResponse::handled(); } - let hotkey = tracked.shortcut_for(); - - match hotkey { - Hotkey::Power => self.handle_cycle_power(), - Hotkey::Utility => self.handle_cycle_utility(), - Hotkey::Left => self.handle_cycle_left(tracked), - Hotkey::Right => self.handle_cycle_right(tracked), - Hotkey::Equipment => self.handle_cycle_equipset(tracked), - Hotkey::Activate => { + match requested_action { + Action::Power => self.handle_cycle_power(), + Action::Utility => self.handle_cycle_utility(), + Action::Left => self.handle_cycle_left(tracked), + Action::Right => self.handle_cycle_right(tracked), + Action::Equipment => self.handle_cycle_equipset(tracked), + Action::Activate => { let activation_method = options.utility_activation_method(); if matches!(activation_method, ActivationMethod::Hotkey) { self.use_utility_item() @@ -353,7 +356,7 @@ impl Controller { KeyEventResponse::default() } } - Hotkey::UnequipHands => { + Action::UnequipHands => { let unarmed_method = options.unequip_method(); if matches!(unarmed_method, UnarmedMethod::Hotkey) { self.disarm_player() @@ -361,11 +364,11 @@ impl Controller { KeyEventResponse::default() } } - Hotkey::Refresh => { + Action::RefreshLayout => { Layout::refresh(); KeyEventResponse::handled() } - Hotkey::ShowHide => { + Action::ShowHide => { if !options.autofade() { self.cycles.toggle_hud(); } @@ -383,7 +386,7 @@ impl Controller { // We don't need to worry about long presses here: those are handled by timers. ActivationMethod::LongPress => {} ActivationMethod::Modifier => { - let hotkey = self.tracked_state_for(&Hotkey::CycleModifier); + let hotkey = self.tracked_modifier(&Modifier::Cycle); if hotkey.is_pressed() { return self.advance_cycle_power(); } @@ -428,7 +431,7 @@ impl Controller { options.utility_activation_method(), ActivationMethod::Modifier ) { - let modifier = self.tracked_state_for(&Hotkey::ActivateModifier); + let modifier = self.tracked_modifier(&Modifier::Activate); if modifier.is_pressed() { log::debug!("activating utilities/consumables"); return self.use_utility_item(); @@ -441,7 +444,7 @@ impl Controller { return self.advance_cycle_utilities(); } if matches!(cycle_method, ActivationMethod::Modifier) { - let modifier = self.tracked_state_for(&Hotkey::CycleModifier); + let modifier = self.tracked_modifier(&Modifier::Cycle); if modifier.is_pressed() { log::debug!("cycling utilities/consumables"); return self.advance_cycle_utilities(); @@ -486,7 +489,7 @@ impl Controller { let unequip_requested = match options.unequip_method() { UnarmedMethod::LongPress => is_long_press, UnarmedMethod::Modifier => { - let unequipmod = self.tracked_state_for(&Hotkey::UnequipModifier); + let unequipmod = self.tracked_modifier(&Modifier::Unequip); unequipmod.is_pressed() } UnarmedMethod::None => false, @@ -506,7 +509,7 @@ impl Controller { ActivationMethod::Hotkey => true, ActivationMethod::LongPress => is_long_press, ActivationMethod::Modifier => { - let cyclemod = self.tracked_state_for(&Hotkey::CycleModifier); + let cyclemod = self.tracked_modifier(&Modifier::Cycle); cyclemod.is_pressed() } }; @@ -840,7 +843,7 @@ impl Controller { return; } - let tracked = self.tracked_state_for(&Hotkey::from(&which)); + let tracked = self.tracked_key(&Hotkey::from(&which)); if tracked.is_pressed() { // Here's the reasoning. The player might be mid-long-press, in // which case we do not want to interrupt by equipping. The player @@ -1503,7 +1506,7 @@ impl Controller { tracked.is_long_press() } ActivationMethod::Modifier => { - let modkey = self.tracked_state_for(&Hotkey::MenuModifier); + let modkey = self.tracked_modifier(&Modifier::Menu); log::debug!( "checking for menu modifier key pressed in menu; {modkey:?} => {}", modkey.is_pressed() @@ -1568,7 +1571,7 @@ impl Controller { in_menu: bool, ) -> Option { let mut return_the_key = true; - let tracking_long_presses = !in_menu; // && settings().start_long_press_timer(tracked.hotkeys); + let should_start_timer = !in_menu && settings().should_start_long_press_timer(key); let tracked = if let Some(previous) = self.tracked_keys.get_mut(&key) { // We have seen this key before. @@ -1576,7 +1579,7 @@ impl Controller { // We ask this question before we update the tracking data. if matches!(previous.state, KeyState::Pressed) && previous.is_long_press() - && tracking_long_presses + && should_start_timer { return_the_key = false; } @@ -1590,23 +1593,23 @@ impl Controller { }; // long press timers; not started if we're in a menu - if tracking_long_presses { - let shortcut = tracked.shortcut_for(); + if should_start_timer { + let action = tracked.action(); if matches!(tracked.state, KeyState::Down) { let duration = settings().long_press_ms(); - match shortcut { - Hotkey::Power => startTimer(Action::LongPressPower, duration), - Hotkey::Utility => startTimer(Action::LongPressUtility, duration), - Hotkey::Left => startTimer(Action::LongPressLeft, duration), - Hotkey::Right => startTimer(Action::LongPressRight, duration), + match action { + Action::Power => startTimer(Action::LongPressPower, duration), + Action::Utility => startTimer(Action::LongPressUtility, duration), + Action::Left => startTimer(Action::LongPressLeft, duration), + Action::Right => startTimer(Action::LongPressRight, duration), _ => {} } } else if matches!(tracked.state, KeyState::Up) { - match shortcut { - Hotkey::Power => stopTimer(Action::LongPressPower), - Hotkey::Utility => stopTimer(Action::LongPressUtility), - Hotkey::Left => stopTimer(Action::LongPressLeft), - Hotkey::Right => stopTimer(Action::LongPressRight), + match action { + Action::Power => stopTimer(Action::LongPressPower), + Action::Utility => stopTimer(Action::LongPressUtility), + Action::Left => stopTimer(Action::LongPressLeft), + Action::Right => stopTimer(Action::LongPressRight), _ => {} } } @@ -1619,7 +1622,19 @@ impl Controller { } } - fn tracked_state_for(&self, hotkey: &Hotkey) -> TrackedKey { + fn tracked_modifier(&self, modifier: &Modifier) -> TrackedKey { + let key = modifier.key_for(); + if key < 0 { + return TrackedKey::default(); + } + if let Some(tracked) = self.tracked_keys.get(&key.unsigned_abs()) { + tracked.clone() + } else { + TrackedKey::default() + } + } + + fn tracked_key(&self, hotkey: &Hotkey) -> TrackedKey { let key = hotkey.key_for(); if key < 0 { return TrackedKey::default(); @@ -1643,7 +1658,7 @@ impl Controller { ActivationMethod::LongPress => {} ActivationMethod::Hotkey => return self.advance_cycle_equipset(), ActivationMethod::Modifier => { - let modifier = self.tracked_state_for(&Hotkey::CycleModifier); + let modifier = self.tracked_modifier(&Modifier::Cycle); if modifier.is_pressed() { return self.advance_cycle_equipset(); } diff --git a/src/controller/keys.rs b/src/controller/keys.rs index 7f48a72c..0aa14292 100644 --- a/src/controller/keys.rs +++ b/src/controller/keys.rs @@ -4,7 +4,7 @@ use std::fmt::Display; use std::time::{Duration, Instant}; -use enumset::{enum_set, EnumSet, EnumSetType}; +use enumset::{EnumSet, EnumSetType}; use eyre::eyre; use strum::Display; @@ -20,7 +20,27 @@ pub enum CycleSlot { Utility, } -#[derive(Debug, Hash, Default, Display, EnumSetType)] +#[derive(Debug, Hash, Display, EnumSetType)] +pub enum Modifier { + Unequip, + Cycle, + Activate, + Menu, +} + +impl Modifier { + pub fn key_for(&self) -> i32 { + let options = settings(); + match self { + Modifier::Unequip => options.unequip_modifier(), + Modifier::Cycle => options.cycle_modifier(), + Modifier::Activate => options.activate_modifier(), + Modifier::Menu => options.menu_modifier(), + } + } +} + +#[derive(Debug, Hash, Default, Display, Clone, PartialEq, Eq)] pub enum Hotkey { Power, Utility, @@ -31,22 +51,58 @@ pub enum Hotkey { UnequipHands, Refresh, ShowHide, - UnequipModifier, - CycleModifier, - ActivateModifier, - MenuModifier, + Modifier(EnumSet), // for overloaded modifiers #[default] None, } -const CYCLE_KEYS: EnumSet = - enum_set!(Hotkey::Left | Hotkey::Power | Hotkey::Right | Hotkey::Utility | Hotkey::Equipment); -const MODIFIER_KEYS: EnumSet = enum_set!( - Hotkey::ActivateModifier - | Hotkey::CycleModifier - | Hotkey::MenuModifier - | Hotkey::UnequipModifier -); +impl From for Hotkey { + fn from(v: u32) -> Self { + let options = settings(); + let mut set: EnumSet = EnumSet::new(); + + if options.activate_modifier().is_positive() + && v == options.activate_modifier().unsigned_abs() + { + set.insert(Modifier::Activate); + } + if options.cycle_modifier().is_positive() && v == options.cycle_modifier().unsigned_abs() { + set.insert(Modifier::Cycle); + } + if options.unequip_modifier().is_positive() + && v == options.unequip_modifier().unsigned_abs() + { + set.insert(Modifier::Unequip); + } + if options.menu_modifier().is_positive() && v == options.menu_modifier().unsigned_abs() { + set.insert(Modifier::Menu); + } + + if !set.is_empty() { + Hotkey::Modifier(set) + } else if v == options.power() { + Hotkey::Power + } else if v == options.utility() { + Hotkey::Utility + } else if v == options.left() { + Hotkey::Left + } else if v == options.right() { + Hotkey::Right + } else if v == options.equipset() as u32 { + Hotkey::Equipment + } else if v == options.refresh_layout() { + Hotkey::Refresh + } else if v == options.showhide() { + Hotkey::ShowHide + } else if v == options.activate() { + Hotkey::Activate + } else if v == options.unequip_hotkey() as u32 { + Hotkey::UnequipHands + } else { + Hotkey::None + } + } +} impl Hotkey { pub fn key_for(&self) -> i32 { @@ -62,71 +118,18 @@ impl Hotkey { Hotkey::UnequipHands => options.unequip_hotkey() as i32, Hotkey::Refresh => options.refresh_layout() as i32, Hotkey::ShowHide => options.showhide() as i32, - Hotkey::UnequipModifier => options.unequip_modifier(), - Hotkey::CycleModifier => options.cycle_modifier(), - Hotkey::ActivateModifier => options.activate_modifier(), - Hotkey::MenuModifier => options.menu_modifier(), + Hotkey::Modifier(meanings) => { + // This is going to map to a single re-used key. + if let Some(meaning) = meanings.iter().find_map(Some) { + meaning.key_for() + } else { + -1 + } + } Hotkey::None => -1, } } - pub fn relevant_shortcuts(v: u32) -> EnumSet { - let settings = settings(); - let mut set: EnumSet = EnumSet::new(); - - if v == settings.power() { - set.insert(Hotkey::Power); - } - if v == settings.utility() { - set.insert(Hotkey::Utility); - } - if v == settings.left() { - set.insert(Hotkey::Left); - } - if v == settings.right() { - set.insert(Hotkey::Right); - } - if v == settings.equipset() as u32 { - set.insert(Hotkey::Equipment); - } - if v == settings.refresh_layout() { - set.insert(Hotkey::Refresh); - } - if v == settings.showhide() { - set.insert(Hotkey::ShowHide); - } - if v == settings.activate() { - set.insert(Hotkey::Activate); - } - - if v == settings.unequip_hotkey() as u32 { - set.insert(Hotkey::UnequipHands); - } - - if settings.activate_modifier().is_positive() - && v == settings.activate_modifier().unsigned_abs() - { - set.insert(Hotkey::ActivateModifier); - } - - if settings.cycle_modifier().is_positive() && v == settings.cycle_modifier().unsigned_abs() - { - set.insert(Hotkey::CycleModifier); - } - - if settings.unequip_modifier().is_positive() - && v == settings.unequip_modifier().unsigned_abs() - { - set.insert(Hotkey::UnequipModifier); - } - - if settings.menu_modifier().is_positive() && v == settings.menu_modifier().unsigned_abs() { - set.insert(Hotkey::MenuModifier); - } - - set - } - pub fn long_press_action(&self) -> RequestedAction { let settings = settings(); let advance = matches!(settings.cycle_advance_method(), ActivationMethod::LongPress); @@ -173,6 +176,7 @@ impl Hotkey { } } +// why does this exist? impl From<&CycleSlot> for Hotkey { fn from(value: &CycleSlot) -> Self { match *value { @@ -221,12 +225,13 @@ impl From<&ButtonEvent> for KeyState { } } +/// An input event tracked by the controller. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct TrackedKey { - /// The code for the pressed key being tracked. + /// The code for the pressed input widget being tracked. pub key: u32, /// The UX-meaningful hotkey actions represented by this key event. - hotkeys: EnumSet, + hotkey: Hotkey, /// The current statue of the key. pub state: KeyState, /// When we started tracking this key. @@ -237,30 +242,33 @@ impl TrackedKey { pub fn new(key: u32, event: &ButtonEvent) -> Self { let press_start = Some(Instant::now()); let state = KeyState::from(event); - let hotkeys = Hotkey::relevant_shortcuts(key); + let hotkey = Hotkey::from(key); Self { key, - hotkeys, + hotkey, state, press_start, } } - pub fn shortcut_for(&self) -> Hotkey { - self.hotkeys.iter().find_map(Some).unwrap_or_default() + pub fn action(&self) -> Action { + Action::from(&self.hotkey) } pub fn ignore(&self) -> bool { - self.hotkeys.contains(Hotkey::None) || self.hotkeys.is_empty() + matches!(self.hotkey, Hotkey::None) } pub fn is_modifier(&self) -> bool { - self.hotkeys.is_subset(MODIFIER_KEYS) + matches!(self.hotkey, Hotkey::Modifier(_)) } pub fn is_cycle_key(&self) -> bool { - self.hotkeys.is_subset(CYCLE_KEYS) + matches!( + self.hotkey, + Hotkey::Left | Hotkey::Power | Hotkey::Right | Hotkey::Utility | Hotkey::Equipment + ) } pub fn update(&mut self, event: &ButtonEvent) { @@ -302,7 +310,7 @@ impl Default for TrackedKey { fn default() -> Self { Self { key: 0, - hotkeys: enum_set!(Hotkey::None), + hotkey: Hotkey::None, state: KeyState::Up, press_start: None, } @@ -325,6 +333,7 @@ impl From<&Hotkey> for Action { Hotkey::Activate => Action::Activate, Hotkey::Refresh => Action::RefreshLayout, Hotkey::ShowHide => Action::ShowHide, + Hotkey::Equipment => Action::Equipment, _ => Action::None, } } diff --git a/src/controller/settings.rs b/src/controller/settings.rs index c4a06b45..5cc0593e 100644 --- a/src/controller/settings.rs +++ b/src/controller/settings.rs @@ -318,9 +318,10 @@ impl UserSettings { } } - pub fn start_long_press_timer(&self, key: &Hotkey) -> bool { - let is_hand_cycle = matches!(key, Hotkey::Left | Hotkey::Right); - let can_be_unequipped = matches!(key, Hotkey::Left | Hotkey::Power | Hotkey::Right); + pub fn should_start_long_press_timer(&self, key: u32) -> bool { + let hotkey = Hotkey::from(key); + let is_hand_cycle = matches!(hotkey, Hotkey::Left | Hotkey::Right); + let can_be_unequipped = matches!(hotkey, Hotkey::Left | Hotkey::Power | Hotkey::Right); // These three should be mutually exclusive, so order shouldn't matter. // "should" ha ha ha @@ -329,7 +330,7 @@ impl UserSettings { } if matches!(self.how_to_activate, ActivationMethod::LongPress) && matches!( - key, + hotkey, Hotkey::Left | Hotkey::Power | Hotkey::Right | Hotkey::Utility ) {