smooth scroll speed estimation to reduce red-dot spikes
Tests / test_core_function (push) Failing after 8s
Tests / test_core_function (push) Failing after 8s
This commit is contained in:
+39
-18
@@ -40,11 +40,29 @@ struct Args {
|
||||
no_grab: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct AxisRuntime {
|
||||
last_event_at: Option<Instant>,
|
||||
remainder: f64,
|
||||
smoothed_speed: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ScrollState {
|
||||
last_scroll_event_at: Option<Instant>,
|
||||
remainder_v: f64,
|
||||
remainder_h: f64,
|
||||
vertical: AxisRuntime,
|
||||
horizontal: AxisRuntime,
|
||||
}
|
||||
|
||||
const SPEED_EMA_ALPHA: f64 = 0.25;
|
||||
const MIN_DT_SECONDS: f64 = 0.004;
|
||||
const SPEED_IDLE_RESET_SECONDS: f64 = 0.2;
|
||||
|
||||
fn axis_runtime_mut(state: &mut ScrollState, axis: RelativeAxisCode) -> &mut AxisRuntime {
|
||||
if axis == RelativeAxisCode::REL_HWHEEL || axis == RelativeAxisCode::REL_HWHEEL_HI_RES {
|
||||
&mut state.horizontal
|
||||
} else {
|
||||
&mut state.vertical
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
@@ -269,13 +287,14 @@ fn transform_event(
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let axis_state = axis_runtime_mut(state, axis);
|
||||
let now = Instant::now();
|
||||
let dt = state
|
||||
.last_scroll_event_at
|
||||
let dt = axis_state
|
||||
.last_event_at
|
||||
.map(|t| now.saturating_duration_since(t).as_secs_f64())
|
||||
.unwrap_or(0.016)
|
||||
.max(0.001);
|
||||
state.last_scroll_event_at = Some(now);
|
||||
.max(MIN_DT_SECONDS);
|
||||
axis_state.last_event_at = Some(now);
|
||||
|
||||
let axis_unit = if axis == RelativeAxisCode::REL_WHEEL_HI_RES
|
||||
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
||||
@@ -288,7 +307,17 @@ fn transform_event(
|
||||
// Normalize hi-res wheel units (120 per detent) to "detent-equivalent"
|
||||
// speed so tuning behaves similarly across REL_WHEEL and REL_WHEEL_HI_RES.
|
||||
let normalized_value = (value as f64) / axis_unit;
|
||||
let speed = normalized_value.abs() / dt;
|
||||
let raw_speed = normalized_value.abs() / dt;
|
||||
|
||||
// Smooth out bursty evdev timing so the live indicator and accel input
|
||||
// don't jump wildly on single tightly-packed events.
|
||||
let speed = if dt > SPEED_IDLE_RESET_SECONDS {
|
||||
raw_speed
|
||||
} else {
|
||||
SPEED_EMA_ALPHA * raw_speed + (1.0 - SPEED_EMA_ALPHA) * axis_state.smoothed_speed
|
||||
};
|
||||
axis_state.smoothed_speed = speed;
|
||||
|
||||
let (gain_x, gain_y) = sensitivity(speed, *mode, params);
|
||||
let gain = if axis == RelativeAxisCode::REL_HWHEEL
|
||||
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
||||
@@ -298,17 +327,9 @@ fn transform_event(
|
||||
gain_y
|
||||
};
|
||||
|
||||
let remainder = if axis == RelativeAxisCode::REL_HWHEEL
|
||||
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
||||
{
|
||||
&mut state.remainder_h
|
||||
} else {
|
||||
&mut state.remainder_v
|
||||
};
|
||||
|
||||
let scaled = (value as f64) * gain + *remainder;
|
||||
let scaled = (value as f64) * gain + axis_state.remainder;
|
||||
let quantized = scaled.trunc() as i32;
|
||||
*remainder = scaled - (quantized as f64);
|
||||
axis_state.remainder = scaled - (quantized as f64);
|
||||
|
||||
let _ = write_speed_stat(speed);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user