diff options
Diffstat (limited to 'src/devices/input_device.rs')
-rw-r--r-- | src/devices/input_device.rs | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/devices/input_device.rs b/src/devices/input_device.rs new file mode 100644 index 0000000..638c277 --- /dev/null +++ b/src/devices/input_device.rs @@ -0,0 +1,233 @@ +use crate::*; +use bedrock_core::*; +use phosphor::*; + +use std::collections::VecDeque; + +macro_rules! fn_on_scroll { + ($fn_name:ident($value:ident, $delta:ident)) => { + pub fn $fn_name(&mut self, delta: f32) { + self.$delta += delta; + while self.$delta >= 1.0 { + self.$value = self.$value.saturating_add(1); + self.$delta -= 1.0; + self.wake = true; + } + while self.$delta <= -1.0 { + self.$value = self.$value.saturating_sub(1); + self.$delta += 1.0; + self.wake = true; + } + } + }; +} + + +pub struct InputDevice { + pub wake: bool, + pub accessed: bool, + + pub pointer_active: bool, + pub pointer_buttons: u8, + pub position: ScreenPosition, + pub x_read: u16, + pub y_read: u16, + + pub h_scroll: i8, + pub v_scroll: i8, + pub h_scroll_delta: f32, + pub v_scroll_delta: f32, + + pub keyboard_active: bool, + pub characters: VecDeque<u8>, + pub navigation: u8, + pub modifiers: u8, + + pub gamepad_1: u8, + pub gamepad_2: u8, + pub gamepad_3: u8, + pub gamepad_4: u8, +} + +impl InputDevice { + pub fn new() -> Self { + Self { + wake: false, + accessed: false, + + pointer_active: false, + pointer_buttons: 0, + + position: ScreenPosition::ZERO, + x_read: 0, + y_read: 0, + + h_scroll: 0, + v_scroll: 0, + h_scroll_delta: 0.0, + v_scroll_delta: 0.0, + + keyboard_active: true, + characters: VecDeque::new(), + modifiers: 0, + navigation: 0, + + gamepad_1: 0, + gamepad_2: 0, + gamepad_3: 0, + gamepad_4: 0, + } + } + + pub fn on_cursor_enter(&mut self) { + self.pointer_active = true; + self.wake = true; + } + + pub fn on_cursor_exit(&mut self) { + self.pointer_active = false; + self.wake = true; + } + + pub fn on_cursor_move(&mut self, position: Position) { + let screen_position = ScreenPosition { + x: position.x as i16 as u16, + y: position.y as i16 as u16, + }; + if self.position != screen_position { + self.position = screen_position; + self.wake = true; + } + } + + pub fn on_mouse_button(&mut self, button: MouseButton, action: Action) { + let mask = match button { + MouseButton::Left => 0x80, + MouseButton::Middle => 0x40, + MouseButton::Right => 0x20, + }; + let pointer_buttons = match action { + Action::Pressed => self.pointer_buttons | mask, + Action::Released => self.pointer_buttons & !mask, + }; + if self.pointer_buttons != pointer_buttons { + self.pointer_buttons = pointer_buttons; + self.wake = true; + } + } + + fn_on_scroll!(on_horizontal_scroll(h_scroll, h_scroll_delta)); + fn_on_scroll!(on_vertical_scroll(v_scroll, v_scroll_delta)); + + pub fn read_horizontal_scroll(&mut self) -> u8 { + std::mem::take(&mut self.h_scroll) as u8 + } + + pub fn read_vertical_scroll(&mut self) -> u8 { + std::mem::take(&mut self.v_scroll) as u8 + } + + pub fn on_character(&mut self, character: char) { + let character = match character { + '\r' => '\n', + _ => character, + }; + let mut bytes = [0; 4]; + let string = character.encode_utf8(&mut bytes); + for byte in string.bytes() { + self.characters.push_back(byte); + } + self.wake = true; + } + + pub fn on_keypress(&mut self, key: KeyCode, action: Action) { + let shift = self.modifiers & 0x40 != 0; + let mask = match key { + KeyCode::ArrowUp => 0x80, // up + KeyCode::ArrowDown => 0x40, // down + KeyCode::ArrowLeft => 0x20, // left + KeyCode::ArrowRight => 0x10, // right + KeyCode::Enter => 0x08, // confirm + KeyCode::Escape => 0x04, // cancel + KeyCode::Tab => match shift { // shift + false => 0x02, // next + true => 0x01 // previous + }, + _ => return, + }; + let navigation = match action { + Action::Pressed => self.navigation | mask, + Action::Released => self.navigation & !mask, + }; + if self.navigation != navigation { + self.navigation = navigation; + self.wake = true; + } + } + + pub fn on_modifier(&mut self, state: ModifiersState) { + let mut modifiers = 0; + if state.control_key() { modifiers |= 0x80 } + if state.shift_key() { modifiers |= 0x40 } + if state.alt_key() { modifiers |= 0x20 } + if state.super_key() { modifiers |= 0x10 } + if self.modifiers != modifiers { + self.modifiers = modifiers; + self.wake = true; + } + } +} + +impl Device for InputDevice { + fn read(&mut self, port: u8) -> u8 { + self.accessed = true; + match port { + 0x0 => read_b!(self.pointer_active), + 0x1 => self.pointer_buttons, + 0x2 => self.read_horizontal_scroll(), + 0x3 => self.read_vertical_scroll(), + 0x4 => { self.x_read = self.position.x as u16; read_h!(self.x_read) }, + 0x5 => read_l!(self.position.x), + 0x6 => { self.y_read = self.position.y as u16; read_h!(self.y_read) }, + 0x7 => read_l!(self.position.y), + 0x8 => read_b!(self.keyboard_active), + 0x9 => self.characters.pop_front().unwrap_or(0), + 0xa => self.navigation, + 0xb => self.modifiers, + 0xc => self.gamepad_1, + 0xd => self.gamepad_2, + 0xe => self.gamepad_3, + 0xf => self.gamepad_4, + _ => unreachable!(), + } + } + + fn write(&mut self, port: u8, _value: u8) -> Option<Signal> { + self.accessed = true; + match port { + 0x0 => (), + 0x1 => (), + 0x2 => (), + 0x3 => (), + 0x4 => (), + 0x5 => (), + 0x6 => (), + 0x7 => (), + 0x8 => (), + 0x9 => self.characters.clear(), + 0xa => (), + 0xb => (), + 0xc => (), + 0xd => (), + 0xe => (), + 0xf => (), + _ => unreachable!(), + }; + return None; + } + + fn wake(&mut self) -> bool { + self.accessed = true; + std::mem::take(&mut self.wake) + } +} |