gcrecomp_runtime/input/
controller.rs1use crate::input::backends::{Backend, ControllerInfo};
3use crate::input::gamecube_mapping::GameCubeMapping;
4use crate::input::profiles::ControllerProfile;
5use anyhow::Result;
6use std::collections::HashMap;
7
8pub struct ControllerManager {
9 backends: Vec<Box<dyn Backend>>,
10 controllers: HashMap<usize, ControllerState>,
11 gamecube_mappings: HashMap<usize, GameCubeMapping>,
12 profiles: HashMap<String, ControllerProfile>,
13 next_id: usize,
14}
15
16#[derive(Debug, Clone)]
17pub struct ControllerState {
18 pub id: usize,
19 pub info: ControllerInfo,
20 pub connected: bool,
21 pub last_update: std::time::Instant,
22}
23
24impl ControllerManager {
25 pub fn new() -> Result<Self> {
26 let mut backends: Vec<Box<dyn Backend>> = Vec::new();
27
28 if let Ok(sdl2_backend) = crate::input::backends::sdl2::SDL2Backend::new() {
30 backends.push(Box::new(sdl2_backend));
31 }
32
33 if let Ok(gilrs_backend) = crate::input::backends::gilrs::GilrsBackend::new() {
35 backends.push(Box::new(gilrs_backend));
36 }
37
38 #[cfg(target_os = "windows")]
39 {
40 if let Ok(xinput_backend) = crate::input::backends::xinput::XInputBackend::new() {
42 backends.push(Box::new(xinput_backend));
43 }
44 }
45
46 Ok(Self {
47 backends,
48 controllers: HashMap::new(),
49 gamecube_mappings: HashMap::new(),
50 profiles: HashMap::new(),
51 next_id: 0,
52 })
53 }
54
55 pub fn update(&mut self) -> Result<()> {
56 let mut all_controller_infos: Vec<ControllerInfo> = Vec::new();
59
60 for backend in &mut self.backends {
61 backend.update()?;
62 all_controller_infos.extend(backend.enumerate_controllers()?);
63 }
64
65 for controller in &all_controller_infos {
67 if !self.controllers.contains_key(&controller.id) {
68 let state = ControllerState {
69 id: controller.id,
70 info: controller.clone(),
71 connected: true,
72 last_update: std::time::Instant::now(),
73 };
74 self.controllers.insert(controller.id, state);
75
76 self.load_default_mapping(controller.id)?;
78 }
79 }
80
81 let connected_ids: Vec<usize> = all_controller_infos.iter().map(|c| c.id).collect();
83
84 self.controllers.retain(|id, state| {
85 if !connected_ids.contains(id) {
86 state.connected = false;
87 false
88 } else {
89 true
90 }
91 });
92
93 Ok(())
94 }
95
96 pub fn get_controller_count(&self) -> usize {
97 self.controllers.values().filter(|c| c.connected).count()
98 }
99
100 pub fn get_controller_state(&self, id: usize) -> Option<&ControllerState> {
101 self.controllers.get(&id)
102 }
103
104 pub fn get_gamecube_input(&self, controller_id: usize) -> Option<GameCubeInput> {
105 let mapping = self.gamecube_mappings.get(&controller_id)?;
106
107 for backend in &self.backends {
109 if let Ok(input) = backend.get_input(controller_id) {
110 return Some(mapping.map_to_gamecube(&input));
111 }
112 }
113
114 None
115 }
116
117 pub fn set_mapping(&mut self, controller_id: usize, mapping: GameCubeMapping) {
118 self.gamecube_mappings.insert(controller_id, mapping);
119 }
120
121 pub fn load_profile(&mut self, controller_id: usize, profile_name: &str) -> Result<()> {
122 if let Some(profile) = self.profiles.get(profile_name) {
123 let mapping = profile.to_gamecube_mapping()?;
124 self.set_mapping(controller_id, mapping);
125 }
126 Ok(())
127 }
128
129 pub fn save_profile(&mut self, name: String, controller_id: usize) -> Result<()> {
130 if let Some(mapping) = self.gamecube_mappings.get(&controller_id) {
131 let profile = ControllerProfile::from_mapping(name, mapping.clone());
132 self.profiles.insert(profile.name.clone(), profile);
133 }
134 Ok(())
135 }
136
137 fn load_default_mapping(&mut self, controller_id: usize) -> Result<()> {
138 if let Some(state) = self.controllers.get(&controller_id) {
140 let default_mapping = GameCubeMapping::default_for_controller(&state.info)?;
141 self.set_mapping(controller_id, default_mapping);
142 }
143 Ok(())
144 }
145}
146
147#[derive(Debug, Clone)]
148pub struct GameCubeInput {
149 pub buttons: GameCubeButtons,
150 pub left_stick: (f32, f32),
151 pub right_stick: (f32, f32),
152 pub left_trigger: f32,
153 pub right_trigger: f32,
154}
155
156#[derive(Debug, Clone, Default)]
157pub struct GameCubeButtons {
158 pub a: bool,
159 pub b: bool,
160 pub x: bool,
161 pub y: bool,
162 pub start: bool,
163 pub d_up: bool,
164 pub d_down: bool,
165 pub d_left: bool,
166 pub d_right: bool,
167 pub l: bool,
168 pub r: bool,
169 pub z: bool,
170}