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,
|
no_grab: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct AxisRuntime {
|
||||||
|
last_event_at: Option<Instant>,
|
||||||
|
remainder: f64,
|
||||||
|
smoothed_speed: f64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct ScrollState {
|
struct ScrollState {
|
||||||
last_scroll_event_at: Option<Instant>,
|
vertical: AxisRuntime,
|
||||||
remainder_v: f64,
|
horizontal: AxisRuntime,
|
||||||
remainder_h: f64,
|
}
|
||||||
|
|
||||||
|
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<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@@ -269,13 +287,14 @@ fn transform_event(
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let axis_state = axis_runtime_mut(state, axis);
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let dt = state
|
let dt = axis_state
|
||||||
.last_scroll_event_at
|
.last_event_at
|
||||||
.map(|t| now.saturating_duration_since(t).as_secs_f64())
|
.map(|t| now.saturating_duration_since(t).as_secs_f64())
|
||||||
.unwrap_or(0.016)
|
.unwrap_or(0.016)
|
||||||
.max(0.001);
|
.max(MIN_DT_SECONDS);
|
||||||
state.last_scroll_event_at = Some(now);
|
axis_state.last_event_at = Some(now);
|
||||||
|
|
||||||
let axis_unit = if axis == RelativeAxisCode::REL_WHEEL_HI_RES
|
let axis_unit = if axis == RelativeAxisCode::REL_WHEEL_HI_RES
|
||||||
|| axis == RelativeAxisCode::REL_HWHEEL_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"
|
// Normalize hi-res wheel units (120 per detent) to "detent-equivalent"
|
||||||
// speed so tuning behaves similarly across REL_WHEEL and REL_WHEEL_HI_RES.
|
// speed so tuning behaves similarly across REL_WHEEL and REL_WHEEL_HI_RES.
|
||||||
let normalized_value = (value as f64) / axis_unit;
|
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_x, gain_y) = sensitivity(speed, *mode, params);
|
||||||
let gain = if axis == RelativeAxisCode::REL_HWHEEL
|
let gain = if axis == RelativeAxisCode::REL_HWHEEL
|
||||||
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
||||||
@@ -298,17 +327,9 @@ fn transform_event(
|
|||||||
gain_y
|
gain_y
|
||||||
};
|
};
|
||||||
|
|
||||||
let remainder = if axis == RelativeAxisCode::REL_HWHEEL
|
let scaled = (value as f64) * gain + axis_state.remainder;
|
||||||
|| axis == RelativeAxisCode::REL_HWHEEL_HI_RES
|
|
||||||
{
|
|
||||||
&mut state.remainder_h
|
|
||||||
} else {
|
|
||||||
&mut state.remainder_v
|
|
||||||
};
|
|
||||||
|
|
||||||
let scaled = (value as f64) * gain + *remainder;
|
|
||||||
let quantized = scaled.trunc() as i32;
|
let quantized = scaled.trunc() as i32;
|
||||||
*remainder = scaled - (quantized as f64);
|
axis_state.remainder = scaled - (quantized as f64);
|
||||||
|
|
||||||
let _ = write_speed_stat(speed);
|
let _ = write_speed_stat(speed);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user