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,
_ => 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;
}
}
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)
}
}