Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src-tauri/src/point_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,27 @@ pub enum KeyboardLayout {
CommonLetters,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum MouseRepeatStopEdge {
Press,
#[default]
Release,
}
impl MouseRepeatStopEdge {
pub fn instruction(self) -> &'static str {
match self {
Self::Press => "Press a switch to stop",
Self::Release => "Press and release a switch to stop",
}
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct Config {
pub control_mode: ControlMode,
pub mouse_repeat_stop_edge: MouseRepeatStopEdge,
#[serde(deserialize_with = "crate::scan_preferences::deserialize_preferences")]
pub scan_preferences: crate::scan_preferences::Preferences,
pub word_prediction: bool,
Expand Down Expand Up @@ -58,6 +75,7 @@ impl Default for Config {
fn default() -> Self {
Self {
control_mode: ControlMode::Point,
mouse_repeat_stop_edge: MouseRepeatStopEdge::Release,
scan_preferences: Default::default(),
word_prediction: true,
keyboard_layout: KeyboardLayout::Qwerty,
Expand Down Expand Up @@ -128,6 +146,7 @@ impl Config {
pub fn point(&self) -> PointSettings {
PointSettings {
control_mode: self.control_mode,
mouse_repeat_stop_edge: self.mouse_repeat_stop_edge,
scan: self.resolved(crate::scan_preferences::Area::Point),
menu_scan: self.resolved(crate::scan_preferences::Area::Menu),
keyboard_scan: self.resolved(crate::scan_preferences::Area::Keyboard),
Expand All @@ -154,6 +173,7 @@ impl Config {
#[derive(Clone)]
pub struct PointSettings {
pub control_mode: ControlMode,
pub mouse_repeat_stop_edge: MouseRepeatStopEdge,
pub scan: crate::scan_preferences::Resolved,
pub menu_scan: crate::scan_preferences::Resolved,
pub keyboard_scan: crate::scan_preferences::Resolved,
Expand Down Expand Up @@ -1133,6 +1153,7 @@ mod tests {
json["autoSelectDelayMs"] = serde_json::json!(1000);
json["scannerColor"] = serde_json::json!("blue");
json["controlMode"] = serde_json::json!("point");
json["mouseRepeatStopEdge"] = serde_json::json!("release");
json["wordPrediction"] = serde_json::json!(true);
json["keyboardLayout"] = serde_json::json!("qwerty");
json["enhancedWordPrediction"] = serde_json::json!(false);
Expand Down Expand Up @@ -1182,6 +1203,23 @@ mod tests {
.is_err());
}
#[test]
fn mouse_repeat_stop_edge_is_saved_and_older_settings_default_to_release() {
let older: Config = serde_json::from_str(r#"{"controlMode":"mouse"}"#).unwrap();
assert_eq!(older.mouse_repeat_stop_edge, MouseRepeatStopEdge::Release);
for (value, edge) in [
("press", MouseRepeatStopEdge::Press),
("release", MouseRepeatStopEdge::Release),
] {
let config: Config =
serde_json::from_value(serde_json::json!({"mouseRepeatStopEdge":value})).unwrap();
assert_eq!(config.point().mouse_repeat_stop_edge, edge);
let saved = serde_json::to_value(&config).unwrap();
assert_eq!(saved["mouseRepeatStopEdge"], value);
assert_eq!(serde_json::from_value::<Config>(saved).unwrap(), config);
}
assert!(serde_json::from_str::<Config>(r#"{"mouseRepeatStopEdge":"unknown"}"#).is_err());
}
#[test]
fn keyboard_layout_is_additive_and_uses_stable_saved_names() {
let older: Config = serde_json::from_str(r#"{"wordPrediction":false}"#).unwrap();
assert_eq!(older.keyboard_layout, KeyboardLayout::Qwerty);
Expand Down
35 changes: 20 additions & 15 deletions src-tauri/src/point_workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ impl Workflow {
),
keyboard_layout_pending: false,
keyboard_area: screen,
mouse: crate::scan_mouse::MousePanel::new(mouse_options, 1, 100),
mouse: crate::scan_mouse::MousePanel::new(mouse_options, 1, 100)
.with_repeat_stop_edge(config.mouse_repeat_stop_edge),
mouse_area: screen,
dock: Default::default(),
pointer: None,
Expand Down Expand Up @@ -199,7 +200,8 @@ impl Workflow {
self.point.config.mouse_scan,
1,
self.mouse.speed_percent,
);
)
.with_repeat_stop_edge(self.point.config.mouse_repeat_stop_edge);
mouse.dock = self.dock;
mouse
}
Expand Down Expand Up @@ -744,7 +746,10 @@ impl Technique for Workflow {
fn mouse_repeating(&self) -> bool {
matches!(self.stage, Stage::MouseMoving | Stage::MouseScrolling)
}
fn switch_released(&mut self) -> bool {
fn mouse_repeat_stop_edge(&self) -> crate::point_scan::MouseRepeatStopEdge {
self.point.config.mouse_repeat_stop_edge
}
fn stop_mouse_repeat(&mut self) -> bool {
if !matches!(self.stage, Stage::MouseMoving | Stage::MouseScrolling) {
return false;
}
Expand Down Expand Up @@ -1292,7 +1297,7 @@ mod tests {
session.action(Action::Select),
Some(Request::MouseMove { dy: 0, .. })
));
assert!(session.technique.switch_released());
assert!(session.technique.stop_mouse_repeat());
let status = |session: &Session<Workflow>| {
let mut frame = session.technique.frame();
frame.tiles.pop().unwrap().text
Expand All @@ -1303,7 +1308,7 @@ mod tests {
assert_eq!(status(&session), "Movement · Select →");
// A move that fails starts again from the top.
assert!(session.action(Action::Select).is_some());
session.technique.switch_released();
session.technique.stop_mouse_repeat();
session.action(Action::Select);
session.technique.mouse_repeat_enabled = false;
assert!(session.action(Action::Select).is_some());
Expand Down Expand Up @@ -1535,8 +1540,8 @@ mod tests {
matches!(session.take_selection(), Some(Request::MouseMove { dx, dy: 0 }) if dx > 0)
);
assert!(session.technique.mouse_repeating());
assert!(session.technique.switch_released());
assert!(!session.technique.switch_released());
assert!(session.technique.stop_mouse_repeat());
assert!(!session.technique.stop_mouse_repeat());
assert_eq!(
session.technique.phase(),
Phase::Workflow(WorkflowPhase::Mouse)
Expand Down Expand Up @@ -1585,7 +1590,7 @@ mod tests {
},
);
assert!(workflow.take_selection().is_none());
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());
}

#[test]
Expand Down Expand Up @@ -1668,8 +1673,8 @@ mod tests {
);
assert_eq!(workflow.take_selection(), Some(Request::MouseScroll { dy }));
assert!(workflow.mouse_repeating());
assert!(workflow.switch_released());
assert!(!workflow.switch_released());
assert!(workflow.stop_mouse_repeat());
assert!(!workflow.stop_mouse_repeat());
assert_eq!(workflow.phase(), Phase::Workflow(WorkflowPhase::Mouse));
workflow.update(
120,
Expand All @@ -1693,7 +1698,7 @@ mod tests {
Some(Request::MouseScroll { dy: 5 })
);
assert_eq!(workflow.phase(), Phase::Workflow(WorkflowPhase::Mouse));
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());
workflow.set_mouse_settings(100, 1000, 250, 80, true);
workflow.mouse_key(crate::scan_mouse::Key::Scroll(-1));
workflow.execution_failed("input failed".into());
Expand All @@ -1706,7 +1711,7 @@ mod tests {
workflow.mouse_key(crate::scan_mouse::Key::Scroll(1));
workflow.set_mouse_settings(100, 1000, 250, 80, false);
assert_eq!(workflow.phase(), Phase::Workflow(WorkflowPhase::Mouse));
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());
workflow.set_mouse_settings(100, 1000, 250, 80, true);
workflow.mouse_key(crate::scan_mouse::Key::Scroll(1));
let next_screen = Rect {
Expand Down Expand Up @@ -1743,7 +1748,7 @@ mod tests {
assert!(workflow.mouse_repeating());
workflow.set_mouse_settings(105, 1000, 250, 80, true);
assert!(!workflow.mouse_repeating());
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());

workflow.mouse_key(Key::Move(1, 0));
let next_screen = Rect {
Expand All @@ -1755,7 +1760,7 @@ mod tests {
workflow.set_mouse_area(next_screen, next_screen, 1.0, 2);
assert!(!workflow.mouse_repeating());
assert!(workflow.move_repeat.is_none());
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());
}

#[test]
Expand Down Expand Up @@ -1910,7 +1915,7 @@ mod tests {
));
workflow.execution_failed("input failed".into());
assert_eq!(workflow.mouse_feedback(), None);
assert!(!workflow.switch_released());
assert!(!workflow.stop_mouse_repeat());
workflow.handle(Action::Select);
assert_eq!(
workflow.mouse_feedback(),
Expand Down
20 changes: 12 additions & 8 deletions src-tauri/src/scan_mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct MousePanel {
pub speed_percent: u16,
pub error: bool,
notice: Option<&'static str>,
repeat_stop_edge: crate::point_scan::MouseRepeatStopEdge,
positioning: bool,
displays: usize,
rows: Vec<Vec<Key>>,
Expand All @@ -56,12 +57,17 @@ impl MousePanel {
speed_percent,
error: false,
notice: None,
repeat_stop_edge: Default::default(),
positioning: false,
displays,
rows,
scan,
}
}
pub fn with_repeat_stop_edge(mut self, edge: crate::point_scan::MouseRepeatStopEdge) -> Self {
self.repeat_stop_edge = edge;
self
}
fn rows(more: bool, positioning: bool, displays: usize) -> Vec<Vec<Key>> {
use Key::*;
if positioning {
Expand Down Expand Up @@ -221,14 +227,12 @@ impl MousePanel {
let escaping = self.scan.nav.escaping();
let highlight_row = row_scan || escaping;
let status = if let Some(repeating) = repeating {
match repeating {
RepeatPrompt::Moving => "Moving pointer · Press and release a switch to stop",
RepeatPrompt::Scrolling(dy) if dy > 0 => {
"Scrolling up · Press and release a switch to stop"
}
RepeatPrompt::Scrolling(_) => "Scrolling down · Press and release a switch to stop",
}
.to_owned()
let action = match repeating {
RepeatPrompt::Moving => "Moving pointer",
RepeatPrompt::Scrolling(dy) if dy > 0 => "Scrolling up",
RepeatPrompt::Scrolling(_) => "Scrolling down",
};
format!("{action} · {}", self.repeat_stop_edge.instruction())
} else if self.error {
"Mouse action failed · Select to resume".to_owned()
} else if let Some(notice) = self.notice {
Expand Down
8 changes: 6 additions & 2 deletions src-tauri/src/scanning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,12 @@ pub trait Technique {
fn mouse_repeating(&self) -> bool {
false
}
/// Ends a repeating scanned Mouse action after its stop switch is released.
fn switch_released(&mut self) -> bool {
/// Which switch edge stops a repeating scanned Mouse action.
fn mouse_repeat_stop_edge(&self) -> crate::point_scan::MouseRepeatStopEdge {
Default::default()
}
/// Ends a repeating scanned Mouse action.
fn stop_mouse_repeat(&mut self) -> bool {
false
}
fn execution_failed(&mut self, _message: String) {}
Expand Down
Loading
Loading