improve inputs

This commit is contained in:
bQUARKz 2026-01-10 06:44:34 +00:00
parent 4ccd38580f
commit cdfb1188ee
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
9 changed files with 144 additions and 95 deletions

View File

@ -0,0 +1,25 @@
#[derive(Default, Clone, Copy, Debug)]
pub struct CButton {
pub pressed: bool,
pub released: bool,
pub down: bool,
pub hold_frames: u32,
}
impl CButton {
pub fn begin_frame(&mut self, is_down_now: bool) {
let was_down = self.down;
self.down = is_down_now;
// Detecta transições
self.pressed = !was_down && self.down;
self.released = was_down && !self.down;
// Atualiza contador de frames
if self.down {
self.hold_frames = self.hold_frames.saturating_add(1);
} else {
self.hold_frames = 0;
}
}
}

View File

@ -1,6 +1,7 @@
pub mod machine; pub mod machine;
pub mod peripherals; pub mod peripherals;
mod color; mod color;
mod c_button;
pub use machine::Machine; pub use machine::Machine;
pub use color::Color; pub use color::Color;

View File

@ -1,11 +1,11 @@
use crate::peripherals::{Gfx, Input, Touch}; use crate::peripherals::{Gfx, InputSignals, Pad, Touch};
use crate::Color; use crate::Color;
/// PROMETEU "hardware lógico" (v0). /// PROMETEU "hardware lógico" (v0).
/// O Host alimenta INPUT/TOUCH e chama `step_frame()` em 60Hz. /// O Host alimenta INPUT/TOUCH e chama `step_frame()` em 60Hz.
pub struct Machine { pub struct Machine {
pub gfx: Gfx, pub gfx: Gfx,
pub input: Input, pub pad: Pad,
pub touch: Touch, pub touch: Touch,
pub frame_index: u64, pub frame_index: u64,
} }
@ -17,7 +17,7 @@ impl Machine {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
gfx: Gfx::new(Self::W, Self::H), gfx: Gfx::new(Self::W, Self::H),
input: Input::default(), pad: Pad::default(),
touch: Touch::default(), touch: Touch::default(),
frame_index: 0, frame_index: 0,
} }
@ -25,21 +25,21 @@ impl Machine {
/// "Contrato de frame" do PROMETEU (Template Method sem loop). /// "Contrato de frame" do PROMETEU (Template Method sem loop).
/// O Host controla tempo/event loop; o Core define a sequência do frame. /// O Host controla tempo/event loop; o Core define a sequência do frame.
pub fn step_frame(&mut self) { pub fn step_frame(&mut self, signals: &InputSignals) {
self.begin_frame(); self.begin_frame(signals);
self.tick(); // futuro: executa cartucho/VM self.tick(); // futuro: executa cartucho/VM
self.end_frame(); // present/housekeeping self.end_frame(); // present/housekeeping
} }
/// Início do frame: zera flags transitórias. /// Início do frame: zera flags transitórias.
pub fn begin_frame(&mut self) { pub fn begin_frame(&mut self, signals: &InputSignals) {
self.frame_index += 1; self.frame_index += 1;
// Flags transitórias do TOUCH devem durar 1 frame. // Flags transitórias do TOUCH devem durar 1 frame.
self.touch.begin_frame(); self.touch.begin_frame(signals);
// Se você quiser input com pressed/released depois: // Se você quiser input com pressed/released depois:
// self.input.begin_frame(); self.pad.begin_frame(signals);
} }
/// Lógica do frame (demo hardcoded por enquanto). /// Lógica do frame (demo hardcoded por enquanto).
@ -48,7 +48,7 @@ impl Machine {
let (x, y) = self.demo_pos(); let (x, y) = self.demo_pos();
let color = if self.input.a_down || self.touch.down { let color = if self.pad.a.down || self.touch.f.down {
Color::rgb(0x00, 0xFF, 0x00) Color::rgb(0x00, 0xFF, 0x00)
} else { } else {
Color::rgb(0xFF, 0x40, 0x40) Color::rgb(0xFF, 0x40, 0x40)

View File

@ -1,20 +0,0 @@
#[derive(Default, Clone, Copy, Debug)]
pub struct Input {
pub up: bool,
pub down: bool,
pub left: bool,
pub right: bool,
pub a_down: bool,
pub b_down: bool,
pub start: bool,
pub select: bool,
}
impl Input {
pub fn begin_frame(&mut self) {
// No v0, nada a fazer.
// No futuro: a_pressed/a_released, etc.
}
}

View File

@ -0,0 +1,26 @@
#[derive(Default, Clone, Copy, Debug)]
pub struct InputSignals {
// PAD
pub up_signal: bool,
pub down_signal: bool,
pub left_signal: bool,
pub right_signal: bool,
pub a_signal: bool,
pub d_signal: bool,
pub w_signal: bool,
pub s_signal: bool,
pub q_signal: bool,
pub e_signal: bool,
pub start_signal: bool,
pub select_signal: bool,
// TOUCH
pub t_signal: bool,
pub x_pos: i32,
pub y_pos: i32,
}
impl InputSignals {
}

View File

@ -1,7 +1,9 @@
mod gfx; mod gfx;
mod input; mod pad;
mod touch; mod touch;
mod input_signal;
pub use gfx::Gfx; pub use gfx::Gfx;
pub use input::Input; pub use input_signal::InputSignals;
pub use pad::Pad;
pub use touch::Touch; pub use touch::Touch;

View File

@ -0,0 +1,41 @@
use crate::c_button::CButton;
use crate::peripherals::input_signal::InputSignals;
#[derive(Default, Clone, Copy, Debug)]
pub struct Pad {
pub up: CButton,
pub down: CButton,
pub left: CButton,
pub right: CButton,
pub a: CButton, // ps: square
pub d: CButton, // ps: circle
pub w: CButton, // ps: triangle
pub s: CButton, // ps: cross
pub q: CButton, // ps: R
pub e: CButton, // ps: L
pub start: CButton,
pub select: CButton,
}
impl Pad {
pub fn begin_frame(&mut self, signals: &InputSignals) {
self.up.begin_frame(signals.up_signal);
self.down.begin_frame(signals.down_signal);
self.left.begin_frame(signals.left_signal);
self.right.begin_frame(signals.right_signal);
self.a.begin_frame(signals.a_signal);
self.d.begin_frame(signals.d_signal);
self.w.begin_frame(signals.w_signal);
self.s.begin_frame(signals.s_signal);
self.q.begin_frame(signals.q_signal);
self.e.begin_frame(signals.e_signal);
self.start.begin_frame(signals.start_signal);
self.select.begin_frame(signals.select_signal);
}
}

View File

@ -1,17 +1,18 @@
use crate::c_button::CButton;
use crate::peripherals::input_signal::InputSignals;
#[derive(Default, Clone, Copy, Debug)] #[derive(Default, Clone, Copy, Debug)]
pub struct Touch { pub struct Touch {
pub present: bool, pub f: CButton,
pub down: bool,
pub pressed: bool,
pub released: bool,
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
} }
impl Touch { impl Touch {
/// Flags transitórias devem durar apenas 1 frame. /// Flags transitórias devem durar apenas 1 frame.
pub fn begin_frame(&mut self) { pub fn begin_frame(&mut self, signals: &InputSignals) {
self.pressed = false; self.f.begin_frame(signals.t_signal);
self.released = false; self.x = signals.x_pos;
self.y = signals.y_pos;
} }
} }

View File

@ -1,6 +1,7 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use pixels::{Pixels, SurfaceTexture}; use pixels::{Pixels, SurfaceTexture};
use prometeu_core::peripherals::InputSignals;
use prometeu_core::Machine; use prometeu_core::Machine;
use winit::{ use winit::{
application::ApplicationHandler, application::ApplicationHandler,
@ -23,15 +24,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
struct PrometeuApp { struct PrometeuApp {
window: Option<&'static Window>, window: Option<&'static Window>,
pixels: Option<Pixels<'static>>, pixels: Option<Pixels<'static>>,
machine: Machine, machine: Machine,
input_signals: InputSignals,
frame_dt: Duration, frame_dt: Duration,
next_frame: Instant, next_frame: Instant,
mouse_down: bool,
mouse_just_pressed: bool,
mouse_just_released: bool,
mouse_pos_fb: (i32, i32),
} }
impl PrometeuApp { impl PrometeuApp {
@ -39,15 +38,11 @@ impl PrometeuApp {
Self { Self {
window: None, window: None,
pixels: None, pixels: None,
input_signals: InputSignals::default(),
machine: Machine::new(), machine: Machine::new(),
frame_dt: Duration::from_nanos(1_000_000_000 / 60), frame_dt: Duration::from_nanos(1_000_000_000 / 60),
next_frame: Instant::now(), next_frame: Instant::now(),
mouse_down: false,
mouse_just_pressed: false,
mouse_just_released: false,
mouse_pos_fb: (0, 0),
} }
} }
@ -70,39 +65,6 @@ impl PrometeuApp {
w.request_redraw(); w.request_redraw();
} }
} }
fn map_key(&mut self, code: KeyCode, is_down: bool) {
match code {
KeyCode::ArrowUp => self.machine.input.up = is_down,
KeyCode::ArrowDown => self.machine.input.down = is_down,
KeyCode::ArrowLeft => self.machine.input.left = is_down,
KeyCode::ArrowRight => self.machine.input.right = is_down,
// A/B (troque depois como quiser)
KeyCode::KeyZ => self.machine.input.a_down = is_down,
KeyCode::KeyX => self.machine.input.b_down = is_down,
KeyCode::Enter => self.machine.input.start = is_down,
KeyCode::ShiftLeft | KeyCode::ShiftRight => self.machine.input.select = is_down,
_ => {}
}
}
fn update_touch_in_core(&mut self) {
// no desktop, mouse emula touch
self.machine.touch.present = true;
self.machine.touch.x = self.mouse_pos_fb.0;
self.machine.touch.y = self.mouse_pos_fb.1;
// pressed/released devem durar 1 frame (o core limpa em begin_frame)
self.machine.touch.pressed = self.mouse_just_pressed;
self.machine.touch.released = self.mouse_just_released;
self.machine.touch.down = self.mouse_down;
self.mouse_just_pressed = false;
self.mouse_just_released = false;
}
} }
impl ApplicationHandler for PrometeuApp { impl ApplicationHandler for PrometeuApp {
@ -169,28 +131,42 @@ impl ApplicationHandler for PrometeuApp {
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput { event, .. } => {
if let PhysicalKey::Code(code) = event.physical_key { if let PhysicalKey::Code(code) = event.physical_key {
let is_down = event.state == ElementState::Pressed; let is_down = event.state == ElementState::Pressed;
self.map_key(code, is_down); match code {
KeyCode::ArrowUp => self.input_signals.up_signal = is_down,
KeyCode::ArrowDown => self.input_signals.down_signal = is_down,
KeyCode::ArrowLeft => self.input_signals.left_signal = is_down,
KeyCode::ArrowRight => self.input_signals.right_signal = is_down,
// A/B (troque depois como quiser)
KeyCode::KeyA => self.input_signals.a_signal = is_down,
KeyCode::KeyD => self.input_signals.d_signal = is_down,
KeyCode::KeyW => self.input_signals.w_signal = is_down,
KeyCode::KeyS => self.input_signals.s_signal = is_down,
KeyCode::KeyQ => self.input_signals.q_signal = is_down,
KeyCode::KeyE => self.input_signals.e_signal = is_down,
KeyCode::KeyZ => self.input_signals.start_signal = is_down,
KeyCode::ShiftLeft | KeyCode::ShiftRight => self.input_signals.select_signal = is_down,
_ => {}
}
} }
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
self.mouse_pos_fb = window_to_fb(position.x as f32, position.y as f32, self.window()); let v = window_to_fb(position.x as f32, position.y as f32, self.window());
self.input_signals.x_pos = v.0;
self.input_signals.y_pos = v.1;
} }
WindowEvent::MouseInput { state, button, .. } => { WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left { if button == MouseButton::Left {
match state { match state {
ElementState::Pressed => { ElementState::Pressed => {
if !self.mouse_down { self.input_signals.t_signal = true;
self.mouse_down = true;
self.mouse_just_pressed = true;
}
} }
ElementState::Released => { ElementState::Released => {
if self.mouse_down { self.input_signals.t_signal = false;
self.mouse_down = false;
self.mouse_just_released = true;
}
} }
} }
} }
@ -207,11 +183,8 @@ impl ApplicationHandler for PrometeuApp {
if now >= self.next_frame { if now >= self.next_frame {
self.next_frame += self.frame_dt; self.next_frame += self.frame_dt;
// atualiza touch/input no core
self.update_touch_in_core();
// executa 1 frame do PROMETEU // executa 1 frame do PROMETEU
self.machine.step_frame(); self.machine.step_frame(&self.input_signals);
// pede redraw // pede redraw
self.request_redraw(); self.request_redraw();