@@ -17,7 +17,7 @@ use std::fmt::Display;
1717use std:: iter:: once;
1818use std:: str;
1919
20- type CallbackFunction = dyn Fn ( & str ) -> ( CallbackResult , Option < Cow < ' static , str > > ) ;
20+ type CallbackFunction = dyn FnMut ( & str ) -> CallbackResult ;
2121
2222/// Configuration structure to setup the Software Keyboard applet.
2323#[ doc( alias = "SwkbdState" ) ]
@@ -59,15 +59,24 @@ pub enum Kind {
5959///
6060/// The custom callback can be set using [`SoftwareKeyboard::set_filter_callback()`].
6161#[ doc( alias = "SwkbdCallbackResult" ) ]
62- #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
62+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
6363#[ repr( u8 ) ]
6464pub enum CallbackResult {
6565 /// The callback yields a positive result.
6666 Ok = ctru_sys:: SWKBD_CALLBACK_OK ,
6767 /// The callback finds the input invalid, but lets the user try again.
68- Retry = ctru_sys:: SWKBD_CALLBACK_CONTINUE ,
68+ Retry ( Cow < ' static , str > ) = ctru_sys:: SWKBD_CALLBACK_CONTINUE ,
6969 /// The callback finds the input invalid and closes the Software Keyboard view.
70- Close = ctru_sys:: SWKBD_CALLBACK_CLOSE ,
70+ Close ( Cow < ' static , str > ) = ctru_sys:: SWKBD_CALLBACK_CLOSE ,
71+ }
72+
73+ impl CallbackResult {
74+ fn discriminant ( & self ) -> u8 {
75+ // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)` `union`
76+ // between `repr(C)` structs, each of which has the `u8` discriminant as its first
77+ // field, so we can read the discriminant without offsetting the pointer.
78+ unsafe { * ( self as * const Self ) . cast ( ) }
79+ }
7180}
7281
7382/// Represents which button the user pressed to close the [`SoftwareKeyboard`].
@@ -210,9 +219,8 @@ bitflags! {
210219}
211220
212221// Internal book-keeping struct used to send data to `aptSetMessageCallback` when calling the software keyboard.
213- #[ derive( Copy , Clone ) ]
214222struct MessageCallbackData {
215- filter_callback : * const Box < CallbackFunction > ,
223+ filter_callback : * mut Box < CallbackFunction > ,
216224 swkbd_shared_mem_ptr : * mut libc:: c_void ,
217225}
218226
@@ -347,12 +355,12 @@ impl SoftwareKeyboard {
347355 ///
348356 /// let mut keyboard = SoftwareKeyboard::default();
349357 ///
350- /// keyboard.set_filter_callback(Some(Box::new(move |str| {
351- /// if str.contains("boo") {
352- /// return (CallbackResult::Retry, Some("Ah, you scared me!".into()));
358+ /// keyboard.set_filter_callback(Some(Box::new(move |input| {
359+ /// if input.contains("boo") {
360+ /// CallbackResult::Retry("Aaaah, you scared me!".into())
361+ /// } else {
362+ /// CallbackResult::Ok
353363 /// }
354- ///
355- /// (CallbackResult::Ok, None)
356364 /// })));
357365 /// #
358366 /// # }
@@ -733,7 +741,7 @@ impl SoftwareKeyboard {
733741 // `self` is allowed to be moved again, we can safely use a pointer to the local value contained in `self.filter_callback`
734742 // The cast here is also sound since the pointer will only be read from if `self.filter_callback.is_some()` returns true.
735743 let mut data = MessageCallbackData {
736- filter_callback : ( & raw const self . filter_callback ) . cast ( ) ,
744+ filter_callback : ( & raw mut self . filter_callback ) . cast ( ) ,
737745 swkbd_shared_mem_ptr,
738746 } ;
739747
@@ -813,7 +821,8 @@ impl SoftwareKeyboard {
813821 }
814822
815823 let swkbd = unsafe { & mut * msg. cast :: < SwkbdState > ( ) } ;
816- let data = unsafe { * user. cast :: < MessageCallbackData > ( ) } ;
824+
825+ let data = unsafe { & * user. cast :: < MessageCallbackData > ( ) } ;
817826
818827 let text16 = unsafe {
819828 widestring:: Utf16Str :: from_slice_unchecked ( std:: slice:: from_raw_parts (
@@ -824,13 +833,11 @@ impl SoftwareKeyboard {
824833
825834 let text8 = text16. to_string ( ) ;
826835
827- let filter_callback = unsafe { & * * data. filter_callback } ;
828-
829- let ( result, retmsg) = filter_callback ( & text8) ;
836+ let result = unsafe { & mut * * data. filter_callback } ( & text8) ;
830837
831- swkbd. callback_result = result as _ ;
838+ swkbd. callback_result = result. discriminant ( ) . into ( ) ;
832839
833- if let Some ( msg) = retmsg . as_deref ( ) {
840+ if let CallbackResult :: Retry ( msg) | CallbackResult :: Close ( msg ) = result {
834841 for ( idx, code_unit) in msg
835842 . encode_utf16 ( )
836843 . take ( swkbd. callback_msg . len ( ) - 1 )
@@ -989,4 +996,3 @@ from_impl!(ValidInput, i32);
989996from_impl ! ( ValidInput , u32 ) ;
990997from_impl ! ( ButtonConfig , i32 ) ;
991998from_impl ! ( PasswordMode , u32 ) ;
992- from_impl ! ( CallbackResult , u32 ) ;
0 commit comments