|
@@ -36,6 +36,8 @@ static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
|
|
|
static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
|
|
|
static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
|
|
|
static void IME_Quit(SDL_VideoData *videodata);
|
|
|
+static void IME_ClearComposition(SDL_VideoData *videodata);
|
|
|
+static SDL_bool IME_IsTextInputShown(SDL_VideoData* videodata);
|
|
|
#endif /* !SDL_DISABLE_WINDOWS_IME */
|
|
|
|
|
|
#ifndef MAPVK_VK_TO_VSC
|
|
@@ -62,6 +64,8 @@ WIN_InitKeyboard(_THIS)
|
|
|
data->ime_hwnd_main = 0;
|
|
|
data->ime_hwnd_current = 0;
|
|
|
data->ime_himc = 0;
|
|
|
+ data->ime_composition_length = 32 * sizeof(WCHAR);
|
|
|
+ data->ime_composition = (WCHAR*)SDL_malloc(data->ime_composition_length);
|
|
|
data->ime_composition[0] = 0;
|
|
|
data->ime_readingstring[0] = 0;
|
|
|
data->ime_cursor = 0;
|
|
@@ -272,6 +276,18 @@ WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void WIN_ClearComposition(_THIS)
|
|
|
+{
|
|
|
+ SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
|
|
|
+ IME_ClearComposition(videodata);
|
|
|
+}
|
|
|
+
|
|
|
+SDL_bool WIN_IsTextInputShown(_THIS)
|
|
|
+{
|
|
|
+ SDL_VideoData* videodata = (SDL_VideoData*)_this->driverdata;
|
|
|
+ return IME_IsTextInputShown(videodata);
|
|
|
+}
|
|
|
+
|
|
|
static SDL_bool
|
|
|
WIN_ShouldShowNativeUI()
|
|
|
{
|
|
@@ -742,18 +758,51 @@ IME_ClearComposition(SDL_VideoData *videodata)
|
|
|
SDL_SendEditingText("", 0, 0);
|
|
|
}
|
|
|
|
|
|
+static SDL_bool
|
|
|
+IME_IsTextInputShown(SDL_VideoData* videodata)
|
|
|
+{
|
|
|
+ BOOL result;
|
|
|
+ HIMC himc;
|
|
|
+
|
|
|
+ if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
|
|
|
+ return SDL_FALSE;
|
|
|
+
|
|
|
+ return videodata->ime_uicontext != 0 ? SDL_TRUE : SDL_FALSE;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
|
|
|
{
|
|
|
- LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition) - sizeof(videodata->ime_composition[0]));
|
|
|
+ LONG length;
|
|
|
+ DWORD dwLang = ((DWORD_PTR)videodata->ime_hkl & 0xffff);
|
|
|
+
|
|
|
+ length = ImmGetCompositionStringW(himc, string, NULL, 0);
|
|
|
+ if (length > 0 && videodata->ime_composition_length < length) {
|
|
|
+ if (videodata->ime_composition != NULL)
|
|
|
+ SDL_free(videodata->ime_composition);
|
|
|
+
|
|
|
+ videodata->ime_composition = (WCHAR*)SDL_malloc(length + sizeof(WCHAR));
|
|
|
+ videodata->ime_composition_length = length;
|
|
|
+ }
|
|
|
+
|
|
|
+ length = ImmGetCompositionStringW(
|
|
|
+ himc,
|
|
|
+ string,
|
|
|
+ videodata->ime_composition,
|
|
|
+ videodata->ime_composition_length
|
|
|
+ );
|
|
|
+
|
|
|
if (length < 0)
|
|
|
length = 0;
|
|
|
|
|
|
- length /= sizeof(videodata->ime_composition[0]);
|
|
|
+ length /= sizeof(WCHAR);
|
|
|
videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
|
|
|
- if (videodata->ime_cursor > 0 &&
|
|
|
- videodata->ime_cursor < SDL_arraysize(videodata->ime_composition) &&
|
|
|
- videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
|
|
|
+ if ((dwLang == LANG_CHT || dwLang == LANG_CHS) &&
|
|
|
+ videodata->ime_cursor > 0 &&
|
|
|
+ videodata->ime_cursor < videodata->ime_composition_length / sizeof(WCHAR) &&
|
|
|
+ (videodata->ime_composition[0] == 0x3000 || videodata->ime_composition[0] == 0x0020)) {
|
|
|
+ // Traditional Chinese IMEs add a placeholder U+3000
|
|
|
+ // Simplified Chinese IMEs seem to add a placholder U+0020 sometimes
|
|
|
int i;
|
|
|
for (i = videodata->ime_cursor + 1; i < length; ++i)
|
|
|
videodata->ime_composition[i - 1] = videodata->ime_composition[i];
|
|
@@ -762,6 +811,39 @@ IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
|
|
|
}
|
|
|
|
|
|
videodata->ime_composition[length] = 0;
|
|
|
+
|
|
|
+ // Get the correct caret position if we've selected a candidate from the candidate window
|
|
|
+ if (videodata->ime_cursor == 0 && length > 0) {
|
|
|
+ Sint32 start = 0;
|
|
|
+ Sint32 end = 0;
|
|
|
+
|
|
|
+ length = ImmGetCompositionStringW(himc, GCS_COMPATTR, NULL, 0);
|
|
|
+ if (length > 0) {
|
|
|
+ Uint8* attributes = (Uint8*)SDL_malloc(length);
|
|
|
+ ImmGetCompositionString(himc, GCS_COMPATTR, attributes, length);
|
|
|
+
|
|
|
+ for (start = 0; start < length; ++start) {
|
|
|
+ if (attributes[start] == ATTR_TARGET_CONVERTED ||
|
|
|
+ attributes[start] == ATTR_TARGET_NOTCONVERTED)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (end = start; end < length; ++end) {
|
|
|
+ if (attributes[end] != ATTR_TARGET_CONVERTED &&
|
|
|
+ attributes[end] != ATTR_TARGET_NOTCONVERTED)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (start == length) {
|
|
|
+ start = 0;
|
|
|
+ end = length;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_free(attributes);
|
|
|
+ }
|
|
|
+
|
|
|
+ videodata->ime_cursor = end;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -780,22 +862,30 @@ IME_SendInputEvent(SDL_VideoData *videodata)
|
|
|
static void
|
|
|
IME_SendEditingEvent(SDL_VideoData *videodata)
|
|
|
{
|
|
|
- char *s = 0;
|
|
|
- WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
|
|
|
- const size_t size = SDL_arraysize(buffer);
|
|
|
- buffer[0] = 0;
|
|
|
+ char *s = NULL;
|
|
|
+ WCHAR *buffer = NULL;
|
|
|
+ size_t size = videodata->ime_composition_length;
|
|
|
if (videodata->ime_readingstring[0]) {
|
|
|
size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
|
|
|
+
|
|
|
+ size += sizeof(videodata->ime_readingstring);
|
|
|
+ buffer = (WCHAR*)SDL_malloc(size);
|
|
|
+ buffer[0] = 0;
|
|
|
+
|
|
|
SDL_wcslcpy(buffer, videodata->ime_composition, len + 1);
|
|
|
SDL_wcslcat(buffer, videodata->ime_readingstring, size);
|
|
|
SDL_wcslcat(buffer, &videodata->ime_composition[len], size);
|
|
|
}
|
|
|
else {
|
|
|
+ buffer = (WCHAR*)SDL_malloc(size);
|
|
|
+ buffer[0] = 0;
|
|
|
SDL_wcslcpy(buffer, videodata->ime_composition, size);
|
|
|
}
|
|
|
+
|
|
|
s = WIN_StringToUTF8W(buffer);
|
|
|
SDL_SendEditingText(s, videodata->ime_cursor + (int)SDL_wcslen(videodata->ime_readingstring), 0);
|
|
|
SDL_free(s);
|
|
|
+ SDL_free(buffer);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -914,6 +1004,15 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
|
|
|
return SDL_FALSE;
|
|
|
|
|
|
switch (msg) {
|
|
|
+ case WM_KEYDOWN:
|
|
|
+ if (wParam == VK_PROCESSKEY)
|
|
|
+ {
|
|
|
+ videodata->ime_uicontext = 1;
|
|
|
+ trap = SDL_TRUE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ videodata->ime_uicontext = 0;
|
|
|
+ break;
|
|
|
case WM_INPUTLANGCHANGE:
|
|
|
IME_InputLangChanged(videodata);
|
|
|
break;
|
|
@@ -922,14 +1021,17 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
|
|
|
*lParam = 0;
|
|
|
}
|
|
|
break;
|
|
|
- case WM_IME_STARTCOMPOSITION:
|
|
|
+ case WM_IME_STARTCOMPOSITION:
|
|
|
+ videodata->ime_suppress_endcomposition_event = SDL_FALSE;
|
|
|
trap = SDL_TRUE;
|
|
|
break;
|
|
|
case WM_IME_COMPOSITION:
|
|
|
trap = SDL_TRUE;
|
|
|
himc = ImmGetContext(hwnd);
|
|
|
if (*lParam & GCS_RESULTSTR) {
|
|
|
+ videodata->ime_suppress_endcomposition_event = SDL_TRUE;
|
|
|
IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
|
|
|
+ SDL_SendEditingText("", 0, 0);
|
|
|
IME_SendInputEvent(videodata);
|
|
|
}
|
|
|
if (*lParam & GCS_COMPSTR) {
|
|
@@ -942,10 +1044,13 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
|
|
|
ImmReleaseContext(hwnd, himc);
|
|
|
break;
|
|
|
case WM_IME_ENDCOMPOSITION:
|
|
|
+ videodata->ime_uicontext = 0;
|
|
|
videodata->ime_composition[0] = 0;
|
|
|
videodata->ime_readingstring[0] = 0;
|
|
|
videodata->ime_cursor = 0;
|
|
|
- SDL_SendEditingText("", 0, 0);
|
|
|
+ if (videodata->ime_suppress_endcomposition_event == SDL_FALSE)
|
|
|
+ SDL_SendEditingText("", 0, 0);
|
|
|
+ videodata->ime_suppress_endcomposition_event = SDL_FALSE;
|
|
|
break;
|
|
|
case WM_IME_NOTIFY:
|
|
|
switch (wParam) {
|
|
@@ -959,10 +1064,12 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
|
|
|
break;
|
|
|
|
|
|
trap = SDL_TRUE;
|
|
|
+ videodata->ime_uicontext = 1;
|
|
|
IME_GetCandidateList(hwnd, videodata);
|
|
|
break;
|
|
|
case IMN_CLOSECANDIDATE:
|
|
|
trap = SDL_TRUE;
|
|
|
+ videodata->ime_uicontext = 0;
|
|
|
IME_HideCandidateList(videodata);
|
|
|
break;
|
|
|
case IMN_PRIVATE:
|