Browse Source

SWKBD method additions and doc tests

pull/149/head
Andrea Ciliberti 1 year ago
parent
commit
95faa5f2a7
  1. 5
      ctru-rs/examples/software-keyboard.rs
  2. 6
      ctru-rs/src/applets/mii_selector.rs
  3. 116
      ctru-rs/src/applets/swkbd.rs

5
ctru-rs/examples/software-keyboard.rs

@ -14,10 +14,7 @@ fn main() {
// Prepares a software keyboard with two buttons: one to cancel input and one // Prepares a software keyboard with two buttons: one to cancel input and one
// to accept it. You can also use `SoftwareKeyboard::new()` to launch the keyboard // to accept it. You can also use `SoftwareKeyboard::new()` to launch the keyboard
// with different configurations. // with different configurations.
let mut keyboard = SoftwareKeyboard::new( let mut keyboard = SoftwareKeyboard::default();
ctru::applets::swkbd::Kind::Normal,
ctru::applets::swkbd::ButtonConfig::LeftMiddleRight,
);
println!("Press A to enter some text or press Start to exit."); println!("Press A to enter some text or press Start to exit.");

6
ctru-rs/src/applets/mii_selector.rs

@ -262,6 +262,10 @@ impl MiiSelector {
/// ```no_run /// ```no_run
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # use ctru::services::{apt::Apt, gfx::Gfx};
/// #
/// # let gfx = Gfx::new().unwrap();
/// # let apt = Apt::new().unwrap();
/// # /// #
/// use ctru::applets::mii_selector::{MiiSelector, Options}; /// use ctru::applets::mii_selector::{MiiSelector, Options};
/// ///
@ -271,7 +275,7 @@ impl MiiSelector {
/// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS;
/// mii_selector.set_options(opts); /// mii_selector.set_options(opts);
/// ///
/// let result = mii_selector.launch()?; /// let result = mii_selector.launch(&apt, &gfx)?;
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }

116
ctru-rs/src/applets/swkbd.rs

@ -1,14 +1,11 @@
//! Software Keyboard applet. //! Software Keyboard applet.
//! //!
//! This applet opens a virtual keyboard on the console's bottom screen which lets the user write UTF-16 valid text. //! This applet opens a virtual keyboard on the console's bottom screen which lets the user write UTF-16 valid text.
// TODO: Implement remaining functionality (password mode, filter callbacks, etc.). Also improve "max text length" API. // TODO: Implement remaining functionality (filter callbacks, etc.). Also improve "max text length" API.
#![doc(alias = "keyboard")] #![doc(alias = "keyboard")]
use crate::services::{apt::Apt, gfx::Gfx}; use crate::services::{apt::Apt, gfx::Gfx};
use ctru_sys::{ use ctru_sys::{self, SwkbdState};
self, swkbdInit, swkbdInputText, swkbdSetButton, swkbdSetFeatures, swkbdSetHintText,
swkbdSetInitialText, SwkbdState,
};
use bitflags::bitflags; use bitflags::bitflags;
use libc; use libc;
@ -66,6 +63,21 @@ pub enum Button {
Right = ctru_sys::SWKBD_BUTTON_RIGHT, Right = ctru_sys::SWKBD_BUTTON_RIGHT,
} }
/// Represents the password mode to conceal the input text for the [`SoftwareKeyboard`].
///
/// Can be set using [`SoftwareKeyboard::set_password_mode()`].
#[doc(alias = "SwkbdPasswordMode")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum PasswordMode {
/// The input text will not be concealed.
None = ctru_sys::SWKBD_PASSWORD_NONE,
/// The input text will be concealed immediately after typing.
Hide = ctru_sys::SWKBD_PASSWORD_HIDE,
/// The input text will be concealed a second after typing.
HideDelay = ctru_sys::SWKBD_PASSWORD_HIDE_DELAY,
}
/// Configuration to setup the on-screen buttons to exit the [`SoftwareKeyboard`] prompt. /// Configuration to setup the on-screen buttons to exit the [`SoftwareKeyboard`] prompt.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(i32)] #[repr(i32)]
@ -201,7 +213,7 @@ impl SoftwareKeyboard {
pub fn new(keyboard_type: Kind, buttons: ButtonConfig) -> Self { pub fn new(keyboard_type: Kind, buttons: ButtonConfig) -> Self {
unsafe { unsafe {
let mut state = Box::<SwkbdState>::default(); let mut state = Box::<SwkbdState>::default();
swkbdInit(state.as_mut(), keyboard_type.into(), buttons.into(), -1); ctru_sys::swkbdInit(state.as_mut(), keyboard_type.into(), buttons.into(), -1);
Self { state } Self { state }
} }
} }
@ -219,11 +231,15 @@ impl SoftwareKeyboard {
/// # let _runner = test_runner::GdbRunner::default(); /// # let _runner = test_runner::GdbRunner::default();
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # use ctru::services::{apt::Apt, gfx::Gfx};
/// #
/// # let gfx = Gfx::new().unwrap();
/// # let apt = Apt::new().unwrap();
/// # /// #
/// use ctru::applets::swkbd::SoftwareKeyboard; /// use ctru::applets::swkbd::SoftwareKeyboard;
/// let mut keyboard = SoftwareKeyboard::default(); /// let mut keyboard = SoftwareKeyboard::default();
/// ///
/// let (text, button) = keyboard.get_string(2048)?; /// let (text, button) = keyboard.get_string(2048, &apt, &gfx)?;
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -267,13 +283,17 @@ impl SoftwareKeyboard {
/// # let _runner = test_runner::GdbRunner::default(); /// # let _runner = test_runner::GdbRunner::default();
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # use ctru::services::{apt::Apt, gfx::Gfx};
/// #
/// # let gfx = Gfx::new().unwrap();
/// # let apt = Apt::new().unwrap();
/// # /// #
/// use ctru::applets::swkbd::SoftwareKeyboard; /// use ctru::applets::swkbd::SoftwareKeyboard;
/// let mut keyboard = SoftwareKeyboard::default(); /// let mut keyboard = SoftwareKeyboard::default();
/// ///
/// let mut buffer = vec![0; 100]; /// let mut buffer = vec![0; 100];
/// ///
/// let button = keyboard.write_exact(&mut buffer)?; /// let button = keyboard.write_exact(&mut buffer, &apt, &gfx)?;
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -282,7 +302,7 @@ impl SoftwareKeyboard {
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn write_exact(&mut self, buf: &mut [u8], apt: &Apt, gfx: &Gfx) -> Result<Button, Error> { pub fn write_exact(&mut self, buf: &mut [u8], apt: &Apt, gfx: &Gfx) -> Result<Button, Error> {
unsafe { unsafe {
match swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), buf.len()) { match ctru_sys::swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), buf.len()) {
ctru_sys::SWKBD_BUTTON_NONE => Err(self.state.result.into()), ctru_sys::SWKBD_BUTTON_NONE => Err(self.state.result.into()),
ctru_sys::SWKBD_BUTTON_LEFT => Ok(Button::Left), ctru_sys::SWKBD_BUTTON_LEFT => Ok(Button::Left),
ctru_sys::SWKBD_BUTTON_MIDDLE => Ok(Button::Middle), ctru_sys::SWKBD_BUTTON_MIDDLE => Ok(Button::Middle),
@ -310,7 +330,7 @@ impl SoftwareKeyboard {
/// # } /// # }
#[doc(alias = "swkbdSetFeatures")] #[doc(alias = "swkbdSetFeatures")]
pub fn set_features(&mut self, features: Features) { pub fn set_features(&mut self, features: Features) {
unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits()) } unsafe { ctru_sys::swkbdSetFeatures(self.state.as_mut(), features.bits()) }
} }
/// Configure input validation for this keyboard. /// Configure input validation for this keyboard.
@ -383,7 +403,7 @@ impl SoftwareKeyboard {
pub fn set_initial_text(&mut self, text: &str) { pub fn set_initial_text(&mut self, text: &str) {
unsafe { unsafe {
let nul_terminated: String = text.chars().chain(once('\0')).collect(); let nul_terminated: String = text.chars().chain(once('\0')).collect();
swkbdSetInitialText(self.state.as_mut(), nul_terminated.as_ptr()); ctru_sys::swkbdSetInitialText(self.state.as_mut(), nul_terminated.as_ptr());
} }
} }
@ -407,7 +427,57 @@ impl SoftwareKeyboard {
pub fn set_hint_text(&mut self, text: &str) { pub fn set_hint_text(&mut self, text: &str) {
unsafe { unsafe {
let nul_terminated: String = text.chars().chain(once('\0')).collect(); let nul_terminated: String = text.chars().chain(once('\0')).collect();
swkbdSetHintText(self.state.as_mut(), nul_terminated.as_ptr()); ctru_sys::swkbdSetHintText(self.state.as_mut(), nul_terminated.as_ptr());
}
}
/// Set a password mode for this software keyboard.
///
/// Depending on the selected mode the input text will be concealed.
///
/// # Example
///
/// ```
/// # let _runner = test_runner::GdbRunner::default();
/// # fn main() {
/// #
/// use ctru::applets::swkbd::{SoftwareKeyboard, PasswordMode};
/// let mut keyboard = SoftwareKeyboard::default();
///
/// keyboard.set_password_mode(PasswordMode::Hide);
/// #
/// # }
#[doc(alias = "swkbdSetPasswordMode")]
pub fn set_password_mode(&mut self, mode: PasswordMode) {
unsafe {
ctru_sys::swkbdSetPasswordMode(self.state.as_mut(), mode.into());
}
}
/// Set the 2 custom characters to add to the keyboard while using [`Kind::Numpad`].
///
/// These characters will appear in their own buttons right next to the `0` key.
///
/// # Notes
///
/// You can set one or both of these keys to `NUL` (value 0) to avoid showing the additional buttons to the user.
///
/// # Example
///
/// ```
/// # let _runner = test_runner::GdbRunner::default();
/// # fn main() {
/// #
/// use ctru::applets::swkbd::{SoftwareKeyboard, Kind, ButtonConfig};
/// let mut keyboard = SoftwareKeyboard::new(Kind::Numpad, ButtonConfig::LeftRight);
///
/// keyboard.set_numpad_keys(('#', '.'));
/// #
/// # }
#[doc(alias = "swkbdSetNumpadKeys")]
pub fn set_numpad_keys(&mut self, keys: (char, char)) {
unsafe {
ctru_sys::swkbdSetNumpadKeys(self.state.as_mut(), keys.0 as i32, keys.1 as i32);
} }
} }
@ -441,7 +511,7 @@ impl SoftwareKeyboard {
pub fn configure_button(&mut self, button: Button, text: &str, submit: bool) { pub fn configure_button(&mut self, button: Button, text: &str, submit: bool) {
unsafe { unsafe {
let nul_terminated: String = text.chars().chain(once('\0')).collect(); let nul_terminated: String = text.chars().chain(once('\0')).collect();
swkbdSetButton( ctru_sys::swkbdSetButton(
self.state.as_mut(), self.state.as_mut(),
button.into(), button.into(),
nul_terminated.as_ptr(), nul_terminated.as_ptr(),
@ -455,6 +525,8 @@ impl SoftwareKeyboard {
/// ///
/// # Notes /// # Notes
/// ///
/// This action will overwrite any previously submitted [`ValidInput`] validation.
///
/// Keyboard input is converted from UTF-16 to UTF-8 before being handed to Rust, /// Keyboard input is converted from UTF-16 to UTF-8 before being handed to Rust,
/// so this code point limit does not necessarily equal the max number of UTF-8 code points /// so this code point limit does not necessarily equal the max number of UTF-8 code points
/// receivable by [`SoftwareKeyboard::get_string()`] and [`SoftwareKeyboard::write_exact()`]. /// receivable by [`SoftwareKeyboard::get_string()`] and [`SoftwareKeyboard::write_exact()`].
@ -474,6 +546,9 @@ impl SoftwareKeyboard {
/// # } /// # }
pub fn set_max_text_len(&mut self, len: u16) { pub fn set_max_text_len(&mut self, len: u16) {
self.state.max_text_len = len; self.state.max_text_len = len;
// Activate the specific validation rule for maximum length.
self.state.valid_input = ValidInput::FixedLen.into();
} }
} }
@ -495,8 +570,8 @@ impl ParentalLock {
pub fn new() -> Self { pub fn new() -> Self {
unsafe { unsafe {
let mut state = Box::<SwkbdState>::default(); let mut state = Box::<SwkbdState>::default();
swkbdInit(state.as_mut(), Kind::Normal.into(), 1, -1); ctru_sys::swkbdInit(state.as_mut(), Kind::Normal.into(), 1, -1);
swkbdSetFeatures(state.as_mut(), ctru_sys::SWKBD_PARENTAL); ctru_sys::swkbdSetFeatures(state.as_mut(), ctru_sys::SWKBD_PARENTAL);
Self { state } Self { state }
} }
} }
@ -508,12 +583,15 @@ impl ParentalLock {
/// ``` /// ```
/// # let _runner = test_runner::GdbRunner::default(); /// # let _runner = test_runner::GdbRunner::default();
/// # fn main() { /// # fn main() {
/// # use ctru::services::{apt::Apt, gfx::Gfx};
/// # /// #
/// use ctru::applets::swkbd::ParentalLock; /// # let gfx = Gfx::new().unwrap();
/// # let apt = Apt::new().unwrap();
/// use ctru::applets::swkbd::{ParentalLock, Error};
/// ///
/// let parental_lock = ParentalLock::new(); /// let parental_lock = ParentalLock::new();
/// ///
/// match parental_lock.launch() { /// match parental_lock.launch(&apt, &gfx) {
/// Ok(_) => println!("You can access parental-only features and settings."), /// Ok(_) => println!("You can access parental-only features and settings."),
/// Err(Error::ParentalFail) => println!("Is a kid trying to access this?"), /// Err(Error::ParentalFail) => println!("Is a kid trying to access this?"),
/// Err(_) => println!("Something wrong happened during the parental lock prompt.") /// Err(_) => println!("Something wrong happened during the parental lock prompt.")
@ -525,7 +603,7 @@ impl ParentalLock {
pub fn launch(&mut self, apt: &Apt, gfx: &Gfx) -> Result<(), Error> { pub fn launch(&mut self, apt: &Apt, gfx: &Gfx) -> Result<(), Error> {
unsafe { unsafe {
let mut buf = [0; 10]; let mut buf = [0; 10];
swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), 10); ctru_sys::swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), 10);
let e = self.state.result.into(); let e = self.state.result.into();
match e { match e {
@ -601,4 +679,6 @@ from_impl!(Kind, ctru_sys::SwkbdType);
from_impl!(Button, ctru_sys::SwkbdButton); from_impl!(Button, ctru_sys::SwkbdButton);
from_impl!(Error, ctru_sys::SwkbdResult); from_impl!(Error, ctru_sys::SwkbdResult);
from_impl!(ValidInput, i32); from_impl!(ValidInput, i32);
from_impl!(ValidInput, u32);
from_impl!(ButtonConfig, i32); from_impl!(ButtonConfig, i32);
from_impl!(PasswordMode, u32);

Loading…
Cancel
Save