use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum ClickTiming {
#[default]
Makcu,
Ferrum,
Fixed(Duration),
Off,
}
impl ClickTiming {
fn range(self) -> Option<(Duration, Duration)> {
match self {
Self::Makcu => Some((Duration::from_millis(35), Duration::from_millis(75))),
Self::Ferrum => Some((Duration::from_millis(75), Duration::from_millis(125))),
Self::Fixed(hold) => Some((hold, hold)),
Self::Off => None,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Timing {
#[default]
Any,
NativeOnly,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct Click {
pub hold: Option<Duration>,
pub timing: Timing,
}
impl Click {
pub fn hold(hold: Duration) -> Self {
Self {
hold: Some(hold),
timing: Timing::Any,
}
}
pub fn native_only(self) -> Self {
Self {
timing: Timing::NativeOnly,
..self
}
}
}
#[derive(Debug)]
pub(crate) struct Holds(u64);
impl Holds {
pub(crate) fn seeded(seed: u64) -> Self {
Self(seed | 1)
}
pub(crate) fn from_clock() -> Self {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_or(0, |since| since.as_nanos() as u64);
Self::seeded(nanos)
}
pub(crate) fn pick(&mut self, timing: ClickTiming) -> Option<Duration> {
let (min, max) = timing.range()?;
let span = (max - min).as_micros() as u64;
if span == 0 {
return Some(min);
}
self.0 ^= self.0 << 13;
self.0 ^= self.0 >> 7;
self.0 ^= self.0 << 17;
Some(min + Duration::from_micros(self.0 % (span + 1)))
}
}
#[cfg(test)]
mod tests;