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, display_size: (usize, usize)) -> Option { 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 = display_size.0 as f32; let fb_h = display_size.1 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, display_size: (usize, usize), } impl Default for HostInputHandler { fn default() -> Self { Self::new((480, 270)) } } impl HostInputHandler { pub fn new(display_size: (usize, usize)) -> Self { Self { signals: InputSignals::default(), display_size } } 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.display_size) { 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, display_size: (usize, usize), ) -> Option<(i32, i32)> { let viewport = FbViewport::framebuffer_viewport(window, display_size)?; 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, display_size.0 as i32 - 1), fb_y.clamp(0, display_size.1 as i32 - 1), )) } } }