summaryrefslogtreecommitdiff
path: root/src/devices/input_device.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/input_device.rs')
-rw-r--r--src/devices/input_device.rs233
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)
+ }
+}