Initial SwkbdInline impl, minor swkbd adjustments.

This commit is contained in:
yellows8 2019-01-04 22:05:06 -05:00
parent 06733c4750
commit 2900622cb5
2 changed files with 233 additions and 13 deletions

View File

@ -40,6 +40,13 @@ typedef enum {
SwkbdTextDrawType_DownloadCode = 2, ///< Used by \ref swkbdConfigMakePresetDownloadCode on 5.0.0+. Enables using \ref SwkbdArgV7 unk_x3e0.
} SwkbdTextDrawType;
/// SwkbdInline Interactive input storage request ID.
typedef enum {
SwkbdRequestCommand_Finalize = 0x4,
SwkbdRequestCommand_SetCustomizeDic = 0x7,
SwkbdRequestCommand_Calc = 0xA,
} SwkbdRequestCommand;
typedef SwkbdTextCheckResult (*SwkbdTextCheckCb)(char* tmp_string, size_t tmp_string_size); /// TextCheck callback set by \ref swkbdConfigSetTextCheckCallback, for validating the input string when the swkbd ok-button is pressed. This buffer contains an UTF-8 string. This callback should validate the input string, then return a \ref SwkbdTextCheckResult indicating success/failure. On failure, this function must write an error message to the tmp_string buffer, which will then be displayed by swkbd.
/// Base swkbd arg struct.
@ -93,6 +100,71 @@ typedef struct {
u8 unk_x0[0x64];
} SwkbdDictWord;
typedef struct {
u32 unk_x0;
u8 mode; ///< Controls the LibAppletMode when launching the applet. Non-zero indicates LibAppletMode_Background, otherwise LibAppletMode_Unknown3
u8 unk_x5; ///< Only set on 5.0.0+.
u8 pad[2];
} SwkbdInitializeArg;
typedef struct {
u32 unk_x0;
u64 unk_x4;
u64 unk_xc;
u8 unk_x14[0x6];
u8 unk_x1a;
u8 unk_x1b;
u32 unk_x1c;
s32 unk_x20;
s32 unk_x24;
u64 unk_x28;
u8 unk_x30;
u8 unk_x31[0x17];
} SwkbdAppearArg;
typedef struct {
u32 unk_x0;
u16 size; ///< Size of this struct.
u8 unk_x6;
u8 unk_x7;
u64 flags;
SwkbdInitializeArg initArg; ///< Flags bitmask 0x1.
float volume; ///< Flags bitmask 0x2.
s32 cursorPos; ///< Flags bitmask 0x10.
SwkbdAppearArg appearArg;
u8 unk_x68[0x3d4];
u8 utf8Mode; ///< Flags bitmask 0x20.
u8 unk_x43d;
u8 enableBackspace; ///< Flags bitmask 0x8000. Added with 5.x.
u8 unk_x43f[3];
u8 keytopAsFloating; ///< Flags bitmask 0x200.
u8 footerScalable; ///< Flags bitmask 0x100.
u8 alphaEnabledInInputMode; ///< Flags bitmask 0x200.
u8 inputModeFadeType; ///< Flags bitmask 0x100.
u8 disableTouch; ///< Flags bitmask 0x200.
u8 disableUSBKeyboard; ///< Flags bitmask 0x800.
u8 unk_x448[5];
u16 unk_x44d;
u8 unk_x44f;
float keytopScale0; ///< Flags bitmask 0x200.
float keytopScale1; ///< Flags bitmask 0x200.
float keytopTranslate0; ///< Flags bitmask 0x200.
float keytopTranslate1; ///< Flags bitmask 0x200.
float keytopBgAlpha; ///< Flags bitmask 0x100.
float unk_x464;
float balloonScale; ///< Flags bitmask 0x200.
float unk_x46c;
u64 unk_x470[4];
u8 unk_x490[0x10];
} PACKED SwkbdInlineCalcArg;
/// InlineKeyboard
typedef struct {
u32 version;
AppletHolder holder;
SwkbdInlineCalcArg calcArg;
} SwkbdInline;
/**
* @brief Creates a SwkbdConfig struct.
* @param c SwkbdConfig struct.
@ -214,3 +286,30 @@ void swkbdConfigSetTextCheckCallback(SwkbdConfig* c, SwkbdTextCheckCb cb);
*/
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.
* @param s SwkbdInline object.
*/
Result swkbdInlineCreate(SwkbdInline* s);
/**
* @brief Closes a SwkbdInline object. If the applet is running, this will tell the applet to exit, then wait for the applet to exit + applet exit handling.
* @param s SwkbdInline object.
*/
Result swkbdInlineClose(SwkbdInline* s);
/**
* @brief Launches the applet with the SwkbdInline object.
* @param s SwkbdInline object.
*/
Result swkbdInlineLaunch(SwkbdInline* s);
/**
* @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.
* @note Handles applet Interactive storage output when needed.
* @param s SwkbdInline object.
*/
Result swkbdInlineUpdate(SwkbdInline* s);

View File

