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
1 change: 1 addition & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod scan_host;
mod scan_items;
mod scan_keyboard;
mod scan_menu;
mod scan_mouse;
mod scan_preferences;
mod scan_tile;
mod scan_tree;
Expand Down
89 changes: 89 additions & 0 deletions src-tauri/src/mouse_repeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,57 @@ struct MoveRepeatState {
initial_emitted: bool,
}

/// Drives a scanned direction with the same movement integral as a remote
/// repeat. Scanner ticks are slower than remote ticks, so split their elapsed
/// time into remote-sized slices before asking the shared motion state.
pub struct ScanMoveRepeat {
direction: (i32, i32),
now: Instant,
movement: MoveRepeatState,
}

impl ScanMoveRepeat {
pub fn new(dx: i32, dy: i32, now: Instant) -> Self {
Self {
direction: (dx, dy),
now,
movement: MoveRepeatState::new(now),
}
}

pub fn initial_move(&mut self) -> (i32, i32) {
self.movement
.initial_delta(self.direction.0, self.direction.1)
}

pub fn advance(
&mut self,
elapsed_ms: u64,
move_interval_ms: u32,
pointer_scale_percent: u8,
acceleration_duration_ms: u32,
) -> (i32, i32) {
let mut remaining = elapsed_ms.min(64);
let mut result = (0, 0);
while remaining > 0 {
let step = remaining.min(MOVE_TICK_INTERVAL_MS);
self.now += std::time::Duration::from_millis(step);
let delta = self.movement.advance(
self.now,
self.direction.0,
self.direction.1,
move_interval_ms,
pointer_scale_percent,
acceleration_duration_ms,
);
result.0 += delta.0;
result.1 += delta.1;
remaining -= step;
}
result
}
}

impl MoveRepeatState {
fn new(now: Instant) -> Self {
Self {
Expand Down Expand Up @@ -603,6 +654,44 @@ mod tests {
);
}

#[test]
fn scanning_motion_matches_remote_repeat_ticks() {
for direction in [(12, 0), (-12, 12), (0, -12)] {
for acceleration in [0, 1000] {
let now = Instant::now();
let mut scan = ScanMoveRepeat::new(direction.0, direction.1, now);
let mut remote = MouseRepeatController::default();
let active = remote.start(
"remote".into(),
RepeatCommand::Move {
dx: direction.0,
dy: direction.1,
},
acceleration,
now,
);
assert_eq!(
scan.initial_move(),
remote.initial_move("remote", active.generation).unwrap()
);
let mut time = now;
for _ in 0..40 {
let scanned = scan.advance(32, 250, 100, acceleration);
let mut expected = (0, 0);
for _ in 0..4 {
time += Duration::from_millis(8);
let delta = remote
.advance_move("remote", active.generation, time, 250, 100)
.unwrap();
expected.0 += delta.0;
expected.1 += delta.1;
}
assert_eq!(scanned, expected);
}
}
}
}

#[test]
fn parses_only_bounded_move_and_scroll_commands() {
assert_eq!(
Expand Down
Loading
Loading