Added support for [8.0.0+] swkbd functionality: swkbdConfigSetUnkFlag, swkbdConfigSetTrigger, swkbdInlineSetChangedStringV2Callback, and swkbdInlineSetMovedCursorV2Callback. Added swkbdInlineLaunchForLibraryApplet and swkbdInlineSetDecidedCancelCallback. Moved initArg setup into swkbdInlineLaunch*.

This commit is contained in:
yellows8 2019-06-04 19:13:36 -04:00
parent 133ffe92fd
commit 9947048f8b
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
2 changed files with 171 additions and 10 deletions

View File

@ -50,6 +50,8 @@ typedef enum {
SwkbdRequestCommand_Calc = 0xA,
SwkbdRequestCommand_SetCustomizedDictionaries = 0xB,
SwkbdRequestCommand_UnsetCustomizedDictionaries = 0xC,
SwkbdRequestCommand_SetChangedStringV2Flag = 0xD,
SwkbdRequestCommand_SetMovedCursorV2Flag = 0xE,
} SwkbdRequestCommand;
/// SwkbdInline Interactive output storage reply ID.
@ -66,6 +68,10 @@ typedef enum {
SwkbdReplyType_UnsetCustomizeDic = 0xA,
SwkbdReplyType_ReleasedUserWordInfo = 0xB,
SwkbdReplyType_UnsetCustomizedDictionaries = 0xC,
SwkbdReplyType_ChangedStringV2 = 0xD,
SwkbdReplyType_MovedCursorV2 = 0xE,
SwkbdReplyType_ChangedStringUtf8V2 = 0xF,
SwkbdReplyType_MovedCursorUtf8V2 = 0x10,
} SwkbdReplyType;
/// SwkbdInline State
@ -151,7 +157,10 @@ typedef struct {
u32 textGrouping[8]; ///< Same as SwkbdArgV7::textGrouping.
u64 entries[0x18]; ///< This is SwkbdCustomizedDictionarySet::entries.
u8 total_entries; ///< This is SwkbdCustomizedDictionarySet::total_entries.
u8 pad_x4b5[0x13];
u8 unkFlag; ///< [8.0.0+]
u8 pad_x4b6[0xD];
u8 trigger; ///< [8.0.0+]
u8 pad_x4c4[4];
} SwkbdArgVB;
typedef struct {
@ -163,12 +172,16 @@ typedef struct {
SwkbdCustomizedDictionarySet customizedDictionarySet;
u8 unkFlag;
u8 trigger;
u32 version;
} SwkbdConfig;
/// InitializeArg for SwkbdInline.
typedef struct {
u32 unk_x0;
u8 mode; ///< See \ref SwkbdInlineMode.
u8 mode; ///< See \ref SwkbdInlineMode. (u8 bool)
u8 unk_x5; ///< Only set on 5.0.0+.
u8 pad[2];
} SwkbdInitializeArg;
@ -259,10 +272,18 @@ typedef struct {
/// 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 ChangedString*V2 replies (text changed by the user or by \ref swkbdInlineSetInputText).
/// str is the UTF-8 string for the current text.
typedef void (*SwkbdChangedStringV2Cb)(const char* str, SwkbdChangedStringArg* arg, bool flag);
/// 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 MovedCursor*V2 replies.
/// str is the UTF-8 string for the current text.
typedef void (*SwkbdMovedCursorV2Cb)(const char* str, SwkbdMovedCursorArg* arg, bool flag);
/// 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);
@ -292,8 +313,11 @@ typedef struct {
size_t interactive_strbuf_size;
VoidFn finishedInitializeCb;
VoidFn decidedCancelCb;
SwkbdChangedStringCb changedStringCb;
SwkbdChangedStringV2Cb changedStringV2Cb;
SwkbdMovedCursorCb movedCursorCb;
SwkbdMovedCursorV2Cb movedCursorV2Cb;
SwkbdMovedTabCb movedTabCb;
SwkbdDecidedEnterCb decidedEnterCb;
VoidFn releasedUserWordInfoCb;
@ -519,6 +543,22 @@ static inline void swkbdConfigSetTextGrouping(SwkbdConfig* c, u32 index, u32 val
c->arg.textGrouping[index] = value;
}
/**
* @brief Sets SwkbdConfig::unkFlag, default is 0. Copied to SwkbdArgVB::unkFlag with [8.0.0+].
* @param flag Flag
*/
static inline void swkbdConfigSetUnkFlag(SwkbdConfig* c, u8 flag) {
c->unkFlag = flag;
}
/**
* @brief Sets SwkbdConfig::trigger, default is 0. Copied to SwkbdArgVB::trigger with [8.0.0+].
* @param trigger Trigger
*/
static inline void swkbdConfigSetTrigger(SwkbdConfig* c, u8 trigger) {
c->trigger = trigger;
}
/**
* @brief Launch swkbd with the specified config. This will return once swkbd is finished running.
* @note The string buffer is also used for the buffer passed to the \ref SwkbdTextCheckCb, when it's set. Hence, in that case this buffer should be large enough to handle TextCheck string input/output. The size passed to the callback is the same size passed here, -1.
@ -543,11 +583,20 @@ Result swkbdInlineCreate(SwkbdInline* s);
Result swkbdInlineClose(SwkbdInline* s);
/**
* @brief Launches the applet with the SwkbdInline object.
* @brief Does setup for \ref SwkbdInitializeArg and launches the applet with the SwkbdInline object.
* @note The initArg is cleared, and on [5.0.0+] unk_x5 is set to 1.
* @param s SwkbdInline object.
*/
Result swkbdInlineLaunch(SwkbdInline* s);
/**
* @brief Same as \ref swkbdInlineLaunch, except mode and unk_x5 for \ref SwkbdInitializeArg are set to the input params.
* @param s SwkbdInline object.
* @param mode Value for SwkbdInitializeArg::mode.
* @param unk_x5 Value for SwkbdInitializeArg::unk_x5.
*/
Result swkbdInlineLaunchForLibraryApplet(SwkbdInline* s, u8 mode, u8 unk_x5);
/**
* @brief Handles updating SwkbdInline state, this should be called periodically.
* @note Handles applet exit if needed, and also sends the \ref SwkbdInlineCalcArg to the applet if needed. Hence, this should be called at some point after writing to \ref SwkbdInlineCalcArg.
@ -564,20 +613,49 @@ Result swkbdInlineUpdate(SwkbdInline* s, SwkbdState* out_state);
*/
void swkbdInlineSetFinishedInitializeCallback(SwkbdInline* s, VoidFn cb);
/**
* @brief Sets the DecidedCancel callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @param s SwkbdInline object.
* @param cb Callback
*/
void swkbdInlineSetDecidedCancelCallback(SwkbdInline* s, VoidFn cb);
/**
* @brief Sets the ChangedString callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @note This clears the callback set by \ref swkbdInlineSetChangedStringV2Callback.
* @note This should be called after \ref swkbdInlineLaunch / \ref swkbdInlineLaunchForLibraryApplet.
* @param s SwkbdInline object.
* @param cb \ref SwkbdChangedStringCb Callback
*/
void swkbdInlineSetChangedStringCallback(SwkbdInline* s, SwkbdChangedStringCb cb);
/**
* @brief Sets the ChangedStringV2 callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @note Only available with [8.0.0+].
* @note This must be called after \ref swkbdInlineLaunch / \ref swkbdInlineLaunchForLibraryApplet.
* @param s SwkbdInline object.
* @param cb \ref SwkbdChangedStringV2Cb Callback
*/
void swkbdInlineSetChangedStringV2Callback(SwkbdInline* s, SwkbdChangedStringV2Cb cb);
/**
* @brief Sets the MovedCursor callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @note This clears the callback set by \ref swkbdInlineSetMovedCursorV2Callback.
* @note This should be called after \ref swkbdInlineLaunch / \ref swkbdInlineLaunchForLibraryApplet.
* @param s SwkbdInline object.
* @param cb \ref SwkbdMovedCursorCb Callback
*/
void swkbdInlineSetMovedCursorCallback(SwkbdInline* s, SwkbdMovedCursorCb cb);
/**
* @brief Sets the MovedCursorV2 callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @note Only available with [8.0.0+].
* @note This must be called after \ref swkbdInlineLaunch / \ref swkbdInlineLaunchForLibraryApplet.
* @param s SwkbdInline object.
* @param cb \ref SwkbdMovedCursorV2Cb Callback
*/
void swkbdInlineSetMovedCursorV2Callback(SwkbdInline* s, SwkbdMovedCursorV2Cb cb);
/**
* @brief Sets the MovedTab callback, used by \ref swkbdInlineUpdate. The default is NULL for none.
* @param s SwkbdInline object.

View File

@ -52,7 +52,9 @@ static void _swkbdConfigClear(SwkbdConfig* c) {
static void _swkbdInitVersion(u32* version) {
u32 hosver = hosversionGet();
if (hosver >= MAKEHOSVERSION(6,0,0))
if (hosver >= MAKEHOSVERSION(8,0,0))
*version = 0x8000D;
else if (hosver >= MAKEHOSVERSION(6,0,0))
*version = 0x6000B;
else if (hosver >= MAKEHOSVERSION(5,0,0))
*version = 0x50009;
@ -68,14 +70,17 @@ static void _swkbdInitVersion(u32* version) {
Result swkbdCreate(SwkbdConfig* c, s32 max_dictwords) {
Result rc=0;
s32 maxwords = 0x3e8;
memset(c, 0, sizeof(SwkbdConfig));
_swkbdConfigClear(c);
_swkbdInitVersion(&c->version);
if (c->version >= 0x8000D) maxwords = 0x1388;
c->workbuf_size = 0x1000;
if (max_dictwords > 0 && max_dictwords <= 0x3e8) c->max_dictwords = max_dictwords;
if (max_dictwords > 0 && max_dictwords <= maxwords) c->max_dictwords = max_dictwords;
if (c->max_dictwords) {
c->workbuf_size = c->max_dictwords*sizeof(SwkbdDictWord) + 0x7e8;
@ -301,6 +306,11 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size) {
memcpy(arg_vb.entries, c->customizedDictionarySet.entries, sizeof(arg_vb.entries));
arg_vb.total_entries = c->customizedDictionarySet.total_entries;
if (c->version >= 0x8000D) { // [8.0.0+]
arg_vb.unkFlag = c->unkFlag;
arg_vb.trigger = c->trigger;
}
rc = libappletPushInData(&holder, &arg_vb, sizeof(arg_vb));
}
else if (c->version >= 0x30007) rc = libappletPushInData(&holder, &c->arg, sizeof(c->arg)); // [3.0.0+] has a larger struct.
@ -381,8 +391,6 @@ Result swkbdInlineCreate(SwkbdInline* s) {
s->calcArg.unk_x0 = 0x30000;
s->calcArg.size = sizeof(s->calcArg);
//if (s->version >= 0x50009) s->calcArg.initArg.unk_x5 = 0x1;//Set in a separate init func by official sw on 5.0.0+.
s->calcArg.volume = 1.0f;
s->calcArg.appearArg.type = SwkbdType_QWERTY;
s->calcArg.unk_x6 = 1;
@ -479,9 +487,12 @@ Result swkbdInlineClose(SwkbdInline* s) {
return rc;
}
Result swkbdInlineLaunch(SwkbdInline* s) {
static Result _swkbdInlineLaunch(SwkbdInline* s, SwkbdInitializeArg *initArg) {
Result rc=0;
memcpy(&s->calcArg.initArg, initArg, sizeof(*initArg));
s->calcArg.flags |= 0x1;
rc = appletCreateLibraryApplet(&s->holder, AppletId_swkbd, s->calcArg.initArg.mode!=SwkbdInlineMode_UserDisplay ? LibAppletMode_Background : LibAppletMode_Unknown3);
if (R_FAILED(rc)) return rc;
@ -496,6 +507,23 @@ Result swkbdInlineLaunch(SwkbdInline* s) {
return rc;
}
Result swkbdInlineLaunch(SwkbdInline* s) {
SwkbdInitializeArg initArg = {0};
if (s->version >= 0x50009) initArg.unk_x5 = 0x1; // [5.0.0+]
return _swkbdInlineLaunch(s, &initArg);
}
Result swkbdInlineLaunchForLibraryApplet(SwkbdInline* s, u8 mode, u8 unk_x5) {
SwkbdInitializeArg initArg = {0};
initArg.mode = mode;
initArg.unk_x5 = unk_x5;
return _swkbdInlineLaunch(s, &initArg);
}
static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t size) {
size_t stringendoff_utf8 = 0x7D4;
size_t stringendoff_utf16 = 0x3EC;
@ -507,10 +535,14 @@ static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t
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_ChangedStringV2 && size != 0x3FC+0x1) || (ReplyType==SwkbdReplyType_ChangedStringUtf8V2 && size != 0x7E4+0x1)) return;
if ((ReplyType==SwkbdReplyType_MovedCursorV2 && size != 0x3F4+0x1) || (ReplyType==SwkbdReplyType_MovedCursorUtf8V2 && size != 0x7DC+0x1)) 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) {
if (ReplyType==SwkbdReplyType_ChangedString || ReplyType==SwkbdReplyType_ChangedStringV2 || ReplyType==SwkbdReplyType_MovedCursor || ReplyType==SwkbdReplyType_MovedCursorV2 || ReplyType==SwkbdReplyType_MovedTab || ReplyType==SwkbdReplyType_DecidedEnter) {
_swkbdConvertToUTF8(s->interactive_strbuf, (u16*)strdata, s->interactive_strbuf_size-1);
strdata = s->interactive_strbuf;
}
@ -520,6 +552,10 @@ static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t
if (s->finishedInitializeCb) s->finishedInitializeCb();
break;
case SwkbdReplyType_DecidedCancel:
if (s->decidedCancelCb) s->decidedCancelCb();
break;
case SwkbdReplyType_ChangedString:
case SwkbdReplyType_ChangedStringUtf8:
if (s->changedStringCb) {
@ -528,6 +564,14 @@ static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t
}
break;
case SwkbdReplyType_ChangedStringV2:
case SwkbdReplyType_ChangedStringUtf8V2:
if (s->changedStringV2Cb) {
if (ReplyType==SwkbdReplyType_ChangedStringV2) s->changedStringV2Cb(strdata, (SwkbdChangedStringArg*)argdataend_utf16, s->interactive_tmpbuf[size-1]==0);
if (ReplyType==SwkbdReplyType_ChangedStringUtf8V2) s->changedStringV2Cb(strdata, (SwkbdChangedStringArg*)argdataend_utf8, s->interactive_tmpbuf[size-1]==0);
}
break;
case SwkbdReplyType_MovedCursor:
case SwkbdReplyType_MovedCursorUtf8:
if (s->movedCursorCb) {
@ -536,6 +580,14 @@ static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t
}
break;
case SwkbdReplyType_MovedCursorV2:
case SwkbdReplyType_MovedCursorUtf8V2:
if (s->movedCursorV2Cb) {
if (ReplyType==SwkbdReplyType_MovedCursorV2) s->movedCursorV2Cb(strdata, (SwkbdMovedCursorArg*)argdataend_utf16, s->interactive_tmpbuf[size-1]==0);
if (ReplyType==SwkbdReplyType_MovedCursorUtf8V2) s->movedCursorV2Cb(strdata, (SwkbdMovedCursorArg*)argdataend_utf8, s->interactive_tmpbuf[size-1]==0);
}
break;
case SwkbdReplyType_MovedTab:
if (s->movedTabCb) s->movedTabCb(strdata, (SwkbdMovedTabArg*)argdataend_utf16);
break;
@ -632,16 +684,44 @@ Result swkbdInlineUpdate(SwkbdInline* s, SwkbdState* out_state) {
return rc;
}
static inline Result _swkbdSendRequestV2Flag(SwkbdInline* s, SwkbdRequestCommand req, bool flag) {
if (s->version < 0x8000D) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u8 tmp = flag!=0;
return _swkbdSendRequest(s, req, &tmp, sizeof(tmp));
}
void swkbdInlineSetFinishedInitializeCallback(SwkbdInline* s, VoidFn cb) {
s->finishedInitializeCb = cb;
}
void swkbdInlineSetDecidedCancelCallback(SwkbdInline* s, VoidFn cb) {
s->decidedCancelCb = cb;
}
void swkbdInlineSetChangedStringCallback(SwkbdInline* s, SwkbdChangedStringCb cb) {
s->changedStringCb = cb;
s->changedStringV2Cb = NULL;
_swkbdSendRequestV2Flag(s, SwkbdRequestCommand_SetChangedStringV2Flag, false);
}
void swkbdInlineSetChangedStringV2Callback(SwkbdInline* s, SwkbdChangedStringV2Cb cb) {
if (R_FAILED(_swkbdSendRequestV2Flag(s, SwkbdRequestCommand_SetChangedStringV2Flag, cb!=NULL))) return;
s->changedStringV2Cb = cb;
}
void swkbdInlineSetMovedCursorCallback(SwkbdInline* s, SwkbdMovedCursorCb cb) {
s->movedCursorCb = cb;
s->movedCursorV2Cb = NULL;
_swkbdSendRequestV2Flag(s, SwkbdRequestCommand_SetMovedCursorV2Flag, false);
}
void swkbdInlineSetMovedCursorV2Callback(SwkbdInline* s, SwkbdMovedCursorV2Cb cb) {
if (R_FAILED(_swkbdSendRequestV2Flag(s, SwkbdRequestCommand_SetMovedCursorV2Flag, cb!=NULL))) return;
s->movedCursorV2Cb = cb;
}
void swkbdInlineSetMovedTabCallback(SwkbdInline* s, SwkbdMovedTabCb cb) {
@ -726,9 +806,12 @@ void swkbdInlineSetCursorPos(SwkbdInline* s, s32 pos) {
Result swkbdInlineSetUserWordInfo(SwkbdInline* s, const SwkbdDictWord *input, s32 entries) {
Result rc=0;
size_t size=0;
s32 maxwords = 0x3e8;
if (s->version >= 0x8000D) maxwords = 0x1388;
if (s->state > SwkbdState_Initialized || s->wordInfoInitialized) return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
if (entries < 0 || entries > 0x3e8) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (entries < 0 || entries > maxwords) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (input==NULL || entries==0) return swkbdInlineUnsetUserWordInfo(s);
size = size*sizeof(SwkbdDictWord) + 0x8;