cotis_web/
interactivity.rs1use std::collections::HashMap;
17use std::sync::{LazyLock, Mutex};
18
19use cotis_utils::interactivity::keyboard::{KEYBOARD_LIST, KeyboardKey, SimpleKeyboardProvider};
20use cotis_utils::interactivity::mouse;
21use cotis_utils::interactivity::mouse::MouseProvider;
22use cotis_utils::math::Vector2;
23
24use crate::renderer::HTMLRenderer;
25use crate::web_functions::primitives::{
26 get_mouse_position, get_mouse_wheel_move_v, get_next_char, mouse_button_down,
27};
28
29pub struct HTMLInteractivity;
31
32impl MouseProvider for HTMLRenderer {
33 fn get_mouse_position(&self) -> Vector2 {
34 let array = get_mouse_position();
35 Vector2 {
36 x: array.0,
37 y: array.1,
38 }
39 }
40
41 fn mouse_button_down(&self, n: mouse::MouseButton) -> bool {
42 mouse_button_down(n)
43 }
44
45 fn get_mouse_wheel_move_v(&self) -> Vector2 {
46 let array = get_mouse_wheel_move_v();
47 Vector2 {
48 x: array.0,
49 y: array.1,
50 }
51 }
52}
53
54pub(crate) struct HTMLKeyboardProvider {
55 keyboard_prev_state: Vec<KeyboardKey>,
56 keyboard_once_state: Vec<KeyboardKey>,
57 keyboard_once_release: Vec<KeyboardKey>,
58 cooldown: HashMap<KeyboardKey, f32>,
59}
60
61impl HTMLKeyboardProvider {
62 const COOLDOWN: f32 = 0.1;
63 const INITIAL_COOLDOWN: f32 = 5.0;
64
65 pub(crate) fn update(&mut self, delta_time: f32) {
66 self.keyboard_once_state.clear();
67 self.keyboard_once_release.clear();
68 for key in KEYBOARD_LIST {
69 if self.is_key_down(key) {
70 if !self.keyboard_prev_state.contains(&key) {
71 self.keyboard_prev_state.push(key);
72 self.keyboard_once_state.push(key);
73 self.cooldown.insert(key, Self::INITIAL_COOLDOWN);
74 }
75 } else {
76 if self.keyboard_prev_state.contains(&key)
77 && !self.keyboard_once_release.contains(&key)
78 {
79 self.keyboard_once_release.push(key);
80 }
81 self.keyboard_prev_state.retain(|e| *e != key);
82 self.cooldown.retain(|e, _| *e != key);
83 }
84 }
85 for timer in self.cooldown.values_mut() {
86 if *timer > 0.0 {
87 *timer = (*timer - delta_time).max(0.0);
88 } else {
89 *timer = Self::COOLDOWN;
90 }
91 }
92 }
93
94 fn get_next_char(&mut self) -> Option<char> {
95 get_next_char()
96 }
97
98 fn is_key_pressed(&self, key: KeyboardKey) -> bool {
99 self.keyboard_once_state.contains(&key)
100 }
101
102 fn is_key_pressed_repeat(&self, key: KeyboardKey) -> bool {
103 if !self.keyboard_prev_state.contains(&key) {
104 return false;
105 }
106 if let Some(timer) = self.cooldown.get(&key) {
107 timer <= &0.0
108 } else {
109 false
110 }
111 }
112
113 fn is_key_down(&self, key: KeyboardKey) -> bool {
114 self.keyboard_prev_state.contains(&key)
115 }
116
117 fn is_key_released(&self, key: KeyboardKey) -> bool {
118 self.keyboard_once_release.contains(&key)
119 }
120
121 fn is_key_up(&self, key: KeyboardKey) -> bool {
122 !self.is_key_down(key)
123 }
124
125 fn get_key_pressed(&mut self) -> Option<KeyboardKey> {
126 self.keyboard_once_state.first().cloned()
127 }
128
129 fn get_char_pressed(&mut self) -> Option<char> {
130 self.get_next_char()
131 }
132}
133
134static KEYBOARD_PROVIDER: LazyLock<Mutex<HTMLKeyboardProvider>> = LazyLock::new(|| {
135 Mutex::new(HTMLKeyboardProvider {
136 keyboard_prev_state: Vec::new(),
137 keyboard_once_state: Vec::new(),
138 keyboard_once_release: Vec::new(),
139 cooldown: HashMap::new(),
140 })
141});
142
143impl MouseProvider for HTMLInteractivity {
144 fn get_mouse_position(&self) -> Vector2 {
145 let array = get_mouse_position();
146 Vector2 {
147 x: array.0,
148 y: array.1,
149 }
150 }
151
152 fn mouse_button_down(&self, n: mouse::MouseButton) -> bool {
153 mouse_button_down(n)
154 }
155
156 fn get_mouse_wheel_move_v(&self) -> Vector2 {
157 let array = get_mouse_wheel_move_v();
158 Vector2 {
159 x: array.0,
160 y: array.1,
161 }
162 }
163}
164
165impl SimpleKeyboardProvider for HTMLInteractivity {
166 fn get_pressed_keys(&self) -> indexmap::set::IndexSet<KeyboardKey> {
167 KEYBOARD_PROVIDER
168 .lock()
169 .map(|provider| provider.keyboard_prev_state.iter().cloned().collect())
170 .unwrap_or_default()
171 }
172}