rpk-common 0.1.0

RPK common fields between config tool and firmware builder
Documentation
use core::cell::RefCell;

use crate::{f32_from_u16, math::cubic_bezier};

#[derive(Debug, Clone, Copy)]
pub struct MouseConfig {
    pub movement: MouseAnalogSetting,
    pub scroll: MouseAnalogSetting,
}
impl Default for MouseConfig {
    fn default() -> Self {
        MouseConfig::normal()
    }
}
impl MouseConfig {
    pub const fn slow() -> Self {
        Self {
            movement: MouseAnalogSetting {
                curve: (0.1, 0.5),
                max_time: 1_000.0,
                min_ticks_per_ms: 0.02,
                max_ticks_per_ms: 1.0,
            },
            scroll: MouseAnalogSetting {
                curve: (0.0, 0.0),
                max_time: 5_000.0,
                min_ticks_per_ms: 0.01,
                max_ticks_per_ms: 0.25,
            },
        }
    }
    pub const fn normal() -> Self {
        Self {
            movement: MouseAnalogSetting {
                curve: (0.1, 0.5),
                max_time: 1_000.0,
                min_ticks_per_ms: 0.02,
                max_ticks_per_ms: 3.0,
            },
            scroll: MouseAnalogSetting {
                curve: (0.0, 0.0),
                max_time: 5_000.0,
                min_ticks_per_ms: 0.01,
                max_ticks_per_ms: 0.5,
            },
        }
    }
    pub const fn fast() -> Self {
        Self {
            movement: MouseAnalogSetting {
                curve: (0.1, 0.5),
                max_time: 1_000.0,
                min_ticks_per_ms: 0.02,
                max_ticks_per_ms: 5.0,
            },
            scroll: MouseAnalogSetting {
                curve: (0.0, 0.0),
                max_time: 5_000.0,
                min_ticks_per_ms: 0.01,
                max_ticks_per_ms: 1.0,
            },
        }
    }
    pub fn input(&self, i: usize) -> &MouseAnalogSetting {
        if i < 2 {
            &self.movement
        } else {
            &self.scroll
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct MouseAnalogSetting {
    pub curve: (f32, f32),
    pub max_time: f32,
    pub min_ticks_per_ms: f32,
    pub max_ticks_per_ms: f32,
}
impl MouseAnalogSetting {
    pub fn deserialize(bin: &mut impl Iterator<Item = u16>) -> Option<MouseAnalogSetting> {
        Some(MouseAnalogSetting {
            curve: (
                f32_from_u16(bin.next()?, bin.next()?),
                f32_from_u16(bin.next()?, bin.next()?),
            ),
            max_time: f32_from_u16(bin.next()?, bin.next()?),
            min_ticks_per_ms: f32_from_u16(bin.next()?, bin.next()?),
            max_ticks_per_ms: f32_from_u16(bin.next()?, bin.next()?),
        })
    }

    pub fn mouse_delta(&self, time_since_last_report: f32, now: u32, k: &MouseMove) -> i8 {
        if k.start == 0 {
            return 0;
        }
        let mut guard = k.fraction.borrow_mut();
        let r = self.t2rate(time_since_last_report, now, k.start) + *guard;
        let ticks = r as i8;
        *guard = r - ticks as f32;
        ticks * k.delta
    }

    fn t2rate(&self, period: f32, now: u32, then: u32) -> f32 {
        let t = now - then;
        let (c0, c1) = self.curve;
        let t = min(t as f32, self.max_time) / self.max_time;
        min(
            (self.min_ticks_per_ms + self.max_ticks_per_ms * cubic_bezier(t, c0, c1)) * period,
            127.0,
        )
    }
}

#[derive(Default)]
pub struct MouseMove {
    pub start: u32,
    pub fraction: RefCell<f32>,
    pub delta: i8,
}
impl MouseMove {
    pub fn action(&mut self, is_down: bool, delta: i8) {
        if is_down {
            if self.start == 0 || delta != self.delta {
                self.delta = delta;
            }
        } else if self.start != 0 && delta == self.delta {
            self.start = 0;
        }
    }
}

fn min(a: f32, b: f32) -> f32 {
    if a < b {
        a
    } else {
        b
    }
}

#[cfg(test)]
#[path = "mouse_test.rs"]
mod test;