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.rs254
1 files changed, 254 insertions, 0 deletions
diff --git a/src/devices/input_device.rs b/src/devices/input_device.rs
new file mode 100644
index 0000000..83e8039
--- /dev/null
+++ b/src/devices/input_device.rs
@@ -0,0 +1,254 @@
+use crate::*;
+
+use std::collections::VecDeque;
+
+
+pub struct InputDevice {
+ pub cursor: ScreenPosition,
+ pub x_read: u16,
+ pub y_read: u16,
+ pub h_scroll_read: i16,
+ pub v_scroll_read: i16,
+ pub h_scroll: f32,
+ pub v_scroll: f32,
+ pub pointer_buttons: u8,
+ pub pointer_active: bool,
+
+ pub navigation: u8,
+ pub modifiers: u8,
+ pub characters: VecDeque<u8>,
+ pub gamepad_1: OwnedGamepad,
+ pub gamepad_2: OwnedGamepad,
+ pub gamepad_3: OwnedGamepad,
+ pub gamepad_4: OwnedGamepad,
+
+ pub accessed: bool,
+ pub wake: bool,
+}
+
+
+impl Device for InputDevice {
+ fn read(&mut self, port: u8) -> u8 {
+ self.accessed = true;
+ match port {
+ 0x0 => { self.x_read = self.cursor.x; read_h!(self.x_read) },
+ 0x1 => read_l!(self.cursor.x),
+ 0x2 => { self.y_read = self.cursor.y; read_h!(self.y_read) },
+ 0x3 => read_l!(self.cursor.y),
+ 0x4 => { self.update_horizontal_scroll(); read_h!(self.h_scroll_read) },
+ 0x5 => read_l!(self.h_scroll_read),
+ 0x6 => { self.update_vertical_scroll(); read_h!(self.v_scroll_read) },
+ 0x7 => read_l!(self.v_scroll_read),
+ 0x8 => read_b!(self.pointer_active),
+ 0x9 => self.pointer_buttons,
+ 0xA => self.characters.pop_front().unwrap_or(0),
+ 0xB => self.modifiers,
+ 0xC => self.gamepad_1.state() | self.navigation,
+ 0xD => self.gamepad_2.state(),
+ 0xE => self.gamepad_3.state(),
+ 0xF => self.gamepad_4.state(),
+ _ => unreachable!(),
+ }
+ }
+
+ fn write(&mut self, port: u8, _value: u8) -> Option<Signal> {
+ let signal = if self.accessed { None } else { Some(Signal::Break) };
+ self.accessed = true;
+ match port {
+ 0x0 => (),
+ 0x1 => (),
+ 0x2 => (),
+ 0x3 => (),
+ 0x4 => (),
+ 0x5 => (),
+ 0x6 => (),
+ 0x7 => (),
+ 0x8 => (),
+ 0x9 => (),
+ 0xA => self.characters.clear(),
+ 0xB => (),
+ 0xC => (),
+ 0xD => (),
+ 0xE => (),
+ 0xF => (),
+ _ => unreachable!(),
+ };
+ return signal;
+ }
+
+ fn wake(&mut self) -> bool {
+ self.accessed = true;
+ std::mem::take(&mut self.wake)
+ }
+
+ fn reset(&mut self) {
+ self.cursor = ScreenPosition::ZERO;
+ self.x_read = 0;
+ self.y_read = 0;
+ self.h_scroll_read = 0;
+ self.v_scroll_read = 0;
+ self.h_scroll = 0.0;
+ self.v_scroll = 0.0;
+ self.pointer_active = false;
+ self.pointer_buttons = 0;
+
+ self.navigation = 0;
+ self.modifiers = 0;
+ self.characters.clear();
+ self.gamepad_1.reset();
+ self.gamepad_2.reset();
+ self.gamepad_3.reset();
+ self.gamepad_4.reset();
+
+ self.accessed = false;
+ self.wake = false;
+ }
+}
+
+
+impl InputDevice {
+ pub fn new() -> Self {
+ Self {
+ cursor: ScreenPosition::ZERO,
+ x_read: 0,
+ y_read: 0,
+ h_scroll_read: 0,
+ v_scroll_read: 0,
+ h_scroll: 0.0,
+ v_scroll: 0.0,
+ pointer_active: false,
+ pointer_buttons: 0,
+
+ navigation: 0,
+ modifiers: 0,
+ characters: VecDeque::new(),
+ gamepad_1: OwnedGamepad::new(1),
+ gamepad_2: OwnedGamepad::new(2),
+ gamepad_3: OwnedGamepad::new(3),
+ gamepad_4: OwnedGamepad::new(4),
+
+ accessed: false,
+ wake: false,
+ }
+ }
+
+ pub fn on_gamepad_event(&mut self, event: gilrs::Event) {
+ if let Some(g) = self.gamepad_1.register(event.id) {
+ self.wake |= g.process_event(&event); return; }
+ if let Some(g) = self.gamepad_2.register(event.id) {
+ self.wake |= g.process_event(&event); return; }
+ if let Some(g) = self.gamepad_3.register(event.id) {
+ self.wake |= g.process_event(&event); return; }
+ if let Some(g) = self.gamepad_4.register(event.id) {
+ self.wake |= g.process_event(&event); return; }
+ }
+
+ 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) {
+ self.pointer_active = true;
+ let cursor_position = ScreenPosition {
+ x: position.x as i16 as u16,
+ y: position.y as i16 as u16,
+ };
+ if self.cursor != cursor_position {
+ self.cursor = cursor_position;
+ self.wake = true;
+ }
+ }
+
+ pub fn on_mouse_button(&mut self, button: MouseButton, action: Action) {
+ let mask = match button {
+ MouseButton::Left => 0x80,
+ MouseButton::Right => 0x40,
+ MouseButton::Middle => 0x20,
+ _ => return,
+ };
+ 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;
+ }
+ }
+
+ pub fn on_horizontal_scroll(&mut self, delta: f32) {
+ self.h_scroll += delta;
+ self.h_scroll = self.h_scroll.clamp(-32768.0, 32767.0);
+ }
+
+ pub fn on_vertical_scroll(&mut self, delta: f32) {
+ self.v_scroll += delta;
+ self.v_scroll = self.v_scroll.clamp(i16::MIN as f32, i16::MAX as f32);
+ }
+
+ pub fn update_horizontal_scroll(&mut self) {
+ self.h_scroll_read = self.h_scroll.trunc() as i16;
+ self.h_scroll -= self.h_scroll.trunc();
+ }
+
+ pub fn update_vertical_scroll(&mut self) {
+ self.v_scroll_read = self.v_scroll.trunc() as i16;
+ self.v_scroll -= self.v_scroll.trunc();
+ }
+
+ 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;
+ }
+ }
+}