use crate::render::motion::MotionProfile;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MotionDeviceProfile {
Mouse,
Trackpad,
Trackball,
}
impl MotionDeviceProfile {
pub fn for_ua(ua: &str) -> Self {
let u = ua.to_ascii_lowercase();
if u.contains("macintosh") || u.contains("mac os x") {
return MotionDeviceProfile::Trackpad;
}
if u.contains("iphone") || u.contains("ipad") || u.contains("android") {
return MotionDeviceProfile::Mouse;
}
MotionDeviceProfile::Mouse
}
pub fn scroll_inertia(self) -> bool {
matches!(self, MotionDeviceProfile::Trackpad)
}
pub fn velocity_scale(self) -> f64 {
match self {
MotionDeviceProfile::Mouse => 1.0,
MotionDeviceProfile::Trackpad => 1.05,
MotionDeviceProfile::Trackball => 0.9,
}
}
pub fn extra_jitter_sigma(self, profile: MotionProfile) -> f64 {
let base = match profile {
MotionProfile::Fast => 0.0,
MotionProfile::Balanced => 0.1,
MotionProfile::Human => 0.15,
MotionProfile::Paranoid => 0.2,
};
match self {
MotionDeviceProfile::Mouse => base,
MotionDeviceProfile::Trackpad => base * 0.6,
MotionDeviceProfile::Trackball => base * 1.8,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mac_ua_is_trackpad() {
let ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/131";
assert_eq!(
MotionDeviceProfile::for_ua(ua),
MotionDeviceProfile::Trackpad
);
}
#[test]
fn linux_ua_is_mouse() {
let ua = "Mozilla/5.0 (X11; Linux x86_64) Chrome/131";
assert_eq!(MotionDeviceProfile::for_ua(ua), MotionDeviceProfile::Mouse);
}
#[test]
fn scroll_inertia_matches_device() {
assert!(MotionDeviceProfile::Trackpad.scroll_inertia());
assert!(!MotionDeviceProfile::Mouse.scroll_inertia());
assert!(!MotionDeviceProfile::Trackball.scroll_inertia());
}
#[test]
fn velocity_scale_has_expected_ordering() {
let m = MotionDeviceProfile::Mouse.velocity_scale();
let tp = MotionDeviceProfile::Trackpad.velocity_scale();
let tb = MotionDeviceProfile::Trackball.velocity_scale();
assert!(tp > m);
assert!(tb < m);
}
#[test]
fn trackball_jitter_exceeds_mouse() {
let m = MotionDeviceProfile::Mouse.extra_jitter_sigma(MotionProfile::Human);
let tb = MotionDeviceProfile::Trackball.extra_jitter_sigma(MotionProfile::Human);
assert!(tb > m);
}
#[test]
fn fast_profile_has_zero_extra_jitter() {
for d in [
MotionDeviceProfile::Mouse,
MotionDeviceProfile::Trackpad,
MotionDeviceProfile::Trackball,
] {
assert_eq!(d.extra_jitter_sigma(MotionProfile::Fast), 0.0);
}
}
}