Support full controller input

This commit is contained in:
Simon Gellis 2024-11-05 00:07:48 -05:00
parent 75fa3be25c
commit 5c5d56cb12
7 changed files with 109 additions and 21 deletions

1
Cargo.lock generated
View File

@ -1957,6 +1957,7 @@ name = "shrooms-vb-native"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.6.0",
"bytemuck", "bytemuck",
"cc", "cc",
"clap", "clap",

View File

@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
bitflags = "2"
bytemuck = { version = "1", features = ["derive"] } bytemuck = { version = "1", features = ["derive"] }
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
cpal = "0.15" cpal = "0.15"

View File

@ -9,13 +9,13 @@ use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows as _
use winit::{ use winit::{
application::ApplicationHandler, application::ApplicationHandler,
dpi::{LogicalSize, PhysicalSize}, dpi::{LogicalSize, PhysicalSize},
event::{ElementState, Event, WindowEvent}, event::{Event, WindowEvent},
event_loop::ActiveEventLoop, event_loop::ActiveEventLoop,
keyboard::Key,
window::Window, window::Window,
}; };
use crate::{ use crate::{
controller::ControllerState,
emulator::{EmulatorClient, EmulatorCommand}, emulator::{EmulatorClient, EmulatorCommand},
renderer::GameRenderer, renderer::GameRenderer,
}; };
@ -270,13 +270,17 @@ impl AppWindow {
pub struct App { pub struct App {
window: Option<AppWindow>, window: Option<AppWindow>,
client: EmulatorClient, client: EmulatorClient,
controller: ControllerState,
} }
impl App { impl App {
pub fn new(client: EmulatorClient) -> Self { pub fn new(client: EmulatorClient) -> Self {
let controller = ControllerState::new();
client.send_command(EmulatorCommand::SetKeys(controller.pressed()));
Self { Self {
window: None, window: None,
client, client,
controller,
} }
} }
} }
@ -305,15 +309,9 @@ impl ApplicationHandler for App {
} }
WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput { event, .. } => {
if let Key::Character("s") = event.logical_key.as_ref() { if self.controller.key_event(event) {
match event.state { self.client
ElementState::Pressed => { .send_command(EmulatorCommand::SetKeys(self.controller.pressed()));
self.client.send_command(EmulatorCommand::PressStart)
}
ElementState::Released => {
self.client.send_command(EmulatorCommand::ReleaseStart)
}
}
} }
} }
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {

64
src/controller.rs Normal file
View File

@ -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<VBKey> {
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,
}
}
}

View File

@ -10,7 +10,11 @@ use std::{
use anyhow::Result; 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 { pub struct EmulatorBuilder {
rom: Option<PathBuf>, rom: Option<PathBuf>,
@ -132,11 +136,8 @@ impl Emulator {
self.sim.reset(); self.sim.reset();
self.running.store(true, Ordering::Release); self.running.store(true, Ordering::Release);
} }
EmulatorCommand::PressStart => { EmulatorCommand::SetKeys(keys) => {
self.sim.set_keys(0x1003); self.sim.set_keys(keys);
}
EmulatorCommand::ReleaseStart => {
self.sim.set_keys(0x0003);
} }
} }
} }
@ -149,8 +150,7 @@ pub enum EmulatorCommand {
Pause, Pause,
Resume, Resume,
Reset, Reset,
PressStart, SetKeys(VBKey),
ReleaseStart,
} }
pub struct EmulatorClient { pub struct EmulatorClient {

View File

@ -8,6 +8,7 @@ use winit::event_loop::{ControlFlow, EventLoop};
mod app; mod app;
mod audio; mod audio;
mod controller;
mod emulator; mod emulator;
mod renderer; mod renderer;
mod shrooms_vb_core; mod shrooms_vb_core;

View File

@ -1,6 +1,7 @@
use std::{ffi::c_void, ptr, slice}; use std::{ffi::c_void, ptr, slice};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use bitflags::bitflags;
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
#[repr(C)] #[repr(C)]
@ -24,6 +25,28 @@ enum VBDataType {
F32 = 5, 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; type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
#[link(name = "vb")] #[link(name = "vb")]
@ -198,8 +221,8 @@ impl CoreVB {
}; };
} }
pub fn set_keys(&mut self, keys: u16) { pub fn set_keys(&mut self, keys: VBKey) {
unsafe { vb_set_keys(self.sim, keys) }; unsafe { vb_set_keys(self.sim, keys.bits()) };
} }
} }