1 use crate::sys;
2 
3 use crate::JoystickSubsystem;
4 use crate::get_error;
5 use crate::clear_error;
6 use std::ffi::{CString, CStr, NulError};
7 use std::fmt::{Display, Formatter, Error};
8 use libc::c_char;
9 use crate::common::{validate_int, IntegerOrSdlError};
10 
11 impl JoystickSubsystem {
12     /// Retrieve the total number of attached joysticks *and* controllers identified by SDL.
num_joysticks(&self) -> Result<u32, String>13     pub fn num_joysticks(&self) -> Result<u32, String> {
14         let result = unsafe { sys::SDL_NumJoysticks() };
15 
16         if result >= 0 {
17             Ok(result as u32)
18         } else {
19             Err(get_error())
20         }
21     }
22 
23     /// Attempt to open the joystick at index `joystick_index` and return it.
open(&self, joystick_index: u32) -> Result<Joystick, IntegerOrSdlError>24     pub fn open(&self, joystick_index: u32)
25             -> Result<Joystick, IntegerOrSdlError> {
26         use crate::common::IntegerOrSdlError::*;
27         let joystick_index = r#try!(validate_int(joystick_index, "joystick_index"));
28 
29         let joystick = unsafe { sys::SDL_JoystickOpen(joystick_index) };
30 
31         if joystick.is_null() {
32             Err(SdlError(get_error()))
33         } else {
34             Ok(Joystick {
35                 subsystem: self.clone(),
36                 raw: joystick
37             })
38         }
39     }
40 
41     /// Return the name of the joystick at index `joystick_index`.
name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError>42     pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
43         use crate::common::IntegerOrSdlError::*;
44         let joystick_index = r#try!(validate_int(joystick_index, "joystick_index"));
45 
46         let c_str = unsafe { sys::SDL_JoystickNameForIndex(joystick_index) };
47 
48         if c_str.is_null() {
49             Err(SdlError(get_error()))
50         } else {
51             Ok(unsafe {
52                 CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
53             })
54         }
55     }
56 
57     /// Get the GUID for the joystick at index `joystick_index`
device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError>58     pub fn device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError> {
59         use crate::common::IntegerOrSdlError::*;
60         let joystick_index = r#try!(validate_int(joystick_index, "joystick_index"));
61 
62         let raw = unsafe { sys::SDL_JoystickGetDeviceGUID(joystick_index) };
63 
64         let guid = Guid { raw: raw };
65 
66         if guid.is_zero() {
67             Err(SdlError(get_error()))
68         } else {
69             Ok(guid)
70         }
71     }
72 
73     /// If state is `true` joystick events are processed, otherwise
74     /// they're ignored.
set_event_state(&self, state: bool)75     pub fn set_event_state(&self, state: bool) {
76         unsafe { sys::SDL_JoystickEventState(state as i32) };
77     }
78 
79     /// Return `true` if joystick events are processed.
event_state(&self) -> bool80     pub fn event_state(&self) -> bool {
81         unsafe { sys::SDL_JoystickEventState(sys::SDL_QUERY as i32)
82                  == sys::SDL_ENABLE as i32 }
83     }
84 
85     /// Force joystick update when not using the event loop
86     #[inline]
update(&self)87     pub fn update(&self) {
88         unsafe { sys::SDL_JoystickUpdate() };
89     }
90 
91 }
92 
93 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
94 #[repr(i32)]
95 pub enum PowerLevel {
96     Unknown = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN as i32,
97     Empty   = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY as i32,
98     Low     = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW as i32,
99     Medium  = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM as i32,
100     Full    = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL as i32,
101     Wired   = sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED as i32,
102 }
103 
104 impl PowerLevel {
from_ll(raw: sys::SDL_JoystickPowerLevel) -> PowerLevel105     pub fn from_ll(raw: sys::SDL_JoystickPowerLevel) -> PowerLevel {
106         match raw {
107             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN => PowerLevel::Unknown,
108             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY   => PowerLevel::Empty,
109             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW     => PowerLevel::Low,
110             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM  => PowerLevel::Medium,
111             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL    => PowerLevel::Full,
112             sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED   => PowerLevel::Wired,
113             _  => panic!("Unexpected power level: {:?}", raw),
114         }
115     }
116 
to_ll(&self) -> sys::SDL_JoystickPowerLevel117     pub fn to_ll(&self) -> sys::SDL_JoystickPowerLevel {
118         match *self {
119             PowerLevel::Unknown => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN,
120             PowerLevel::Empty   => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY,
121             PowerLevel::Low     => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW,
122             PowerLevel::Medium  => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM,
123             PowerLevel::Full    => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL,
124             PowerLevel::Wired   => sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED,
125         }
126 
127     }
128 }
129 
130 /// Wrapper around the `SDL_Joystick` object
131 pub struct Joystick {
132     subsystem: JoystickSubsystem,
133     raw: *mut sys::SDL_Joystick
134 }
135 
136 impl Joystick {
137     #[inline]
subsystem(&self) -> &JoystickSubsystem138     pub fn subsystem(&self) -> &JoystickSubsystem { &self.subsystem }
139 
140     /// Return the name of the joystick or an empty string if no name
141     /// is found.
name(&self) -> String142     pub fn name(&self) -> String {
143         let name = unsafe { sys::SDL_JoystickName(self.raw) };
144 
145         c_str_to_string(name)
146     }
147 
148     /// Return true if the joystick has been opened and currently
149     /// connected.
attached(&self) -> bool150     pub fn attached(&self) -> bool {
151         unsafe { sys::SDL_JoystickGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
152     }
153 
instance_id(&self) -> i32154     pub fn instance_id(&self) -> i32 {
155         let result = unsafe { sys::SDL_JoystickInstanceID(self.raw) };
156 
157         if result < 0 {
158             // Should only fail if the joystick is NULL.
159             panic!(get_error())
160         } else {
161             result
162         }
163     }
164 
165     /// Retrieve the joystick's GUID
guid(&self) -> Guid166     pub fn guid(&self) -> Guid {
167         let raw = unsafe { sys::SDL_JoystickGetGUID(self.raw) };
168 
169         let guid = Guid { raw: raw };
170 
171         if guid.is_zero() {
172             // Should only fail if the joystick is NULL.
173             panic!(get_error())
174         } else {
175             guid
176         }
177     }
178 
179     /// Retrieve the battery level of this joystick
power_level(&self) -> Result<PowerLevel, IntegerOrSdlError>180     pub fn power_level(&self) -> Result<PowerLevel, IntegerOrSdlError> {
181         use crate::common::IntegerOrSdlError::*;
182         clear_error();
183 
184         let result = unsafe { sys::SDL_JoystickCurrentPowerLevel(self.raw) };
185 
186         let state = PowerLevel::from_ll(result);
187 
188         if result != sys::SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN {
189             Ok(state)
190         } else {
191             let err = get_error();
192 
193             if err.is_empty() {
194                 Ok(state)
195             } else {
196                 Err(SdlError(err))
197             }
198         }
199     }
200 
201     /// Retrieve the number of axes for this joystick
num_axes(&self) -> u32202     pub fn num_axes(&self) -> u32 {
203         let result = unsafe { sys::SDL_JoystickNumAxes(self.raw) };
204 
205         if result < 0 {
206             // Should only fail if the joystick is NULL.
207             panic!(get_error())
208         } else {
209             result as u32
210         }
211     }
212 
213     /// Gets the position of the given `axis`.
214     ///
215     /// The function will fail if the joystick doesn't have the provided axis.
axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError>216     pub fn axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError> {
217         use crate::common::IntegerOrSdlError::*;
218         // This interface is a bit messed up: 0 is a valid position
219         // but can also mean that an error occured. As far as I can
220         // tell the only way to know if an error happened is to see if
221         // get_error() returns a non-empty string.
222         clear_error();
223 
224         let axis = r#try!(validate_int(axis, "axis"));
225         let pos = unsafe { sys::SDL_JoystickGetAxis(self.raw, axis) };
226 
227         if pos != 0 {
228             Ok(pos)
229         } else {
230             let err = get_error();
231 
232             if err.is_empty() {
233                 Ok(pos)
234             } else {
235                 Err(SdlError(err))
236             }
237         }
238     }
239 
240     /// Retrieve the number of buttons for this joystick
num_buttons(&self) -> u32241     pub fn num_buttons(&self) -> u32 {
242         let result = unsafe { sys::SDL_JoystickNumButtons(self.raw) };
243 
244         if result < 0 {
245             // Should only fail if the joystick is NULL.
246             panic!(get_error())
247         } else {
248             result as u32
249         }
250     }
251 
252     /// Return `Ok(true)` if `button` is pressed.
253     ///
254     /// The function will fail if the joystick doesn't have the provided button.
button(&self, button: u32) -> Result<bool, IntegerOrSdlError>255     pub fn button(&self, button: u32) -> Result<bool, IntegerOrSdlError> {
256         use crate::common::IntegerOrSdlError::*;
257         // Same deal as axis, 0 can mean both unpressed or
258         // error...
259         clear_error();
260 
261         let button = r#try!(validate_int(button, "button"));
262         let pressed = unsafe { sys::SDL_JoystickGetButton(self.raw, button) };
263 
264         match pressed {
265             1 => Ok(true),
266             0 => {
267                 let err = get_error();
268 
269                 if err.is_empty() {
270                     // Button is not pressed
271                     Ok(false)
272                 } else {
273                     Err(SdlError(err))
274                 }
275             }
276             // Should be unreachable
277             _ => unreachable!(),
278         }
279     }
280 
281     /// Retrieve the number of balls for this joystick
num_balls(&self) -> u32282     pub fn num_balls(&self) -> u32 {
283         let result = unsafe { sys::SDL_JoystickNumBalls(self.raw) };
284 
285         if result < 0 {
286             // Should only fail if the joystick is NULL.
287             panic!(get_error())
288         } else {
289             result as u32
290         }
291     }
292 
293     /// Return a pair `(dx, dy)` containing the difference in axis
294     /// position since the last poll
ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError>295     pub fn ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError> {
296         use crate::common::IntegerOrSdlError::*;
297         let mut dx = 0;
298         let mut dy = 0;
299 
300         let ball = r#try!(validate_int(ball, "ball"));
301         let result = unsafe { sys::SDL_JoystickGetBall(self.raw, ball, &mut dx, &mut dy) };
302 
303         if result == 0 {
304             Ok((dx, dy))
305         } else {
306             Err(SdlError(get_error()))
307         }
308     }
309 
310     /// Retrieve the number of balls for this joystick
num_hats(&self) -> u32311     pub fn num_hats(&self) -> u32 {
312         let result = unsafe { sys::SDL_JoystickNumHats(self.raw) };
313 
314         if result < 0 {
315             // Should only fail if the joystick is NULL.
316             panic!(get_error())
317         } else {
318             result as u32
319         }
320     }
321 
322     /// Return the position of `hat` for this joystick
hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError>323     pub fn hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError> {
324         use crate::common::IntegerOrSdlError::*;
325         // Guess what? This function as well uses 0 to report an error
326         // but 0 is also a valid value (HatState::Centered). So we
327         // have to use the same hack as `axis`...
328         clear_error();
329 
330         let hat = r#try!(validate_int(hat, "hat"));
331         let result = unsafe { sys::SDL_JoystickGetHat(self.raw, hat) };
332 
333         let state = HatState::from_raw(result as u8);
334 
335         if result != 0 {
336             Ok(state)
337         } else {
338             let err = get_error();
339 
340             if err.is_empty() {
341                 Ok(state)
342             } else {
343                 Err(SdlError(err))
344             }
345         }
346     }
347 
348     /// Set the rumble motors to their specified intensities, if supported.
349     /// Automatically resets back to zero after `duration_ms` milliseconds have passed.
350     ///
351     /// # Notes
352     ///
353     /// The value range for the intensities is 0 to 0xFFFF.
354     ///
355     /// Do *not* use `std::u32::MAX` or similar for `duration_ms` if you want
356     /// the rumble effect to keep playing for a long time, as this results in
357     /// the effect ending immediately after starting due to an overflow.
358     /// Use some smaller, "huge enough" number instead.
set_rumble(&mut self, low_frequency_rumble: u16, high_frequency_rumble: u16, duration_ms: u32) -> Result<(), IntegerOrSdlError>359     pub fn set_rumble(&mut self,
360                       low_frequency_rumble: u16,
361                       high_frequency_rumble: u16,
362                       duration_ms: u32)
363                       -> Result<(), IntegerOrSdlError>
364     {
365         let result = unsafe {
366             sys::SDL_JoystickRumble(self.raw,
367                                     low_frequency_rumble,
368                                     high_frequency_rumble,
369                                     duration_ms)
370         };
371 
372         if result != 0 {
373             Err(IntegerOrSdlError::SdlError(get_error()))
374         } else {
375             Ok(())
376         }
377     }
378 }
379 
380 impl Drop for Joystick {
drop(&mut self)381     fn drop(&mut self) {
382         if self.attached() {
383             unsafe { sys::SDL_JoystickClose(self.raw) }
384         }
385     }
386 }
387 
388 /// Wrapper around a `SDL_JoystickGUID`, a globally unique identifier
389 /// for a joystick.
390 #[derive(Copy, Clone)]
391 pub struct Guid {
392     raw: sys::SDL_JoystickGUID,
393 }
394 
395 impl PartialEq for Guid {
eq(&self, other: &Guid) -> bool396     fn eq(&self, other: &Guid) -> bool {
397         self.raw.data == other.raw.data
398     }
399 }
400 
401 impl Eq for Guid {}
402 
403 impl Guid {
404     /// Create a GUID from a string representation.
from_string(guid: &str) -> Result<Guid, NulError>405     pub fn from_string(guid: &str) -> Result<Guid, NulError> {
406         let guid = r#try!(CString::new(guid));
407 
408         let raw = unsafe { sys::SDL_JoystickGetGUIDFromString(guid.as_ptr() as *const c_char) };
409 
410         Ok(Guid { raw: raw })
411     }
412 
413     /// Return `true` if GUID is full 0s
is_zero(&self) -> bool414     pub fn is_zero(&self) -> bool {
415         for &i in &self.raw.data {
416             if i != 0 {
417                 return false;
418             }
419         }
420 
421         true
422     }
423 
424     /// Return a String representation of GUID
string(&self) -> String425     pub fn string(&self) -> String {
426         // Doc says "buf should supply at least 33bytes". I took that
427         // to mean that 33bytes should be enough in all cases, but
428         // maybe I'm wrong?
429         let mut buf = [0; 33];
430 
431         let len   = buf.len() as i32;
432         let c_str = buf.as_mut_ptr();
433 
434         unsafe {
435             sys::SDL_JoystickGetGUIDString(self.raw, c_str, len);
436         }
437 
438         // The buffer should always be NUL terminated (the
439         // documentation doesn't explicitly say it but I checked the
440         // code)
441         if c_str.is_null() {
442             String::new()
443         } else {
444             unsafe {
445                 CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
446             }
447         }
448     }
449 
450     /// Return a copy of the internal SDL_JoystickGUID
raw(self) -> sys::SDL_JoystickGUID451     pub fn raw(self) -> sys::SDL_JoystickGUID {
452         self.raw
453     }
454 }
455 
456 impl Display for Guid {
fmt(&self, f: &mut Formatter) -> Result<(), Error>457     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
458         write!(f, "{}", self.string())
459     }
460 }
461 
462 /// This is represented in SDL2 as a bitfield but obviously not all
463 /// combinations make sense: 5 for instance would mean up and down at
464 /// the same time... To simplify things I turn it into an enum which
465 /// is how the SDL2 docs present it anyway (using macros).
466 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
467 pub enum HatState {
468     Centered  = 0,
469     Up        = 0x01,
470     Right     = 0x02,
471     Down      = 0x04,
472     Left      = 0x08,
473     RightUp   = 0x02 | 0x01,
474     RightDown = 0x02 | 0x04,
475     LeftUp    = 0x08 | 0x01,
476     LeftDown  = 0x08 | 0x04,
477 }
478 
479 impl HatState {
from_raw(raw: u8) -> HatState480     pub fn from_raw(raw: u8) -> HatState {
481         match raw {
482             0  => HatState::Centered,
483             1  => HatState::Up,
484             2  => HatState::Right,
485             4  => HatState::Down,
486             8  => HatState::Left,
487             3  => HatState::RightUp,
488             6  => HatState::RightDown,
489             9  => HatState::LeftUp,
490             12 => HatState::LeftDown,
491             _  => panic!("Unexpected hat position: {}", raw),
492         }
493     }
494 
to_raw(&self) -> u8495     pub fn to_raw(&self) -> u8 {
496         match *self {
497             HatState::Centered => 0,
498             HatState::Up => 1,
499             HatState::Right => 2,
500             HatState::Down => 4,
501             HatState::Left => 8,
502             HatState::RightUp => 3,
503             HatState::RightDown => 6,
504             HatState::LeftUp => 9,
505             HatState::LeftDown => 12,
506         }
507 
508     }
509 }
510 
511 /// Convert C string `c_str` to a String. Return an empty string if
512 /// `c_str` is NULL.
c_str_to_string(c_str: *const c_char) -> String513 fn c_str_to_string(c_str: *const c_char) -> String {
514     if c_str.is_null() {
515         String::new()
516     } else {
517         let bytes = unsafe { CStr::from_ptr(c_str as *const _).to_bytes() };
518 
519         String::from_utf8_lossy(bytes).to_string()
520     }
521 }
522