diff --git a/nx/include/switch/applets/swkbd.h b/nx/include/switch/applets/swkbd.h index b42ac109..23861949 100644 --- a/nx/include/switch/applets/swkbd.h +++ b/nx/include/switch/applets/swkbd.h @@ -184,6 +184,47 @@ typedef struct { u8 pad_x49d[3]; } PACKED SwkbdInlineCalcArg; +/// Struct data for SwkbdInline Interactive reply storage ChangedString*, at the end following the string. +typedef struct { + u32 stringLen; ///< String length in characters, without NUL-terminator. + s32 unk_x4; + s32 unk_x8; + s32 cursorPos; ///< Cursor position. +} SwkbdChangedStringArg; + +/// Struct data for SwkbdInline Interactive reply storage MovedCursor*, at the end following the string. +typedef struct { + u32 stringLen; ///< String length in characters, without NUL-terminator. + s32 cursorPos; ///< Cursor position. +} SwkbdMovedCursorArg; + +/// Struct data for SwkbdInline Interactive reply storage MovedTab*, at the end following the string. +typedef struct { + u32 unk_x0; + u32 unk_x4; +} SwkbdMovedTabArg; + +/// Struct data for SwkbdInline Interactive reply storage DecidedEnter*, at the end following the string. +typedef struct { + u32 stringLen; ///< String length in characters, without NUL-terminator. +} SwkbdDecidedEnterArg; + +/// This callback is used by \ref swkbdInlineUpdate when handling ChangedString* replies (text changed by the user or by \ref swkbdInlineSetInputText). +/// str is the UTF-8 string for the current text. +typedef void (*SwkbdChangedStringCb)(const char* str, SwkbdChangedStringArg* arg); + +/// This callback is used by \ref swkbdInlineUpdate when handling MovedCursor* replies. +/// str is the UTF-8 string for the current text. +typedef void (*SwkbdMovedCursorCb)(const char* str, SwkbdMovedCursorArg* arg); + +/// This callback is used by \ref swkbdInlineUpdate when handling MovedTab* replies. +/// str is the UTF-8 string for the current text. +typedef void (*SwkbdMovedTabCb)(const char* str, SwkbdMovedTabArg* arg); + +/// This callback is used by \ref swkbdInlineUpdate when handling DecidedEnter* replies (when the final text was submitted via the button). +/// str is the UTF-8 string for the current text. +typedef void (*SwkbdDecidedEnterCb)(const char* str, SwkbdDecidedEnterArg* arg); + /// InlineKeyboard typedef struct { u32 version; @@ -195,6 +236,13 @@ typedef struct { size_t interactive_tmpbuf_size; char* interactive_strbuf; size_t interactive_strbuf_size; + + VoidFn finishedInitializeCb; + SwkbdChangedStringCb changedStringCb; + SwkbdMovedCursorCb movedCursorCb; + SwkbdMovedTabCb movedTabCb; + SwkbdDecidedEnterCb decidedEnterCb; + VoidFn releasedUserWordInfoCb; } SwkbdInline; /** @@ -321,6 +369,7 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size); /** * @brief Creates a SwkbdInline object. * @note This is essentially an asynchronous version of the regular swkbd. + * @note This calls \ref swkbdInlineSetUtf8Mode internally with flag=true. * @param s SwkbdInline object. */ Result swkbdInlineCreate(SwkbdInline* s); @@ -345,6 +394,48 @@ Result swkbdInlineLaunch(SwkbdInline* s); */ Result swkbdInlineUpdate(SwkbdInline* s); +/** + * @brief Sets the FinishedInitialize callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb Callback + */ +void swkbdInlineSetFinishedInitializeCallback(SwkbdInline* s, VoidFn cb); + +/** + * @brief Sets the ChangedString callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb \ref SwkbdChangedStringCb Callback + */ +void swkbdInlineSetChangedStringCallback(SwkbdInline* s, SwkbdChangedStringCb cb); + +/** + * @brief Sets the MovedCursor callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb \ref SwkbdMovedCursorCb Callback + */ +void swkbdInlineSetMovedCursorCallback(SwkbdInline* s, SwkbdMovedCursorCb cb); + +/** + * @brief Sets the MovedTab callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb \ref SwkbdMovedTabCb Callback + */ +void swkbdInlineSetMovedTabCallback(SwkbdInline* s, SwkbdMovedTabCb cb); + +/** + * @brief Sets the DecidedEnter callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb \ref SwkbdDecidedEnterCb Callback + */ +void swkbdInlineSetDecidedEnterCallback(SwkbdInline* s, SwkbdDecidedEnterCb cb); + +/** + * @brief Sets the ReleasedUserWordInfo callback, used by \ref swkbdInlineUpdate. The default is NULL for none. + * @param s SwkbdInline object. + * @param cb Callback + */ +void swkbdInlineSetReleasedUserWordInfoCallback(SwkbdInline* s, VoidFn cb); + /** * @brief Appear the kbd and set \ref SwkbdAppearArg. * @note \ref swkbdInlineUpdate must be called at some point afterwards for this to take affect. @@ -397,6 +488,7 @@ void swkbdInlineSetCursorPos(SwkbdInline* s, s32 pos); /** * @brief Sets the utf8Mode. * @note \ref swkbdInlineUpdate must be called at some point afterwards for this to take affect. + * @note Automatically used internally by \ref swkbdInlineCreate. * @param s SwkbdInline object. * @param flag Flag */ diff --git a/nx/source/applets/swkbd.c b/nx/source/applets/swkbd.c index 37de569f..abe54f48 100644 --- a/nx/source/applets/swkbd.c +++ b/nx/source/applets/swkbd.c @@ -372,6 +372,8 @@ Result swkbdInlineCreate(SwkbdInline* s) { s->calcArg.balloonScale = 1.0f; s->calcArg.unk_x48c = 1.0f; + swkbdInlineSetUtf8Mode(s, true); + s->interactive_tmpbuf_size = 0x1000; s->interactive_tmpbuf = (u8*)malloc(s->interactive_tmpbuf_size); if (s->interactive_tmpbuf==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); @@ -446,11 +448,63 @@ Result swkbdInlineLaunch(SwkbdInline* s) { } static void _swkbdProcessReply(SwkbdInline* s, u32 State, SwkbdReplyType ReplyType, size_t size) { + size_t stringendoff_utf8 = 0x7D4; + size_t stringendoff_utf16 = 0x3EC; + void* argdataend_utf8 = &s->interactive_tmpbuf[stringendoff_utf8]; + void* argdataend_utf16 = &s->interactive_tmpbuf[stringendoff_utf16]; + char* strdata = (char*)s->interactive_tmpbuf; + + memset(s->interactive_strbuf, 0, s->interactive_strbuf_size); + + if ((ReplyType==SwkbdReplyType_ChangedString && size != 0x3FC) || (ReplyType==SwkbdReplyType_ChangedStringUtf8 && size != 0x7E4)) return; + if ((ReplyType==SwkbdReplyType_MovedCursor && size != 0x3F4) || (ReplyType==SwkbdReplyType_MovedCursorUtf8 && size != 0x7DC)) return; + if ((ReplyType==SwkbdReplyType_DecidedEnter && size != 0x3F0) || (ReplyType==SwkbdReplyType_DecidedEnterUtf8 && size != 0x7D8)) return; + if (ReplyType==SwkbdReplyType_MovedTab && size != 0x3F4) return; + + if (ReplyType==SwkbdReplyType_ChangedString || ReplyType==SwkbdReplyType_MovedCursor || ReplyType==SwkbdReplyType_MovedTab || ReplyType==SwkbdReplyType_DecidedEnter) { + _swkbdConvertToUTF8(s->interactive_strbuf, (u16*)strdata, s->interactive_strbuf_size-1); + strdata = s->interactive_strbuf; + } + switch(ReplyType) { - default: + case SwkbdReplyType_FinishedInitialize: + if (s->finishedInitializeCb) s->finishedInitializeCb(); break; - //TODO: Process storage content. + case SwkbdReplyType_ChangedString: + case SwkbdReplyType_ChangedStringUtf8: + if (s->changedStringCb) { + if (ReplyType==SwkbdReplyType_ChangedString) s->changedStringCb(strdata, (SwkbdChangedStringArg*)argdataend_utf16); + if (ReplyType==SwkbdReplyType_ChangedStringUtf8) s->changedStringCb(strdata, (SwkbdChangedStringArg*)argdataend_utf8); + } + break; + + case SwkbdReplyType_MovedCursor: + case SwkbdReplyType_MovedCursorUtf8: + if (s->movedCursorCb) { + if (ReplyType==SwkbdReplyType_MovedCursor) s->movedCursorCb(strdata, (SwkbdMovedCursorArg*)argdataend_utf16); + if (ReplyType==SwkbdReplyType_MovedCursorUtf8) s->movedCursorCb(strdata, (SwkbdMovedCursorArg*)argdataend_utf8); + } + break; + + case SwkbdReplyType_MovedTab: + if (s->movedTabCb) s->movedTabCb(strdata, (SwkbdMovedTabArg*)argdataend_utf16); + break; + + case SwkbdReplyType_DecidedEnter: + case SwkbdReplyType_DecidedEnterUtf8: + if (s->decidedEnterCb) { + if (ReplyType==SwkbdReplyType_DecidedEnter) s->decidedEnterCb(strdata, (SwkbdDecidedEnterArg*)argdataend_utf16); + if (ReplyType==SwkbdReplyType_DecidedEnterUtf8) s->decidedEnterCb(strdata, (SwkbdDecidedEnterArg*)argdataend_utf8); + } + break; + + case SwkbdReplyType_ReleasedUserWordInfo: + if (s->releasedUserWordInfoCb) s->releasedUserWordInfoCb(); + break; + + default: + break; } } @@ -503,6 +557,30 @@ Result swkbdInlineUpdate(SwkbdInline* s) { return rc; } +void swkbdInlineSetFinishedInitializeCallback(SwkbdInline* s, VoidFn cb) { + s->finishedInitializeCb = cb; +} + +void swkbdInlineSetChangedStringCallback(SwkbdInline* s, SwkbdChangedStringCb cb) { + s->changedStringCb = cb; +} + +void swkbdInlineSetMovedCursorCallback(SwkbdInline* s, SwkbdMovedCursorCb cb) { + s->movedCursorCb = cb; +} + +void swkbdInlineSetMovedTabCallback(SwkbdInline* s, SwkbdMovedTabCb cb) { + s->movedTabCb = cb; +} + +void swkbdInlineSetDecidedEnterCallback(SwkbdInline* s, SwkbdDecidedEnterCb cb) { + s->decidedEnterCb = cb; +} + +void swkbdInlineSetReleasedUserWordInfoCallback(SwkbdInline* s, VoidFn cb) { + s->releasedUserWordInfoCb = cb; +} + static void _swkbdInlineUpdateAppearFlags(SwkbdInline* s) { u32 mask = 0x10000000; u32 tmp = s->calcArg.appearArg.flags;