Use GameControllers instead of Joysticks
[kaka/rust-sdl-test.git] / src / core / controller.rs
CommitLineData
09cd68fe
TW
1use geometry::{Angle, ToAngle, Point};
2use sdl2::GameControllerSubsystem;
3f344b63 3use sdl2::HapticSubsystem;
09cd68fe 4use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton};
3f344b63 5use sdl2::event::Event;
bf7b5671 6use sdl2::haptic::Haptic;
bf7b5671
TW
7use std::cell::RefCell;
8use std::collections::HashMap;
3f344b63 9use std::rc::Rc;
902b2b31 10use time::{Duration, prelude::*};
09cd68fe 11use {hashmap, point};
3f344b63 12
09cd68fe 13#[derive(Debug)]
bf7b5671 14pub struct Button {
09cd68fe 15 id: SDLButton,
902b2b31
TW
16 pub time_pressed: Duration,
17 pub time_released: Duration,
bf7b5671
TW
18 pub is_pressed: bool,
19 pub was_pressed: bool,
20 pub toggle: bool,
21}
22
23impl Button {
09cd68fe
TW
24 pub fn new(id: SDLButton) -> Self {
25 Button {
26 id,
27 time_pressed: Duration::zero(),
28 time_released: Duration::zero(),
29 is_pressed: false,
30 was_pressed: false,
31 toggle: false,
32 }
33 }
34
35 fn update(&mut self, device: &GameController, dt: Duration) {
bf7b5671 36 self.was_pressed = self.is_pressed;
09cd68fe
TW
37 self.is_pressed = match device.button(self.id) {
38 true => {
bf7b5671 39 if !self.was_pressed {
902b2b31 40 self.time_pressed = 0.seconds();
bf7b5671
TW
41 self.toggle = !self.toggle;
42 }
43 self.time_pressed += dt;
44 true
45 }
09cd68fe 46 false => {
bf7b5671 47 if self.was_pressed {
902b2b31 48 self.time_released = 0.seconds();
bf7b5671
TW
49 }
50 self.time_released += dt;
51 false
52 }
bf7b5671
TW
53 }
54 }
55}
56
09cd68fe 57#[derive(Debug)]
bf7b5671 58pub struct Axis {
09cd68fe 59 id: SDLAxis,
bf7b5671
TW
60 pub val: f32,
61}
62
63impl Axis {
64 #[allow(dead_code)]
09cd68fe
TW
65 fn update(&mut self, device: &GameController, _dt: Duration) {
66 self.val = device.axis(self.id) as f32 / 32768.0;
bf7b5671
TW
67 }
68}
69
09cd68fe 70#[derive(Debug)]
bf7b5671 71pub struct Stick {
09cd68fe 72 id: (SDLAxis, SDLAxis),
bf7b5671
TW
73 pub x: f32,
74 pub y: f32,
40742678 75 pub a: Angle,
bf7b5671
TW
76}
77
78impl Stick {
09cd68fe
TW
79 pub fn new(idx: SDLAxis, idy: SDLAxis) -> Self {
80 Stick {
81 id: (idx, idy),
82 x: 0.0,
83 y: 0.0,
84 a: 0.radians(),
85 }
86 }
87
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;
40742678 91 self.a = point!(self.x as f64, self.y as f64).to_angle();
bf7b5671
TW
92 }
93
3fd8761b
TW
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 }
bf7b5671 98
e570927a 99 pub fn to_axis_point(&self) -> Point<f64> {
eca25591 100 point!(self.x as f64, self.y as f64)
bf7b5671
TW
101 }
102
e570927a 103 pub fn to_point(&self) -> Point<f64> {
eca25591
TW
104 let p = point!(self.x as f64, self.y as f64);
105 if p.length() > 1.0 {
93fc5734 106 p.normalized()
eca25591
TW
107 } else {
108 p
109 }
bf7b5671
TW
110 }
111}
112
e570927a 113impl From<&Stick> for Point<f64> {
bf7b5671
TW
114 fn from(item: &Stick) -> Self {
115 Self {
116 x: item.x as f64,
117 y: item.y as f64,
118 }
119 }
120}
121
122impl From<&Stick> for (f64, f64) {
123 fn from(item: &Stick) -> Self {
124 (item.x as f64, item.y as f64)
125 }
3f344b63
TW
126}
127
05ba0976 128#[derive(Eq, PartialEq, Hash)]
05ba0976
TW
129enum ActionControls {
130 MovementX,
131 MovementY,
132 AimX,
133 AimY,
134 Jump,
135 Shoot,
136 Start,
5d731022 137}
5d42eba1 138use self::ActionControls::*;
5d731022 139
3f344b63
TW
140//#[derive(Debug)]
141pub struct Controller {
09cd68fe 142 pub device: GameController,
3f344b63 143 haptic: Option<Rc<RefCell<Haptic>>>,
bf7b5671
TW
144
145 pub mov: Stick,
146 pub aim: Stick,
147 pub jump: Button,
148 pub start: Button,
149 pub shoot: Button,
150}
151
152impl Controller {
09cd68fe
TW
153 pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
154 let map = get_action_mapping();
5d731022 155 let mut ctrl = Controller {
bf7b5671
TW
156 device,
157 haptic,
09cd68fe
TW
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()),
5d731022 163 };
09cd68fe 164 ctrl.set_mapping(&map);
5d731022
TW
165 ctrl
166 }
167
09cd68fe
TW
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();
bf7b5671
TW
176 }
177
902b2b31 178 pub fn update(&mut self, dt: Duration) {
5d731022
TW
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);
bf7b5671
TW
184 }
185
186 /// strength [0 - 1]
902b2b31 187 pub fn rumble(&self, strength: f32, duration: Duration) {
bf7b5671 188 if let Some(h) = &self.haptic {
902b2b31 189 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
bf7b5671
TW
190 }
191 }
192}
193
09cd68fe
TW
194struct ActionMapping {
195 axes: HashMap<ActionControls, SDLAxis>,
196 buttons: HashMap<ActionControls, SDLButton>,
05ba0976
TW
197}
198
09cd68fe
TW
199fn get_action_mapping() -> ActionMapping {
200 ActionMapping {
201 axes: hashmap!(
202 MovementX => SDLAxis::LeftX,
203 MovementY => SDLAxis::LeftY,
204 AimX => SDLAxis::RightX,
205 AimY => SDLAxis::RightY
05ba0976 206 ),
09cd68fe
TW
207 buttons: hashmap!(
208 Jump => SDLButton::A,
209 Shoot => SDLButton::RightShoulder,
210 Start => SDLButton::Start
211 )
05ba0976
TW
212 }
213}
214
bf7b5671
TW
215//#[derive(Debug)]
216pub struct ControllerManager {
09cd68fe 217 pub subsystem: GameControllerSubsystem,
bf7b5671
TW
218 haptic: Rc<HapticSubsystem>,
219 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
3f344b63
TW
220}
221
222impl ControllerManager {
09cd68fe
TW
223 pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self {
224 subsystem.set_event_state(true);
b0566120 225 let mut c = ControllerManager {
09cd68fe 226 subsystem,
3f344b63 227 haptic: Rc::new(haptic),
b0566120
TW
228 controllers: HashMap::new(),
229 };
230 c.init();
231 c
232 }
233
234 fn init(&mut self) {
09cd68fe 235 for i in 0..self.subsystem.num_joysticks().unwrap() {
b0566120 236 self.add_device(i);
3f344b63
TW
237 }
238 }
239
902b2b31 240 pub fn update(&mut self, dt: Duration) {
bf7b5671
TW
241 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
242 }
243
3f344b63
TW
244 pub fn handle_event(&mut self, event: &Event) {
245 match event {
09cd68fe
TW
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) }
3f344b63
TW
251 _ => {}
252 }
253 }
254
bf7b5671 255 fn add_device(&mut self, id: u32) {
3f344b63 256 println!("device added ({})!", id);
09cd68fe 257 let mut device = self.subsystem.open(id).unwrap();
bf7b5671 258 println!("opened {}", device.name());
ca99d4d7
TW
259
260 /*
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
264 */
bf7b5671 265 let haptic = match device.set_rumble(0, 256, 100) {
3f344b63
TW
266 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
267 Err(_) => None
268 };
269
b0566120
TW
270 if self.controllers.contains_key(&id) {
271 return;
272 }
273
bf7b5671 274 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
ca99d4d7
TW
275 match detached {
276 Some(c) => {
277 let mut c = c.borrow_mut();
bf7b5671 278 c.device = device;
ca99d4d7
TW
279 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
280 }
281 None => {
bf7b5671 282 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
b0566120 283 self.controllers.insert(id, c);
ca99d4d7
TW
284 }
285 };
3f344b63
TW
286 }
287
bf7b5671 288 fn remove_device(&mut self, id: i32) {
3f344b63 289 println!("device removed ({})!", id);
ca99d4d7 290 // TODO
3f344b63
TW
291 }
292}