Browse Source

Merge pull request #42 from FenrirWolf/hid-update

Refactor HID module
pull/10/head
Ronald Kinard 8 years ago committed by GitHub
parent
commit
9f575ccd71
  1. 4
      ctru-rs/Cargo.toml
  2. 35
      ctru-rs/src/services/fs.rs
  3. 182
      ctru-rs/src/services/hid.rs
  4. 75
      examples/src/bin/buttons.rs
  5. 4
      examples/src/bin/hello-both-screens.rs
  6. 4
      examples/src/bin/hello-world.rs

4
ctru-rs/Cargo.toml

@ -4,7 +4,7 @@ description = "A safe wrapper around smealum's ctrulib."
license = "https://en.wikipedia.org/wiki/Zlib_License" license = "https://en.wikipedia.org/wiki/Zlib_License"
name = "ctru-rs" name = "ctru-rs"
links = "ctru" links = "ctru"
version = "0.5.1" version = "0.6.0"
[lib] [lib]
crate-type = ["rlib"] crate-type = ["rlib"]
@ -15,7 +15,7 @@ path = "../ctru-sys"
version = "0.4" version = "0.4"
[dependencies.bitflags] [dependencies.bitflags]
version = "0.7.0" version = "0.9.0"
[dependencies.widestring] [dependencies.widestring]
version = "0.2.2" version = "0.2.2"

35
ctru-rs/src/services/fs.rs

