diff --git a/include/mgba-util/gui.h b/include/mgba-util/gui.h index 9ac225eb6..ec2a00b9e 100644 --- a/include/mgba-util/gui.h +++ b/include/mgba-util/gui.h @@ -14,6 +14,9 @@ CXX_GUARD_START #include #include +#define MAX_KEYBOARD_LEN 256 +#define MAX_KEYBOARD_TITLE_LEN 128 + struct GUIFont; enum GUIInput { @@ -40,6 +43,11 @@ enum GUICursorState { GUI_CURSOR_DRAGGING }; +enum GUIKeyboardStatus { + GUI_KEYBOARD_DONE = 0, + GUI_KEYBOARD_CANCEL, +}; + enum { BATTERY_EMPTY = 0, BATTERY_LOW = 25, @@ -57,6 +65,13 @@ struct GUIBackground { void (*draw)(struct GUIBackground*, void* context); }; +struct GUIKeyboardParams { + char title[MAX_KEYBOARD_TITLE_LEN]; + char result[MAX_KEYBOARD_LEN]; + size_t maxLen; + bool multiline; +}; + struct GUIParams { unsigned width; unsigned height; @@ -70,6 +85,7 @@ struct GUIParams { int (*batteryState)(void); void (*guiPrepare)(void); void (*guiFinish)(void); + enum GUIKeyboardStatus (*getText)(struct GUIKeyboardParams*); // State struct mInputMap keyMap; @@ -87,6 +103,8 @@ void GUIPollInput(struct GUIParams* params, uint32_t* newInput, uint32_t* heldIn enum GUICursorState GUIPollCursor(struct GUIParams* params, unsigned* x, unsigned* y); void GUIInvalidateKeys(struct GUIParams* params); +void GUIKeyboardParamsInit(struct GUIKeyboardParams*); + CXX_GUARD_END #endif diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index e9626fa77..218ce7f54 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -797,6 +797,22 @@ static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* rig } } +static enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard) { + SwkbdState swkbd; + swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 2, keyboard->maxLen); + swkbdSetInitialText(&swkbd, keyboard->result); + if (keyboard->multiline) { + swkbdSetFeatures(&swkbd, SWKBD_MULTILINE); + } + + SwkbdButton button = swkbdInputText(&swkbd, keyboard->result, sizeof( keyboard->result)); + if (button == SWKBD_BUTTON_CONFIRM) { + return GUI_KEYBOARD_DONE; + } else { + return GUI_KEYBOARD_CANCEL; + } +} + THREAD_ENTRY _core2Test(void* context) { UNUSED(context); } @@ -892,6 +908,7 @@ int main() { _pollInput, _pollCursor, _batteryState, _guiPrepare, _guiFinish, + _keyboardRun, }, .keySources = (struct GUIInputKeys[]) { { diff --git a/src/platform/psp2/CMakeLists.txt b/src/platform/psp2/CMakeLists.txt index 47094b9f9..60d37e070 100644 --- a/src/platform/psp2/CMakeLists.txt +++ b/src/platform/psp2/CMakeLists.txt @@ -22,6 +22,7 @@ set(OS_LIB -lvita2d -l${M_LIBRARY} -lSceCtrl_stub -lSceDisplay_stub -lSceGxm_stub + -lSceIme_stub -lSceMotion_stub -lScePgf_stub -lScePhotoExport_stub diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 74199d299..1296baa0e 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -36,6 +38,7 @@ static void _drawStart(void) { static void _drawEnd(void) { vita2d_end_drawing(); + vita2d_common_dialog_update(); vita2d_swap_buffers(); } @@ -81,6 +84,66 @@ static int _batteryState(void) { return state | charge; } +static enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard) { + SceImeDialogParam params; + sceImeDialogParamInit(¶ms); + params.supportedLanguages = 0x0001FFFF; + params.languagesForced = SCE_TRUE; + params.type = SCE_IME_TYPE_DEFAULT; + params.option = 0; + if (keyboard->multiline) { + params.option = SCE_IME_OPTION_MULTILINE; + } + params.dialogMode = SCE_IME_DIALOG_DIALOG_MODE_WITH_CANCEL; + params.maxTextLength = keyboard->maxLen; + params.title = calloc(sizeof(SceWChar16), MAX_KEYBOARD_TITLE_LEN + 1); + params.inputTextBuffer = calloc(sizeof(SceWChar16), keyboard->maxLen + 1); + params.initialText = calloc(sizeof(SceWChar16), keyboard->maxLen + 1); + + uint16_t* utf16Buffer = params.initialText; + char* utf8Buffer = keyboard->result; + size_t i = keyboard->maxLen; + while (i > 0 && *utf8Buffer) { + uint32_t unichar = utf8Char((const char**) &utf8Buffer, &i); + utf16Buffer += toUtf16(unichar, utf16Buffer); + } + + utf16Buffer = params.title; + utf8Buffer = keyboard->title; + i = MAX_KEYBOARD_TITLE_LEN; + while (i > 0 && *utf8Buffer) { + uint32_t unichar = utf8Char((const char**) &utf8Buffer, &i); + utf16Buffer += toUtf16(unichar, utf16Buffer); + } + + sceImeDialogInit(¶ms); + SceCommonDialogStatus status = SCE_COMMON_DIALOG_STATUS_RUNNING; + while (status == SCE_COMMON_DIALOG_STATUS_RUNNING) { + _drawStart(); + status = sceImeDialogGetStatus(); + _drawEnd(); + } + + SceImeDialogResult result; + memset(&result, 0, sizeof(SceImeDialogResult)); + sceImeDialogGetResult(&result); + sceImeDialogTerm(); + + utf16Buffer = params.inputTextBuffer; + utf8Buffer = keyboard->result; + i = keyboard->maxLen; + while (i > 0 && *utf16Buffer) { + uint32_t unichar = utf16Char((const uint16_t**) &utf16Buffer, &i); + utf8Buffer += toUtf8(unichar, utf8Buffer); + } + utf8Buffer[0] = 0; + + free(params.initialText); + free(params.inputTextBuffer); + + return result.button == SCE_IME_DIALOG_BUTTON_ENTER ? GUI_KEYBOARD_DONE : GUI_KEYBOARD_CANCEL; +} + int main() { vita2d_init(); struct GUIFont* font = GUIFontCreate(); @@ -92,6 +155,7 @@ int main() { _pollInput, _pollCursor, _batteryState, 0, 0, + _keyboardRun, }, .configExtra = (struct GUIMenuItem[]) { { @@ -167,6 +231,7 @@ int main() { sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); sceSysmoduleLoadModule(SCE_SYSMODULE_PHOTO_EXPORT); sceSysmoduleLoadModule(SCE_SYSMODULE_APPUTIL); + sceSysmoduleLoadModule(SCE_SYSMODULE_IME); mGUIInit(&runner, "psvita"); diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 67eeb7bed..7ba497d85 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -674,6 +674,24 @@ static void _guiFinish(void) { GUIFontDrawSubmit(font); } +static enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard) { + SwkbdConfig swkbd; + swkbdCreate(&swkbd, 0); + swkbdConfigMakePresetDefault(&swkbd); + swkbdConfigSetStringLenMax(&swkbd, keyboard->maxLen); + swkbdConfigSetInitialText(&swkbd, keyboard->result); + swkbdConfigSetHeaderText(&swkbd, keyboard->title); + swkbdConfigSetReturnButtonFlag(&swkbd, keyboard->multiline); + + Result rc = swkbdShow(&swkbd, keyboard->result, sizeof(keyboard->result)); + swkbdClose(&swkbd); + if (R_SUCCEEDED(rc)) { + return GUI_KEYBOARD_DONE; + } else { + return GUI_KEYBOARD_CANCEL; + } +} + static void glInit(void) { glViewport(0, 1080 - vheight, vwidth, vheight); glClearColor(0.f, 0.f, 0.f, 1.f); @@ -865,6 +883,7 @@ int main(int argc, char* argv[]) { _pollInput, _pollCursor, _batteryState, _guiPrepare, _guiFinish, + _keyboardRun, }, .keySources = (struct GUIInputKeys[]) { { diff --git a/src/util/gui.c b/src/util/gui.c index 82165939a..09eb4f1b1 100644 --- a/src/util/gui.c +++ b/src/util/gui.c @@ -72,3 +72,10 @@ void GUIInvalidateKeys(struct GUIParams* params) { params->inputHistory[i] = 0; } } + +void GUIKeyboardParamsInit(struct GUIKeyboardParams* keyboard) { + memset(keyboard->title, 0, sizeof(keyboard->title)); + memset(keyboard->result, 0, sizeof(keyboard->result)); + keyboard->maxLen = sizeof(keyboard->result); + keyboard->multiline = false; +}