use crate::sys;
use crate::sys::SDL_JoystickPowerLevel;
use crate::JoystickSubsystem;
use crate::get_error;
use crate::clear_error;
use std::ffi::{CString, CStr, NulError};
use std::fmt::{Display, Formatter, Error};
use libc::c_char;
use crate::common::{validate_int, IntegerOrSdlError};
impl JoystickSubsystem {
pub fn num_joysticks(&self) -> Result<u32, String> {
let result = unsafe { sys::SDL_NumJoysticks() };
if result >= 0 {
Ok(result as u32)
} else {
Err(get_error())
}
}
pub fn open(&self, joystick_index: u32)
-> Result<Joystick, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
let joystick_index = validate_int(joystick_index, "joystick_index")?;
let joystick = unsafe { sys::SDL_JoystickOpen(joystick_index) };
if joystick.is_null() {
Err(SdlError(get_error()))
} else {
Ok(Joystick {
subsystem: self.clone(),
raw: joystick
})
}
}
pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
let joystick_index = validate_int(joystick_index, "joystick_index")?;
let c_str = unsafe { sys::SDL_JoystickNameForIndex(joystick_index) };
if c_str.is_null() {
Err(SdlError(get_error()))
} else {
Ok(unsafe {
CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
})
}
}
pub fn device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
let joystick_index = validate_int(joystick_index, "joystick_index")?;
let raw = unsafe { sys::SDL_JoystickGetDeviceGUID(joystick_index) };
let guid = Guid { raw };
if guid.is_zero() {
Err(SdlError(get_error()))
} else {
Ok(guid)
}
}
pub fn set_event_state(&self, state: bool) {
unsafe { sys::SDL_JoystickEventState(state as i32) };
}
pub fn event_state(&self) -> bool {
unsafe { sys::SDL_JoystickEventState(sys::SDL_QUERY as i32)
== sys::SDL_ENABLE as i32 }
}
#[inline]
pub fn update(&self) {
unsafe { sys::SDL_JoystickUpdate() };
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum PowerLevel {
Unknown = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN as i32,
Empty = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY as i32,
Low = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW as i32,
Medium = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM as i32,
Full = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL as i32,
Wired = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED as i32,
}
impl PowerLevel {
pub fn from_ll(raw: SDL_JoystickPowerLevel) -> PowerLevel {
match raw {
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN => PowerLevel::Unknown,
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY => PowerLevel::Empty,
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW => PowerLevel::Low,
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM => PowerLevel::Medium,
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL => PowerLevel::Full,
SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED => PowerLevel::Wired,
_ => panic!("Unexpected power level: {:?}", raw),
}
}
pub fn to_ll(self) -> SDL_JoystickPowerLevel {
match self {
PowerLevel::Unknown => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN,
PowerLevel::Empty => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY,
PowerLevel::Low => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW,
PowerLevel::Medium => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM,
PowerLevel::Full => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL,
PowerLevel::Wired => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED,
}
}
}
pub struct Joystick {
subsystem: JoystickSubsystem,
raw: *mut sys::SDL_Joystick
}
impl Joystick {
#[inline]
pub const fn subsystem(&self) -> &JoystickSubsystem { &self.subsystem }
pub fn name(&self) -> String {
let name = unsafe { sys::SDL_JoystickName(self.raw) };
c_str_to_string(name)
}
pub fn attached(&self) -> bool {
unsafe { sys::SDL_JoystickGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
}
pub fn instance_id(&self) -> u32 {
let result = unsafe { sys::SDL_JoystickInstanceID(self.raw) };
if result < 0 {
panic!(get_error())
} else {
result as u32
}
}
pub fn guid(&self) -> Guid {
let raw = unsafe { sys::SDL_JoystickGetGUID(self.raw) };
let guid = Guid { raw };
if guid.is_zero() {
panic!(get_error())
} else {
guid
}
}
pub fn power_level(&self) -> Result<PowerLevel, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
clear_error();
let result = unsafe { sys::SDL_JoystickCurrentPowerLevel(self.raw) };
let state = PowerLevel::from_ll(result);
if result != SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN {
Ok(state)
} else {
let err = get_error();
if err.is_empty() {
Ok(state)
} else {
Err(SdlError(err))
}
}
}
pub fn num_axes(&self) -> u32 {
let result = unsafe { sys::SDL_JoystickNumAxes(self.raw) };
if result < 0 {
panic!(get_error())
} else {
result as u32
}
}
pub fn axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
clear_error();
let axis = validate_int(axis, "axis")?;
let pos = unsafe { sys::SDL_JoystickGetAxis(self.raw, axis) };
if pos != 0 {
Ok(pos)
} else {
let err = get_error();
if err.is_empty() {
Ok(pos)
} else {
Err(SdlError(err))
}
}
}
pub fn num_buttons(&self) -> u32 {
let result = unsafe { sys::SDL_JoystickNumButtons(self.raw) };
if result < 0 {
panic!(get_error())
} else {
result as u32
}
}
pub fn button(&self, button: u32) -> Result<bool, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
clear_error();
let button = validate_int(button, "button")?;
let pressed = unsafe { sys::SDL_JoystickGetButton(self.raw, button) };
match pressed {
1 => Ok(true),
0 => {
let err = get_error();
if err.is_empty() {
Ok(false)
} else {
Err(SdlError(err))
}
}
_ => unreachable!(),
}
}
pub fn num_balls(&self) -> u32 {
let result = unsafe { sys::SDL_JoystickNumBalls(self.raw) };
if result < 0 {
panic!(get_error())
} else {
result as u32
}
}
pub fn ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
let mut dx = 0;
let mut dy = 0;
let ball = validate_int(ball, "ball")?;
let result = unsafe { sys::SDL_JoystickGetBall(self.raw, ball, &mut dx, &mut dy) };
if result == 0 {
Ok((dx, dy))
} else {
Err(SdlError(get_error()))
}
}
pub fn num_hats(&self) -> u32 {
let result = unsafe { sys::SDL_JoystickNumHats(self.raw) };
if result < 0 {
panic!(get_error())
} else {
result as u32
}
}
pub fn hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError> {
use crate::common::IntegerOrSdlError::*;
clear_error();
let hat = validate_int(hat, "hat")?;
let result = unsafe { sys::SDL_JoystickGetHat(self.raw, hat) };
let state = HatState::from_raw(result as u8);
if result != 0 {
Ok(state)
} else {
let err = get_error();
if err.is_empty() {
Ok(state)
} else {
Err(SdlError(err))
}
}
}
pub fn set_rumble(&mut self,
low_frequency_rumble: u16,
high_frequency_rumble: u16,
duration_ms: u32)
-> Result<(), IntegerOrSdlError>
{
let result = unsafe {
sys::SDL_JoystickRumble(self.raw,
low_frequency_rumble,
high_frequency_rumble,
duration_ms)
};
if result != 0 {
Err(IntegerOrSdlError::SdlError(get_error()))
} else {
Ok(())
}
}
}
impl Drop for Joystick {
fn drop(&mut self) {
if self.attached() {
unsafe { sys::SDL_JoystickClose(self.raw) }
}
}
}
#[derive(Copy, Clone)]
pub struct Guid {
raw: sys::SDL_JoystickGUID,
}
impl PartialEq for Guid {
fn eq(&self, other: &Guid) -> bool {
self.raw.data == other.raw.data
}
}
impl Eq for Guid {}
impl Guid {
pub fn from_string(guid: &str) -> Result<Guid, NulError> {
let guid = CString::new(guid)?;
let raw = unsafe { sys::SDL_JoystickGetGUIDFromString(guid.as_ptr() as *const c_char) };
Ok(Guid { raw })
}
pub fn is_zero(&self) -> bool {
for &i in &self.raw.data {
if i != 0 {
return false;
}
}
true
}
pub fn string(&self) -> String {
let mut buf = [0; 33];
let len = buf.len() as i32;
let c_str = buf.as_mut_ptr();
unsafe {
sys::SDL_JoystickGetGUIDString(self.raw, c_str, len);
}
if c_str.is_null() {
String::new()
} else {
unsafe {
CStr::from_ptr(c_str as *const _).to_str().unwrap().to_string()
}
}
}
pub fn raw(self) -> sys::SDL_JoystickGUID {
self.raw
}
}
impl Display for Guid {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.string())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum HatState {
Centered = 0,
Up = 0x01,
Right = 0x02,
Down = 0x04,
Left = 0x08,
RightUp = 0x02 | 0x01,
RightDown = 0x02 | 0x04,
LeftUp = 0x08 | 0x01,
LeftDown = 0x08 | 0x04,
}
impl HatState {
pub fn from_raw(raw: u8) -> HatState {
match raw {
0 => HatState::Centered,
1 => HatState::Up,
2 => HatState::Right,
4 => HatState::Down,
8 => HatState::Left,
3 => HatState::RightUp,
6 => HatState::RightDown,
9 => HatState::LeftUp,
12 => HatState::LeftDown,
_ => HatState::Centered,
}
}
pub fn to_raw(self) -> u8 {
match self {
HatState::Centered => 0,
HatState::Up => 1,
HatState::Right => 2,
HatState::Down => 4,
HatState::Left => 8,
HatState::RightUp => 3,
HatState::RightDown => 6,
HatState::LeftUp => 9,
HatState::LeftDown => 12,
}
}
}
fn c_str_to_string(c_str: *const c_char) -> String {
if c_str.is_null() {
String::new()
} else {
let bytes = unsafe { CStr::from_ptr(c_str as *const _).to_bytes() };
String::from_utf8_lossy(bytes).to_string()
}
}