@ -39,25 +39,29 @@ static void _swkbdConfigClear(SwkbdConfig* c) {
memset(c->arg.unk_x3e0, 0xff, sizeof(c->arg.unk_x3e0));
}
static void _swkbdInitVersion(u32* version) {
*version=0x5;//1.0.0+ version
if (kernelAbove500()) {
*version = 0x50009;
}
else if (kernelAbove400()) {
*version = 0x40008;
}
else if (kernelAbove300()) {
*version = 0x30007;
}
else if (kernelAbove200()) {
*version = 0x10006;
}
}
Result swkbdCreate(SwkbdConfig* c, s32 max_dictwords) {
Result rc=0;
memset(c, 0, sizeof(SwkbdConfig));
_swkbdConfigClear(c);
c->version=0x5;//1.0.0+ version
if (kernelAbove500()) {
c->version = 0x50009;
}
else if (kernelAbove400()) {
c->version = 0x40008;
}
else if (kernelAbove300()) {
c->version = 0x30007;
}
else if (kernelAbove200()) {
c->version = 0x10006;
}
_swkbdInitVersion(&c->version);
c->workbuf_size = 0x1000;
if (max_dictwords > 0 && max_dictwords <= 0x3e8) c->max_dictwords = max_dictwords;
@ -310,3 +314,120 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size) {
return rc;
}
static Result _swkbdSendRequest(SwkbdInline* s, u32 RequestCommand, const void* buffer, size_t size) {
Result rc=0;
AppletStorage storage;
rc = appletCreateStorage(&storage, size+sizeof(u32));
if (R_FAILED(rc)) return rc;
rc = appletStorageWrite(&storage, 0, &RequestCommand, sizeof(RequestCommand));
if (R_SUCCEEDED(rc) && buffer!=NULL) rc = appletStorageWrite(&storage, sizeof(RequestCommand), buffer, size);
if (R_FAILED(rc)) {
appletStorageClose(&storage);
return rc;
}
return appletHolderPushInteractiveInData(&s->holder, &storage);
}
Result swkbdInlineCreate(SwkbdInline* s) {
memset(s, 0, sizeof(SwkbdInline));
_swkbdInitVersion(&s->version);
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.unk_x0 = 0x2;
s->calcArg.unk_x6 = 1;
s->calcArg.unk_x7 = 1;
s->calcArg.appearArg.unk_x20 = -1;
s->calcArg.appearArg.unk_x24 = -1;
s->calcArg.appearArg.unk_x30 = 1;
s->calcArg.enableBackspace = 1;
s->calcArg.unk_x43f[0] = 1;
s->calcArg.footerScalable = 1;
s->calcArg.inputModeFadeType = 1;
s->calcArg.keytopScale0 = 1.0f;
s->calcArg.keytopScale1 = 1.0f;
s->calcArg.keytopBgAlpha = 1.0f;
s->calcArg.unk_x464 = 1.0f;
s->calcArg.balloonScale = 1.0f;
s->calcArg.unk_x46c = 1.0f;
return 0;
}
Result swkbdInlineClose(SwkbdInline* s) {
Result rc=0;
if (appletHolderActive(&s->holder))
{
_swkbdSendRequest(s, SwkbdRequestCommand_Finalize, NULL, 0);//Finalize cmd
appletHolderJoin(&s->holder);
LibAppletExitReason reason = appletHolderGetExitReason(&s->holder);
if (reason == LibAppletExitReason_Canceled) {
rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit);
}
else if (reason == LibAppletExitReason_Abnormal || reason == LibAppletExitReason_Unexpected) {
rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit);
}
appletHolderClose(&s->holder);
}
return rc;
}
Result swkbdInlineLaunch(SwkbdInline* s) {
Result rc=0;
rc = appletCreateLibraryApplet(&s->holder, AppletId_swkbd, s->calcArg.initArg.mode!=0 ? LibAppletMode_Background : LibAppletMode_Unknown3);
if (R_FAILED(rc)) return rc;
LibAppletArgs commonargs;
libappletArgsCreate(&commonargs, s->version);
rc = libappletArgsPush(&commonargs, &s->holder);
if (R_SUCCEEDED(rc)) rc = libappletPushInData(&s->holder, &s->calcArg.initArg, sizeof(s->calcArg.initArg));
if (R_SUCCEEDED(rc)) rc = appletHolderStart(&s->holder);
return rc;
}
Result swkbdInlineUpdate(SwkbdInline* s) {
Result rc=0;
AppletStorage storage;
//TODO: 'Normalize' floats.
if (appletHolderCheckFinished(&s->holder)) {
appletHolderJoin(&s->holder);
appletHolderClose(&s->holder);
return 0;
}
if (s->calcArg.flags) {
rc = _swkbdSendRequest(s, SwkbdRequestCommand_Calc, &s->calcArg, sizeof(s->calcArg));
s->calcArg.flags = 0;
if (R_FAILED(rc)) return rc;
}
while(R_SUCCEEDED(appletHolderPopInteractiveOutData(&s->holder, &storage))) {
//TODO: Process storage content.
appletStorageClose(&storage);
}
return rc;
}