4 use sdl2::HapticSubsystem;
5 use sdl2::JoystickSubsystem;
6 use sdl2::event::Event;
7 use sdl2::haptic::Haptic;
8 use sdl2::joystick::Joystick;
9 use std::cell::RefCell;
10 use std::collections::HashMap;
12 use time::{Duration, prelude::*};
14 #[derive(Debug, Default)]
17 pub time_pressed: Duration,
18 pub time_released: Duration,
20 pub was_pressed: bool,
25 fn update(&mut self, device: &Joystick, dt: Duration) {
26 self.was_pressed = self.is_pressed;
27 self.is_pressed = match device.button(self.id as u32) {
29 if !self.was_pressed {
30 self.time_pressed = 0.seconds();
31 self.toggle = !self.toggle;
33 self.time_pressed += dt;
38 self.time_released = 0.seconds();
40 self.time_released += dt;
43 Err(_) => { panic!("invalid button {}", self.id) }
48 #[derive(Debug, Default)]
56 fn update(&mut self, device: &Joystick, _dt: Duration) {
57 self.val = match device.axis(self.id as u32) {
58 Ok(val) => val as f32 / 32768.0,
59 Err(_) => panic!("invalid axis {}", self.id),
64 #[derive(Debug, Default)]
74 fn update(&mut self, device: &Joystick, _dt: Duration) {
75 self.x = match device.axis(self.idx as u32) {
76 Ok(val) => val as f32 / 32768.0,
77 Err(_) => panic!("invalid x axis {}", self.idx),
79 self.y = match device.axis(self.idy as u32) {
80 Ok(val) => val as f32 / 32768.0,
81 Err(_) => panic!("invalid y axis {}", self.idy),
83 self.a = Radians(self.y.atan2(self.x) as f64);
86 #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 }
87 #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 }
88 #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 }
89 #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 }
91 pub fn to_axis_point(&self) -> Point<f64> {
92 point!(self.x as f64, self.y as f64)
95 pub fn to_point(&self) -> Point<f64> {
96 let p = point!(self.x as f64, self.y as f64);
105 impl From<&Stick> for Point<f64> {
106 fn from(item: &Stick) -> Self {
114 impl From<&Stick> for (f64, f64) {
115 fn from(item: &Stick) -> Self {
116 (item.x as f64, item.y as f64)
120 #[derive(Eq, PartialEq, Hash)]
121 enum DeviceControls {
146 use self::DeviceControls::*;
148 #[derive(Eq, PartialEq, Hash)]
149 enum ActionControls {
158 use self::ActionControls::*;
161 pub struct Controller {
162 pub device: Joystick,
163 haptic: Option<Rc<RefCell<Haptic>>>,
173 pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
174 let action_map = get_action_mapping();
175 let device_map = get_device_mapping(&device.name());
176 let mut ctrl = Controller {
179 mov: Default::default(),
180 aim: Default::default(),
181 jump: Default::default(),
182 start: Default::default(),
183 shoot: Default::default(),
185 ctrl.set_mapping(&action_map, &device_map);
189 fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
190 self.mov.idx = *action.get(&MovementX).map(|i| device.get(i)).flatten().unwrap();
191 self.mov.idy = *action.get(&MovementY).map(|i| device.get(i)).flatten().unwrap();
192 self.aim.idx = *action.get(&AimX).map(|i| device.get(i)).flatten().unwrap();
193 self.aim.idy = *action.get(&AimY).map(|i| device.get(i)).flatten().unwrap();
194 self.jump.id = *action.get(&Jump).map(|i| device.get(i)).flatten().unwrap();
195 self.shoot.id = *action.get(&Shoot).map(|i| device.get(i)).flatten().unwrap();
196 self.start.id = *action.get(&Start).map(|i| device.get(i)).flatten().unwrap();
199 pub fn update(&mut self, dt: Duration) {
200 self.mov.update(&self.device, dt);
201 self.aim.update(&self.device, dt);
202 self.jump.update(&self.device, dt);
203 self.shoot.update(&self.device, dt);
204 self.start.update(&self.device, dt);
208 pub fn rumble(&self, strength: f32, duration: Duration) {
209 if let Some(h) = &self.haptic {
210 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
215 fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
227 fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
229 "Sony PLAYSTATION(R)3 Controller" => hashmap!(
254 _ => panic!("No controller mapping for device '{}'", device_name)
259 pub struct ControllerManager {
260 pub joystick: JoystickSubsystem,
261 haptic: Rc<HapticSubsystem>,
262 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
265 impl ControllerManager {
266 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
267 joystick.set_event_state(true);
268 let mut c = ControllerManager {
270 haptic: Rc::new(haptic),
271 controllers: HashMap::new(),
278 for i in 0..self.joystick.num_joysticks().unwrap() {
283 pub fn update(&mut self, dt: Duration) {
284 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
287 pub fn handle_event(&mut self, event: &Event) {
289 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
290 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
291 // Event::JoyButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
292 // Event::JoyButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
293 // Event::JoyAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
298 fn add_device(&mut self, id: u32) {
299 println!("device added ({})!", id);
300 let mut device = self.joystick.open(id).unwrap();
301 println!("opened {}", device.name());
304 note about set_rumble (for dualshock 3 at least):
305 the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
306 the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
308 let haptic = match device.set_rumble(0, 256, 100) {
309 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
313 if self.controllers.contains_key(&id) {
317 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
320 let mut c = c.borrow_mut();
322 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
325 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
326 self.controllers.insert(id, c);
331 fn remove_device(&mut self, id: i32) {
332 println!("device removed ({})!", id);