code cleanup

- make joypad a directory module, split retropad implementation into new module (but re-export it). also rename joypad to InputDevice

- remove spurious retro_reset (it's not needed and in fact crashes some cores)

- rename frontend input device APIs, add one for removing (unplugging) a device
This commit is contained in:
Lily Tsuru 2024-08-04 20:26:30 -04:00
parent ad634bf1fa
commit a7544cb64d
6 changed files with 71 additions and 54 deletions

View file

@ -1,4 +1,4 @@
use crate::joypad::Joypad; use crate::input_devices::InputDevice;
use crate::libretro_callbacks; use crate::libretro_callbacks;
use crate::libretro_core_variable::CoreVariable; use crate::libretro_core_variable::CoreVariable;
use crate::result::{Error, Result}; use crate::result::{Error, Result};
@ -66,13 +66,19 @@ pub struct Frontend {
pub(crate) fb_height: u32, pub(crate) fb_height: u32,
pub(crate) fb_pitch: u32, pub(crate) fb_pitch: u32,
/// The "system" directory. Used for BIOS roms
pub(crate) system_directory: CString, pub(crate) system_directory: CString,
/// The save directory. Used for saves. (TODO: Should make this per-core!!!)
pub(crate) save_directory: CString, pub(crate) save_directory: CString,
/// The config directory. Stores configuration for each core.
pub(crate) config_directory: String, pub(crate) config_directory: String,
/// Hashmap of core variabels.
pub(crate) variables: HashMap<String, CoreVariable>, pub(crate) variables: HashMap<String, CoreVariable>,
pub(crate) joypads: HashMap<u32 /* port */, *mut dyn Joypad>, pub(crate) joypads: HashMap<u32 /* port */, *mut dyn InputDevice>,
pub(crate) interface: *mut dyn FrontendInterface, pub(crate) interface: *mut dyn FrontendInterface,
} }
@ -111,7 +117,7 @@ impl Frontend {
// Assign to the global fronend pointer // Assign to the global fronend pointer
unsafe { unsafe {
assert!(FRONTEND.is_null(), "Cannot have multiple sir."); assert!(FRONTEND.is_null(), "Cannot have multiple frontends.");
FRONTEND = &mut *boxed as *mut Frontend; FRONTEND = &mut *boxed as *mut Frontend;
} }
@ -123,7 +129,8 @@ impl Frontend {
self.core_library.is_some() && self.core_api.is_some() self.core_library.is_some() && self.core_api.is_some()
} }
pub fn set_input_port_device(&mut self, port: u32, device: *mut dyn Joypad) { /// Plugs in an input device to the specified port.
pub fn plug_input_device(&mut self, port: u32, device: *mut dyn InputDevice) {
if self.core_loaded() { if self.core_loaded() {
let core_api = self.core_api.as_mut().unwrap(); let core_api = self.core_api.as_mut().unwrap();
@ -131,11 +138,28 @@ impl Frontend {
(core_api.retro_set_controller_port_device)(port, (*device).device_type()); (core_api.retro_set_controller_port_device)(port, (*device).device_type());
} }
self.joypads.insert(port, device); if !self.joypads.contains_key(&port) {
self.joypads.insert(port, device);
} else {
(*self.joypads.get_mut(&port).unwrap()) = device;
}
} }
} }
// clear_input_port_device? /// Unplugs a input device from the given port.
pub fn unplug_input_device(&mut self, port: u32) {
if self.core_loaded() {
let core_api = self.core_api.as_mut().unwrap();
unsafe {
(core_api.retro_set_controller_port_device)(port, DEVICE_NONE);
}
if !self.joypads.contains_key(&port) {
self.joypads.remove(&port);
}
}
}
fn get_config_file_path(&self) -> String { fn get_config_file_path(&self) -> String {
let path = unsafe { let path = unsafe {
@ -280,8 +304,6 @@ impl Frontend {
libretro_callbacks::audio_sample_batch_callback, libretro_callbacks::audio_sample_batch_callback,
); );
(core_api_ref.retro_reset)();
info!("Core {} loaded", path.as_ref().display()); info!("Core {} loaded", path.as_ref().display());
// Get AV info // Get AV info

View file

@ -0,0 +1,17 @@
//! Input devices
pub mod retropad;
pub use retropad::*;
/// Trait for implementing Libretro input devices
pub trait InputDevice {
// TODO: is_pressed(id: u32)?
fn device_type(&self) -> u32;
fn get_button(&self, id: u32) -> i16;
fn reset(&mut self);
fn press_button(&mut self, id: u32, pressure: Option<i16>);
}

View file

@ -1,23 +1,8 @@
//! libretro pad abstraction //! RetroPad
use super::InputDevice;
use crate::libretro_sys_new; use crate::libretro_sys_new;
pub trait Joypad { /// Implementation of the [InputDevice] trait for the Libretro
// TODO: is_pressed(id: u32)?
fn device_type(&self) -> u32;
fn get_button(&self, id: u32) -> i16;
fn reset(&mut self);
fn press_button(&mut self, id: u32, pressure: Option<i16>);
}
// TODO: Split this into a new module, and make this a dir based one
// (mod.rs/retropad.rs/analogpad.rs) once we have AnalogPad support.
/// Implementation of the [Joypad] trait for the Libretro
/// RetroPad; which is essentially a standard PS1 controller, /// RetroPad; which is essentially a standard PS1 controller,
/// with a couple more buttons inherited from the Dual Analog/DualShock. /// with a couple more buttons inherited from the Dual Analog/DualShock.
pub struct RetroPad { pub struct RetroPad {
@ -30,7 +15,7 @@ impl RetroPad {
} }
} }
impl Joypad for RetroPad { impl InputDevice for RetroPad {
fn device_type(&self) -> u32 { fn device_type(&self) -> u32 {
libretro_sys_new::DEVICE_JOYPAD libretro_sys_new::DEVICE_JOYPAD
} }

View file

@ -6,7 +6,7 @@ mod libretro_log;
pub mod libretro_sys_new; pub mod libretro_sys_new;
pub mod joypad; pub mod input_devices;
pub mod util; pub mod util;
pub mod frontend; pub mod frontend;

View file

@ -6,13 +6,24 @@ use tracing::*;
#[no_mangle] #[no_mangle]
/// This recieves log messages from our C++ helper code, and pulls them out into Tracing messages. /// This recieves log messages from our C++ helper code, and pulls them out into Tracing messages.
pub extern "C" fn libretro_log_recieve(level: LogLevel, buf: *const ffi::c_char) { pub extern "C" fn libretro_log_recieve(level: LogLevel, buf: *const ffi::c_char) {
let mut msg: Option<&str> = None;
// Safety: This pointer is never null, and always comes from the stack; // Safety: This pointer is never null, and always comes from the stack;
// we really only should get UTF-8 errors here in the case a core spits out something invalid. // we really only should get UTF-8 errors here in the case a core spits out something invalid.
unsafe { unsafe {
match ffi::CStr::from_ptr(buf).to_str() { match ffi::CStr::from_ptr(buf).to_str() {
Ok(message) => msg = Some(message), Ok(message) => match level {
LogLevel::Debug => {
debug!("{}", message)
}
LogLevel::Info => {
info!("{}", message)
}
LogLevel::Warn => {
warn!("{}", message)
}
LogLevel::Error => {
error!("{}", message)
}
},
Err(err) => { Err(err) => {
error!( error!(
"Core for some reason gave a broken string to log interface: {:?}", "Core for some reason gave a broken string to log interface: {:?}",
@ -21,23 +32,6 @@ pub extern "C" fn libretro_log_recieve(level: LogLevel, buf: *const ffi::c_char)
} }
} }
} }
if let Some(message) = &msg {
match level {
LogLevel::Debug => {
debug!("Core log: {}", message)
}
LogLevel::Info => {
info!("Core log: {}", message)
}
LogLevel::Warn => {
warn!("Core log: {}", message)
}
LogLevel::Error => {
error!("Core log: {}", message)
}
}
}
} }
extern "C" { extern "C" {

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use retro_frontend::{ use retro_frontend::{
frontend::{Frontend, FrontendInterface}, frontend::{Frontend, FrontendInterface},
joypad::{Joypad, RetroPad}, input_devices::{InputDevice, RetroPad},
}; };
use tracing::Level; use tracing::Level;
use tracing_subscriber::FmtSubscriber; use tracing_subscriber::FmtSubscriber;
@ -25,7 +25,6 @@ impl App {
let mut boxed = Box::new(Self { let mut boxed = Box::new(Self {
frontend: None, frontend: None,
rfb_server: RfbServer::new(rfb_config)?, rfb_server: RfbServer::new(rfb_config)?,
// nasty, but idk a better way
pad: RetroPad::new(), pad: RetroPad::new(),
}); });
@ -43,9 +42,9 @@ impl App {
fn init(&mut self) { fn init(&mut self) {
// Currently retrovnc just hardcodes the assumption of a single RetroPad. // Currently retrovnc just hardcodes the assumption of a single RetroPad.
let pad = &mut self.pad as *mut dyn Joypad; let pad = &mut self.pad as *mut dyn InputDevice;
self.get_frontend().set_input_port_device(0, pad); self.get_frontend().plug_input_device(0, pad);
// Initalize the display // Initalize the display
self.init_display(); self.init_display();
@ -66,7 +65,7 @@ impl App {
} }
} }
fn load_core<P: AsRef<Path>>(&mut self, path: P) -> Result<(), retro_frontend::result::Error> { fn load_core<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
if self.get_frontend().core_loaded() { if self.get_frontend().core_loaded() {
println!("???"); println!("???");
let _ = self.get_frontend().unload_core(); let _ = self.get_frontend().unload_core();
@ -76,7 +75,7 @@ impl App {
Ok(()) Ok(())
} }
fn load_game<P: AsRef<Path>>(&mut self, path: P) -> Result<(), retro_frontend::result::Error> { fn load_game<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
self.get_frontend().load_game(path)?; self.get_frontend().load_game(path)?;
Ok(()) Ok(())
} }