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