diff -r 08db6a6f6c23 include/SDL_events.h --- a/include/SDL_events.h Sat Aug 31 22:58:11 2019 +0200 +++ b/include/SDL_events.h Wed Sep 04 16:40:56 2019 +0900 @@ -96,6 +96,7 @@ SDL_KEYDOWN = 0x300, /**< Key pressed */ SDL_KEYUP, /**< Key released */ SDL_TEXTEDITING, /**< Keyboard text editing (composition) */ + SDL_TEXTEDITINGEX, /**< Keyboard text editing with extra information */ SDL_TEXTINPUT, /**< Keyboard text input */ SDL_KEYMAPCHANGED, /**< Keymap changed due to a system event such as an input language or keyboard layout change. @@ -220,7 +221,8 @@ SDL_Keysym keysym; /**< The key that was pressed or released */ } SDL_KeyboardEvent; -#define SDL_TEXTEDITINGEVENT_TEXT_SIZE (32) +#define SDL_TEXTEDITINGEVENT_TEXT_MINI (32) +#define SDL_TEXTEDITINGEVENT_TEXT_SIZE (512) /** * \brief Keyboard text editing event structure (event.edit.*) */ @@ -229,13 +231,35 @@ Uint32 type; /**< ::SDL_TEXTEDITING */ Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ Uint32 windowID; /**< The window with keyboard focus, if any */ - char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; /**< The editing text */ - Sint32 start; /**< The start cursor of selected editing text */ - Sint32 length; /**< The length of selected editing text */ + char text[SDL_TEXTEDITINGEVENT_TEXT_MINI]; /**< The editing text */ + Sint32 start; /**< The cursor, where the reading text starts if any */ + Sint32 length; /**< The length of the reading text */ } SDL_TextEditingEvent; +#define MAX_CANDLIST (10) +#define MAX_CANDLENGTH (256) +/** + * \brief Keyboard text editing event structure with extra information (event.editx.*) + */ +typedef struct SDL_TextEditingExEvent +{ + Uint32 type; /**< ::SDL_TEXTEDITINGEX */ + Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ + Uint32 windowID; /**< The window with keyboard focus, if any */ + char* composition; /**< The editing text, needs freeing */ + SDL_bool commit; /**< Whether the event should be treated as TEXTINPUT */ + Uint16 cursor; /**< The cursor position */ + // char* readingstring; /**< The pronunciation, needs freeing */ + Uint16 target_start; /**< The starting point of editing part */ + Uint16 target_end; /**< The length of editing part */ + SDL_bool candshow; /**< Whether to show candidate list */ + // Uint8 candcount; /**< The number of the candidates */ + char* candidates; /**< The candidate array[MAX_CANDLIST][MAX_CANDLENGTH], needs freeing */ + Sint8 candsel; /**< The cursor of the candidate list */ +} SDL_TextEditingExEvent; -#define SDL_TEXTINPUTEVENT_TEXT_SIZE (32) +#define SDL_TEXTINPUTEVENT_TEXT_MINI (32) +#define SDL_TEXTINPUTEVENT_TEXT_SIZE (512) /** * \brief Keyboard text input event structure (event.text.*) */ @@ -244,7 +268,7 @@ Uint32 type; /**< ::SDL_TEXTINPUT */ Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ Uint32 windowID; /**< The window with keyboard focus, if any */ - char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; /**< The input text */ + char text[SDL_TEXTINPUTEVENT_TEXT_MINI]; /**< The input text */ } SDL_TextInputEvent; /** @@ -563,6 +587,7 @@ SDL_WindowEvent window; /**< Window event data */ SDL_KeyboardEvent key; /**< Keyboard event data */ SDL_TextEditingEvent edit; /**< Text editing event data */ + SDL_TextEditingExEvent editx; /**< Text editing EX event data */ SDL_TextInputEvent text; /**< Text input event data */ SDL_MouseMotionEvent motion; /**< Mouse motion event data */ SDL_MouseButtonEvent button; /**< Mouse button event data */ diff -r 08db6a6f6c23 src/events/SDL_events.c --- a/src/events/SDL_events.c Sat Aug 31 22:58:11 2019 +0200 +++ b/src/events/SDL_events.c Wed Sep 04 16:40:56 2019 +0900 @@ -439,6 +439,7 @@ /* Process most event types */ SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); + SDL_EventState(SDL_TEXTEDITINGEX, SDL_DISABLE); SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE); #if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */ SDL_EventState(SDL_DROPFILE, SDL_DISABLE); diff -r 08db6a6f6c23 src/events/SDL_keyboard.c --- a/src/events/SDL_keyboard.c Sat Aug 31 22:58:11 2019 +0200 +++ b/src/events/SDL_keyboard.c Wed Sep 04 16:40:56 2019 +0900 @@ -652,7 +652,7 @@ 0, 0); /* Ensures IME compositions are committed */ - if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { + if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY) || SDL_EventState(SDL_TEXTEDITINGEX, SDL_QUERY)) { SDL_VideoDevice *video = SDL_GetVideoDevice(); if (video && video->StopTextInput) { video->StopTextInput(video); @@ -666,7 +666,7 @@ SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); - if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { + if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY) || SDL_EventState(SDL_TEXTEDITINGEX, SDL_QUERY)) { SDL_VideoDevice *video = SDL_GetVideoDevice(); if (video && video->StartTextInput) { video->StartTextInput(video); @@ -828,6 +828,52 @@ return (posted); } +int SDL_SendEditingTextEx(char* composition, SDL_bool commit, + Uint16 cursor, /* char* readingstring, */ + Uint16 target_start, Uint16 target_end, + SDL_bool candshow, /* Uint8 candcount, */ + WCHAR* candidates, Sint8 candsel) +{ + SDL_Keyboard* keyboard = &SDL_keyboard; + int posted = 0; + + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_TEXTEDITINGEX) == SDL_ENABLE) { + SDL_Event event; + char* newcands = NULL; +#define U8_CH_LEN (2) /* 3 or 4 is better */ + if (candidates) { + size_t i; + newcands = (char*)SDL_calloc(MAX_CANDLIST, MAX_CANDLENGTH * U8_CH_LEN); + for (i = 0; i < MAX_CANDLIST; i++) { + char* u8can = SDL_iconv_string("UTF-8", "UTF-16LE", + (char*)(candidates + (i * MAX_CANDLENGTH)), MAX_CANDLENGTH); + if (u8can) { + SDL_utf8strlcpy(newcands + (i * MAX_CANDLENGTH * U8_CH_LEN), + u8can, MAX_CANDLENGTH); + SDL_free(u8can); + } + } + } +#undef U8_CH_LEN + event.editx.type = SDL_TEXTEDITINGEX; + event.editx.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.editx.composition = SDL_strdup(composition); /* needs freeing */ + event.editx.commit = commit; + event.editx.cursor = cursor; + // event.editx.readingstring = SDL_strdup(readingstring); /* needs freeing */ + event.editx.target_start = target_start; + event.editx.target_end = target_end; + event.editx.candshow = candshow; + // event.editx.candcount = candcount; + event.editx.candidates = newcands; /* needs freeing if not null */ + event.editx.candsel = candsel; + posted = (SDL_PushEvent(&event) > 0); + } + return (posted); +} + + void SDL_KeyboardQuit(void) { diff -r 08db6a6f6c23 src/events/SDL_keyboard_c.h --- a/src/events/SDL_keyboard_c.h Sat Aug 31 22:58:11 2019 +0200 +++ b/src/events/SDL_keyboard_c.h Wed Sep 04 16:40:56 2019 +0900 @@ -53,8 +53,17 @@ /* Send keyboard text input */ extern int SDL_SendKeyboardText(const char *text); -/* Send editing text for selected range from start to end */ -extern int SDL_SendEditingText(const char *text, int start, int end); +/* Send editing text which may contain a reading string in specified length from start */ +extern int SDL_SendEditingText(const char *text, int read_start, int read_length); + +/* Send editing text with extra information such as cursor, pronunciation, + target range, and candidate list */ +extern int SDL_SendEditingTextEx(char *composition, SDL_bool commit, + Uint16 cursor, // char *readingstring, + Uint16 target_start, Uint16 target_end, + SDL_bool candshow, // Uint8 candcount, + WCHAR *candidates, Sint8 candsel); + /* Shutdown the keyboard subsystem */ extern void SDL_KeyboardQuit(void); diff -r 08db6a6f6c23 src/video/SDL_video.c --- a/src/video/SDL_video.c Sat Aug 31 22:58:11 2019 +0200 +++ b/src/video/SDL_video.c Wed Sep 04 16:40:56 2019 +0900 @@ -3759,6 +3759,7 @@ /* First, enable text events */ SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE); + /* SDL_TEXTEDITINGEX needs explicit enabling */ /* Then show the on-screen keyboard, if any */ window = SDL_GetFocusWindow(); @@ -3797,6 +3798,7 @@ /* Finally disable text events */ SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); + /* XXX: disable SDL_TEXTEDITINGEX ? */ } void diff -r 08db6a6f6c23 src/video/windows/SDL_windowskeyboard.c --- a/src/video/windows/SDL_windowskeyboard.c Sat Aug 31 22:58:11 2019 +0200 +++ b/src/video/windows/SDL_windowskeyboard.c Wed Sep 04 16:40:56 2019 +0900 @@ -64,6 +64,8 @@ data->ime_composition[0] = 0; data->ime_readingstring[0] = 0; data->ime_cursor = 0; + data->ime_target_start = 0; + data->ime_target_end = 0; data->ime_candlist = SDL_FALSE; SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates)); @@ -329,6 +331,7 @@ static void IME_SetupAPI(SDL_VideoData *videodata); static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex); static void IME_SendEditingEvent(SDL_VideoData *videodata); +static void IME_SendEditingExEvent(SDL_VideoData* videodata, SDL_bool commit); static void IME_DestroyTextures(SDL_VideoData *videodata); static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); @@ -530,6 +533,7 @@ } ImmReleaseContext(hwnd, himc); IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); } static void @@ -724,6 +728,7 @@ ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); ImmReleaseContext(videodata->ime_hwnd_current, himc); SDL_SendEditingText("", 0, 0); + SDL_SendEditingTextEx("", SDL_FALSE, 0, 0, 0, SDL_FALSE, NULL, 0); } static void @@ -743,6 +748,19 @@ --length; } videodata->ime_composition[length] = 0; + + LONG attrs_size = ImmGetCompositionStringW(himc, GCS_COMPATTR, NULL, 0); + if (attrs_size) { + char* attrs = (char *)SDL_calloc(attrs_size, sizeof(char)); + ImmGetCompositionStringW(himc, GCS_COMPATTR, attrs, attrs_size); + Uint16 i; + for (i = 0; i < attrs_size / sizeof(attrs[0]) && + attrs[i] != ATTR_TARGET_CONVERTED && attrs[i] != ATTR_TARGET_NOTCONVERTED; i++); + videodata->ime_target_start = i; + for (; i < attrs_size / sizeof(attrs[0]) && + attrs[i] == ATTR_TARGET_CONVERTED || attrs[i] == ATTR_TARGET_NOTCONVERTED; i++); + videodata->ime_target_end = i; + } } static void @@ -756,30 +774,46 @@ videodata->ime_composition[0] = 0; videodata->ime_readingstring[0] = 0; videodata->ime_cursor = 0; + videodata->ime_target_start = 0; + videodata->ime_target_end = 0; } static void IME_SendEditingEvent(SDL_VideoData *videodata) { char *s = 0; + size_t cursor; WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; const size_t size = SDL_arraysize(buffer); buffer[0] = 0; if (videodata->ime_readingstring[0]) { - size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor); - SDL_wcslcpy(buffer, videodata->ime_composition, len + 1); + cursor = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor); + SDL_wcslcpy(buffer, videodata->ime_composition, cursor + 1); SDL_wcslcat(buffer, videodata->ime_readingstring, size); - SDL_wcslcat(buffer, &videodata->ime_composition[len], size); + SDL_wcslcat(buffer, &videodata->ime_composition[cursor], size); } else { - SDL_wcslcpy(buffer, videodata->ime_composition, size); + cursor = SDL_wcslcpy(buffer, videodata->ime_composition, size); } s = WIN_StringToUTF8(buffer); - SDL_SendEditingText(s, videodata->ime_cursor + (int)SDL_wcslen(videodata->ime_readingstring), 0); + SDL_SendEditingText(s, (int)cursor, (int)SDL_wcslen(videodata->ime_readingstring)); SDL_free(s); } static void +IME_SendEditingExEvent(SDL_VideoData* videodata, SDL_bool commit) +{ + char* composit = WIN_StringToUTF8(videodata->ime_composition); + // char* readings = WIN_StringToUTF8(videodata->ime_readingstring); + SDL_SendEditingTextEx(composit, commit, videodata->ime_cursor, // readings, + videodata->ime_target_start, videodata->ime_target_end, + videodata->ime_candlist, // videodata->ime_candcount, + videodata->ime_candidates, videodata->ime_candsel); + SDL_free(composit); + // SDL_free(readings); +} + +static void IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate) { LPWSTR dst = videodata->ime_candidates[i]; @@ -855,6 +889,7 @@ videodata->ime_candlist = SDL_TRUE; IME_DestroyTextures(videodata); IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); } static void @@ -864,6 +899,7 @@ videodata->ime_candlist = SDL_FALSE; IME_DestroyTextures(videodata); IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); } SDL_bool @@ -889,6 +925,7 @@ himc = ImmGetContext(hwnd); if (*lParam & GCS_RESULTSTR) { IME_GetCompositionString(videodata, himc, GCS_RESULTSTR); + IME_SendEditingExEvent(videodata, SDL_TRUE); IME_SendInputEvent(videodata); } if (*lParam & GCS_COMPSTR) { @@ -897,6 +934,7 @@ IME_GetCompositionString(videodata, himc, GCS_COMPSTR); IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); } ImmReleaseContext(hwnd, himc); break; @@ -904,7 +942,8 @@ videodata->ime_composition[0] = 0; videodata->ime_readingstring[0] = 0; videodata->ime_cursor = 0; - SDL_SendEditingText("", 0, 0); + SDL_SendEditingText("", 0, 0, 0, 0); + SDL_SendEditingTextEx("", SDL_FALSE, 0, 0, 0, SDL_FALSE, NULL, 0); break; case WM_IME_NOTIFY: switch (wParam) { @@ -1112,6 +1151,7 @@ WCHAR *s = (WCHAR *)bstr; SDL_wcslcpy(videodata->ime_readingstring, s, SDL_arraysize(videodata->ime_readingstring)); IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); SysFreeString(bstr); } preading->lpVtbl->Release(preading); @@ -1135,6 +1175,7 @@ if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { videodata->ime_readingstring[0] = 0; IME_SendEditingEvent(videodata); + IME_SendEditingExEvent(videodata, SDL_FALSE); preading->lpVtbl->Release(preading); } if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { diff -r 08db6a6f6c23 src/video/windows/SDL_windowsvideo.h --- a/src/video/windows/SDL_windowsvideo.h Sat Aug 31 22:58:11 2019 +0200 +++ b/src/video/windows/SDL_windowsvideo.h Wed Sep 04 16:40:56 2019 +0900 @@ -35,9 +35,6 @@ #include -#define MAX_CANDLIST 10 -#define MAX_CANDLENGTH 256 - #include "SDL_windowsclipboard.h" #include "SDL_windowsevents.h" #include "SDL_windowskeyboard.h" @@ -153,6 +150,8 @@ WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; WCHAR ime_readingstring[16]; int ime_cursor; + Uint16 ime_target_start; + Uint16 ime_target_end; SDL_bool ime_candlist; WCHAR ime_candidates[MAX_CANDLIST][MAX_CANDLENGTH];