Support full controller input
This commit is contained in:
parent
75fa3be25c
commit
5c5d56cb12
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
20
src/app.rs
20
src/app.rs
|
@ -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 => {
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue