diff --git a/CMakeLists.txt b/CMakeLists.txt index b1f37fba3..50a8ed3ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -354,6 +354,11 @@ if(SWITCH) SourceX/platform/switch/docking.cpp) set(BIN_TARGET devilutionx.elf) endif() + +if(VITA) + list(APPEND devilutionx_SRCS + SourceX/platform/vita/keyboard.cpp) +endif() if(N3DS) list(APPEND devilutionx_SRCS diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index 533a311c2..50c900ef5 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -23,6 +23,10 @@ // for virtual keyboard on Switch #include "platform/switch/keyboard.h" #endif +#ifdef __vita__ +// for virtual keyboard on Vita +#include "platform/vita/keyboard.h" +#endif namespace dvl { @@ -102,6 +106,8 @@ void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int valu textInputActive = true; #ifdef __SWITCH__ switch_start_text_input("", pItemUIEdit->m_value, pItemUIEdit->m_max_length, /*multiline=*/0); +#elif defined(__vita__) + vita_start_text_input("", pItemUIEdit->m_value, pItemUIEdit->m_max_length); #else SDL_StartTextInput(); #endif @@ -218,6 +224,12 @@ void selhero_CatToName(char *in_buf, char *out_buf, int cnt) strncat(out_buf, output.c_str(), cnt - strlen(out_buf)); } +void selhero_SetName(char *in_buf, char *out_buf, int cnt) +{ + std::string output = utf8_to_latin1(in_buf); + strncpy(out_buf, output.c_str(), cnt); +} + bool HandleMenuAction(MenuAction menu_action) { switch (menu_action) { @@ -333,7 +345,11 @@ void UiFocusNavigation(SDL_Event *event) #ifndef USE_SDL1 case SDL_TEXTINPUT: if (textInputActive) { +#ifdef __vita__ + selhero_SetName(event->text.text, UiTextInput, UiTextInputLen); +#else selhero_CatToName(event->text.text, UiTextInput, UiTextInputLen); +#endif } return; #endif diff --git a/SourceX/platform/vita/keyboard.cpp b/SourceX/platform/vita/keyboard.cpp new file mode 100644 index 000000000..adb529226 --- /dev/null +++ b/SourceX/platform/vita/keyboard.cpp @@ -0,0 +1,120 @@ +#include +#include + +#include +#include +#include +#include "platform/vita/keyboard.h" + +static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) +{ + int i; + for (i = 0; src[i]; i++) { + if ((src[i] & 0xFF80) == 0) { + *(dst++) = src[i] & 0xFF; + } else if((src[i] & 0xF800) == 0) { + *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0; + *(dst++) = (src[i] & 0x3F) | 0x80; + } else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) { + *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0; + *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80; + *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF); + *(dst++) = (src[i + 1] & 0x3F) | 0x80; + i += 1; + } else { + *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0; + *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80; + *(dst++) = (src[i] & 0x3F) | 0x80; + } + } + + *dst = '\0'; +} + +static void utf8_to_utf16(const uint8_t *src, uint16_t *dst) +{ + int i; + for (i = 0; src[i];) { + if ((src[i] & 0xE0) == 0xE0) { + *(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F); + i += 3; + } else if ((src[i] & 0xC0) == 0xC0) { + *(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F); + i += 2; + } else { + *(dst++) = src[i]; + i += 1; + } + } + + *dst = '\0'; +} + +static int vita_input_thread(void *ime_buffer) +{ + while(1) { + // update IME status. Terminate, if finished + SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus(); + if (dialogStatus == SCE_COMMON_DIALOG_STATUS_FINISHED) { + uint8_t utf8_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; + SceImeDialogResult result; + + SDL_memset(&result, 0, sizeof(SceImeDialogResult)); + sceImeDialogGetResult(&result); + + // Convert UTF16 to UTF8 + utf16_to_utf8((SceWChar16*)ime_buffer, utf8_buffer); + + // send sdl event + SDL_Event event; + event.text.type = SDL_TEXTINPUT; + SDL_utf8strlcpy(event.text.text, (const char*)utf8_buffer, SDL_arraysize(event.text.text)); + SDL_PushEvent(&event); + + sceImeDialogTerm(); + break; + } + } + return 0; +} + +static int vita_keyboard_get(const char *guide_text, const char *initial_text, int max_len, SceWChar16 *buf) +{ + SceWChar16 title[SCE_IME_DIALOG_MAX_TITLE_LENGTH]; + SceWChar16 text[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; + SceInt32 res; + + SDL_memset(&title, 0, sizeof(title)); + SDL_memset(&text, 0, sizeof(text)); + utf8_to_utf16((const uint8_t*)guide_text, title); + utf8_to_utf16((const uint8_t*)initial_text, text); + + SceImeDialogParam param; + sceImeDialogParamInit(¶m); + + param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH; + param.languagesForced = SCE_FALSE; + param.type = SCE_IME_TYPE_DEFAULT; + param.option = 0; + param.textBoxMode = SCE_IME_DIALOG_TEXTBOX_MODE_WITH_CLEAR; + param.maxTextLength = max_len; + + param.title = title; + param.initialText = text; + param.inputTextBuffer = buf; + + res = sceImeDialogInit(¶m); + if (res < 0) { + return 0; + } + + return 1; +} + +void vita_start_text_input(const char *guide_text, const char *initial_text, int max_length) +{ + SceWChar16 ime_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; + if (vita_keyboard_get(guide_text, initial_text, max_length, ime_buffer)) { + SDL_CreateThread(vita_input_thread, "vita_input_thread", (void *)ime_buffer); + } +} diff --git a/SourceX/platform/vita/keyboard.h b/SourceX/platform/vita/keyboard.h new file mode 100644 index 000000000..8a229527d --- /dev/null +++ b/SourceX/platform/vita/keyboard.h @@ -0,0 +1,3 @@ +#pragma once + +void vita_start_text_input(const char *guide_text, const char *initial_text, int max_length);