@ -1,15 +1,21 @@
//! Human Interface Device service.
//! Human Interface Device service.
//!
//!
//! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position),
//! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position),
//! and [circle pad information](Hid::circlepad_position). It also provides information from the sound volume slider, the accelerometer, and the gyroscope.
//! and [circle pad information](Hid::circlepad_position). It also provides information from the [3D slider](Hid::slider_3d()), the [volume slider](Hid::slider_volume()),
// TODO: Implement volume slider, accelerometer and gyroscope + any other missing functionality .
//! the [accelerometer](Hid::accellerometer_vector()), and the [gyroscope](Hid::gyroscope_rate()) .
#![ doc(alias = " input " ) ]
#![ doc(alias = " input " ) ]
#![ doc(alias = " controller " ) ]
#![ doc(alias = " controller " ) ]
#![ doc(alias = " gamepad " ) ]
#![ doc(alias = " gamepad " ) ]
use std ::sync ::Mutex ;
use crate ::error ::ResultCode ;
use crate ::error ::ResultCode ;
use crate ::services ::ServiceReference ;
use bitflags ::bitflags ;
use bitflags ::bitflags ;
static HID_ACTIVE : Mutex < ( ) > = Mutex ::new ( ( ) ) ;
bitflags ! {
bitflags ! {
/// A set of flags corresponding to the button and directional pad inputs present on the 3DS.
/// A set of flags corresponding to the button and directional pad inputs present on the 3DS.
#[ derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy) ]
#[ derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy) ]
@ -75,7 +81,11 @@ bitflags! {
}
}
/// Handle to the HID service.
/// Handle to the HID service.
pub struct Hid ( ( ) ) ;
pub struct Hid {
active_accellerometer : bool ,
active_gyroscope : bool ,
_service_handler : ServiceReference ,
}
impl Hid {
impl Hid {
/// Initialize a new service handle.
/// Initialize a new service handle.
@ -100,10 +110,26 @@ impl Hid {
/// ```
/// ```
#[ doc(alias = " hidInit " ) ]
#[ doc(alias = " hidInit " ) ]
pub fn new ( ) -> crate ::Result < Hid > {
pub fn new ( ) -> crate ::Result < Hid > {
unsafe {
let handler = ServiceReference ::new (
ResultCode ( ctru_sys ::hidInit ( ) ) ? ;
& HID_ACTIVE ,
Ok ( Hid ( ( ) ) )
| | {
}
ResultCode ( unsafe { ctru_sys ::hidInit ( ) } ) ? ;
Ok ( ( ) )
} ,
| | unsafe {
let _ = ctru_sys ::HIDUSER_DisableGyroscope ( ) ;
let _ = ctru_sys ::HIDUSER_DisableAccelerometer ( ) ;
ctru_sys ::hidExit ( ) ;
} ,
) ? ;
Ok ( Self {
active_accellerometer : false ,
active_gyroscope : false ,
_service_handler : handler ,
} )
}
}
/// Scan the HID service for all user input occurring on the current frame.
/// Scan the HID service for all user input occurring on the current frame.
@ -282,11 +308,122 @@ impl Hid {
( res . dx , res . dy )
( res . dx , res . dy )
}
}
}
impl Drop for Hid {
/// Returns the current volume slider position (between 0 and 1).
#[ doc(alias = " hidExit " ) ]
///
fn drop ( & mut self ) {
/// # Notes
unsafe { ctru_sys ::hidExit ( ) } ;
///
/// The [`ndsp`](crate::services::ndsp) service automatically uses the volume slider's position to handle audio mixing.
/// As such this method should not be used to programmatically change the volume.
///
/// Its purpose is only to inform the program of the volume slider's position (e.g. checking if the user has muted the audio).
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::hid::Hid;
/// let mut hid = Hid::new()?;
///
/// hid.scan_input();
///
/// let volume = hid.slider_volume();
/// #
/// # Ok(())
/// # }
/// ```
#[ doc(alias = " HIDUSER_GetSoundVolume " ) ]
pub fn slider_volume ( & self ) -> f32 {
let mut slider = 0 ;
unsafe {
let _ = ctru_sys ::HIDUSER_GetSoundVolume ( & mut slider ) ;
}
( slider as f32 ) / 63.
}
/// Returns the current 3D slider position (between 0 and 1).
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::hid::Hid;
/// let mut hid = Hid::new()?;
///
/// hid.scan_input();
///
/// let volume = hid.volume_slider();
/// #
/// # Ok(())
/// # }
/// ```
#[ doc(alias = " osGet3DSliderState " ) ]
pub fn slider_3d ( & self ) -> f32 {
// TODO: Replace with the static inline function `osGet3DSliderState`, which works the exact same way.
unsafe { ( * ( ctru_sys ::OS_SHAREDCFG_VADDR as * mut ctru_sys ::osSharedConfig_s ) ) . slider_3d }
}
#[ doc(alias = " HIDUSER_EnableAccelerometer " ) ]
pub fn enable_accellerometer ( & mut self ) {
let _ = unsafe { ctru_sys ::HIDUSER_EnableAccelerometer ( ) } ;
self . active_accellerometer = true ;
}
#[ doc(alias = " HIDUSER_EnableGyroscope " ) ]
pub fn enable_gyroscope ( & mut self ) {
let _ = unsafe { ctru_sys ::HIDUSER_EnableGyroscope ( ) } ;
self . active_gyroscope = true ;
}
#[ doc(alias = " HIDUSER_DisableAccelerometer " ) ]
pub fn disable_accellerometer ( & mut self ) {
let _ = unsafe { ctru_sys ::HIDUSER_DisableAccelerometer ( ) } ;
self . active_accellerometer = false ;
}
#[ doc(alias = " HIDUSER_DisableGyroscope " ) ]
pub fn disable_gyroscope ( & mut self ) {
let _ = unsafe { ctru_sys ::HIDUSER_DisableGyroscope ( ) } ;
self . active_gyroscope = false ;
}
#[ doc(alias = " hidAccelRead " ) ]
pub fn accellerometer_vector ( & self ) -> ( i16 , i16 , i16 ) {
if ! self . active_accellerometer {
panic! ( "tried to read accellerometer while disabled" )
}
let mut res = ctru_sys ::accelVector { x : 0 , y : 0 , z : 0 } ;
unsafe {
ctru_sys ::hidAccelRead ( & mut res ) ;
}
( res . x , res . y , res . z )
}
#[ doc(alias = " hidGyroRead " ) ]
pub fn gyroscope_rate ( & self ) -> ( i16 , i16 , i16 ) {
if ! self . active_gyroscope {
panic! ( "tried to read accellerometer while disabled" )
}
let mut res = ctru_sys ::angularRate { x : 0 , y : 0 , z : 0 } ;
unsafe {
ctru_sys ::hidGyroRead ( & mut res ) ;
}
( res . x , res . y , res . z )
}
}
}
}