1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::cell::Cell;
use std::num::NonZeroU64;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
use instant::Instant;
use crate::kurbo::Point;
use crate::WinHandler;
const MULTI_CLICK_INTERVAL: Duration = Duration::from_millis(500);
const MULTI_CLICK_MAX_DISTANCE: f64 = 5.0;
#[allow(dead_code)]
pub fn strip_access_key(raw_menu_text: &str) -> String {
let mut saw_ampersand = false;
let mut result = String::new();
for c in raw_menu_text.chars() {
if c == '&' {
if saw_ampersand {
result.push(c);
}
saw_ampersand = !saw_ampersand;
} else {
result.push(c);
saw_ampersand = false;
}
}
result
}
pub(crate) trait IdleCallback: Send {
fn call(self: Box<Self>, a: &mut dyn WinHandler);
}
impl<F: FnOnce(&mut dyn WinHandler) + Send> IdleCallback for F {
fn call(self: Box<F>, a: &mut dyn WinHandler) {
(*self)(a)
}
}
pub struct Counter(AtomicU64);
impl Counter {
pub const fn new() -> Counter {
Counter(AtomicU64::new(1))
}
pub const unsafe fn new_unchecked(init: u64) -> Counter {
Counter(AtomicU64::new(init))
}
pub fn next(&self) -> u64 {
self.0.fetch_add(1, Ordering::Relaxed)
}
pub fn next_nonzero(&self) -> NonZeroU64 {
unsafe { NonZeroU64::new_unchecked(self.0.fetch_add(1, Ordering::Relaxed)) }
}
}
#[derive(Debug, Clone)]
pub struct ClickCounter {
max_interval: Cell<Duration>,
max_distance: Cell<f64>,
last_click: Cell<Instant>,
last_pos: Cell<Point>,
click_count: Cell<u8>,
}
#[allow(dead_code)]
impl ClickCounter {
pub fn new(max_interval: Duration, max_distance: f64) -> ClickCounter {
ClickCounter {
max_interval: Cell::new(max_interval),
max_distance: Cell::new(max_distance),
last_click: Cell::new(Instant::now()),
click_count: Cell::new(0),
last_pos: Cell::new(Point::new(f64::MAX, 0.0)),
}
}
pub fn set_interval_ms(&self, millis: u64) {
self.max_interval.set(Duration::from_millis(millis))
}
pub fn set_distance(&self, distance: f64) {
self.max_distance.set(distance)
}
pub fn count_for_click(&self, click_pos: Point) -> u8 {
let click_time = Instant::now();
let last_time = self.last_click.replace(click_time);
let last_pos = self.last_pos.replace(click_pos);
let elapsed = click_time - last_time;
let distance = last_pos.distance(click_pos);
if elapsed > self.max_interval.get() || distance > self.max_distance.get() {
self.click_count.set(0);
}
let click_count = self.click_count.get().saturating_add(1);
self.click_count.set(click_count);
click_count
}
}
impl Default for ClickCounter {
fn default() -> Self {
ClickCounter::new(MULTI_CLICK_INTERVAL, MULTI_CLICK_MAX_DISTANCE)
}
}