1use crate::rwops::RWops;
2use libc::c_char;
3use std::error;
4use std::ffi::{CStr, CString, NulError};
5use std::fmt;
6use std::io;
7use std::path::Path;
8
9#[cfg(feature = "hidapi")]
10use crate::sensor::SensorType;
11#[cfg(feature = "hidapi")]
12use std::convert::TryInto;
13
14use crate::common::{validate_int, IntegerOrSdlError};
15use crate::get_error;
16use crate::joystick;
17use crate::GameControllerSubsystem;
18use std::mem::transmute;
19
20use crate::sys;
21
22#[derive(Debug, Clone)]
23pub enum AddMappingError {
24 InvalidMapping(NulError),
25 InvalidFilePath(String),
26 ReadError(String),
27 SdlError(String),
28}
29
30impl fmt::Display for AddMappingError {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 use self::AddMappingError::*;
33
34 match *self {
35 InvalidMapping(ref e) => write!(f, "Null error: {}", e),
36 InvalidFilePath(ref value) => write!(f, "Invalid file path ({})", value),
37 ReadError(ref e) => write!(f, "Read error: {}", e),
38 SdlError(ref e) => write!(f, "SDL error: {}", e),
39 }
40 }
41}
42
43impl error::Error for AddMappingError {
44 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
45 match self {
46 Self::InvalidMapping(err) => Some(err),
47 Self::InvalidFilePath(_) | Self::ReadError(_) | Self::SdlError(_) => None,
48 }
49 }
50}
51
52impl GameControllerSubsystem {
53 #[doc(alias = "SDL_NumJoysticks")]
55 pub fn num_joysticks(&self) -> Result<u32, String> {
56 let result = unsafe { sys::SDL_NumJoysticks() };
57
58 if result >= 0 {
59 Ok(result as u32)
60 } else {
61 Err(get_error())
62 }
63 }
64
65 #[inline]
67 #[doc(alias = "SDL_IsGameController")]
68 pub fn is_game_controller(&self, joystick_index: u32) -> bool {
69 match validate_int(joystick_index, "joystick_index") {
70 Ok(joystick_index) => unsafe {
71 sys::SDL_IsGameController(joystick_index) != sys::SDL_bool::SDL_FALSE
72 },
73 Err(_) => false,
74 }
75 }
76
77 #[doc(alias = "SDL_GameControllerOpen")]
81 pub fn open(&self, joystick_index: u32) -> Result<GameController, IntegerOrSdlError> {
82 use crate::common::IntegerOrSdlError::*;
83 let joystick_index = validate_int(joystick_index, "joystick_index")?;
84 let controller = unsafe { sys::SDL_GameControllerOpen(joystick_index) };
85
86 if controller.is_null() {
87 Err(SdlError(get_error()))
88 } else {
89 Ok(GameController {
90 subsystem: self.clone(),
91 raw: controller,
92 })
93 }
94 }
95
96 #[doc(alias = "SDL_GameControllerNameForIndex")]
98 pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
99 use crate::common::IntegerOrSdlError::*;
100 let joystick_index = validate_int(joystick_index, "joystick_index")?;
101 let c_str = unsafe { sys::SDL_GameControllerNameForIndex(joystick_index) };
102
103 if c_str.is_null() {
104 Err(SdlError(get_error()))
105 } else {
106 Ok(unsafe {
107 CStr::from_ptr(c_str as *const _)
108 .to_str()
109 .unwrap()
110 .to_owned()
111 })
112 }
113 }
114
115 #[doc(alias = "SDL_GameControllerFromPlayerIndex")]
117 pub fn instance_id_for_player_index(
118 &self,
119 player_index: u32,
120 ) -> Result<Option<u32>, IntegerOrSdlError> {
121 let player_index = validate_int(player_index, "player_index")?;
122
123 let controller = unsafe { sys::SDL_GameControllerFromPlayerIndex(player_index) };
124
125 if controller.is_null() {
126 Ok(None)
127 } else {
128 let result = unsafe {
129 let joystick = sys::SDL_GameControllerGetJoystick(controller);
130 sys::SDL_JoystickInstanceID(joystick)
131 };
132
133 if result < 0 {
134 panic!("{}", get_error())
136 } else {
137 Ok(Some(result as u32))
138 }
139 }
140 }
141
142 #[doc(alias = "SDL_GameControllerEventState")]
145 pub fn set_event_state(&self, state: bool) {
146 unsafe { sys::SDL_GameControllerEventState(state as i32) };
147 }
148
149 #[doc(alias = "SDL_GameControllerEventState")]
151 pub fn event_state(&self) -> bool {
152 unsafe { sys::SDL_GameControllerEventState(sys::SDL_QUERY) == sys::SDL_ENABLE as i32 }
153 }
154
155 #[doc(alias = "SDL_GameControllerAddMapping")]
157 pub fn add_mapping(&self, mapping: &str) -> Result<MappingStatus, AddMappingError> {
158 use self::AddMappingError::*;
159 let mapping = match CString::new(mapping) {
160 Ok(s) => s,
161 Err(err) => return Err(InvalidMapping(err)),
162 };
163
164 let result =
165 unsafe { sys::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };
166
167 match result {
168 1 => Ok(MappingStatus::Added),
169 0 => Ok(MappingStatus::Updated),
170 _ => Err(SdlError(get_error())),
171 }
172 }
173
174 pub fn load_mappings<P: AsRef<Path>>(&self, path: P) -> Result<i32, AddMappingError> {
176 use self::AddMappingError::*;
177
178 let rw = RWops::from_file(path, "r").map_err(InvalidFilePath)?;
179 self.load_mappings_from_rw(rw)
180 }
181
182 pub fn load_mappings_from_read<R: io::Read>(
184 &self,
185 read: &mut R,
186 ) -> Result<i32, AddMappingError> {
187 use self::AddMappingError::*;
188
189 let mut buffer = Vec::with_capacity(1024);
190 let rw = RWops::from_read(read, &mut buffer).map_err(ReadError)?;
191 self.load_mappings_from_rw(rw)
192 }
193
194 #[doc(alias = "SDL_GameControllerAddMappingsFromRW")]
196 pub fn load_mappings_from_rw(&self, rw: RWops<'_>) -> Result<i32, AddMappingError> {
197 use self::AddMappingError::*;
198
199 let result = unsafe { sys::SDL_GameControllerAddMappingsFromRW(rw.raw(), 0) };
200 match result {
201 -1 => Err(SdlError(get_error())),
202 _ => Ok(result),
203 }
204 }
205
206 #[doc(alias = "SDL_GameControllerMappingForGUID")]
207 pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
208 let c_str = unsafe { sys::SDL_GameControllerMappingForGUID(guid.raw()) };
209
210 c_str_to_string_or_err(c_str)
211 }
212
213 #[inline]
214 #[doc(alias = "SDL_GameControllerUpdate")]
216 pub fn update(&self) {
217 unsafe { sys::SDL_GameControllerUpdate() };
218 }
219}
220
221#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
222#[repr(i32)]
223pub enum Axis {
224 LeftX = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX as i32,
225 LeftY = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY as i32,
226 RightX = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX as i32,
227 RightY = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY as i32,
228 TriggerLeft = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT as i32,
229 TriggerRight = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT as i32,
230}
231
232impl Axis {
233 #[doc(alias = "SDL_GameControllerGetAxisFromString")]
236 pub fn from_string(axis: &str) -> Option<Axis> {
237 let id = match CString::new(axis) {
238 Ok(axis) => unsafe {
239 sys::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char)
240 },
241 Err(_) => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_INVALID,
243 };
244
245 Axis::from_ll(id)
246 }
247
248 #[doc(alias = "SDL_GameControllerGetStringForAxis")]
251 pub fn string(self) -> String {
252 let axis: sys::SDL_GameControllerAxis;
253 unsafe {
254 axis = transmute(self);
255 }
256
257 let string = unsafe { sys::SDL_GameControllerGetStringForAxis(axis) };
258
259 c_str_to_string(string)
260 }
261
262 pub fn from_ll(bitflags: sys::SDL_GameControllerAxis) -> Option<Axis> {
263 Some(match bitflags {
264 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_INVALID => return None,
265 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX => Axis::LeftX,
266 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY => Axis::LeftY,
267 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX => Axis::RightX,
268 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY => Axis::RightY,
269 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT => Axis::TriggerLeft,
270 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
271 _ => return None,
272 })
273 }
274
275 pub fn to_ll(self) -> sys::SDL_GameControllerAxis {
276 match self {
277 Axis::LeftX => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX,
278 Axis::LeftY => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY,
279 Axis::RightX => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX,
280 Axis::RightY => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY,
281 Axis::TriggerLeft => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
282 Axis::TriggerRight => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
283 }
284 }
285}
286
287#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
288#[repr(i32)]
289pub enum Button {
290 A = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A as i32,
291 B = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B as i32,
292 X = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X as i32,
293 Y = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y as i32,
294 Back = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK as i32,
295 Guide = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE as i32,
296 Start = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START as i32,
297 LeftStick = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK as i32,
298 RightStick = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK as i32,
299 LeftShoulder = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER as i32,
300 RightShoulder = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER as i32,
301 DPadUp = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP as i32,
302 DPadDown = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN as i32,
303 DPadLeft = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT as i32,
304 DPadRight = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT as i32,
305 Misc1 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1 as i32,
306 Paddle1 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1 as i32,
307 Paddle2 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2 as i32,
308 Paddle3 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3 as i32,
309 Paddle4 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4 as i32,
310 Touchpad = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD as i32,
311}
312
313impl Button {
314 #[doc(alias = "SDL_GameControllerGetButtonFromString")]
317 pub fn from_string(button: &str) -> Option<Button> {
318 let id = match CString::new(button) {
319 Ok(button) => unsafe {
320 sys::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char)
321 },
322 Err(_) => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_INVALID,
324 };
325
326 Button::from_ll(id)
327 }
328
329 #[doc(alias = "SDL_GameControllerGetStringForButton")]
332 pub fn string(self) -> String {
333 let button: sys::SDL_GameControllerButton;
334 unsafe {
335 button = transmute(self);
336 }
337
338 let string = unsafe { sys::SDL_GameControllerGetStringForButton(button) };
339
340 c_str_to_string(string)
341 }
342
343 pub fn from_ll(bitflags: sys::SDL_GameControllerButton) -> Option<Button> {
344 Some(match bitflags {
345 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_INVALID => return None,
346 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A => Button::A,
347 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B => Button::B,
348 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X => Button::X,
349 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y => Button::Y,
350 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK => Button::Back,
351 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE => Button::Guide,
352 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START => Button::Start,
353 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK => Button::LeftStick,
354 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK => Button::RightStick,
355 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER => {
356 Button::LeftShoulder
357 }
358 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => {
359 Button::RightShoulder
360 }
361 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP => Button::DPadUp,
362 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN => Button::DPadDown,
363 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT => Button::DPadLeft,
364 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT => Button::DPadRight,
365 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1 => Button::Misc1,
366 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1 => Button::Paddle1,
367 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2 => Button::Paddle2,
368 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3 => Button::Paddle3,
369 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4 => Button::Paddle4,
370 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD => Button::Touchpad,
371 _ => return None,
372 })
373 }
374
375 pub fn to_ll(self) -> sys::SDL_GameControllerButton {
376 match self {
377 Button::A => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A,
378 Button::B => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B,
379 Button::X => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X,
380 Button::Y => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y,
381 Button::Back => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK,
382 Button::Guide => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE,
383 Button::Start => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START,
384 Button::LeftStick => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK,
385 Button::RightStick => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
386 Button::LeftShoulder => {
387 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER
388 }
389 Button::RightShoulder => {
390 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
391 }
392 Button::DPadUp => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP,
393 Button::DPadDown => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
394 Button::DPadLeft => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
395 Button::DPadRight => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
396 Button::Misc1 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1,
397 Button::Paddle1 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1,
398 Button::Paddle2 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2,
399 Button::Paddle3 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3,
400 Button::Paddle4 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4,
401 Button::Touchpad => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD,
402 }
403 }
404}
405
406#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
408pub enum MappingStatus {
409 Added = 1,
410 Updated = 0,
411}
412
413pub struct GameController {
415 subsystem: GameControllerSubsystem,
416 raw: *mut sys::SDL_GameController,
417}
418
419impl GameController {
420 #[inline]
421 pub fn subsystem(&self) -> &GameControllerSubsystem {
422 &self.subsystem
423 }
424
425 #[doc(alias = "SDL_GameControllerName")]
428 pub fn name(&self) -> String {
429 let name = unsafe { sys::SDL_GameControllerName(self.raw) };
430
431 c_str_to_string(name)
432 }
433
434 #[doc(alias = "SDL_GameControllerMapping")]
437 pub fn mapping(&self) -> String {
438 let mapping = unsafe { sys::SDL_GameControllerMapping(self.raw) };
439
440 c_str_to_string(mapping)
441 }
442
443 #[doc(alias = "SDL_GameControllerGetAttached")]
446 pub fn attached(&self) -> bool {
447 unsafe { sys::SDL_GameControllerGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
448 }
449
450 #[doc(alias = "SDL_GameControllerGetJoystick")]
452 pub fn instance_id(&self) -> u32 {
453 let result = unsafe {
454 let joystick = sys::SDL_GameControllerGetJoystick(self.raw);
455 sys::SDL_JoystickInstanceID(joystick)
456 };
457
458 if result < 0 {
459 panic!("{}", get_error())
461 } else {
462 result as u32
463 }
464 }
465
466 #[doc(alias = "SDL_GameControllerGetVendor")]
468 pub fn vendor_id(&self) -> Option<u16> {
469 let result = unsafe { sys::SDL_GameControllerGetVendor(self.raw) };
470
471 if result == 0 {
472 None
473 } else {
474 Some(result)
475 }
476 }
477
478 #[doc(alias = "SDL_GameControllerGetProduct")]
480 pub fn product_id(&self) -> Option<u16> {
481 let result = unsafe { sys::SDL_GameControllerGetProduct(self.raw) };
482
483 if result == 0 {
484 None
485 } else {
486 Some(result)
487 }
488 }
489
490 #[doc(alias = "SDL_GameControllerGetAxis")]
492 pub fn axis(&self, axis: Axis) -> i16 {
493 let raw_axis: sys::SDL_GameControllerAxis;
499 unsafe {
500 raw_axis = transmute(axis);
501 }
502
503 unsafe { sys::SDL_GameControllerGetAxis(self.raw, raw_axis) }
504 }
505
506 #[doc(alias = "SDL_GameControllerGetButton")]
508 pub fn button(&self, button: Button) -> bool {
509 let raw_button: sys::SDL_GameControllerButton;
515 unsafe {
516 raw_button = transmute(button);
517 }
518
519 unsafe { sys::SDL_GameControllerGetButton(self.raw, raw_button) != 0 }
520 }
521
522 #[doc(alias = "SDL_GameControllerRumble")]
534 pub fn set_rumble(
535 &mut self,
536 low_frequency_rumble: u16,
537 high_frequency_rumble: u16,
538 duration_ms: u32,
539 ) -> Result<(), IntegerOrSdlError> {
540 let result = unsafe {
541 sys::SDL_GameControllerRumble(
542 self.raw,
543 low_frequency_rumble,
544 high_frequency_rumble,
545 duration_ms,
546 )
547 };
548
549 if result != 0 {
550 Err(IntegerOrSdlError::SdlError(get_error()))
551 } else {
552 Ok(())
553 }
554 }
555
556 #[doc(alias = "SDL_GameControllerRumbleTriggers")]
558 pub fn set_rumble_triggers(
559 &mut self,
560 left_rumble: u16,
561 right_rumble: u16,
562 duration_ms: u32,
563 ) -> Result<(), IntegerOrSdlError> {
564 let result = unsafe {
565 sys::SDL_GameControllerRumbleTriggers(self.raw, left_rumble, right_rumble, duration_ms)
566 };
567
568 if result != 0 {
569 Err(IntegerOrSdlError::SdlError(get_error()))
570 } else {
571 Ok(())
572 }
573 }
574
575 #[doc(alias = "SDL_GameControllerSetPlayerIndex")]
577 pub fn set_player_index(&mut self, player_index: Option<u32>) -> Result<(), IntegerOrSdlError> {
578 let player_index = match player_index {
579 None => -1,
580 Some(player_index) => validate_int(player_index, "player_index")?,
581 };
582
583 unsafe { sys::SDL_GameControllerSetPlayerIndex(self.raw, player_index) };
584
585 Ok(())
586 }
587
588 #[doc(alias = "SDL_GameControllerGetPlayerIndex")]
590 pub fn get_player_index(&self) -> Option<u32> {
591 let player_index = unsafe { sys::SDL_GameControllerGetPlayerIndex(self.raw) };
592
593 if player_index < 0 {
595 None
596 } else {
597 Some(player_index as u32)
598 }
599 }
600
601 #[doc(alias = "SDL_GameControllerHasLED")]
603 pub fn has_led(&self) -> bool {
604 let result = unsafe { sys::SDL_GameControllerHasLED(self.raw) };
605
606 match result {
607 sys::SDL_bool::SDL_FALSE => false,
608 sys::SDL_bool::SDL_TRUE => true,
609 }
610 }
611
612 #[doc(alias = "SDL_GameControllerHasRumble")]
614 pub fn has_rumble(&self) -> bool {
615 let result = unsafe { sys::SDL_GameControllerHasRumble(self.raw) };
616
617 match result {
618 sys::SDL_bool::SDL_FALSE => false,
619 sys::SDL_bool::SDL_TRUE => true,
620 }
621 }
622
623 #[doc(alias = "SDL_GameControllerHasRumbleTriggers")]
625 pub fn has_rumble_triggers(&self) -> bool {
626 let result = unsafe { sys::SDL_GameControllerHasRumbleTriggers(self.raw) };
627
628 match result {
629 sys::SDL_bool::SDL_FALSE => false,
630 sys::SDL_bool::SDL_TRUE => true,
631 }
632 }
633
634 #[doc(alias = "SDL_GameControllerSetLED")]
636 pub fn set_led(&mut self, red: u8, green: u8, blue: u8) -> Result<(), IntegerOrSdlError> {
637 let result = unsafe { sys::SDL_GameControllerSetLED(self.raw, red, green, blue) };
638
639 if result != 0 {
640 Err(IntegerOrSdlError::SdlError(get_error()))
641 } else {
642 Ok(())
643 }
644 }
645
646 #[doc(alias = "SDL_GameControllerSendEffect")]
648 pub fn send_effect(&mut self, data: &[u8]) -> Result<(), String> {
649 let result = unsafe {
650 sys::SDL_GameControllerSendEffect(
651 self.raw,
652 data.as_ptr() as *const libc::c_void,
653 data.len() as i32,
654 )
655 };
656
657 if result != 0 {
658 Err(get_error())
659 } else {
660 Ok(())
661 }
662 }
663}
664
665#[cfg(feature = "hidapi")]
666impl GameController {
667 #[doc(alias = "SDL_GameControllerHasSensor")]
668 pub fn has_sensor(&self, sensor_type: crate::sensor::SensorType) -> bool {
669 let result = unsafe { sys::SDL_GameControllerHasSensor(self.raw, sensor_type.into()) };
670
671 match result {
672 sys::SDL_bool::SDL_FALSE => false,
673 sys::SDL_bool::SDL_TRUE => true,
674 }
675 }
676
677 #[doc(alias = "SDL_GameControllerIsSensorEnabled")]
678 pub fn sensor_enabled(&self, sensor_type: crate::sensor::SensorType) -> bool {
679 let result =
680 unsafe { sys::SDL_GameControllerIsSensorEnabled(self.raw, sensor_type.into()) };
681
682 match result {
683 sys::SDL_bool::SDL_FALSE => false,
684 sys::SDL_bool::SDL_TRUE => true,
685 }
686 }
687
688 #[doc(alias = "SDL_GameControllerSetSensorEnabled")]
689 pub fn sensor_set_enabled(
690 &self,
691 sensor_type: crate::sensor::SensorType,
692 enabled: bool,
693 ) -> Result<(), IntegerOrSdlError> {
694 let result = unsafe {
695 sys::SDL_GameControllerSetSensorEnabled(
696 self.raw,
697 sensor_type.into(),
698 if enabled {
699 sys::SDL_bool::SDL_TRUE
700 } else {
701 sys::SDL_bool::SDL_FALSE
702 },
703 )
704 };
705
706 if result != 0 {
707 Err(IntegerOrSdlError::SdlError(get_error()))
708 } else {
709 Ok(())
710 }
711 }
712
713 #[doc(alias = "SDL_GameControllerGetSensorDataRate")]
715 pub fn sensor_get_data_rate(&self, sensor_type: SensorType) -> f32 {
716 unsafe { sys::SDL_GameControllerGetSensorDataRate(self.raw, sensor_type.into()) }
717 }
718
719 #[doc(alias = "SDL_GameControllerGetSensorData")]
724 pub fn sensor_get_data(
725 &self,
726 sensor_type: SensorType,
727 data: &mut [f32],
728 ) -> Result<(), IntegerOrSdlError> {
729 let result = unsafe {
730 sys::SDL_GameControllerGetSensorData(
731 self.raw,
732 sensor_type.into(),
733 data.as_mut_ptr(),
734 data.len().try_into().unwrap(),
735 )
736 };
737
738 if result != 0 {
739 Err(IntegerOrSdlError::SdlError(get_error()))
740 } else {
741 Ok(())
742 }
743 }
744}
745
746impl Drop for GameController {
747 #[doc(alias = "SDL_GameControllerClose")]
748 fn drop(&mut self) {
749 unsafe { sys::SDL_GameControllerClose(self.raw) }
750 }
751}
752
753fn c_str_to_string(c_str: *const c_char) -> String {
756 if c_str.is_null() {
757 String::new()
758 } else {
759 unsafe {
760 CStr::from_ptr(c_str as *const _)
761 .to_str()
762 .unwrap()
763 .to_owned()
764 }
765 }
766}
767
768fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
771 if c_str.is_null() {
772 Err(get_error())
773 } else {
774 Ok(unsafe {
775 CStr::from_ptr(c_str as *const _)
776 .to_str()
777 .unwrap()
778 .to_owned()
779 })
780 }
781}