@ -18,26 +18,29 @@ use std::sync::Arc;
use widestring::{WideCString, WideCStr}; use widestring::{WideCString, WideCStr};
bitflags! { bitflags! {
flags FsOpen: u32 { #[derive(Default)]
const FS_OPEN_READ = 1, struct FsOpen: u32 {
const FS_OPEN_WRITE = 2, const FS_OPEN_READ = 1;
const FS_OPEN_CREATE = 4, const FS_OPEN_WRITE = 2;
const FS_OPEN_CREATE = 4;
} }
} }
bitflags! { bitflags! {
flags FsWrite: u32 { #[derive(Default)]
const FS_WRITE_FLUSH = 1, struct FsWrite: u32 {
const FS_WRITE_UPDATE_TIME = 256, const FS_WRITE_FLUSH = 1;
const FS_WRITE_UPDATE_TIME = 256;
} }
} }
bitflags! { bitflags! {
flags FsAttribute: u32 { #[derive(Default)]
const FS_ATTRIBUTE_DIRECTORY = 1, struct FsAttribute: u32 {
const FS_ATTRIBUTE_HIDDEN = 256, const FS_ATTRIBUTE_DIRECTORY = 1;
const FS_ATTRIBUTE_ARCHIVE = 65536, const FS_ATTRIBUTE_HIDDEN = 256;
const FS_ATTRIBUTE_READ_ONLY = 16777216, const FS_ATTRIBUTE_ARCHIVE = 65536;
const FS_ATTRIBUTE_READ_ONLY = 16777216;
} }
} }
@ -467,7 +470,7 @@ impl File {
impl Metadata { impl Metadata {
/// Returns whether this metadata is for a directory. /// Returns whether this metadata is for a directory.
pub fn is_dir(&self) -> bool { pub fn is_dir(&self) -> bool {
self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY.bits self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY.bits()
} }
/// Returns whether this metadata is for a regular file. /// Returns whether this metadata is for a regular file.
@ -586,7 +589,7 @@ impl OpenOptions {
let path = to_utf16(path); let path = to_utf16(path);
let fs_path = ::libctru::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let fs_path = ::libctru::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _);
let r = ::libctru::FSUSER_OpenFile(&mut file_handle, self.arch_handle, let r = ::libctru::FSUSER_OpenFile(&mut file_handle, self.arch_handle,
fs_path, flags.bits, 0); fs_path, flags.bits(), 0);
if r < 0 { if r < 0 {
return Err(IoError::new(IoErrorKind::Other, ::Error::from(r))); return Err(IoError::new(IoErrorKind::Other, ::Error::from(r)));
} }
@ -685,7 +688,7 @@ pub fn create_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> IoResult<()> {
let path = to_utf16(path.as_ref()); let path = to_utf16(path.as_ref());
let fs_path = ::libctru::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let fs_path = ::libctru::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _);
let r = ::libctru::FSUSER_CreateDirectory(arch.handle, fs_path, let r = ::libctru::FSUSER_CreateDirectory(arch.handle, fs_path,
FS_ATTRIBUTE_DIRECTORY.bits); FS_ATTRIBUTE_DIRECTORY.bits());
if r < 0 { if r < 0 {
Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) Err(IoError::new(IoErrorKind::Other, ::Error::from(r)))
} else { } else {
@ -722,7 +725,7 @@ pub fn metadata<P: AsRef<Path>>(arch: &Archive, path: P) -> IoResult<Metadata> {
let maybe_dir = read_dir(&arch, path.as_ref()); let maybe_dir = read_dir(&arch, path.as_ref());
match (maybe_file, maybe_dir) { match (maybe_file, maybe_dir) {
(Ok(file), _) => file.metadata(), (Ok(file), _) => file.metadata(),
(_, Ok(_dir)) => Ok(Metadata { attributes: FS_ATTRIBUTE_DIRECTORY.bits, size: 0 }), (_, Ok(_dir)) => Ok(Metadata { attributes: FS_ATTRIBUTE_DIRECTORY.bits(), size: 0 }),
(Err(e), _) => Err(e), (Err(e), _) => Err(e),
} }
} }

182
ctru-rs/src/services/hid.rs

@ -1,76 +1,65 @@
use std::convert::Into; //! HID service
//!
//! The HID service provides access to user input such as button presses, touch screen presses,
//! and circle pad information. It also provides information from the sound volume slider,
//! the accelerometer, and the gyroscope.
pub enum PadKey {
A,
B,
Select,
Start,
DPadRight,
DPadLeft,
DPadUp,
DPadDown,
R,
L,
X,
Y,
ZL,
ZR,
Touch,
CSRight,
CSLeft,
CSUp,
CSDown,
CRight,
CLeft,
CUp,
CDown,
// convenience catch-all for dpad and cpad /// A set of flags corresponding to the button and directional pad
Up, /// inputs on the 3DS
Down, bitflags! {
Left, #[derive(Default)]
Right, pub struct KeyPad: u32 {
} const KEY_A = 1u32 << 0;
const KEY_B = 1u32 << 1;
impl From<PadKey> for u32 { const KEY_SELECT = 1u32 << 2;
fn from(p: PadKey) -> u32 { const KEY_START = 1u32 << 3;
use self::PadKey::*; const KEY_DRIGHT = 1u32 << 4;
use ::libctru::_bindgen_ty_18::*; const KEY_DLEFT = 1u32 << 5;
match p { const KEY_DUP = 1u32 << 6;
Up => KEY_DUP as u32 | KEY_CPAD_UP as u32, const KEY_DDOWN = 1u32 << 7;
Down => KEY_DDOWN as u32 | KEY_CPAD_DOWN as u32, const KEY_R = 1u32 << 8;
Left => KEY_DLEFT as u32 | KEY_CPAD_LEFT as u32, const KEY_L = 1u32 << 9;
Right => KEY_DRIGHT as u32 | KEY_CPAD_RIGHT as u32, const KEY_X = 1u32 << 10;
const KEY_Y = 1u32 << 11;
A => KEY_A as u32, const KEY_ZL = 1u32 << 14;
B => KEY_B as u32, const KEY_ZR = 1u32 << 15;
X => KEY_X as u32, const KEY_TOUCH = 1u32 << 20;
Y => KEY_Y as u32, const KEY_CSTICK_RIGHT = 1u32 << 24;
L => KEY_L as u32, const KEY_CSTICK_LEFT = 1u32 << 25;
R => KEY_R as u32, const KEY_CSTICK_UP = 1u32 << 26;
ZL => KEY_ZL as u32, const KEY_CSTICK_DOWN = 1u32 << 27;
ZR => KEY_ZR as u32, const KEY_CPAD_RIGHT = 1u32 << 28;
Start => KEY_START as u32, const KEY_CPAD_LEFT = 1u32 << 29;
Select => KEY_SELECT as u32, const KEY_CPAD_UP = 1u32 << 30;
Touch => KEY_TOUCH as u32, const KEY_CPAD_DOWN = 1u32 << 31;
CSRight => KEY_CSTICK_RIGHT as u32, // convenience catch-all for the dpad and cpad
CSLeft => KEY_CSTICK_LEFT as u32, const KEY_UP = KEY_DUP.bits | KEY_CPAD_UP.bits;
CSUp => KEY_CSTICK_UP as u32, const KEY_DOWN = KEY_DDOWN.bits | KEY_CPAD_DOWN.bits;
CSDown => KEY_CSTICK_DOWN as u32, const KEY_LEFT = KEY_DLEFT.bits | KEY_CPAD_LEFT.bits;
CRight => KEY_CPAD_RIGHT as u32, const KEY_RIGHT = KEY_DRIGHT.bits | KEY_CPAD_RIGHT.bits;
CLeft => KEY_CPAD_LEFT as u32,
CDown => KEY_CPAD_DOWN as u32,
CUp => KEY_CPAD_UP as u32,
DPadLeft => KEY_DLEFT as u32,
DPadRight => KEY_DRIGHT as u32,
DPadUp => KEY_DUP as u32,
DPadDown => KEY_DDOWN as u32,
}
} }
} }
/// A reference-counted handle to the HID service. The service is closed
/// when all instances of this struct fall out of scope.
///
/// This service requires no special permissions to use.
pub struct Hid(()); pub struct Hid(());
/// Represents user input to the touchscreen.
pub struct TouchPosition(::libctru::touchPosition);
/// Represents the current position of the 3DS circle pad.
pub struct CirclePosition(::libctru::circlePosition);
/// Initializes the HID service.
///
/// # Errors
///
/// This function will return an error if the service was unable to be initialized.
/// Since this service requires no special or elevated permissions, errors are
/// rare in practice.
impl Hid { impl Hid {
pub fn init() -> ::Result<Hid> { pub fn init() -> ::Result<Hid> {
unsafe { unsafe {
@ -83,42 +72,65 @@ impl Hid {
} }
} }
/// Scans the HID service for all user input occurring on the current
/// frame. This function should be called on every frame when polling
/// for user input.
pub fn scan_input(&self) { pub fn scan_input(&self) {
unsafe { ::libctru::hidScanInput() }; unsafe { ::libctru::hidScanInput() };
} }
pub fn key_down(&self, key: PadKey) -> bool { /// Returns a bitflag struct representing which buttons have just been pressed
let k: u32 = key.into(); /// on the current frame (and were not pressed on the previous frame).
pub fn keys_down(&self) -> KeyPad {
unsafe { unsafe {
if ::libctru::hidKeysDown() & k != 0 { let keys = ::libctru::hidKeysDown();
true KeyPad::from_bits_truncate(keys)
} else {
false
} }
} }
/// Returns a bitflag struct representing which buttons have been held down
/// during the current frame.
pub fn keys_held(&self) -> KeyPad {
unsafe {
let keys = ::libctru::hidKeysHeld();
KeyPad::from_bits_truncate(keys)
}
} }
pub fn key_held(&self, key: PadKey) -> bool { /// Returns a bitflag struct representing which buttons have just been released on
let k: u32 = key.into(); /// the current frame.
pub fn keys_up(&self) -> KeyPad {
unsafe { unsafe {
if ::libctru::hidKeysHeld() & k != 0 { let keys = ::libctru::hidKeysUp();
true KeyPad::from_bits_truncate(keys)
} else {
false
} }
} }
} }
pub fn key_up(&self, key: PadKey) -> bool { impl TouchPosition {
let k: u32 = key.into(); /// Create a new TouchPosition instance.
unsafe { pub fn new() -> Self {
if ::libctru::hidKeysUp() & k != 0 { TouchPosition(::libctru::touchPosition { px: 0, py: 0 })
return true;
} else {
return false;
} }
/// Returns the current touch position in pixels.
pub fn get(&mut self) -> (u16, u16) {
unsafe { ::libctru::hidTouchRead(&mut self.0); }
(self.0.px, self.0.py)
} }
} }
impl CirclePosition {
/// Create a new CirclePosition instance.
pub fn new() -> Self {
CirclePosition(::libctru::circlePosition { dx: 0, dy: 0 })
}
/// Returns the current circle pad position in (x, y) form.
pub fn get(&mut self) -> (i16, i16) {
unsafe { ::libctru::hidCircleRead(&mut self.0); }
(self.0.dx, self.0.dy)
}
} }
impl Drop for Hid { impl Drop for Hid {

75
examples/src/bin/buttons.rs

@ -0,0 +1,75 @@
extern crate ctru;
use ctru::gfx::Gfx;
use ctru::console::Console;
use ctru::services::apt::Apt;
use ctru::services::hid::{self, Hid, KeyPad};
fn main() {
// Setup services
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let mut gfx = Gfx::default();
let mut console = Console::default();
println!("Hi there! Try pressing a button");
println!("\x1b[29;16HPress Start to exit");
// This struct will contain the keys that we held on the previous frame
let mut old_keys = KeyPad::empty();
while apt.main_loop() {
// Scan for user input on the current frame.
hid.scan_input();
// Get information about which keys were held down on this frame
let keys = hid.keys_held();
// We only want to print when the keys we're holding now are different
// from what they were on the previous frame
if keys != old_keys {
// Clear the screen
console.clear();
// We print these again because we just cleared the screen above
println!("Hi there! Try pressing a button");
println!("\x1b[29;16HPress Start to exit");
// Move the cursor back to the top of the screen
println!("\x1b[3;0H");
// Print to the screen depending on which keys were held.
//
// The .contains() method checks for all of the provided keys,
// and the .intersects() method checks for any of the provided keys.
//
// You can also use the .bits() method to do direct comparisons on
// the underlying bits
if keys.contains(hid::KEY_A) {
println!("You held A!");
}
if keys.bits() & hid::KEY_B.bits() != 0 {
println!("You held B!");
}
if keys.contains(hid::KEY_X | hid::KEY_Y) {
println!("You held X and Y!");
}
if keys.intersects(hid::KEY_L | hid::KEY_R | hid::KEY_ZL | hid::KEY_ZR) {
println!("You held a shoulder button!");
}
if keys.intersects(hid::KEY_START) {
println!("See ya!");
break
}
}
// Save our current key presses for the next frame
old_keys = keys;
// Flush and swap framebuffers
gfx.flush_buffers();
gfx.swap_buffers();
}
}

4
examples/src/bin/hello-both-screens.rs

@ -3,7 +3,7 @@ extern crate ctru;
use ctru::gfx::{Gfx, Screen}; use ctru::gfx::{Gfx, Screen};
use ctru::console::Console; use ctru::console::Console;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, PadKey}; use ctru::services::hid::{self, Hid};
fn main() { fn main() {
// Initialize services // Initialize services
@ -35,7 +35,7 @@ fn main() {
gfx.swap_buffers(); gfx.swap_buffers();
hid.scan_input(); hid.scan_input();
if hid.key_down(PadKey::Start) { if hid.keys_down().contains(hid::KEY_START) {
break; break;
} }
} }

4
examples/src/bin/hello-world.rs

@ -3,7 +3,7 @@ extern crate ctru;
use ctru::gfx::Gfx; use ctru::gfx::Gfx;
use ctru::console::Console; use ctru::console::Console;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, PadKey}; use ctru::services::hid::{self, Hid};
fn main() { fn main() {
// Initialize ctrulib service handles. // Initialize ctrulib service handles.
@ -45,7 +45,7 @@ fn main() {
hid.scan_input(); hid.scan_input();
// Check if the user has pressed the given button on this frame. // Check if the user has pressed the given button on this frame.
// If so, break out of the loop. // If so, break out of the loop.
if hid.key_down(PadKey::Start) { if hid.keys_down().contains(hid::KEY_START) {
break; break;
} }
} }

Loading…
Cancel
Save