From 5c5d56cb123e96731ebc4ecce9b0b0810ad2380a Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Tue, 5 Nov 2024 00:07:48 -0500 Subject: [PATCH] Support full controller input --- Cargo.lock | 1 + Cargo.toml | 1 + src/app.rs | 20 ++++++------- src/controller.rs | 64 ++++++++++++++++++++++++++++++++++++++++++ src/emulator.rs | 16 +++++------ src/main.rs | 1 + src/shrooms_vb_core.rs | 27 ++++++++++++++++-- 7 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 src/controller.rs diff --git a/Cargo.lock b/Cargo.lock index 3944f49..70ce33d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1957,6 +1957,7 @@ name = "shrooms-vb-native" version = "0.1.0" dependencies = [ "anyhow", + "bitflags 2.6.0", "bytemuck", "cc", "clap", diff --git a/Cargo.toml b/Cargo.toml index e2c6317..5ce4bf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] anyhow = "1" +bitflags = "2" bytemuck = { version = "1", features = ["derive"] } clap = { version = "4", features = ["derive"] } cpal = "0.15" diff --git a/src/app.rs b/src/app.rs index a2be00c..2906783 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,13 +9,13 @@ use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows as _ use winit::{ application::ApplicationHandler, dpi::{LogicalSize, PhysicalSize}, - event::{ElementState, Event, WindowEvent}, + event::{Event, WindowEvent}, event_loop::ActiveEventLoop, - keyboard::Key, window::Window, }; use crate::{ + controller::ControllerState, emulator::{EmulatorClient, EmulatorCommand}, renderer::GameRenderer, }; @@ -270,13 +270,17 @@ impl AppWindow { pub struct App { window: Option, client: EmulatorClient, + controller: ControllerState, } impl App { pub fn new(client: EmulatorClient) -> Self { + let controller = ControllerState::new(); + client.send_command(EmulatorCommand::SetKeys(controller.pressed())); Self { window: None, client, + controller, } } } @@ -305,15 +309,9 @@ impl ApplicationHandler for App { } WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::KeyboardInput { event, .. } => { - if let Key::Character("s") = event.logical_key.as_ref() { - match event.state { - ElementState::Pressed => { - self.client.send_command(EmulatorCommand::PressStart) - } - ElementState::Released => { - self.client.send_command(EmulatorCommand::ReleaseStart) - } - } + if self.controller.key_event(event) { + self.client + .send_command(EmulatorCommand::SetKeys(self.controller.pressed())); } } WindowEvent::RedrawRequested => { diff --git a/src/controller.rs b/src/controller.rs new file mode 100644 index 0000000..1e8995e --- /dev/null +++ b/src/controller.rs @@ -0,0 +1,64 @@ +use winit::{ + event::{ElementState, KeyEvent}, + keyboard::{Key, NamedKey}, +}; + +use crate::shrooms_vb_core::VBKey; + +pub struct ControllerState { + pressed: VBKey, +} + +impl ControllerState { + pub fn new() -> Self { + Self { + pressed: VBKey::SGN, + } + } + + pub fn pressed(&self) -> VBKey { + self.pressed + } + + pub fn key_event(&mut self, event: &KeyEvent) -> bool { + let Some(input) = self.key_to_input(&event.logical_key) else { + return false; + }; + match event.state { + ElementState::Pressed => { + if self.pressed.contains(input) { + return false; + } + self.pressed.insert(input); + true + } + ElementState::Released => { + if !self.pressed.contains(input) { + return false; + } + self.pressed.remove(input); + true + } + } + } + + fn key_to_input(&self, key: &Key) -> Option { + match key.as_ref() { + Key::Character("a") => Some(VBKey::SEL), + Key::Character("s") => Some(VBKey::STA), + Key::Character("d") => Some(VBKey::B), + Key::Character("f") => Some(VBKey::A), + Key::Character("e") => Some(VBKey::LT), + Key::Character("r") => Some(VBKey::RT), + Key::Character("i") => Some(VBKey::RU), + Key::Character("j") => Some(VBKey::RL), + Key::Character("k") => Some(VBKey::RD), + Key::Character("l") => Some(VBKey::RR), + Key::Named(NamedKey::ArrowUp) => Some(VBKey::LU), + Key::Named(NamedKey::ArrowLeft) => Some(VBKey::LL), + Key::Named(NamedKey::ArrowDown) => Some(VBKey::LD), + Key::Named(NamedKey::ArrowRight) => Some(VBKey::LR), + _ => None, + } + } +} diff --git a/src/emulator.rs b/src/emulator.rs index e87a9b4..f93d310 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -10,7 +10,11 @@ use std::{ use anyhow::Result; -use crate::{audio::Audio, renderer::GameRenderer, shrooms_vb_core::CoreVB}; +use crate::{ + audio::Audio, + renderer::GameRenderer, + shrooms_vb_core::{CoreVB, VBKey}, +}; pub struct EmulatorBuilder { rom: Option, @@ -132,11 +136,8 @@ impl Emulator { self.sim.reset(); self.running.store(true, Ordering::Release); } - EmulatorCommand::PressStart => { - self.sim.set_keys(0x1003); - } - EmulatorCommand::ReleaseStart => { - self.sim.set_keys(0x0003); + EmulatorCommand::SetKeys(keys) => { + self.sim.set_keys(keys); } } } @@ -149,8 +150,7 @@ pub enum EmulatorCommand { Pause, Resume, Reset, - PressStart, - ReleaseStart, + SetKeys(VBKey), } pub struct EmulatorClient { diff --git a/src/main.rs b/src/main.rs index 474bad5..7a588ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; mod app; mod audio; +mod controller; mod emulator; mod renderer; mod shrooms_vb_core; diff --git a/src/shrooms_vb_core.rs b/src/shrooms_vb_core.rs index 19ce04b..8fb1789 100644 --- a/src/shrooms_vb_core.rs +++ b/src/shrooms_vb_core.rs @@ -1,6 +1,7 @@ use std::{ffi::c_void, ptr, slice}; use anyhow::{anyhow, Result}; +use bitflags::bitflags; use num_derive::{FromPrimitive, ToPrimitive}; #[repr(C)] @@ -24,6 +25,28 @@ enum VBDataType { F32 = 5, } +bitflags! { + #[derive(Clone, Copy, Debug)] + pub struct VBKey: u16 { + const PWR = 0x0001; + const SGN = 0x0002; + const A = 0x0004; + const B = 0x0008; + const RT = 0x0010; + const LT = 0x0020; + const RU = 0x0040; + const RR = 0x0080; + const LR = 0x0100; + const LL = 0x0200; + const LD = 0x0400; + const LU = 0x0800; + const STA = 0x1000; + const SEL = 0x2000; + const RL = 0x4000; + const RD = 0x8000; + } +} + type OnFrame = extern "C" fn(sim: *mut VB) -> c_int; #[link(name = "vb")] @@ -198,8 +221,8 @@ impl CoreVB { }; } - pub fn set_keys(&mut self, keys: u16) { - unsafe { vb_set_keys(self.sim, keys) }; + pub fn set_keys(&mut self, keys: VBKey) { + unsafe { vb_set_keys(self.sim, keys.bits()) }; } }