1use std::collections::HashMap;
2use std::iter::Filter;
3
4use uni_app::AppEvent;
5
6pub trait InputApi {
16 fn key(&self, key: &str) -> bool;
19 fn key_pressed(&mut self, key: &str) -> bool;
21 fn keys_pressed(&self) -> Keys;
23 fn key_released(&mut self, key: &str) -> bool;
25 fn keys_released(&self) -> Keys;
27 fn text(&self) -> String;
29 fn mouse_button(&self, num: usize) -> bool;
32 fn mouse_button_pressed(&mut self, num: usize) -> bool;
34 fn mouse_button_released(&mut self, num: usize) -> bool;
36 fn mouse_pos(&self) -> (f32, f32);
38 fn close_requested(&self) -> bool;
40}
41
42pub struct DoryenInput {
43 kdown: HashMap<String, bool>,
44 kpressed: HashMap<String, bool>,
45 kreleased: HashMap<String, bool>,
46 mdown: HashMap<usize, bool>,
47 mpressed: HashMap<usize, bool>,
48 mreleased: HashMap<usize, bool>,
49 text: String,
50 close_request: bool,
51 mpos: (f32, f32),
52 screen_size: (f32, f32),
53 con_size: (f32, f32),
54 mouse_offset: (f32, f32),
55}
56
57impl DoryenInput {
58 pub fn new(
59 (screen_width, screen_height): (u32, u32),
60 (con_width, con_height): (u32, u32),
61 (x_offset, y_offset): (u32, u32),
62 ) -> Self {
63 Self {
64 kdown: HashMap::new(),
65 kpressed: HashMap::new(),
66 kreleased: HashMap::new(),
67 mdown: HashMap::new(),
68 mpressed: HashMap::new(),
69 mreleased: HashMap::new(),
70 mpos: (0.0, 0.0),
71 text: String::new(),
72 close_request: false,
73 screen_size: (screen_width as f32, screen_height as f32),
74 con_size: (con_width as f32, con_height as f32),
75 mouse_offset: (x_offset as f32, y_offset as f32),
76 }
77 }
78 fn on_key_down(&mut self, scan_code: &str) {
79 if !self.key(scan_code) {
80 self.kpressed.insert(scan_code.to_owned(), true);
81 self.kdown.insert(scan_code.to_owned(), true);
82 }
83 }
84 fn on_key_up(&mut self, scan_code: &str) {
85 self.kpressed.insert(scan_code.to_owned(), false);
86 self.kdown.insert(scan_code.to_owned(), false);
87 self.kreleased.insert(scan_code.to_owned(), true);
88 }
89 fn on_mouse_down(&mut self, button: usize) {
90 if !self.mouse_button(button) {
91 self.mpressed.insert(button, true);
92 self.mdown.insert(button, true);
93 }
94 }
95 fn on_mouse_up(&mut self, button: usize) {
96 self.mpressed.insert(button, false);
97 self.mdown.insert(button, false);
98 self.mreleased.insert(button, true);
99 }
100 pub fn on_frame(&mut self) {
101 self.mpressed.clear();
102 self.mreleased.clear();
103 self.kreleased.clear();
104 self.kpressed.clear();
105 self.close_request = false;
106 self.text.clear();
107 }
108 pub fn on_event(&mut self, event: &AppEvent) {
109 match event {
110 AppEvent::KeyDown(ref key) => {
111 self.on_key_down(&key.code);
112 }
113 AppEvent::KeyUp(ref key) => {
114 self.on_key_up(&key.code);
115 }
116 AppEvent::CharEvent(ch) => {
117 if !ch.is_control() {
118 self.text.push(*ch);
119 }
120 }
121 AppEvent::MousePos(ref pos) => {
122 self.mpos = (
123 (pos.0 as f32 - self.mouse_offset.0) / self.screen_size.0 * self.con_size.0,
124 (pos.1 as f32 - self.mouse_offset.1) / self.screen_size.1 * self.con_size.1,
125 );
126 }
127 AppEvent::MouseDown(ref mouse) => {
128 self.on_mouse_down(mouse.button);
129 }
130 AppEvent::MouseUp(ref mouse) => {
131 self.on_mouse_up(mouse.button);
132 }
133 AppEvent::CloseRequested => {
134 self.close_request = true;
135 }
136 _ => (),
137 }
138 }
139 pub(crate) fn resize(
140 &mut self,
141 (screen_width, screen_height): (u32, u32),
142 (con_width, con_height): (u32, u32),
143 (x_offset, y_offset): (u32, u32),
144 ) {
145 self.screen_size = (screen_width as f32, screen_height as f32);
146 self.con_size = (con_width as f32, con_height as f32);
147 self.mouse_offset = (x_offset as f32, y_offset as f32);
148 }
149}
150
151impl InputApi for DoryenInput {
152 fn key(&self, scan_code: &str) -> bool {
153 matches!(self.kdown.get(scan_code), Some(&true))
154 }
155 fn key_pressed(&mut self, scan_code: &str) -> bool {
156 matches!(self.kpressed.get(scan_code), Some(&true))
157 }
158 fn keys_pressed(&self) -> Keys {
159 Keys {
160 inner: self.kpressed.iter().filter(|&(_, &v)| v),
161 }
162 }
163 fn key_released(&mut self, scan_code: &str) -> bool {
164 matches!(self.kreleased.get(scan_code), Some(&true))
165 }
166 fn keys_released(&self) -> Keys {
167 Keys {
168 inner: self.kreleased.iter().filter(|&(_, &v)| v),
169 }
170 }
171 fn text(&self) -> String {
172 self.text.to_owned()
173 }
174 fn mouse_button(&self, num: usize) -> bool {
175 matches!(self.mdown.get(&num), Some(&true))
176 }
177 fn mouse_button_pressed(&mut self, num: usize) -> bool {
178 matches!(self.mpressed.get(&num), Some(&true))
179 }
180 fn mouse_button_released(&mut self, num: usize) -> bool {
181 matches!(self.mreleased.get(&num), Some(&true))
182 }
183 fn mouse_pos(&self) -> (f32, f32) {
184 self.mpos
185 }
186 fn close_requested(&self) -> bool {
187 self.close_request
188 }
189}
190
191type KeyMapFilter<'a> =
192 Filter<std::collections::hash_map::Iter<'a, String, bool>, fn(&(&'a String, &'a bool)) -> bool>;
193
194pub struct Keys<'a> {
196 inner: KeyMapFilter<'a>,
197}
198
199impl<'a> Iterator for Keys<'a> {
200 type Item = &'a str;
201
202 fn next(&mut self) -> Option<Self::Item> {
203 self.inner.next().map(|(k, _)| k.as_ref())
204 }
205}