1 use geometry::{Angle, ToAngle, Point};
2 use sdl2::GameControllerSubsystem;
3 use sdl2::HapticSubsystem;
4 use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton};
5 use sdl2::event::Event;
6 use sdl2::haptic::Haptic;
7 use std::cell::RefCell;
8 use std::collections::HashMap;
10 use time::{Duration, prelude::*};
16 pub time_pressed: Duration,
17 pub time_released: Duration,
19 pub was_pressed: bool,
24 pub fn new(id: SDLButton) -> Self {
27 time_pressed: Duration::zero(),
28 time_released: Duration::zero(),
35 fn update(&mut self, device: &GameController, dt: Duration) {
36 self.was_pressed = self.is_pressed;
37 self.is_pressed = match device.button(self.id) {
39 if !self.was_pressed {
40 self.time_pressed = 0.seconds();
41 self.toggle = !self.toggle;
43 self.time_pressed += dt;
48 self.time_released = 0.seconds();
50 self.time_released += dt;
65 fn update(&mut self, device: &GameController, _dt: Duration) {
66 self.val = device.axis(self.id) as f32 / 32768.0;
72 id: (SDLAxis, SDLAxis),
79 pub fn new(idx: SDLAxis, idy: SDLAxis) -> Self {
88 fn update(&mut self, device: &GameController, _dt: Duration) {
89 self.x = device.axis(self.id.0) as f32 / 32768.0;
90 self.y = device.axis(self.id.1) as f32 / 32768.0;
91 self.a = point!(self.x as f64, self.y as f64).to_angle();
94 #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 }
95 #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 }
96 #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 }
97 #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 }
99 pub fn to_axis_point(&self) -> Point<f64> {
100 point!(self.x as f64, self.y as f64)
103 pub fn to_point(&self) -> Point<f64> {
104 let p = point!(self.x as f64, self.y as f64);
105 if p.length() > 1.0 {
113 impl From<&Stick> for Point<f64> {
114 fn from(item: &Stick) -> Self {
122 impl From<&Stick> for (f64, f64) {
123 fn from(item: &Stick) -> Self {
124 (item.x as f64, item.y as f64)
128 #[derive(Eq, PartialEq, Hash)]
129 enum ActionControls {
138 use self::ActionControls::*;
141 pub struct Controller {
142 pub device: GameController,
143 haptic: Option<Rc<RefCell<Haptic>>>,
153 pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
154 let map = get_action_mapping();
155 let mut ctrl = Controller {
158 mov: Stick::new(*map.axes.get(&MovementX).unwrap(), *map.axes.get(&MovementY).unwrap()),
159 aim: Stick::new(*map.axes.get(&AimX).unwrap(), *map.axes.get(&AimY).unwrap()),
160 jump: Button::new(*map.buttons.get(&Jump).unwrap()),
161 start: Button::new(*map.buttons.get(&Start).unwrap()),
162 shoot: Button::new(*map.buttons.get(&Shoot).unwrap()),
164 ctrl.set_mapping(&map);
168 fn set_mapping(&mut self, map: &ActionMapping) {
169 self.mov.id.0 = *map.axes.get(&MovementX).unwrap();
170 self.mov.id.1 = *map.axes.get(&MovementY).unwrap();
171 self.aim.id.0 = *map.axes.get(&AimX).unwrap();
172 self.aim.id.1 = *map.axes.get(&AimY).unwrap();
173 self.jump.id = *map.buttons.get(&Jump).unwrap();
174 self.shoot.id = *map.buttons.get(&Shoot).unwrap();
175 self.start.id = *map.buttons.get(&Start).unwrap();
178 pub fn update(&mut self, dt: Duration) {
179 self.mov.update(&self.device, dt);
180 self.aim.update(&self.device, dt);
181 self.jump.update(&self.device, dt);
182 self.shoot.update(&self.device, dt);
183 self.start.update(&self.device, dt);
187 pub fn rumble(&self, strength: f32, duration: Duration) {
188 if let Some(h) = &self.haptic {
189 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
194 struct ActionMapping {
195 axes: HashMap<ActionControls, SDLAxis>,
196 buttons: HashMap<ActionControls, SDLButton>,
199 fn get_action_mapping() -> ActionMapping {
202 MovementX => SDLAxis::LeftX,
203 MovementY => SDLAxis::LeftY,
204 AimX => SDLAxis::RightX,
205 AimY => SDLAxis::RightY
208 Jump => SDLButton::A,
209 Shoot => SDLButton::RightShoulder,
210 Start => SDLButton::Start
216 pub struct ControllerManager {
217 pub subsystem: GameControllerSubsystem,
218 haptic: Rc<HapticSubsystem>,
219 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
222 impl ControllerManager {
223 pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self {
224 subsystem.set_event_state(true);
225 let mut c = ControllerManager {
227 haptic: Rc::new(haptic),
228 controllers: HashMap::new(),
235 for i in 0..self.subsystem.num_joysticks().unwrap() {
240 pub fn update(&mut self, dt: Duration) {
241 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
244 pub fn handle_event(&mut self, event: &Event) {
246 Event::ControllerDeviceAdded { which, .. } => { self.add_device(*which) }
247 Event::ControllerDeviceRemoved { which, .. } => { self.remove_device(*which) }
248 // Event::ControllerButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
249 // Event::ControllerButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
250 // Event::ControllerAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
255 fn add_device(&mut self, id: u32) {
256 println!("device added ({})!", id);
257 let mut device = self.subsystem.open(id).unwrap();
258 println!("opened {}", device.name());
261 note about set_rumble (for dualshock 3 at least):
262 the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
263 the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
265 let haptic = match device.set_rumble(0, 256, 100) {
266 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
270 if self.controllers.contains_key(&id) {
274 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
277 let mut c = c.borrow_mut();
279 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
282 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
283 self.controllers.insert(id, c);
288 fn remove_device(&mut self, id: i32) {
289 println!("device removed ({})!", id);