#include "SDL_internal.h"
#include "SDL_gdktextinput.h"
#ifdef SDL_GDK_TEXTINPUT
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <XGameUI.h>
#include <XUser.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "../../events/SDL_keyboard_c.h"
#include "../windows/SDL_windowsvideo.h"
static XTaskQueueHandle g_TextTaskQueue = NULL;
static XAsyncBlock *g_TextBlock = NULL;
static bool g_DidRegisterHints = false;
static char *g_TitleText = NULL;
static char *g_DescriptionText = NULL;
static char *g_DefaultText = NULL;
static const Sint32 g_DefaultTextInputScope = (Sint32)XGameUiTextEntryInputScope::Default;
static Sint32 g_TextInputScope = g_DefaultTextInputScope;
static const Sint32 g_DefaultMaxTextLength = 1024; static Sint32 g_MaxTextLength = g_DefaultMaxTextLength;
static void SDLCALL GDK_InternalHintCallback(
void *userdata,
const char *name,
const char *oldValue,
const char *newValue)
{
if (!userdata) {
return;
}
if (userdata == &g_TextInputScope || userdata == &g_MaxTextLength) {
Sint32 intValue = (!newValue || newValue[0] == '\0') ? 0 : SDL_atoi(newValue);
if (userdata == &g_MaxTextLength && intValue <= 0) {
intValue = g_DefaultMaxTextLength;
} else if (userdata == &g_TextInputScope && intValue < 0) {
intValue = g_DefaultTextInputScope;
}
*(Sint32 *)userdata = intValue;
} else {
if (!newValue || newValue[0] == '\0') {
SDL_free(*(char **)userdata);
*(char **)userdata = NULL;
} else {
char *newString = SDL_strdup(newValue);
if (newString) {
SDL_free(*(char **)userdata);
*(char **)userdata = newString;
}
}
}
}
static bool GDK_InternalEnsureTaskQueue(void)
{
if (!g_TextTaskQueue) {
if (!SDL_GetGDKTaskQueue(&g_TextTaskQueue)) {
return false;
}
}
return true;
}
static void CALLBACK GDK_InternalTextEntryCallback(XAsyncBlock *asyncBlock)
{
HRESULT hR = S_OK;
Uint32 resultSize = 0;
Uint32 resultUsed = 0;
char *resultBuffer = NULL;
if (FAILED(hR = XGameUiShowTextEntryResultSize(
asyncBlock,
&resultSize))) {
SDL_SetError("XGameUiShowTextEntryResultSize failure with HRESULT of %08X", hR);
} else if (resultSize > 0) {
resultBuffer = (char *)SDL_calloc(1 + (size_t)resultSize, sizeof(*resultBuffer));
if (resultBuffer) {
if (FAILED(hR = XGameUiShowTextEntryResult(
asyncBlock,
resultSize,
resultBuffer,
&resultUsed))) {
SDL_SetError("XGameUiShowTextEntryResult failure with HRESULT of %08X", hR);
}
else if (resultUsed > 0 && resultBuffer[0] != '\0') {
SDL_SendKeyboardText(resultBuffer);
}
SDL_free(resultBuffer);
resultBuffer = NULL;
}
}
SDL_free(asyncBlock);
asyncBlock = NULL;
g_TextBlock = NULL;
SDL_SendScreenKeyboardHidden();
}
void GDK_EnsureHints(void)
{
if (g_DidRegisterHints == false) {
SDL_AddHintCallback(
SDL_HINT_GDK_TEXTINPUT_TITLE,
GDK_InternalHintCallback,
&g_TitleText);
SDL_AddHintCallback(
SDL_HINT_GDK_TEXTINPUT_DESCRIPTION,
GDK_InternalHintCallback,
&g_DescriptionText);
SDL_AddHintCallback(
SDL_HINT_GDK_TEXTINPUT_DEFAULT_TEXT,
GDK_InternalHintCallback,
&g_DefaultText);
SDL_AddHintCallback(
SDL_HINT_GDK_TEXTINPUT_SCOPE,
GDK_InternalHintCallback,
&g_TextInputScope);
SDL_AddHintCallback(
SDL_HINT_GDK_TEXTINPUT_MAX_LENGTH,
GDK_InternalHintCallback,
&g_MaxTextLength);
g_DidRegisterHints = true;
}
}
bool GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
return true;
}
bool GDK_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
{
return true;
}
bool GDK_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
{
return true;
}
bool GDK_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window)
{
return true;
}
bool GDK_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
{
return true;
}
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
HRESULT hR = S_OK;
if (g_TextBlock) {
return;
}
if (!GDK_InternalEnsureTaskQueue()) {
return;
}
g_TextBlock = (XAsyncBlock *)SDL_calloc(1, sizeof(*g_TextBlock));
if (!g_TextBlock) {
return;
}
XGameUiTextEntryInputScope scope;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
scope = (XGameUiTextEntryInputScope)g_TextInputScope;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
scope = XGameUiTextEntryInputScope::EmailSmtpAddress;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
scope = XGameUiTextEntryInputScope::Password;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
scope = XGameUiTextEntryInputScope::Number;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
scope = XGameUiTextEntryInputScope::Number;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
scope = XGameUiTextEntryInputScope::Number;
break;
}
g_TextBlock->queue = g_TextTaskQueue;
g_TextBlock->context = _this;
g_TextBlock->callback = GDK_InternalTextEntryCallback;
if (SUCCEEDED(hR = XGameUiShowTextEntryAsync(
g_TextBlock,
g_TitleText,
g_DescriptionText,
g_DefaultText,
scope,
(uint32_t)g_MaxTextLength))) {
SDL_SendScreenKeyboardShown();
} else {
SDL_free(g_TextBlock);
g_TextBlock = NULL;
SDL_SetError("XGameUiShowTextEntryAsync failure with HRESULT of %08X", hR);
}
}
void GDK_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
if (g_TextBlock) {
XAsyncCancel(g_TextBlock);
}
}
#ifdef __cplusplus
}
#endif
#endif