diff --git a/nx/include/switch/applets/swkbd.h b/nx/include/switch/applets/swkbd.h index 9b7d5ec3..9de119b4 100644 --- a/nx/include/switch/applets/swkbd.h +++ b/nx/include/switch/applets/swkbd.h @@ -92,7 +92,7 @@ typedef enum { /// Value for \ref SwkbdInitializeArg mode. Controls the LibAppletMode when launching the applet. typedef enum { - SwkbdInlineMode_UserDisplay = 0, ///< LibAppletMode_Unknown3. This is the default. The user-process must handle displaying the swkbd gfx on the screen. Attempting to get the swkbd gfx data for this currently throws an error (unknown why), SwkbdInlineMode_AppletDisplay should be used instead. + SwkbdInlineMode_UserDisplay = 0, ///< LibAppletMode_BackgroundIndirect. This is the default. The user-process must handle displaying the swkbd gfx on the screen, by loading the image with \ref swkbdInlineGetImage. SwkbdInlineMode_AppletDisplay = 1, ///< LibAppletMode_Background. The applet will handle displaying gfx on the screen. } SwkbdInlineMode; @@ -597,6 +597,35 @@ Result swkbdInlineClose(SwkbdInline* s); */ Result swkbdInlineLaunch(SwkbdInline* s); +/** + * @brief GetWindowSize + * @param[out] width Output width. + * @param[out] height Output height. + */ +NX_CONSTEXPR void swkbdInlineGetWindowSize(s32 *width, s32 *height) { + *width = 1280; + *height = 720; +} + +/** + * @brief GetImageMemoryRequirement + * @note Wrapper for \ref viGetIndirectLayerImageRequiredMemoryInfo. + * @param[out] out_size Output size. + * @param[out] out_alignment Output alignment. + */ +Result swkbdInlineGetImageMemoryRequirement(u64 *out_size, u64 *out_alignment); + +/** + * @brief GetImage + * @note Only available with ::SwkbdInlineMode_UserDisplay. + * @note For width/height, see \ref swkbdInlineGetWindowSize. + * @param s SwkbdInline object. + * @param[out] buffer Output RGBA8 image buffer, this must use the alignment from \ref swkbdInlineGetImageMemoryRequirement. + * @param[in] size Output buffer size, this must match the size from \ref swkbdInlineGetImageMemoryRequirement. + * @param[out] data_available Whether data is available. + */ +Result swkbdInlineGetImage(SwkbdInline* s, void* buffer, u64 size, bool *data_available); + /** * @brief Same as \ref swkbdInlineLaunch, except mode and unk_x5 for \ref SwkbdInitializeArg are set to the input params. * @param s SwkbdInline object. diff --git a/nx/source/applets/swkbd.c b/nx/source/applets/swkbd.c index 9956b5d0..0e845ed3 100644 --- a/nx/source/applets/swkbd.c +++ b/nx/source/applets/swkbd.c @@ -3,6 +3,7 @@ #include #include "libapplet_internal.h" #include "applets/swkbd.h" +#include "services/vi.h" #include "runtime/hosversion.h" #include "runtime/util/utf.h" @@ -484,6 +485,17 @@ Result swkbdInlineClose(SwkbdInline* s) { return rc; } +static bool _swkbdInlineHandleFinished(SwkbdInline* s) { + bool ret = appletHolderCheckFinished(&s->holder); + if (ret) { + appletHolderJoin(&s->holder); + appletHolderClose(&s->holder); + + s->state = SwkbdState_Inactive; + } + return ret; +} + static Result _swkbdInlineLaunch(SwkbdInline* s, SwkbdInitializeArg *initArg) { Result rc=0; @@ -526,6 +538,44 @@ Result swkbdInlineLaunchForLibraryApplet(SwkbdInline* s, u8 mode, u8 unk_x5) { return _swkbdInlineLaunch(s, &initArg); } +Result swkbdInlineGetImageMemoryRequirement(u64 *out_size, u64 *out_alignment) { + s32 width=0, height=0; + swkbdInlineGetWindowSize(&width, &height); + return viGetIndirectLayerImageRequiredMemoryInfo(width, height, out_size, out_alignment); +} + +Result swkbdInlineGetImage(SwkbdInline* s, void* buffer, u64 size, bool *data_available) { + Result rc=0; + u64 out_size=0, out_alignment=0; + s32 width=0, height=0; + u64 handle=0; + + if (!buffer || !size) return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + if (_swkbdInlineHandleFinished(s)) { + data_available = false; + return 0; + } + + rc = swkbdInlineGetImageMemoryRequirement(&out_size, &out_alignment); + if (R_SUCCEEDED(rc)) { + if (out_size != size || (uintptr_t)buffer & (out_alignment-1)) + rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + } + + swkbdInlineGetWindowSize(&width, &height); + if (R_SUCCEEDED(rc)) rc = appletHolderGetIndirectLayerConsumerHandle(&s->holder, &handle); + if (R_SUCCEEDED(rc)) rc = viGetIndirectLayerImageMap(buffer, size, width, height, handle, NULL, NULL); + + if (R_SUCCEEDED(rc)) *data_available = true; + else if (R_VALUE(rc) == MAKERESULT(114, 11)) { + *data_available = false; + rc = 0; + } + + return rc; +} + static void _swkbdProcessReply(SwkbdInline* s, SwkbdReplyType ReplyType, size_t size) { size_t stringendoff_utf8 = 0x7D4; size_t stringendoff_utf16 = 0x3EC; @@ -664,11 +714,7 @@ Result swkbdInlineUpdate(SwkbdInline* s, SwkbdState* out_state) { } swkbdInlineSetInputModeFadeType(s, fadetype); - if (appletHolderCheckFinished(&s->holder)) { - appletHolderJoin(&s->holder); - appletHolderClose(&s->holder); - - s->state = SwkbdState_Inactive; + if (_swkbdInlineHandleFinished(s)) { if (out_state) *out_state = s->state; return 0; }