1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum VmKey {
13 Escape,
14 Enter,
15 Space,
16 Backspace,
17 Tab,
18 Shift,
19 Alt,
20 ArrowUp,
21 ArrowDown,
22 ArrowLeft,
23 ArrowRight,
24 F(u8),
26 Digit(u8),
28 Letter(char),
30 Other(u32),
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub enum VmMouseButton {
36 Left,
37 Right,
38 Middle,
39 Other(u8),
40}
41
42#[derive(Debug, Clone, Copy)]
43struct KeyState {
44 down: bool,
45 down_stock: bool,
46 up_stock: bool,
47 down_up_stock: u8,
51 flick_stock: bool,
52 flick_angle: f32,
53 flick_pixel: f32,
54 flick_mm: f32,
55 flick_start: Option<(i32, i32)>,
56}
57
58impl KeyState {
59 const fn new() -> Self {
60 Self {
61 down: false,
62 down_stock: false,
63 up_stock: false,
64 down_up_stock: 0,
65 flick_stock: false,
66 flick_angle: 0.0,
67 flick_pixel: 0.0,
68 flick_mm: 0.0,
69 flick_start: None,
70 }
71 }
72
73 fn clear_all(&mut self) {
74 self.down = false;
75 self.down_stock = false;
76 self.up_stock = false;
77 self.down_up_stock = 0;
78 self.flick_stock = false;
79 self.flick_angle = 0.0;
80 self.flick_pixel = 0.0;
81 self.flick_mm = 0.0;
82 self.flick_start = None;
83 }
84
85 fn clear_stocks(&mut self) {
86 self.down_stock = false;
87 self.up_stock = false;
88 if self.down_up_stock == 2 {
91 self.down_up_stock = 0;
92 }
93 self.flick_stock = false;
94 }
95
96 fn use_stocks(&mut self) {
97 self.down_stock = false;
98 self.up_stock = false;
99 self.down_up_stock = 0;
100 self.flick_stock = false;
101 }
102}
103
104#[derive(Debug, Clone)]
105pub struct InputState {
106 keys: [KeyState; 256],
107
108 pub mouse_x: i32,
109 pub mouse_y: i32,
110 mouse_position_valid: bool,
111
112 wheel_delta: i32,
113
114 pub last_key_down: Option<VmKey>,
116 pub last_mouse_down: Option<VmMouseButton>,
118}
119
120impl Default for InputState {
121 fn default() -> Self {
122 Self {
123 keys: [KeyState::new(); 256],
124 mouse_x: -1,
125 mouse_y: -1,
126 mouse_position_valid: false,
127 wheel_delta: 0,
128 last_key_down: None,
129 last_mouse_down: None,
130 }
131 }
132}
133
134impl InputState {
135 pub fn vk_is_down(&self, vk: u8) -> bool {
141 self.keys[vk as usize].down
142 }
143
144 pub fn vk_down_stock(&self, vk: u8) -> bool {
146 self.keys[vk as usize].down_stock
147 }
148
149 pub fn vk_up_stock(&self, vk: u8) -> bool {
151 self.keys[vk as usize].up_stock
152 }
153
154 pub fn vk_down_up_stock(&self, vk: u8) -> bool {
156 self.keys[vk as usize].down_up_stock == 2
157 }
158
159 pub fn vk_flick_stock(&self, vk: u8) -> bool {
161 self.keys[vk as usize].flick_stock
162 }
163
164 pub fn vk_flick_angle(&self, vk: u8) -> f32 {
166 self.keys[vk as usize].flick_angle
167 }
168
169 pub fn vk_flick_pixel(&self, vk: u8) -> f32 {
171 self.keys[vk as usize].flick_pixel
172 }
173
174 pub fn vk_flick_mm(&self, vk: u8) -> f32 {
176 self.keys[vk as usize].flick_mm
177 }
178
179 fn vk_set_down(&mut self, vk: u8) {
180 let st = &mut self.keys[vk as usize];
181 if !st.down {
182 st.down = true;
183 st.down_stock = true;
184 }
185 if st.down_up_stock == 0 {
186 st.down_up_stock = 1;
187 }
188 if st.down_stock && st.up_stock {
190 st.down_up_stock = 2;
191 }
192 }
193
194 fn vk_set_up(&mut self, vk: u8) {
195 let st = &mut self.keys[vk as usize];
196 if st.down {
197 st.down = false;
198 st.up_stock = true;
199 if st.down_up_stock == 1 {
200 st.down_up_stock = 2;
201 }
202 }
203 }
204
205 fn vk_set_flick_start(&mut self, vk: u8) {
206 if !is_mouse_vk(vk) {
207 return;
208 }
209 let st = &mut self.keys[vk as usize];
210 st.flick_stock = false;
211 st.flick_start = Some((self.mouse_x, self.mouse_y));
212 }
213
214 fn vk_set_flick_end(&mut self, vk: u8) {
215 if !is_mouse_vk(vk) {
216 return;
217 }
218 let st = &mut self.keys[vk as usize];
219 let Some((sx, sy)) = st.flick_start.take() else {
220 return;
221 };
222 let dx = (self.mouse_x - sx) as f32;
223 let dy = (self.mouse_y - sy) as f32;
224 let dist = (dx * dx + dy * dy).sqrt();
225 if dist < FLICK_MIN_PIXEL {
226 return;
227 }
228 st.flick_angle = dx.atan2(dy);
230 st.flick_pixel = dist;
231 st.flick_mm = dist * MM_PER_PX;
232 st.flick_stock = true;
233 }
234
235 pub fn clear_all(&mut self) {
237 for st in &mut self.keys {
238 st.clear_all();
239 }
240 self.wheel_delta = 0;
241 self.last_key_down = None;
242 self.last_mouse_down = None;
243 }
244
245 pub fn has_mouse_position(&self) -> bool {
246 self.mouse_position_valid
247 }
248
249 pub fn clear_keyboard(&mut self) {
251 for (idx, st) in self.keys.iter_mut().enumerate() {
252 if matches!(idx as u8, 0x01 | 0x02 | 0x04) {
253 continue;
254 }
255 st.clear_all();
256 }
257 self.last_key_down = None;
258 }
259
260 pub fn clear_mouse(&mut self) {
262 for vk in [0x01usize, 0x02usize, 0x04usize] {
263 self.keys[vk].clear_all();
264 }
265 self.wheel_delta = 0;
266 self.last_mouse_down = None;
267 }
268
269 pub fn use_current(&mut self) {
274 for st in &mut self.keys {
275 st.use_stocks();
276 }
277 self.wheel_delta = 0;
278 self.last_key_down = None;
279 self.last_mouse_down = None;
280 }
281
282 pub fn next_frame(&mut self) {
284 for st in &mut self.keys {
285 st.clear_stocks();
286 }
287 self.wheel_delta = 0;
288 }
289
290 pub fn next_keyboard_frame(&mut self) {
292 for (idx, st) in self.keys.iter_mut().enumerate() {
293 if matches!(idx as u8, 0x01 | 0x02 | 0x04) {
294 continue;
295 }
296 st.clear_stocks();
297 }
298 self.last_key_down = None;
299 }
300
301 pub fn next_mouse_frame(&mut self) {
303 for vk in [0x01usize, 0x02usize, 0x04usize] {
304 self.keys[vk].clear_stocks();
305 }
306 self.wheel_delta = 0;
307 self.last_mouse_down = None;
308 }
309
310 pub fn on_mouse_wheel(&mut self, delta_y: i32) {
315 self.wheel_delta = self.wheel_delta.saturating_add(delta_y);
316 }
317
318 pub fn take_wheel_delta(&mut self) -> i32 {
320 let v = self.wheel_delta;
321 self.wheel_delta = 0;
322 v
323 }
324
325 pub fn is_key_down(&self, k: VmKey) -> bool {
330 vmkey_to_vk(k)
331 .map(|vk| self.vk_is_down(vk))
332 .unwrap_or(false)
333 }
334
335 pub fn is_mouse_down(&self, b: VmMouseButton) -> bool {
336 match b {
337 VmMouseButton::Left => self.vk_is_down(0x01),
338 VmMouseButton::Right => self.vk_is_down(0x02),
339 VmMouseButton::Middle => self.vk_is_down(0x04),
340 VmMouseButton::Other(_) => false,
341 }
342 }
343
344 pub fn on_key_down(&mut self, k: VmKey) {
345 if let Some(vk) = vmkey_to_vk(k) {
346 self.vk_set_down(vk);
347 }
348 self.last_key_down = Some(k);
349 }
350
351 pub fn on_key_up(&mut self, k: VmKey) {
352 if let Some(vk) = vmkey_to_vk(k) {
353 self.vk_set_up(vk);
354 }
355 }
356
357 pub fn on_mouse_down(&mut self, b: VmMouseButton) {
358 match b {
359 VmMouseButton::Left => {
360 self.vk_set_down(0x01);
361 self.vk_set_flick_start(0x01);
362 }
363 VmMouseButton::Right => {
364 self.vk_set_down(0x02);
365 self.vk_set_flick_start(0x02);
366 }
367 VmMouseButton::Middle => {
368 self.vk_set_down(0x04);
369 self.vk_set_flick_start(0x04);
370 }
371 VmMouseButton::Other(_) => {}
372 }
373 self.last_mouse_down = Some(b);
374 }
375
376 pub fn on_mouse_up(&mut self, b: VmMouseButton) {
377 match b {
378 VmMouseButton::Left => {
379 self.vk_set_flick_end(0x01);
380 self.vk_set_up(0x01);
381 }
382 VmMouseButton::Right => {
383 self.vk_set_flick_end(0x02);
384 self.vk_set_up(0x02);
385 }
386 VmMouseButton::Middle => {
387 self.vk_set_flick_end(0x04);
388 self.vk_set_up(0x04);
389 }
390 VmMouseButton::Other(_) => {}
391 }
392 }
393
394 pub fn on_mouse_move(&mut self, x: i32, y: i32) {
395 self.mouse_x = x;
396 self.mouse_y = y;
397 self.mouse_position_valid = true;
398 }
399
400 pub fn dir_mask(&self) -> i64 {
405 let mut m = 0;
406 if self.vk_is_down(0x25) {
407 m |= 1;
408 }
409 if self.vk_is_down(0x27) {
410 m |= 2;
411 }
412 if self.vk_is_down(0x26) {
413 m |= 4;
414 }
415 if self.vk_is_down(0x28) {
416 m |= 8;
417 }
418 m
419 }
420}
421
422pub(crate) fn vmkey_to_vk_code(k: VmKey) -> Option<u8> {
423 vmkey_to_vk(k)
424}
425
426fn vmkey_to_vk(k: VmKey) -> Option<u8> {
427 match k {
428 VmKey::Escape => Some(0x1B),
429 VmKey::Enter => Some(0x0D),
430 VmKey::Space => Some(0x20),
431 VmKey::Backspace => Some(0x08),
432 VmKey::Tab => Some(0x09),
433 VmKey::Shift => Some(0x10),
434 VmKey::Alt => Some(0x12),
435
436 VmKey::ArrowLeft => Some(0x25),
437 VmKey::ArrowUp => Some(0x26),
438 VmKey::ArrowRight => Some(0x27),
439 VmKey::ArrowDown => Some(0x28),
440
441 VmKey::F(n) if (1..=12).contains(&n) => Some(0x6F + n), VmKey::Digit(n) if n <= 9 => Some(0x30 + n),
443 VmKey::Letter(c) => {
444 let uc = c.to_ascii_uppercase();
445 if ('A'..='Z').contains(&uc) {
446 Some(uc as u8)
447 } else {
448 None
449 }
450 }
451 VmKey::Other(_) => None,
452 _ => None,
453 }
454}
455
456fn is_mouse_vk(vk: u8) -> bool {
457 matches!(vk, 0x01 | 0x02 | 0x04)
458}
459
460const FLICK_MIN_PIXEL: f32 = 30.0;
461const MM_PER_PX: f32 = 25.4 / 96.0;