Support choosing which player uses a controller
This commit is contained in:
+93
-6
@@ -11,6 +11,14 @@ use crate::emulator::{SimId, VBKey};
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
struct DeviceId(u16, u16);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GamepadInfo {
|
||||
pub id: GamepadId,
|
||||
pub name: String,
|
||||
device_id: DeviceId,
|
||||
pub bound_to: Option<SimId>,
|
||||
}
|
||||
|
||||
pub struct GamepadMapping {
|
||||
buttons: HashMap<Code, VBKey>,
|
||||
axes: HashMap<Code, (VBKey, VBKey)>,
|
||||
@@ -106,6 +114,7 @@ impl InputMapping {
|
||||
pub struct MappingProvider {
|
||||
device_mappings: Arc<RwLock<HashMap<DeviceId, Arc<RwLock<GamepadMapping>>>>>,
|
||||
sim_mappings: HashMap<SimId, Arc<RwLock<InputMapping>>>,
|
||||
gamepad_info: Arc<RwLock<HashMap<GamepadId, GamepadInfo>>>,
|
||||
}
|
||||
|
||||
impl MappingProvider {
|
||||
@@ -136,6 +145,7 @@ impl MappingProvider {
|
||||
mappings.insert(SimId::Player2, Arc::new(RwLock::new(p2_mappings)));
|
||||
Self {
|
||||
device_mappings: Arc::new(RwLock::new(HashMap::new())),
|
||||
gamepad_info: Arc::new(RwLock::new(HashMap::new())),
|
||||
sim_mappings: mappings,
|
||||
}
|
||||
}
|
||||
@@ -144,24 +154,101 @@ impl MappingProvider {
|
||||
self.sim_mappings.get(&sim_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn map_gamepad(&self, sim_id: SimId, gamepad: &Gamepad) {
|
||||
pub fn handle_gamepad_connect(&self, gamepad: &Gamepad) {
|
||||
let device_id = DeviceId(
|
||||
gamepad.vendor_id().unwrap_or_default(),
|
||||
gamepad.product_id().unwrap_or_default(),
|
||||
);
|
||||
let mut lock = self.device_mappings.write().unwrap();
|
||||
let gamepad_mapping = match lock.entry(device_id) {
|
||||
Entry::Occupied(entry) => entry.get().clone(),
|
||||
let mappings = match lock.entry(device_id) {
|
||||
Entry::Vacant(entry) => {
|
||||
let mappings = GamepadMapping::for_gamepad(gamepad);
|
||||
entry.insert(Arc::new(RwLock::new(mappings))).clone()
|
||||
entry.insert(Arc::new(RwLock::new(mappings)))
|
||||
}
|
||||
};
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
}
|
||||
.clone();
|
||||
drop(lock);
|
||||
let mut lock = self.gamepad_info.write().unwrap();
|
||||
let bound_to = SimId::values()
|
||||
.into_iter()
|
||||
.find(|sim_id| lock.values().all(|info| info.bound_to != Some(*sim_id)));
|
||||
if let Entry::Vacant(entry) = lock.entry(gamepad.id()) {
|
||||
let info = GamepadInfo {
|
||||
id: *entry.key(),
|
||||
name: gamepad.name().to_string(),
|
||||
device_id,
|
||||
bound_to,
|
||||
};
|
||||
entry.insert(info);
|
||||
}
|
||||
drop(lock);
|
||||
if let Some(sim_id) = bound_to {
|
||||
self.for_sim(sim_id)
|
||||
.write()
|
||||
.unwrap()
|
||||
.gamepads
|
||||
.insert(gamepad.id(), mappings);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_gamepad_disconnect(&self, gamepad_id: GamepadId) {
|
||||
let mut lock = self.gamepad_info.write().unwrap();
|
||||
let Some(info) = lock.remove(&gamepad_id) else {
|
||||
return;
|
||||
};
|
||||
if let Some(sim_id) = info.bound_to {
|
||||
self.for_sim(sim_id)
|
||||
.write()
|
||||
.unwrap()
|
||||
.gamepads
|
||||
.remove(&gamepad_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_gamepad(&self, gamepad_id: GamepadId, sim_id: SimId) {
|
||||
self.unassign_gamepad(gamepad_id);
|
||||
let mut lock = self.gamepad_info.write().unwrap();
|
||||
let Some(info) = lock.get_mut(&gamepad_id) else {
|
||||
return;
|
||||
};
|
||||
info.bound_to = Some(sim_id);
|
||||
let device_id = info.device_id;
|
||||
drop(lock);
|
||||
let Some(device_mappings) = self
|
||||
.device_mappings
|
||||
.write()
|
||||
.unwrap()
|
||||
.get(&device_id)
|
||||
.cloned()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
self.for_sim(sim_id)
|
||||
.write()
|
||||
.unwrap()
|
||||
.gamepads
|
||||
.insert(gamepad.id(), gamepad_mapping);
|
||||
.insert(gamepad_id, device_mappings);
|
||||
}
|
||||
|
||||
pub fn unassign_gamepad(&self, gamepad_id: GamepadId) {
|
||||
let mut lock = self.gamepad_info.write().unwrap();
|
||||
let Some(info) = lock.get_mut(&gamepad_id) else {
|
||||
return;
|
||||
};
|
||||
if let Some(sim_id) = info.bound_to {
|
||||
let mut sim_mapping = self.for_sim(sim_id).write().unwrap();
|
||||
sim_mapping.gamepads.remove(&gamepad_id);
|
||||
}
|
||||
info.bound_to = None;
|
||||
}
|
||||
|
||||
pub fn gamepad_info(&self) -> Vec<GamepadInfo> {
|
||||
self.gamepad_info
|
||||
.read()
|
||||
.unwrap()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user