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_GameControllerEventState")]
118 pub fn set_event_state(&self, state: bool) {
119 unsafe { sys::SDL_GameControllerEventState(state as i32) };
120 }
121
122 #[doc(alias = "SDL_GameControllerEventState")]
124 pub fn event_state(&self) -> bool {
125 unsafe { sys::SDL_GameControllerEventState(sys::SDL_QUERY) == sys::SDL_ENABLE as i32 }
126 }
127
128 #[doc(alias = "SDL_GameControllerAddMapping")]
130 pub fn add_mapping(&self, mapping: &str) -> Result<MappingStatus, AddMappingError> {
131 use self::AddMappingError::*;
132 let mapping = match CString::new(mapping) {
133 Ok(s) => s,
134 Err(err) => return Err(InvalidMapping(err)),
135 };
136
137 let result =
138 unsafe { sys::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };
139
140 match result {
141 1 => Ok(MappingStatus::Added),
142 0 => Ok(MappingStatus::Updated),
143 _ => Err(SdlError(get_error())),
144 }
145 }
146
147 pub fn load_mappings<P: AsRef<Path>>(&self, path: P) -> Result<i32, AddMappingError> {
149 use self::AddMappingError::*;
150
151 let rw = RWops::from_file(path, "r").map_err(InvalidFilePath)?;
152 self.load_mappings_from_rw(rw)
153 }
154
155 pub fn load_mappings_from_read<R: io::Read>(
157 &self,
158 read: &mut R,
159 ) -> Result<i32, AddMappingError> {
160 use self::AddMappingError::*;
161
162 let mut buffer = Vec::with_capacity(1024);
163 let rw = RWops::from_read(read, &mut buffer).map_err(ReadError)?;
164 self.load_mappings_from_rw(rw)
165 }
166
167 #[doc(alias = "SDL_GameControllerAddMappingsFromRW")]
169 pub fn load_mappings_from_rw(&self, rw: RWops<'_>) -> Result<i32, AddMappingError> {
170 use self::AddMappingError::*;
171
172 let result = unsafe { sys::SDL_GameControllerAddMappingsFromRW(rw.raw(), 0) };
173 match result {
174 -1 => Err(SdlError(get_error())),
175 _ => Ok(result),
176 }
177 }
178
179 #[doc(alias = "SDL_GameControllerMappingForGUID")]
180 pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
181 let c_str = unsafe { sys::SDL_GameControllerMappingForGUID(guid.raw()) };
182
183 c_str_to_string_or_err(c_str)
184 }
185
186 #[inline]
187 #[doc(alias = "SDL_GameControllerUpdate")]
189 pub fn update(&self) {
190 unsafe { sys::SDL_GameControllerUpdate() };
191 }
192}
193
194#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
195#[repr(i32)]
196pub enum Axis {
197 LeftX = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX as i32,
198 LeftY = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY as i32,
199 RightX = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX as i32,
200 RightY = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY as i32,
201 TriggerLeft = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT as i32,
202 TriggerRight = sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT as i32,
203}
204
205impl Axis {
206 #[doc(alias = "SDL_GameControllerGetAxisFromString")]
209 pub fn from_string(axis: &str) -> Option<Axis> {
210 let id = match CString::new(axis) {
211 Ok(axis) => unsafe {
212 sys::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char)
213 },
214 Err(_) => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_INVALID,
216 };
217
218 Axis::from_ll(id)
219 }
220
221 #[doc(alias = "SDL_GameControllerGetStringForAxis")]
224 pub fn string(self) -> String {
225 let axis: sys::SDL_GameControllerAxis;
226 unsafe {
227 axis = transmute(self);
228 }
229
230 let string = unsafe { sys::SDL_GameControllerGetStringForAxis(axis) };
231
232 c_str_to_string(string)
233 }
234
235 pub fn from_ll(bitflags: sys::SDL_GameControllerAxis) -> Option<Axis> {
236 Some(match bitflags {
237 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_INVALID => return None,
238 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX => Axis::LeftX,
239 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY => Axis::LeftY,
240 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX => Axis::RightX,
241 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY => Axis::RightY,
242 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT => Axis::TriggerLeft,
243 sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
244 _ => return None,
245 })
246 }
247
248 pub fn to_ll(self) -> sys::SDL_GameControllerAxis {
249 match self {
250 Axis::LeftX => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX,
251 Axis::LeftY => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY,
252 Axis::RightX => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX,
253 Axis::RightY => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY,
254 Axis::TriggerLeft => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
255 Axis::TriggerRight => sys::SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
256 }
257 }
258}
259
260#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
261#[repr(i32)]
262pub enum Button {
263 A = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A as i32,
264 B = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B as i32,
265 X = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X as i32,
266 Y = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y as i32,
267 Back = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK as i32,
268 Guide = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE as i32,
269 Start = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START as i32,
270 LeftStick = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK as i32,
271 RightStick = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK as i32,
272 LeftShoulder = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER as i32,
273 RightShoulder = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER as i32,
274 DPadUp = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP as i32,
275 DPadDown = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN as i32,
276 DPadLeft = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT as i32,
277 DPadRight = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT as i32,
278 Misc1 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1 as i32,
279 Paddle1 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1 as i32,
280 Paddle2 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2 as i32,
281 Paddle3 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3 as i32,
282 Paddle4 = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4 as i32,
283 Touchpad = sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD as i32,
284}
285
286impl Button {
287 #[doc(alias = "SDL_GameControllerGetButtonFromString")]
290 pub fn from_string(button: &str) -> Option<Button> {
291 let id = match CString::new(button) {
292 Ok(button) => unsafe {
293 sys::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char)
294 },
295 Err(_) => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_INVALID,
297 };
298
299 Button::from_ll(id)
300 }
301
302 #[doc(alias = "SDL_GameControllerGetStringForButton")]
305 pub fn string(self) -> String {
306 let button: sys::SDL_GameControllerButton;
307 unsafe {
308 button = transmute(self);
309 }
310
311 let string = unsafe { sys::SDL_GameControllerGetStringForButton(button) };
312
313 c_str_to_string(string)
314 }
315
316 pub fn from_ll(bitflags: sys::SDL_GameControllerButton) -> Option<Button> {
317 Some(match bitflags {
318 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_INVALID => return None,
319 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A => Button::A,
320 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B => Button::B,
321 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X => Button::X,
322 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y => Button::Y,
323 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK => Button::Back,
324 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE => Button::Guide,
325 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START => Button::Start,
326 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK => Button::LeftStick,
327 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK => Button::RightStick,
328 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER => {
329 Button::LeftShoulder
330 }
331 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => {
332 Button::RightShoulder
333 }
334 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP => Button::DPadUp,
335 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN => Button::DPadDown,
336 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT => Button::DPadLeft,
337 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT => Button::DPadRight,
338 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1 => Button::Misc1,
339 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1 => Button::Paddle1,
340 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2 => Button::Paddle2,
341 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3 => Button::Paddle3,
342 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4 => Button::Paddle4,
343 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD => Button::Touchpad,
344 _ => return None,
345 })
346 }
347
348 pub fn to_ll(self) -> sys::SDL_GameControllerButton {
349 match self {
350 Button::A => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A,
351 Button::B => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B,
352 Button::X => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X,
353 Button::Y => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y,
354 Button::Back => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK,
355 Button::Guide => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE,
356 Button::Start => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START,
357 Button::LeftStick => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK,
358 Button::RightStick => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
359 Button::LeftShoulder => {
360 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER
361 }
362 Button::RightShoulder => {
363 sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
364 }
365 Button::DPadUp => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP,
366 Button::DPadDown => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
367 Button::DPadLeft => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
368 Button::DPadRight => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
369 Button::Misc1 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1,
370 Button::Paddle1 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1,
371 Button::Paddle2 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2,
372 Button::Paddle3 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3,
373 Button::Paddle4 => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4,
374 Button::Touchpad => sys::SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD,
375 }
376 }
377}
378
379#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
381pub enum MappingStatus {
382 Added = 1,
383 Updated = 0,
384}
385
386pub struct GameController {
388 subsystem: GameControllerSubsystem,
389 raw: *mut sys::SDL_GameController,
390}
391
392impl GameController {
393 #[inline]
394 pub fn subsystem(&self) -> &GameControllerSubsystem {
395 &self.subsystem
396 }
397
398 #[doc(alias = "SDL_GameControllerName")]
401 pub fn name(&self) -> String {
402 let name = unsafe { sys::SDL_GameControllerName(self.raw) };
403
404 c_str_to_string(name)
405 }
406
407 #[doc(alias = "SDL_GameControllerMapping")]
410 pub fn mapping(&self) -> String {
411 let mapping = unsafe { sys::SDL_GameControllerMapping(self.raw) };
412
413 c_str_to_string(mapping)
414 }
415
416 #[doc(alias = "SDL_GameControllerGetAttached")]
419 pub fn attached(&self) -> bool {
420 unsafe { sys::SDL_GameControllerGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
421 }
422
423 #[doc(alias = "SDL_GameControllerGetJoystick")]
425 pub fn instance_id(&self) -> u32 {
426 let result = unsafe {
427 let joystick = sys::SDL_GameControllerGetJoystick(self.raw);
428 sys::SDL_JoystickInstanceID(joystick)
429 };
430
431 if result < 0 {
432 panic!("{}", get_error())
434 } else {
435 result as u32
436 }
437 }
438
439 #[doc(alias = "SDL_GameControllerGetVendor")]
441 pub fn vendor_id(&self) -> Option<u16> {
442 let result = unsafe { sys::SDL_GameControllerGetVendor(self.raw) };
443
444 if result == 0 {
445 None
446 } else {
447 Some(result)
448 }
449 }
450
451 #[doc(alias = "SDL_GameControllerGetProduct")]
453 pub fn product_id(&self) -> Option<u16> {
454 let result = unsafe { sys::SDL_GameControllerGetProduct(self.raw) };
455
456 if result == 0 {
457 None
458 } else {
459 Some(result)
460 }
461 }
462
463 #[doc(alias = "SDL_GameControllerGetAxis")]
465 pub fn axis(&self, axis: Axis) -> i16 {
466 let raw_axis: sys::SDL_GameControllerAxis;
472 unsafe {
473 raw_axis = transmute(axis);
474 }
475
476 unsafe { sys::SDL_GameControllerGetAxis(self.raw, raw_axis) }
477 }
478
479 #[doc(alias = "SDL_GameControllerGetButton")]
481 pub fn button(&self, button: Button) -> bool {
482 let raw_button: sys::SDL_GameControllerButton;
488 unsafe {
489 raw_button = transmute(button);
490 }
491
492 unsafe { sys::SDL_GameControllerGetButton(self.raw, raw_button) != 0 }
493 }
494
495 #[doc(alias = "SDL_GameControllerRumble")]
507 pub fn set_rumble(
508 &mut self,
509 low_frequency_rumble: u16,
510 high_frequency_rumble: u16,
511 duration_ms: u32,
512 ) -> Result<(), IntegerOrSdlError> {
513 let result = unsafe {
514 sys::SDL_GameControllerRumble(
515 self.raw,
516 low_frequency_rumble,
517 high_frequency_rumble,
518 duration_ms,
519 )
520 };
521
522 if result != 0 {
523 Err(IntegerOrSdlError::SdlError(get_error()))
524 } else {
525 Ok(())
526 }
527 }
528
529 #[doc(alias = "SDL_GameControllerRumbleTriggers")]
531 pub fn set_rumble_triggers(
532 &mut self,
533 left_rumble: u16,
534 right_rumble: u16,
535 duration_ms: u32,
536 ) -> Result<(), IntegerOrSdlError> {
537 let result = unsafe {
538 sys::SDL_GameControllerRumbleTriggers(self.raw, left_rumble, right_rumble, duration_ms)
539 };
540
541 if result != 0 {
542 Err(IntegerOrSdlError::SdlError(get_error()))
543 } else {
544 Ok(())
545 }
546 }
547
548 #[doc(alias = "SDL_GameControllerHasLED")]
550 pub fn has_led(&self) -> bool {
551 let result = unsafe { sys::SDL_GameControllerHasLED(self.raw) };
552
553 match result {
554 sys::SDL_bool::SDL_FALSE => false,
555 sys::SDL_bool::SDL_TRUE => true,
556 }
557 }
558
559 #[doc(alias = "SDL_GameControllerHasRumble")]
561 pub fn has_rumble(&self) -> bool {
562 let result = unsafe { sys::SDL_GameControllerHasRumble(self.raw) };
563
564 match result {
565 sys::SDL_bool::SDL_FALSE => false,
566 sys::SDL_bool::SDL_TRUE => true,
567 }
568 }
569
570 #[doc(alias = "SDL_GameControllerHasRumbleTriggers")]
572 pub fn has_rumble_triggers(&self) -> bool {
573 let result = unsafe { sys::SDL_GameControllerHasRumbleTriggers(self.raw) };
574
575 match result {
576 sys::SDL_bool::SDL_FALSE => false,
577 sys::SDL_bool::SDL_TRUE => true,
578 }
579 }
580
581 #[doc(alias = "SDL_GameControllerSetLED")]
583 pub fn set_led(&mut self, red: u8, green: u8, blue: u8) -> Result<(), IntegerOrSdlError> {
584 let result = unsafe { sys::SDL_GameControllerSetLED(self.raw, red, green, blue) };
585
586 if result != 0 {
587 Err(IntegerOrSdlError::SdlError(get_error()))
588 } else {
589 Ok(())
590 }
591 }
592
593 #[doc(alias = "SDL_GameControllerSendEffect")]
595 pub fn send_effect(&mut self, data: &[u8]) -> Result<(), String> {
596 let result = unsafe {
597 sys::SDL_GameControllerSendEffect(
598 self.raw,
599 data.as_ptr() as *const libc::c_void,
600 data.len() as i32,
601 )
602 };
603
604 if result != 0 {
605 Err(get_error())
606 } else {
607 Ok(())
608 }
609 }
610}
611
612#[cfg(feature = "hidapi")]
613impl GameController {
614 #[doc(alias = "SDL_GameControllerHasSensor")]
615 pub fn has_sensor(&self, sensor_type: crate::sensor::SensorType) -> bool {
616 let result = unsafe { sys::SDL_GameControllerHasSensor(self.raw, sensor_type.into()) };
617
618 match result {
619 sys::SDL_bool::SDL_FALSE => false,
620 sys::SDL_bool::SDL_TRUE => true,
621 }
622 }
623
624 #[doc(alias = "SDL_GameControllerIsSensorEnabled")]
625 pub fn sensor_enabled(&self, sensor_type: crate::sensor::SensorType) -> bool {
626 let result =
627 unsafe { sys::SDL_GameControllerIsSensorEnabled(self.raw, sensor_type.into()) };
628
629 match result {
630 sys::SDL_bool::SDL_FALSE => false,
631 sys::SDL_bool::SDL_TRUE => true,
632 }
633 }
634
635 #[doc(alias = "SDL_GameControllerSetSensorEnabled")]
636 pub fn sensor_set_enabled(
637 &self,
638 sensor_type: crate::sensor::SensorType,
639 enabled: bool,
640 ) -> Result<(), IntegerOrSdlError> {
641 let result = unsafe {
642 sys::SDL_GameControllerSetSensorEnabled(
643 self.raw,
644 sensor_type.into(),
645 if enabled {
646 sys::SDL_bool::SDL_TRUE
647 } else {
648 sys::SDL_bool::SDL_FALSE
649 },
650 )
651 };
652
653 if result != 0 {
654 Err(IntegerOrSdlError::SdlError(get_error()))
655 } else {
656 Ok(())
657 }
658 }
659
660 #[doc(alias = "SDL_GameControllerGetSensorDataRate")]
662 pub fn sensor_get_data_rate(&self, sensor_type: SensorType) -> f32 {
663 unsafe { sys::SDL_GameControllerGetSensorDataRate(self.raw, sensor_type.into()) }
664 }
665
666 #[doc(alias = "SDL_GameControllerGetSensorData")]
671 pub fn sensor_get_data(
672 &self,
673 sensor_type: SensorType,
674 data: &mut [f32],
675 ) -> Result<(), IntegerOrSdlError> {
676 let result = unsafe {
677 sys::SDL_GameControllerGetSensorData(
678 self.raw,
679 sensor_type.into(),
680 data.as_mut_ptr(),
681 data.len().try_into().unwrap(),
682 )
683 };
684
685 if result != 0 {
686 Err(IntegerOrSdlError::SdlError(get_error()))
687 } else {
688 Ok(())
689 }
690 }
691}
692
693impl Drop for GameController {
694 #[doc(alias = "SDL_GameControllerClose")]
695 fn drop(&mut self) {
696 unsafe { sys::SDL_GameControllerClose(self.raw) }
697 }
698}
699
700fn c_str_to_string(c_str: *const c_char) -> String {
703 if c_str.is_null() {
704 String::new()
705 } else {
706 unsafe {
707 CStr::from_ptr(c_str as *const _)
708 .to_str()
709 .unwrap()
710 .to_owned()
711 }
712 }
713}
714
715fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
718 if c_str.is_null() {
719 Err(get_error())
720 } else {
721 Ok(unsafe {
722 CStr::from_ptr(c_str as *const _)
723 .to_str()
724 .unwrap()
725 .to_owned()
726 })
727 }
728}