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

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

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

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

@ -1,76 +1,65 @@ @@ -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
Up,
Down,
Left,
Right,
}
impl From<PadKey> for u32 {
fn from(p: PadKey) -> u32 {
use self::PadKey::*;
use ::libctru::_bindgen_ty_18::*;
match p {
Up => KEY_DUP as u32 | KEY_CPAD_UP as u32,
Down => KEY_DDOWN as u32 | KEY_CPAD_DOWN as u32,
Left => KEY_DLEFT as u32 | KEY_CPAD_LEFT as u32,
Right => KEY_DRIGHT as u32 | KEY_CPAD_RIGHT as u32,
A => KEY_A as u32,
B => KEY_B as u32,
X => KEY_X as u32,
Y => KEY_Y as u32,
L => KEY_L as u32,
R => KEY_R as u32,
ZL => KEY_ZL as u32,
ZR => KEY_ZR as u32,
Start => KEY_START as u32,
Select => KEY_SELECT as u32,
Touch => KEY_TOUCH as u32,
CSRight => KEY_CSTICK_RIGHT as u32,
CSLeft => KEY_CSTICK_LEFT as u32,
CSUp => KEY_CSTICK_UP as u32,
CSDown => KEY_CSTICK_DOWN as u32,
CRight => KEY_CPAD_RIGHT as u32,
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 set of flags corresponding to the button and directional pad
/// inputs on the 3DS
bitflags! {
#[derive(Default)]
pub struct KeyPad: u32 {
const KEY_A = 1u32 << 0;
const KEY_B = 1u32 << 1;
const KEY_SELECT = 1u32 << 2;
const KEY_START = 1u32 << 3;
const KEY_DRIGHT = 1u32 << 4;
const KEY_DLEFT = 1u32 << 5;
const KEY_DUP = 1u32 << 6;
const KEY_DDOWN = 1u32 << 7;
const KEY_R = 1u32 << 8;
const KEY_L = 1u32 << 9;
const KEY_X = 1u32 << 10;
const KEY_Y = 1u32 << 11;
const KEY_ZL = 1u32 << 14;
const KEY_ZR = 1u32 << 15;
const KEY_TOUCH = 1u32 << 20;
const KEY_CSTICK_RIGHT = 1u32 << 24;
const KEY_CSTICK_LEFT = 1u32 << 25;
const KEY_CSTICK_UP = 1u32 << 26;
const KEY_CSTICK_DOWN = 1u32 << 27;
const KEY_CPAD_RIGHT = 1u32 << 28;
const KEY_CPAD_LEFT = 1u32 << 29;
const KEY_CPAD_UP = 1u32 << 30;
const KEY_CPAD_DOWN = 1u32 << 31;
// convenience catch-all for the dpad and cpad
const KEY_UP = KEY_DUP.bits | KEY_CPAD_UP.bits;
const KEY_DOWN = KEY_DDOWN.bits | KEY_CPAD_DOWN.bits;
const KEY_LEFT = KEY_DLEFT.bits | KEY_CPAD_LEFT.bits;
const KEY_RIGHT = KEY_DRIGHT.bits | KEY_CPAD_RIGHT.bits;
}
}
/// 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(());
/// 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 {
pub fn init() -> ::Result<Hid> {
unsafe {
@ -83,41 +72,64 @@ impl Hid { @@ -83,41 +72,64 @@ 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) {
unsafe { ::libctru::hidScanInput() };
}
pub fn key_down(&self, key: PadKey) -> bool {
let k: u32 = key.into();
/// Returns a bitflag struct representing which buttons have just been pressed
/// on the current frame (and were not pressed on the previous frame).
pub fn keys_down(&self) -> KeyPad {
unsafe {
if ::libctru::hidKeysDown() & k != 0 {
true
} else {
false
let keys = ::libctru::hidKeysDown();
KeyPad::from_bits_truncate(keys)
}
}
/// 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 {
let k: u32 = key.into();
/// Returns a bitflag struct representing which buttons have just been released on
/// the current frame.
pub fn keys_up(&self) -> KeyPad {
unsafe {
if ::libctru::hidKeysHeld() & k != 0 {
true
} else {
false
let keys = ::libctru::hidKeysUp();
KeyPad::from_bits_truncate(keys)
}
}
}
impl TouchPosition {
/// Create a new TouchPosition instance.
pub fn new() -> Self {
TouchPosition(::libctru::touchPosition { px: 0, py: 0 })
}
pub fn key_up(&self, key: PadKey) -> bool {
let k: u32 = key.into();
unsafe {
if ::libctru::hidKeysUp() & k != 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)
}
}

75
examples/src/bin/buttons.rs

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

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

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

Loading…
Cancel
Save