implement ENVIRONMENT_SET_CONTROLLER_INFO
This commit is contained in:
parent
871e0f799f
commit
604b3f03f8
3 changed files with 61 additions and 24 deletions
|
@ -5,7 +5,7 @@ extern crate sdl2;
|
||||||
use rustro::retro;
|
use rustro::retro;
|
||||||
use rustro::retro::ffi::{GameGeometry, SystemInfo, SystemAvInfo};
|
use rustro::retro::ffi::{GameGeometry, SystemInfo, SystemAvInfo};
|
||||||
use rustro::retro::constants::{Input, DeviceIndex, JoypadButton, AnalogAxis, DeviceType};
|
use rustro::retro::constants::{Input, DeviceIndex, JoypadButton, AnalogAxis, DeviceType};
|
||||||
use rustro::retro::wrapper::{LibretroWrapper, VariableDescriptor};
|
use rustro::retro::wrapper::{LibretroWrapper, VariableDescriptor, ControllerTypeDescriptor};
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
@ -27,6 +27,8 @@ struct MyEmulator {
|
||||||
core_path: PathBuf,
|
core_path: PathBuf,
|
||||||
sys_path: Option<PathBuf>,
|
sys_path: Option<PathBuf>,
|
||||||
|
|
||||||
|
preferred_pad: Option<u32>,
|
||||||
|
|
||||||
sys_info: SystemInfo,
|
sys_info: SystemInfo,
|
||||||
av_info: SystemAvInfo,
|
av_info: SystemAvInfo,
|
||||||
|
|
||||||
|
@ -116,6 +118,8 @@ impl MyEmulator {
|
||||||
let emu = MyEmulator {
|
let emu = MyEmulator {
|
||||||
retro,
|
retro,
|
||||||
core_path,
|
core_path,
|
||||||
|
sys_path: sys_path.as_ref().map(|p| p.as_ref().to_path_buf()),
|
||||||
|
preferred_pad: None,
|
||||||
av_info,
|
av_info,
|
||||||
sys_info,
|
sys_info,
|
||||||
sdl_context,
|
sdl_context,
|
||||||
|
@ -127,7 +131,6 @@ impl MyEmulator {
|
||||||
audio_sender,
|
audio_sender,
|
||||||
gamepad_subsys,
|
gamepad_subsys,
|
||||||
gamepads,
|
gamepads,
|
||||||
sys_path: sys_path.as_ref().map(|p| p.as_ref().to_path_buf())
|
|
||||||
};
|
};
|
||||||
let mut pin_emu = Box::pin(emu);
|
let mut pin_emu = Box::pin(emu);
|
||||||
retro::wrapper::set_handler(pin_emu.as_mut());
|
retro::wrapper::set_handler(pin_emu.as_mut());
|
||||||
|
@ -176,10 +179,10 @@ impl MyEmulator {
|
||||||
self.retro
|
self.retro
|
||||||
.load_game(Some(path), data, None)
|
.load_game(Some(path), data, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
if let Some(device) = self.preferred_pad {
|
||||||
let saturn_3d_pad = DeviceType::Analog.device_subclass(0);
|
for port in 0..self.gamepads.len() as u32 {
|
||||||
for i in 0..self.gamepads.len() as u32 {
|
self.retro.set_controller_port_device(port, device);
|
||||||
self.retro.set_controller_port_device(i, saturn_3d_pad);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,11 +279,12 @@ impl retro::wrapper::Handler for MyEmulator {
|
||||||
match key {
|
match key {
|
||||||
"beetle_saturn_analog_stick_deadzone" => Some("15%".to_string()),
|
"beetle_saturn_analog_stick_deadzone" => Some("15%".to_string()),
|
||||||
"parallel-n64-gfxplugin" => Some("angrylion".to_string()),
|
"parallel-n64-gfxplugin" => Some("angrylion".to_string()),
|
||||||
_ => { eprintln!("ignored: get_variable({})", key); None }
|
"parallel-n64-astick-deadzone" => Some("15%".to_string()),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_variables(&mut self, variables: &[VariableDescriptor]) -> bool {
|
fn set_variables(&mut self, variables: Vec<VariableDescriptor>) -> bool {
|
||||||
for v in variables {
|
for v in variables {
|
||||||
eprintln!("{:?}", v);
|
eprintln!("{:?}", v);
|
||||||
}
|
}
|
||||||
|
@ -299,12 +303,24 @@ impl retro::wrapper::Handler for MyEmulator {
|
||||||
fn get_save_directory(&mut self) -> Option<PathBuf> {
|
fn get_save_directory(&mut self) -> Option<PathBuf> {
|
||||||
Some(std::env::temp_dir())
|
Some(std::env::temp_dir())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_system_av_info(&mut self, av_info: SystemAvInfo) -> bool {
|
fn set_system_av_info(&mut self, av_info: SystemAvInfo) -> bool {
|
||||||
self.set_geometry(av_info.geometry.clone());
|
self.set_geometry(av_info.geometry.clone());
|
||||||
self.av_info = av_info;
|
self.av_info = av_info;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_controller_info(&mut self, controller_info: Vec<ControllerTypeDescriptor>) -> bool {
|
||||||
|
for ci in controller_info {
|
||||||
|
// so we can have analog support in beetle/mednafen saturn
|
||||||
|
if ci.name.as_str() == "3D Control Pad" {
|
||||||
|
self.preferred_pad = Some(ci.device_id());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn set_geometry(&mut self, geom: GameGeometry) -> bool {
|
fn set_geometry(&mut self, geom: GameGeometry) -> bool {
|
||||||
let _ = self.canvas.window_mut().set_size(geom.base_width, geom.base_height);
|
let _ = self.canvas.window_mut().set_size(geom.base_width, geom.base_height);
|
||||||
let _ = self.canvas.set_logical_size(geom.base_width, geom.base_height);
|
let _ = self.canvas.set_logical_size(geom.base_width, geom.base_height);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::ffi::*;
|
||||||
|
|
||||||
// NB: commented-out stuff is from newer versions of libretro.h not yet represented in libretro-sys
|
// NB: commented-out stuff is from newer versions of libretro.h not yet represented in libretro-sys
|
||||||
|
|
||||||
#[derive(TryFromPrimitive, IntoPrimitive, Debug)]
|
#[derive(TryFromPrimitive, IntoPrimitive, Debug, Clone, Copy)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum DeviceType {
|
pub enum DeviceType {
|
||||||
None = DEVICE_NONE,
|
None = DEVICE_NONE,
|
||||||
|
@ -20,8 +20,8 @@ pub enum DeviceType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceType {
|
impl DeviceType {
|
||||||
pub fn device_subclass(self, id: u32) -> u32 {
|
pub fn device_subclass(&self, id: u32) -> u32 {
|
||||||
((id + 1) << DEVICE_TYPE_SHIFT) | u32::from(self)
|
((id + 1) << DEVICE_TYPE_SHIFT) | u32::from(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub trait Handler: Unpin + 'static {
|
||||||
fn set_input_descriptors(&mut self, input_descriptors: &[InputDescriptor]) -> bool { false }
|
fn set_input_descriptors(&mut self, input_descriptors: &[InputDescriptor]) -> bool { false }
|
||||||
fn set_hw_render(&mut self, hw_render_callback: HwRenderCallback) -> bool { false }
|
fn set_hw_render(&mut self, hw_render_callback: HwRenderCallback) -> bool { false }
|
||||||
fn get_variable(&mut self, key: &str) -> Option<String> { None }
|
fn get_variable(&mut self, key: &str) -> Option<String> { None }
|
||||||
fn set_variables(&mut self, variables: &[VariableDescriptor]) -> bool { false }
|
fn set_variables(&mut self, variables: Vec<VariableDescriptor>) -> bool { false }
|
||||||
fn get_variable_update(&mut self) -> Option<bool> { None }
|
fn get_variable_update(&mut self) -> Option<bool> { None }
|
||||||
fn set_support_no_game(&mut self, supports_no_game: bool) -> bool { false }
|
fn set_support_no_game(&mut self, supports_no_game: bool) -> bool { false }
|
||||||
fn get_libretro_path(&mut self) -> Option<PathBuf> { None }
|
fn get_libretro_path(&mut self) -> Option<PathBuf> { None }
|
||||||
|
@ -68,7 +68,7 @@ pub trait Handler: Unpin + 'static {
|
||||||
fn set_system_av_info(&mut self, system_av_info: SystemAvInfo) -> bool { false }
|
fn set_system_av_info(&mut self, system_av_info: SystemAvInfo) -> bool { false }
|
||||||
fn set_proc_address_callback(&mut self, cb: GetProcAddressInterface) -> bool { false }
|
fn set_proc_address_callback(&mut self, cb: GetProcAddressInterface) -> bool { false }
|
||||||
fn set_subsystem_info(&mut self, subsystem_info: SubsystemInfo) -> bool { false }
|
fn set_subsystem_info(&mut self, subsystem_info: SubsystemInfo) -> bool { false }
|
||||||
fn set_controller_info(&mut self, controller_info: ControllerInfo) -> bool { false }
|
fn set_controller_info(&mut self, controller_info: Vec<ControllerTypeDescriptor>) -> bool { false }
|
||||||
fn set_memory_maps(&mut self, memory_map: MemoryMap) -> bool { false }
|
fn set_memory_maps(&mut self, memory_map: MemoryMap) -> bool { false }
|
||||||
fn set_geometry(&mut self, game_geometry: GameGeometry) -> bool { false }
|
fn set_geometry(&mut self, game_geometry: GameGeometry) -> bool { false }
|
||||||
fn get_username(&mut self) -> Option<String> { None }
|
fn get_username(&mut self) -> Option<String> { None }
|
||||||
|
@ -87,6 +87,22 @@ pub struct VariableDescriptor {
|
||||||
pub options: Vec<String>,
|
pub options: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ControllerTypeDescriptor {
|
||||||
|
pub name: String,
|
||||||
|
pub base_type: DeviceType,
|
||||||
|
pub subclass: Option<c_uint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControllerTypeDescriptor {
|
||||||
|
pub fn device_id(&self) -> c_uint {
|
||||||
|
match self.subclass {
|
||||||
|
None => c_uint::from(self.base_type),
|
||||||
|
Some(sc) => self.base_type.device_subclass(sc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct StaticCallbacks {
|
struct StaticCallbacks {
|
||||||
handler: Option<Pin<&'static mut dyn Handler>>,
|
handler: Option<Pin<&'static mut dyn Handler>>,
|
||||||
|
@ -118,7 +134,7 @@ impl StaticCallbacks {
|
||||||
}
|
}
|
||||||
fn environment_cb_inner(cmd: u32, data: *mut c_void) -> Option<bool> {
|
fn environment_cb_inner(cmd: u32, data: *mut c_void) -> Option<bool> {
|
||||||
let maybe_handler = unsafe { CB_SINGLETON.handler.as_mut() };
|
let maybe_handler = unsafe { CB_SINGLETON.handler.as_mut() };
|
||||||
if maybe_handler.is_none() {
|
if cfg!(debug) && maybe_handler.is_none() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"WARNING: env cmd {} called before handler set!",
|
"WARNING: env cmd {} called before handler set!",
|
||||||
match EnvCmd::try_from(cmd) {
|
match EnvCmd::try_from(cmd) {
|
||||||
|
@ -184,7 +200,7 @@ impl StaticCallbacks {
|
||||||
descriptors.push(VariableDescriptor { key, description, options });
|
descriptors.push(VariableDescriptor { key, description, options });
|
||||||
var = var.wrapping_add(1);
|
var = var.wrapping_add(1);
|
||||||
}
|
}
|
||||||
handler.set_variables(descriptors.as_ref())
|
handler.set_variables(descriptors)
|
||||||
},
|
},
|
||||||
EnvCmd::GetVariableUpdate => Self::clone_into_void(data, &handler.get_variable_update()?)?,
|
EnvCmd::GetVariableUpdate => Self::clone_into_void(data, &handler.get_variable_update()?)?,
|
||||||
EnvCmd::SetSupportNoGame => handler.set_support_no_game(*Self::from_void(data)?),
|
EnvCmd::SetSupportNoGame => handler.set_support_no_game(*Self::from_void(data)?),
|
||||||
|
@ -217,18 +233,21 @@ impl StaticCallbacks {
|
||||||
// TODO EnvCmd::SetProcAddressCallback => {},
|
// TODO EnvCmd::SetProcAddressCallback => {},
|
||||||
// TODO EnvCmd::SetSubsystemInfo => {},
|
// TODO EnvCmd::SetSubsystemInfo => {},
|
||||||
EnvCmd::SetControllerInfo => {
|
EnvCmd::SetControllerInfo => {
|
||||||
// TODO: actually implement (wrap in rustic types and send to Handler)
|
|
||||||
let info = unsafe { (data as *const ControllerInfo).as_ref() }?;
|
let info = unsafe { (data as *const ControllerInfo).as_ref() }?;
|
||||||
let types = unsafe { from_raw_parts(info.types, info.num_types as usize) };
|
let mut controller_info = Vec::new();
|
||||||
|
// FIXME: beetle/mednafen saturn crashes without this -1... add conditional on name?
|
||||||
|
let len = info.num_types as usize - 1;
|
||||||
|
let types = unsafe { from_raw_parts(info.types, len) };
|
||||||
for t in types {
|
for t in types {
|
||||||
let orig_name = match DeviceType::try_from(t.id) {
|
let base_type = DeviceType::try_from(t.id & DEVICE_MASK).ok()?;
|
||||||
Ok(x) => format!("{:?}", x),
|
let subclass = match t.id >> DEVICE_TYPE_SHIFT {
|
||||||
Err(_) => format!("[Device ID 0x{:x?}]", t.id),
|
0 => None,
|
||||||
|
n => Some(n - 1),
|
||||||
};
|
};
|
||||||
let new_name = unsafe { CStr::from_ptr(t.desc) }.to_string_lossy();
|
let name = unsafe { CStr::from_ptr(t.desc) }.to_str().ok()?.to_string();
|
||||||
eprintln!("SetControllerInfo: {} is {}", orig_name, new_name);
|
controller_info.push(ControllerTypeDescriptor { base_type, subclass, name });
|
||||||
}
|
}
|
||||||
true
|
handler.set_controller_info(controller_info)
|
||||||
},
|
},
|
||||||
// TODO EnvCmd::SetMemoryMaps => {},
|
// TODO EnvCmd::SetMemoryMaps => {},
|
||||||
EnvCmd::SetGeometry => handler.set_geometry(Self::from_void::<GameGeometry>(data)?.clone()),
|
EnvCmd::SetGeometry => handler.set_geometry(Self::from_void::<GameGeometry>(data)?.clone()),
|
||||||
|
@ -236,7 +255,9 @@ impl StaticCallbacks {
|
||||||
EnvCmd::GetLanguage => Self::clone_into_void(data, &handler.get_language()?)?,
|
EnvCmd::GetLanguage => Self::clone_into_void(data, &handler.get_language()?)?,
|
||||||
// EnvCmd::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?),
|
// EnvCmd::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?),
|
||||||
x => {
|
x => {
|
||||||
|
if cfg!(debug) {
|
||||||
eprintln!("Known but unsupported env cmd: {:?}", x);
|
eprintln!("Known but unsupported env cmd: {:?}", x);
|
||||||
|
}
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
}.into()
|
}.into()
|
||||||
|
|
Loading…
Add table
Reference in a new issue