127 lines
4.1 KiB
Rust

use prometeu_drivers::hardware::Hardware;
use prometeu_hal::InputSignals;
use winit::event::{ElementState, MouseButton, WindowEvent};
use winit::keyboard::{KeyCode, PhysicalKey};
use winit::window::Window;
#[derive(Debug, Clone, Copy)]
struct FbViewport {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
pub scale: f32,
}
impl FbViewport {
fn framebuffer_viewport(window: &Window) -> Option<FbViewport> {
let size = window.inner_size();
let win_w = size.width as f32;
let win_h = size.height as f32;
if win_w <= 0.0 || win_h <= 0.0 {
return None;
}
let fb_w = Hardware::W as f32;
let fb_h = Hardware::H as f32;
let scale_x = (win_w / fb_w).floor();
let scale_y = (win_h / fb_h).floor();
let scale = scale_x.min(scale_y).max(1.0);
let viewport_w = fb_w * scale;
let viewport_h = fb_h * scale;
let viewport_x = ((win_w - viewport_w) * 0.5).floor();
let viewport_y = ((win_h - viewport_h) * 0.5).floor();
Some(FbViewport { x: viewport_x, y: viewport_y, w: viewport_w, h: viewport_h, scale })
}
}
pub struct HostInputHandler {
pub signals: InputSignals,
}
impl Default for HostInputHandler {
fn default() -> Self {
Self::new()
}
}
impl HostInputHandler {
pub fn new() -> Self {
Self { signals: InputSignals::default() }
}
pub fn handle_event(&mut self, event: &WindowEvent, window: &Window) {
match event {
WindowEvent::KeyboardInput { event, .. } => {
if let PhysicalKey::Code(code) = event.physical_key {
let is_down = event.state == ElementState::Pressed;
match code {
KeyCode::ArrowUp => self.signals.up_signal = is_down,
KeyCode::ArrowDown => self.signals.down_signal = is_down,
KeyCode::ArrowLeft => self.signals.left_signal = is_down,
KeyCode::ArrowRight => self.signals.right_signal = is_down,
KeyCode::KeyA => self.signals.a_signal = is_down,
KeyCode::KeyD => self.signals.b_signal = is_down,
KeyCode::KeyW => self.signals.x_signal = is_down,
KeyCode::KeyS => self.signals.y_signal = is_down,
KeyCode::KeyQ => self.signals.l_signal = is_down,
KeyCode::KeyE => self.signals.r_signal = is_down,
KeyCode::KeyZ => self.signals.start_signal = is_down,
KeyCode::ShiftLeft | KeyCode::ShiftRight => {
self.signals.select_signal = is_down
}
_ => {}
}
}
}
WindowEvent::CursorMoved { position, .. } => {
if let Some((x, y)) = window_to_fb(position.x as f32, position.y as f32, window) {
self.signals.x_pos = x;
self.signals.y_pos = y;
}
}
WindowEvent::MouseInput { state, button, .. } if *button == MouseButton::Left => {
match state {
ElementState::Pressed => {
self.signals.f_signal = true;
}
ElementState::Released => {
self.signals.f_signal = false;
}
}
}
_ => {}
}
fn window_to_fb(wx: f32, wy: f32, window: &Window) -> Option<(i32, i32)> {
let viewport = FbViewport::framebuffer_viewport(window)?;
let local_x = wx - viewport.x;
let local_y = wy - viewport.y;
if local_x < 0.0 || local_y < 0.0 || local_x >= viewport.w || local_y >= viewport.h {
return None;
}
let fb_x = (local_x / viewport.scale).floor() as i32;
let fb_y = (local_y / viewport.scale).floor() as i32;
Some((fb_x.clamp(0, Hardware::W as i32 - 1), fb_y.clamp(0, Hardware::H as i32 - 1)))
}
}
}