From d63c61e27cfdff0625618527b39d6469fca722e2 Mon Sep 17 00:00:00 2001 From: rsn8887 Date: Thu, 11 Jul 2019 11:32:00 -0500 Subject: [PATCH] Add virtual keyboard support on Switch --- CMakeLists.txt | 1 + SourceX/DiabloUI/diabloui.cpp | 8 +++ SourceX/platform/switch/keyboard.cpp | 79 ++++++++++++++++++++++++++++ SourceX/platform/switch/keyboard.h | 3 ++ 4 files changed, 91 insertions(+) create mode 100644 SourceX/platform/switch/keyboard.cpp create mode 100644 SourceX/platform/switch/keyboard.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fd947e1ba..9dd3c29fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,7 @@ set(BIN_TARGET devilutionx) if(SWITCH) list(APPEND devilutionx_SRCS + SourceX/platform/switch/keyboard.cpp SourceX/platform/switch/docking.cpp) set(BIN_TARGET devilutionx.elf) endif() diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index f53649f41..e6d72c348 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -16,6 +16,11 @@ #include "DiabloUI/button.h" #include "DiabloUI/dialogs.h" +#ifdef __SWITCH__ +// for virtual keyboard on Switch +#include "platform/switch/keyboard.h" +#endif + namespace dvl { int SelectedItemMin = 1; @@ -80,6 +85,9 @@ void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(i SDL_StopTextInput(); // input is enabled by default for (int i = 0; i < itemCnt; i++) { if (items[i].type == UI_EDIT) { +#ifdef __SWITCH__ + switch_start_text_input(items[i - 1].art_text.text, items[i].edit.value, /*multiline=*/0); +#endif SDL_StartTextInput(); UiTextInput = items[i].edit.value; UiTextInputLen = items[i].edit.max_length; diff --git a/SourceX/platform/switch/keyboard.cpp b/SourceX/platform/switch/keyboard.cpp new file mode 100644 index 000000000..e4e33e0ca --- /dev/null +++ b/SourceX/platform/switch/keyboard.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include "platform/switch/keyboard.h" + +static void switch_keyboard_get(const char *guide_text, char *initial_text, int max_len, int multiline, char *buf) +{ + Result rc = 0; + + SwkbdConfig kbd; + + rc = swkbdCreate(&kbd, 0); + + if (R_SUCCEEDED(rc)) { + swkbdConfigMakePresetDefault(&kbd); + swkbdConfigSetGuideText(&kbd, guide_text); + swkbdConfigSetInitialText(&kbd, initial_text); + swkbdConfigSetStringLenMax(&kbd, max_len); + rc = swkbdShow(&kbd, buf, max_len); + swkbdClose(&kbd); + } +} + +static int get_utf8_character_bytes(const uint8_t *uc) +{ + if (uc[0] < 0x80) { + return 1; + } else if ((uc[0] & 0xe0) == 0xc0 && (uc[1] & 0xc0) == 0x80) { + return 2; + } else if ((uc[0] & 0xf0) == 0xe0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80) { + return 3; + } else if ((uc[0] & 0xf8) == 0xf0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80 && (uc[3] & 0xc0) == 0x80) { + return 4; + } else { + return 1; + } +} + +static void switch_create_and_push_sdlkey_event(uint32_t event_type, SDL_Scancode scan, SDL_Keycode key) +{ + SDL_Event event; + event.type = event_type; + event.key.keysym.scancode = scan; + event.key.keysym.sym = key; + event.key.keysym.mod = 0; + SDL_PushEvent(&event); +} + +void switch_start_text_input(const char *guide_text, char *initial_text, int multiline) +{ + char text[65] = {'\0'}; + switch_keyboard_get(guide_text, initial_text, 64, multiline, text); + for (int i = 0; i < 600; i++) { + switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); + switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); + } + for (int i = 0; i < 600; i++) { + switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_DELETE, SDLK_DELETE); + switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_DELETE, SDLK_DELETE); + } + if (text[0] == '\0') { + strncpy(text, initial_text, 63); + text[64] = {'\0'}; + } + const uint8_t *utf8_text = (uint8_t*) text; + for (int i = 0; i < 599 && utf8_text[i];) { + int bytes_in_char = get_utf8_character_bytes(&utf8_text[i]); + SDL_Event textinput_event; + textinput_event.type = SDL_TEXTINPUT; + for (int n = 0; n < bytes_in_char; n++) { + textinput_event.text.text[n] = text[i + n]; + } + textinput_event.text.text[bytes_in_char] = 0; + SDL_PushEvent(&textinput_event); + i += bytes_in_char; + } +} diff --git a/SourceX/platform/switch/keyboard.h b/SourceX/platform/switch/keyboard.h new file mode 100644 index 000000000..5ab737913 --- /dev/null +++ b/SourceX/platform/switch/keyboard.h @@ -0,0 +1,3 @@ +#pragma once + +void switch_start_text_input(const char *guide_text, char *initial_text, int multiline);