Add a fast-forward command

This commit is contained in:
2025-03-24 23:22:47 -04:00
parent 4a3385f04c
commit caf3a9426e
8 changed files with 325 additions and 145 deletions
+133 -30
View File
@@ -1,13 +1,13 @@
use std::{
cmp::Ordering,
collections::{HashMap, HashSet, hash_map::Entry},
collections::{HashMap, hash_map::Entry},
fmt::Display,
str::FromStr,
sync::{Arc, Mutex, RwLock},
};
use anyhow::anyhow;
use egui::{Key, KeyboardShortcut, Modifiers};
use egui::{Event, Key, KeyboardShortcut, Modifiers};
use gilrs::{Axis, Button, Gamepad, GamepadId, ev::Code};
use serde::{Deserialize, Serialize};
use winit::keyboard::{KeyCode, PhysicalKey};
@@ -468,19 +468,21 @@ pub enum Command {
OpenRom,
Quit,
FrameAdvance,
FastForward(u32),
Reset,
PauseResume,
// if you update this, update Command::all and add a default
}
impl Command {
pub fn all() -> [Self; 5] {
pub fn all() -> [Self; 6] {
[
Self::OpenRom,
Self::Quit,
Self::PauseResume,
Self::Reset,
Self::FrameAdvance,
Self::FastForward(0),
]
}
@@ -491,6 +493,7 @@ impl Command {
Self::PauseResume => "Pause/Resume",
Self::Reset => "Reset",
Self::FrameAdvance => "Frame Advance",
Self::FastForward(_) => "Fast Forward",
}
}
}
@@ -532,6 +535,10 @@ impl Default for Shortcuts {
Command::FrameAdvance,
KeyboardShortcut::new(Modifiers::NONE, Key::F6),
);
shortcuts.set(
Command::FastForward(0),
KeyboardShortcut::new(Modifiers::NONE, Key::Space),
);
shortcuts
}
}
@@ -557,13 +564,11 @@ impl Shortcuts {
}
}
fn save(&self) -> PersistedShortcuts {
let mut shortcuts = PersistedShortcuts { shortcuts: vec![] };
fn save(&self, saved: &mut PersistedSettings) {
for command in Command::all() {
let shortcut = self.by_command.get(&command).copied();
shortcuts.shortcuts.push((command, shortcut));
saved.shortcuts.push((command, shortcut));
}
shortcuts
}
}
@@ -589,52 +594,123 @@ fn specificity(modifiers: egui::Modifiers) -> usize {
mods
}
#[derive(Serialize, Deserialize)]
struct PersistedShortcuts {
#[derive(Serialize, Deserialize, Default)]
struct PersistedSettings {
shortcuts: Vec<(Command, Option<KeyboardShortcut>)>,
#[serde(default)]
ff_settings: FastForwardSettings,
}
#[derive(Default, Clone)]
struct ShortcutState {
ff_toggled: bool,
}
#[derive(Default)]
struct Settings {
shortcuts: Shortcuts,
ff_settings: FastForwardSettings,
state: ShortcutState,
}
impl Settings {
fn save(&self) -> PersistedSettings {
let mut saved = PersistedSettings {
shortcuts: vec![],
ff_settings: self.ff_settings.clone(),
};
self.shortcuts.save(&mut saved);
saved
}
}
#[derive(Clone)]
pub struct ShortcutProvider {
persistence: Persistence,
shortcuts: Arc<Mutex<Shortcuts>>,
settings: Arc<Mutex<Settings>>,
}
impl ShortcutProvider {
pub fn new(persistence: Persistence) -> Self {
let mut shortcuts = Shortcuts::default();
if let Ok(saved) = persistence.load_config::<PersistedShortcuts>("shortcuts") {
let mut settings = Settings::default();
if let Ok(saved) = persistence.load_config::<PersistedSettings>("shortcuts") {
for (command, shortcut) in saved.shortcuts {
if let Some(shortcut) = shortcut {
shortcuts.set(command, shortcut);
settings.shortcuts.set(command, shortcut);
} else {
shortcuts.unset(command);
settings.shortcuts.unset(command);
}
}
}
settings.ff_settings = saved.ff_settings;
};
Self {
persistence,
shortcuts: Arc::new(Mutex::new(shortcuts)),
settings: Arc::new(Mutex::new(settings)),
}
}
pub fn shortcut_for(&self, command: Command) -> Option<KeyboardShortcut> {
let lock = self.shortcuts.lock().unwrap();
lock.by_command.get(&command).copied()
let lock = self.settings.lock().unwrap();
lock.shortcuts.by_command.get(&command).copied()
}
pub fn consume_all(&self, input: &mut egui::InputState) -> HashSet<Command> {
let lock = self.shortcuts.lock().unwrap();
lock.all
.iter()
.filter_map(|(command, shortcut)| input.consume_shortcut(shortcut).then_some(*command))
.collect()
pub fn ff_settings(&self) -> FastForwardSettings {
let lock = self.settings.lock().unwrap();
lock.ff_settings.clone()
}
pub fn consume_all(&self, input: &mut egui::InputState) -> Vec<Command> {
let mut lock = self.settings.lock().unwrap();
let mut state = lock.state.clone();
let mut consumed = vec![];
for (command, shortcut) in &lock.shortcuts.all {
input.events.retain(|event| {
let Event::Key {
key,
pressed,
repeat,
modifiers,
..
} = event
else {
return true;
};
if shortcut.logical_key != *key || !shortcut.modifiers.contains(*modifiers) {
return true;
}
if matches!(command, Command::FastForward(_)) {
if *repeat {
return true;
}
let sped_up = if lock.ff_settings.toggle {
if !*pressed {
return true;
}
state.ff_toggled = !state.ff_toggled;
state.ff_toggled
} else {
*pressed
};
let speed = if sped_up { lock.ff_settings.speed } else { 1 };
consumed.push(Command::FastForward(speed));
false
} else {
if !*pressed {
return true;
}
consumed.push(*command);
false
}
});
}
lock.state = state;
consumed
}
pub fn set(&self, command: Command, shortcut: KeyboardShortcut) {
let updated = {
let mut lock = self.shortcuts.lock().unwrap();
lock.set(command, shortcut);
let mut lock = self.settings.lock().unwrap();
lock.shortcuts.set(command, shortcut);
lock.save()
};
let _ = self.persistence.save_config("shortcuts", &updated);
@@ -642,8 +718,20 @@ impl ShortcutProvider {
pub fn unset(&self, command: Command) {
let updated = {
let mut lock = self.shortcuts.lock().unwrap();
lock.unset(command);
let mut lock = self.settings.lock().unwrap();
lock.shortcuts.unset(command);
lock.save()
};
let _ = self.persistence.save_config("shortcuts", &updated);
}
pub fn update_ff_settings(&self, ff_settings: FastForwardSettings) {
let updated = {
let mut lock = self.settings.lock().unwrap();
lock.ff_settings = ff_settings;
if !lock.ff_settings.toggle {
lock.state.ff_toggled = false;
}
lock.save()
};
let _ = self.persistence.save_config("shortcuts", &updated);
@@ -651,10 +739,25 @@ impl ShortcutProvider {
pub fn reset(&self) {
let updated = {
let mut lock = self.shortcuts.lock().unwrap();
*lock = Shortcuts::default();
let mut lock = self.settings.lock().unwrap();
*lock = Settings::default();
lock.save()
};
let _ = self.persistence.save_config("shortcuts", &updated);
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct FastForwardSettings {
pub toggle: bool,
pub speed: u32,
}
impl Default for FastForwardSettings {
fn default() -> Self {
Self {
toggle: false,
speed: 10,
}
}
}