1use std::collections::VecDeque;
14
15pub mod sc {
17 pub const ESC: u8 = 0x01;
18 pub const N1: u8 = 0x02;
19 pub const N2: u8 = 0x03;
20 pub const N3: u8 = 0x04;
21 pub const N4: u8 = 0x05;
22 pub const N5: u8 = 0x06;
23 pub const N6: u8 = 0x07;
24 pub const N7: u8 = 0x08;
25 pub const N8: u8 = 0x09;
26 pub const N9: u8 = 0x0A;
27 pub const N0: u8 = 0x0B;
28 pub const MINUS: u8 = 0x0C;
29 pub const EQUALS: u8 = 0x0D;
30 pub const BACKSPACE: u8 = 0x0E;
31 pub const TAB: u8 = 0x0F;
32 pub const Q: u8 = 0x10;
33 pub const W: u8 = 0x11;
34 pub const E: u8 = 0x12;
35 pub const R: u8 = 0x13;
36 pub const T: u8 = 0x14;
37 pub const Y: u8 = 0x15;
38 pub const U: u8 = 0x16;
39 pub const I: u8 = 0x17;
40 pub const O: u8 = 0x18;
41 pub const P: u8 = 0x19;
42 pub const LBRACKET: u8 = 0x1A;
43 pub const RBRACKET: u8 = 0x1B;
44 pub const ENTER: u8 = 0x1C;
45 pub const CTRL: u8 = 0x1D;
46 pub const A: u8 = 0x1E;
47 pub const S: u8 = 0x1F;
48 pub const D: u8 = 0x20;
49 pub const F: u8 = 0x21;
50 pub const G: u8 = 0x22;
51 pub const H: u8 = 0x23;
52 pub const J: u8 = 0x24;
53 pub const K: u8 = 0x25;
54 pub const L: u8 = 0x26;
55 pub const SEMICOLON: u8 = 0x27;
56 pub const APOSTROPHE: u8 = 0x28;
57 pub const BACKTICK: u8 = 0x29;
58 pub const LSHIFT: u8 = 0x2A;
59 pub const BACKSLASH: u8 = 0x2B;
60 pub const Z: u8 = 0x2C;
61 pub const X: u8 = 0x2D;
62 pub const C: u8 = 0x2E;
63 pub const V: u8 = 0x2F;
64 pub const B: u8 = 0x30;
65 pub const N: u8 = 0x31;
66 pub const M: u8 = 0x32;
67 pub const COMMA: u8 = 0x33;
68 pub const PERIOD: u8 = 0x34;
69 pub const SLASH: u8 = 0x35;
70 pub const RSHIFT: u8 = 0x36;
71 pub const KP_STAR: u8 = 0x37;
72 pub const ALT: u8 = 0x38;
73 pub const SPACE: u8 = 0x39;
74 pub const CAPSLOCK: u8 = 0x3A;
75 pub const F1: u8 = 0x3B;
76 pub const F2: u8 = 0x3C;
77 pub const F3: u8 = 0x3D;
78 pub const F4: u8 = 0x3E;
79 pub const F5: u8 = 0x3F;
80 pub const F6: u8 = 0x40;
81 pub const F7: u8 = 0x41;
82 pub const F8: u8 = 0x42;
83 pub const F9: u8 = 0x43;
84 pub const F10: u8 = 0x44;
85 pub const NUMLOCK: u8 = 0x45;
86 pub const SCROLLLOCK: u8 = 0x46;
87 pub const HOME: u8 = 0x47;
88 pub const UP: u8 = 0x48;
89 pub const PGUP: u8 = 0x49;
90 pub const KP_MINUS: u8 = 0x4A;
91 pub const LEFT: u8 = 0x4B;
92 pub const KP5: u8 = 0x4C;
93 pub const RIGHT: u8 = 0x4D;
94 pub const KP_PLUS: u8 = 0x4E;
95 pub const END: u8 = 0x4F;
96 pub const DOWN: u8 = 0x50;
97 pub const PGDN: u8 = 0x51;
98 pub const INSERT: u8 = 0x52;
99 pub const DELETE: u8 = 0x53;
100 pub const F11: u8 = 0x57;
101 pub const F12: u8 = 0x58;
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106pub struct KeyPress {
107 pub scan: u8,
109 pub ascii: u8,
111}
112
113#[derive(Clone, Debug)]
115pub struct Keyboard {
116 down: [bool; 128],
117 buffer: VecDeque<KeyPress>,
118 last_code: u8,
119}
120
121impl Default for Keyboard {
122 fn default() -> Self {
123 Self {
124 down: [false; 128],
125 buffer: VecDeque::new(),
126 last_code: 0,
127 }
128 }
129}
130
131const BIOS_BUFFER: usize = 15;
133
134impl Keyboard {
135 pub fn down(&self, scan: u8) -> bool {
137 self.down[(scan & 0x7F) as usize]
138 }
139
140 pub fn table(&self) -> &[bool; 128] {
142 &self.down
143 }
144
145 pub fn hit(&self) -> bool {
147 !self.buffer.is_empty()
148 }
149
150 pub fn read(&mut self) -> Option<KeyPress> {
152 self.buffer.pop_front()
153 }
154
155 pub fn flush(&mut self) {
157 self.buffer.clear();
158 }
159
160 pub fn port60(&self) -> u8 {
162 self.last_code
163 }
164
165 pub fn press(&mut self, scan: u8, ascii: u8) {
167 let s = (scan & 0x7F) as usize;
168 self.down[s] = true;
169 self.last_code = scan & 0x7F;
170 if self.buffer.len() < BIOS_BUFFER {
171 self.buffer.push_back(KeyPress {
172 scan: scan & 0x7F,
173 ascii,
174 });
175 }
176 }
177
178 pub fn release(&mut self, scan: u8) {
180 self.down[(scan & 0x7F) as usize] = false;
181 self.last_code = scan | 0x80;
182 }
183
184 pub fn shift(&self) -> bool {
185 self.down(sc::LSHIFT) || self.down(sc::RSHIFT)
186 }
187
188 pub fn ascii_for(scan: u8, shift: bool) -> u8 {
190 const LOWER: &[u8; 0x3A] =
191 b"\0\x1b1234567890-=\x08\tqwertyuiop[]\r\0asdfghjkl;'`\0\\zxcvbnm,./\0*\0 ";
192 const UPPER: &[u8; 0x3A] =
193 b"\0\x1b!@#$%^&*()_+\x08\tQWERTYUIOP{}\r\0ASDFGHJKL:\"~\0|ZXCVBNM<>?\0*\0 ";
194 let t = if shift { UPPER } else { LOWER };
195 t.get(scan as usize).copied().unwrap_or(0)
196 }
197}
198
199#[derive(Clone, Copy, Debug)]
201pub struct Mouse {
202 pub x: i32,
204 pub y: i32,
205 pub buttons: u8,
207 pub(crate) range: [i32; 4],
208 pub(crate) custom_range: bool,
209 pub(crate) visible: bool,
210 presses: [u16; 3],
211}
212
213impl Default for Mouse {
214 fn default() -> Self {
215 Self {
216 x: 0,
217 y: 0,
218 buttons: 0,
219 range: [0, 639, 0, 199],
220 custom_range: false,
221 visible: false,
222 presses: [0; 3],
223 }
224 }
225}
226
227impl Mouse {
228 pub fn left(&self) -> bool {
229 self.buttons & 1 != 0
230 }
231
232 pub fn right(&self) -> bool {
233 self.buttons & 2 != 0
234 }
235
236 pub fn middle(&self) -> bool {
237 self.buttons & 4 != 0
238 }
239
240 pub fn show(&mut self) {
244 self.visible = true;
245 }
246
247 pub fn hide(&mut self) {
249 self.visible = false;
250 }
251
252 pub fn visible(&self) -> bool {
254 self.visible
255 }
256
257 pub fn take_presses(&mut self, button: usize) -> u16 {
259 std::mem::take(&mut self.presses[button.min(2)])
260 }
261
262 pub fn set_range(&mut self, x_min: i32, x_max: i32, y_min: i32, y_max: i32) {
264 self.range = [x_min, x_max.max(x_min), y_min, y_max.max(y_min)];
265 self.custom_range = true;
266 self.x = self.x.clamp(self.range[0], self.range[1]);
267 self.y = self.y.clamp(self.range[2], self.range[3]);
268 }
269
270 pub fn set_normalized(&mut self, fx: f32, fy: f32) {
272 let [x0, x1, y0, y1] = self.range;
273 let fx = fx.clamp(0.0, 0.999_99);
274 let fy = fy.clamp(0.0, 0.999_99);
275 self.x = x0 + (fx * (x1 - x0 + 1) as f32) as i32;
276 self.y = y0 + (fy * (y1 - y0 + 1) as f32) as i32;
277 }
278
279 pub fn set_buttons(&mut self, buttons: u8) {
281 for b in 0..3 {
282 if buttons & (1 << b) != 0 && self.buttons & (1 << b) == 0 {
283 self.presses[b] = self.presses[b].saturating_add(1);
284 }
285 }
286 self.buttons = buttons;
287 }
288
289 pub(crate) fn reset_for_mode(&mut self, mode: u8, hercules: bool) {
291 self.range = match mode {
292 0x0F | 0x10 => [0, 639, 0, 349],
293 0x11 | 0x12 => [0, 639, 0, 479],
294 0x07 if hercules => [0, 639, 0, 199],
295 0xFF => self.range,
296 _ => [0, 639, 0, 199],
297 };
298 self.custom_range = false;
299 self.visible = false;
300 self.x = (self.range[0] + self.range[1]) / 2;
301 self.y = (self.range[2] + self.range[3]) / 2;
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308
309 #[test]
310 fn ascii_table() {
311 assert_eq!(Keyboard::ascii_for(sc::A, false), b'a');
312 assert_eq!(Keyboard::ascii_for(sc::A, true), b'A');
313 assert_eq!(Keyboard::ascii_for(sc::N1, true), b'!');
314 assert_eq!(Keyboard::ascii_for(sc::SPACE, false), b' ');
315 assert_eq!(Keyboard::ascii_for(sc::ENTER, false), b'\r');
316 assert_eq!(Keyboard::ascii_for(sc::UP, false), 0);
317 }
318
319 #[test]
320 fn mode13h_mouse_reports_640_wide() {
321 let mut m = Mouse::default();
322 m.reset_for_mode(0x13, false);
323 m.set_normalized(0.5, 0.5);
324 assert_eq!((m.x, m.y), (320, 100));
325 }
326}