From d9d7104feb8c8c286f62922582c0c0600589a88f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Jun 2024 15:10:19 -0700 Subject: [PATCH] Removed unneeded Text Services Framework code from IME handling We can get the candidate list in uiless mode using ImmGetCandidateListW() once message processing has completed --- src/video/windows/SDL_windowsevents.c | 4 +- src/video/windows/SDL_windowskeyboard.c | 515 +++++------------------- src/video/windows/SDL_windowskeyboard.h | 3 +- src/video/windows/SDL_windowsvideo.h | 9 +- 4 files changed, 116 insertions(+), 415 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 533e21cbd7..3af8245777 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1051,7 +1051,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara #endif /* WMMSG_DEBUG */ #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata)) { + if (WIN_HandleIMEMessage(hwnd, msg, wParam, &lParam, data->videodata)) { return 0; } #endif @@ -2302,6 +2302,8 @@ void WIN_PumpEvents(SDL_VideoDevice *_this) #endif /*!defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/ + WIN_UpdateIMECandidates(_this); + #ifdef SDL_PLATFORM_GDK GDK_DispatchTaskQueue(); #endif diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c index 80016fea2c..95d6c3ea1b 100644 --- a/src/video/windows/SDL_windowskeyboard.c +++ b/src/video/windows/SDL_windowskeyboard.c @@ -40,6 +40,8 @@ static int IME_Init(SDL_VideoData *videodata, SDL_Window *window); static void IME_Enable(SDL_VideoData *videodata, HWND hwnd); static void IME_Disable(SDL_VideoData *videodata, HWND hwnd); static void IME_SetTextInputArea(SDL_VideoData *videodata, const SDL_Rect *rect, int cursor); +static void IME_ClearComposition(SDL_VideoData *videodata); +static void IME_GetCandidateList(SDL_VideoData *videodata, HWND hwnd); static void IME_Quit(SDL_VideoData *videodata); #endif /* !SDL_DISABLE_WINDOWS_IME */ @@ -59,10 +61,6 @@ void WIN_InitKeyboard(SDL_VideoDevice *_this) data->ime_candlistindexbase = 1; data->ime_composition_length = 32 * sizeof(WCHAR); data->ime_composition = (WCHAR *)SDL_calloc(data->ime_composition_length, sizeof(WCHAR)); - data->ime_uielemsinkcookie = TF_INVALID_COOKIE; - data->ime_alpnsinkcookie = TF_INVALID_COOKIE; - data->ime_openmodesinkcookie = TF_INVALID_COOKIE; - data->ime_convmodesinkcookie = TF_INVALID_COOKIE; #endif /* !SDL_DISABLE_WINDOWS_IME */ WIN_UpdateKeymap(SDL_FALSE); @@ -242,39 +240,29 @@ int WIN_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window) return 0; } -#ifdef SDL_DISABLE_WINDOWS_IME - int WIN_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window) { +#ifndef SDL_DISABLE_WINDOWS_IME + SDL_VideoData *videodata = _this->driverdata; + + IME_ClearComposition(videodata); +#endif return 0; } -SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) +#ifdef SDL_DISABLE_WINDOWS_IME + +SDL_bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) { return SDL_FALSE; } -#else +void WIN_UpdateIMECandidates(SDL_VideoDevice *_this) +{ + return; +} -#ifdef SDL_msctf_h_ -#define USE_INIT_GUID -#elif defined(__GNUC__) -#define USE_INIT_GUID -#endif -#ifdef USE_INIT_GUID -#undef DEFINE_GUID -#define DEFINE_GUID(n, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) static const GUID n = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E, 0x0F28, 0x11D8, 0xA8, 0x2A, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C); -DEFINE_GUID(IID_ITfUIElementSink, 0xEA1EA136, 0x19DF, 0x11D7, 0xA6, 0xD2, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C); -DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63, 0xB2F0, 0x4784, 0x8B, 0x67, 0x5E, 0x12, 0xC8, 0x70, 0x1A, 0x31); -DEFINE_GUID(IID_ITfSource, 0x4EA48A35, 0x60AE, 0x446F, 0x8F, 0xD6, 0xE6, 0xA8, 0xD8, 0x24, 0x59, 0xF7); -DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135, 0x19DF, 0x11D7, 0xA6, 0xD2, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C); -DEFINE_GUID(IID_ITfCandidateListUIElement, 0xEA1EA138, 0x19DF, 0x11D7, 0xA6, 0xD2, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C); -DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139, 0x19DF, 0x11D7, 0xA6, 0xD2, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C); -DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801, 0x2021, 0x11D2, 0x93, 0xE0, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E); -DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B, 0x6587, 0x4F23, 0xAB, 0x9E, 0x9C, 0x7D, 0x68, 0x3E, 0x3C, 0x50); -DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3, 0x7594, 0x4CB0, 0xBB, 0x58, 0x69, 0x62, 0x8F, 0x5F, 0x45, 0x8C); -#endif +#else #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) @@ -312,18 +300,12 @@ DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3, 0x7594, 0x4CB0, 0xBB, 0x58, 0x69, 0x #define SUBLANG() SUBLANGID(LANG()) static void IME_UpdateInputLocale(SDL_VideoData *videodata); -static void IME_ClearComposition(SDL_VideoData *videodata); static void IME_SetWindow(SDL_VideoData *videodata, SDL_Window *window); 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_SendClearComposition(SDL_VideoData *videodata); -static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); -static void UILess_ReleaseSinks(SDL_VideoData *videodata); -static void UILess_EnableUIUpdates(SDL_VideoData *videodata); -static void UILess_DisableUIUpdates(SDL_VideoData *videodata); - static SDL_bool WIN_ShouldShowNativeUI() { return SDL_GetHintBoolean(SDL_HINT_IME_SHOW_UI, SDL_TRUE); @@ -332,21 +314,12 @@ static SDL_bool WIN_ShouldShowNativeUI() static int IME_Init(SDL_VideoData *videodata, SDL_Window *window) { HWND hwnd = window->driverdata->hwnd; - HRESULT hResult = S_OK; if (videodata->ime_initialized) { return 0; } videodata->ime_hwnd_main = hwnd; - if (SUCCEEDED(WIN_CoInitialize())) { - videodata->ime_com_initialized = SDL_TRUE; - hResult = CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (LPVOID *)&videodata->ime_threadmgr); - if (hResult != S_OK) { - videodata->ime_available = SDL_FALSE; - return SDL_SetError("CoCreateInstance() failed, HRESULT is %08X", (unsigned int)hResult); - } - } videodata->ime_initialized = SDL_TRUE; videodata->ime_himm32 = SDL_LoadObject("imm32.dll"); if (!videodata->ime_himm32) { @@ -375,7 +348,7 @@ static int IME_Init(SDL_VideoData *videodata, SDL_Window *window) if (WIN_ShouldShowNativeUI()) { videodata->ime_uiless = SDL_FALSE; } else { - videodata->ime_uiless = UILess_SetupSinks(videodata); + videodata->ime_uiless = SDL_TRUE; } IME_UpdateInputLocale(videodata); IME_Disable(videodata, hwnd); @@ -398,7 +371,6 @@ static void IME_Enable(SDL_VideoData *videodata, HWND hwnd) videodata->ime_enabled = SDL_TRUE; IME_UpdateInputLocale(videodata); - UILess_EnableUIUpdates(videodata); } static void IME_Disable(SDL_VideoData *videodata, HWND hwnd) @@ -413,7 +385,6 @@ static void IME_Disable(SDL_VideoData *videodata, HWND hwnd) } videodata->ime_enabled = SDL_FALSE; - UILess_DisableUIUpdates(videodata); } static void IME_Quit(SDL_VideoData *videodata) @@ -422,7 +393,6 @@ static void IME_Quit(SDL_VideoData *videodata) return; } - UILess_ReleaseSinks(videodata); if (videodata->ime_hwnd_main) { ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc); } @@ -433,14 +403,6 @@ static void IME_Quit(SDL_VideoData *videodata) SDL_UnloadObject(videodata->ime_himm32); videodata->ime_himm32 = 0; } - if (videodata->ime_threadmgr) { - videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr); - videodata->ime_threadmgr = 0; - } - if (videodata->ime_com_initialized) { - WIN_CoUninitialize(); - videodata->ime_com_initialized = SDL_FALSE; - } for (int i = 0; i < videodata->ime_candcount; ++i) { SDL_free(videodata->ime_candidates[i]); videodata->ime_candidates[i] = NULL; @@ -459,10 +421,6 @@ static void IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) BOOL vertical = FALSE; UINT maxuilen = 0; - if (videodata->ime_uiless) { - return; - } - videodata->ime_readingstring[0] = 0; id = IME_GetId(videodata, 0); @@ -554,9 +512,6 @@ static void IME_InputLangChanged(SDL_VideoData *videodata) { UINT lang = PRIMLANG(); IME_UpdateInputLocale(videodata); - if (!videodata->ime_uiless) { - videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1; - } IME_SetupAPI(videodata); if (lang != PRIMLANG()) { @@ -647,11 +602,8 @@ static void IME_SetupAPI(SDL_VideoData *videodata) char ime_file[MAX_PATH + 1]; void *hime = 0; HKL hkl = 0; - videodata->GetReadingString = 0; - videodata->ShowReadingWindow = 0; - if (videodata->ime_uiless) { - return; - } + videodata->GetReadingString = NULL; + videodata->ShowReadingWindow = NULL; hkl = videodata->ime_hkl; if (!ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1)) { @@ -689,15 +641,6 @@ static void IME_SetWindow(SDL_VideoData *videodata, SDL_Window *window) SDL_zero(videodata->ime_candidate_area); } - if (videodata->ime_threadmgr) { - struct ITfDocumentMgr *document_mgr = 0; - if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) { - if (document_mgr) { - document_mgr->lpVtbl->Release(document_mgr); - } - } - } - IME_SetTextInputArea(videodata, &window->text_input_rect, window->text_input_cursor); } @@ -751,6 +694,7 @@ static void IME_UpdateInputLocale(SDL_VideoData *videodata) videodata->ime_hkl = hklnext; videodata->ime_horizontal_candidates = (PRIMLANG() == LANG_KOREAN || LANG() == LANG_CHS); + videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1; } static void IME_ClearComposition(SDL_VideoData *videodata) @@ -766,9 +710,7 @@ static void IME_ClearComposition(SDL_VideoData *videodata) } ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); - if (videodata->ime_uiless) { - ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); - } + ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); ImmReleaseContext(videodata->ime_hwnd_current, himc); @@ -924,7 +866,6 @@ static int IME_OpenCandidateList(SDL_VideoData *videodata) return 0; } - static void IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate) { if (videodata->ime_candidates[i]) { @@ -960,10 +901,83 @@ static void IME_CloseCandidateList(SDL_VideoData *videodata) } } -SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) +static void IME_GetCandidateList(SDL_VideoData *videodata, HWND hwnd) +{ + HIMC himc; + DWORD size; + LPCANDIDATELIST cand_list; + SDL_bool has_candidates = SDL_FALSE; + + himc = ImmGetContext(hwnd); + if (himc) { + size = ImmGetCandidateListW(himc, 0, NULL, 0); + if (size != 0) { + cand_list = (LPCANDIDATELIST)SDL_malloc(size); + if (cand_list != NULL) { + size = ImmGetCandidateListW(himc, 0, cand_list, size); + if (size != 0) { + if (IME_OpenCandidateList(videodata) == 0) { + UINT i, j; + UINT page_start = 0; + UINT page_size = 0; + + videodata->ime_candsel = cand_list->dwSelection; + + if (LANG() == LANG_CHS && IME_GetId(videodata, 0)) { + const UINT maxcandchar = 18; + size_t cchars = 0; + + for (i = 0; i < cand_list->dwCount; ++i) { + size_t len = SDL_wcslen((LPWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i])) + 1; + if (len + cchars > maxcandchar) { + if (i > cand_list->dwSelection) { + break; + } + + page_start = i; + cchars = len; + } else { + cchars += len; + } + } + page_size = i - page_start; + } else { + page_size = SDL_min(cand_list->dwPageSize == 0 ? MAX_CANDLIST : cand_list->dwPageSize, MAX_CANDLIST); + page_start = (cand_list->dwSelection / page_size) * page_size; + } + for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < page_size; i++, j++) { + LPCWSTR candidate = (LPCWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i]); + IME_AddCandidate(videodata, j, candidate); + } + + has_candidates = SDL_TRUE; + IME_SendCandidateList(videodata); + } + } + SDL_free(cand_list); + } + } + ImmReleaseContext(hwnd, himc); + } + + if (!has_candidates) { + IME_CloseCandidateList(videodata); + } +} + +SDL_bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) { SDL_bool trap = SDL_FALSE; HIMC himc = 0; + + if (msg == WM_IME_SETCONTEXT) { + SDL_DebugIMELog("WM_IME_SETCONTEXT\n"); + if (videodata->ime_uiless) { + *lParam = 0; + } + return SDL_FALSE; + } + if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled) { return SDL_FALSE; } @@ -981,12 +995,6 @@ SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, S SDL_DebugIMELog("WM_INPUTLANGCHANGE\n"); IME_InputLangChanged(videodata); break; - case WM_IME_SETCONTEXT: - SDL_DebugIMELog("WM_IME_SETCONTEXT\n"); - if (videodata->ime_uiless) { - *lParam = 0; - } - break; case WM_IME_STARTCOMPOSITION: SDL_DebugIMELog("WM_IME_STARTCOMPOSITION\n"); trap = SDL_TRUE; @@ -1003,10 +1011,7 @@ SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, S } if (*lParam & GCS_COMPSTR) { SDL_DebugIMELog("GCS_COMPSTR\n"); - if (!videodata->ime_uiless) { - videodata->ime_readingstring[0] = 0; - } - + videodata->ime_readingstring[0] = 0; IME_GetCompositionString(videodata, himc, GCS_COMPSTR); IME_SendEditingEvent(videodata); } @@ -1038,11 +1043,18 @@ SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, S case IMN_OPENCANDIDATE: case IMN_CHANGECANDIDATE: SDL_DebugIMELog("%s\n", wParam == IMN_OPENCANDIDATE ? "IMN_OPENCANDIDATE" : "IMN_CHANGECANDIDATE"); - trap = SDL_TRUE; + if (videodata->ime_uiless) { + videodata->ime_update_candidates = SDL_TRUE; + trap = SDL_TRUE; + } break; case IMN_CLOSECANDIDATE: SDL_DebugIMELog("IMN_CLOSECANDIDATE\n"); - trap = SDL_TRUE; + if (videodata->ime_uiless) { + videodata->ime_update_candidates = SDL_FALSE; + IME_CloseCandidateList(videodata); + trap = SDL_TRUE; + } break; case IMN_PRIVATE: { @@ -1080,321 +1092,14 @@ SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, S return trap; } -static void UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pcandlist) -{ - UINT selection = 0; - UINT count = 0; - UINT page = 0; - UINT pgcount = 0; - DWORD pgstart = 0; - DWORD pgsize = 0; - UINT i, j; - - if (IME_OpenCandidateList(videodata) < 0) { - return; - } - - pcandlist->lpVtbl->GetSelection(pcandlist, &selection); - pcandlist->lpVtbl->GetCount(pcandlist, &count); - pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page); - - pcandlist->lpVtbl->GetPageIndex(pcandlist, NULL, 0, &pgcount); - if (pgcount > 0) { - UINT *idxlist = SDL_malloc(sizeof(UINT) * pgcount); - if (idxlist) { - pcandlist->lpVtbl->GetPageIndex(pcandlist, idxlist, pgcount, &pgcount); - pgstart = idxlist[page]; - if (page < pgcount - 1) { - pgsize = SDL_min(count, idxlist[page + 1]) - pgstart; - } else { - pgsize = count - pgstart; - } - - SDL_free(idxlist); - } - } - pgsize = SDL_min(pgsize, MAX_CANDLIST); - videodata->ime_candsel = selection - pgstart; - for (i = pgstart, j = 0; (DWORD)i < count && j < pgsize; i++, j++) { - BSTR bstr; - if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) { - if (bstr) { - IME_AddCandidate(videodata, j, bstr); - SysFreeString(bstr); - } - } - } - - IME_SendCandidateList(videodata); -} - -STDMETHODIMP_(ULONG) -TSFSink_AddRef(TSFSink *sink) -{ - return ++sink->refcount; -} - -STDMETHODIMP_(ULONG) -TSFSink_Release(TSFSink *sink) -{ - --sink->refcount; - if (sink->refcount == 0) { - SDL_free(sink); - return 0; - } - return sink->refcount; -} - -STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) -{ - if (!ppv) { - return E_INVALIDARG; - } - - *ppv = 0; - if (WIN_IsEqualIID(riid, &IID_IUnknown)) { - *ppv = (IUnknown *)sink; - } else if (WIN_IsEqualIID(riid, &IID_ITfUIElementSink)) { - *ppv = (ITfUIElementSink *)sink; - } - - if (*ppv) { - TSFSink_AddRef(sink); - return S_OK; - } - return E_NOINTERFACE; -} - -ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId) -{ - ITfUIElementMgr *puiem = 0; - ITfUIElement *pelem = 0; - ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex; - - if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) { - puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem); - puiem->lpVtbl->Release(puiem); - } - return pelem; -} - -STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow) -{ - ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); - ITfReadingInformationUIElement *preading = 0; - ITfCandidateListUIElement *pcandlist = 0; - SDL_VideoData *videodata = (SDL_VideoData *)sink->data; - if (!element) { - return E_INVALIDARG; - } - - *pbShow = FALSE; - if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { - BSTR bstr; - if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { - SysFreeString(bstr); - } - preading->lpVtbl->Release(preading); - } else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { - videodata->ime_candref++; - UILess_GetCandidateList(videodata, pcandlist); - pcandlist->lpVtbl->Release(pcandlist); - } - return S_OK; -} - -STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId) -{ - ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); - ITfReadingInformationUIElement *preading = 0; - ITfCandidateListUIElement *pcandlist = 0; - SDL_VideoData *videodata = (SDL_VideoData *)sink->data; - if (!element) { - return E_INVALIDARG; - } - - if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { - BSTR bstr; - if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { - WCHAR *s = (WCHAR *)bstr; - SDL_wcslcpy(videodata->ime_readingstring, s, SDL_arraysize(videodata->ime_readingstring)); - IME_SendEditingEvent(videodata); - SysFreeString(bstr); - } - preading->lpVtbl->Release(preading); - } else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { - UILess_GetCandidateList(videodata, pcandlist); - pcandlist->lpVtbl->Release(pcandlist); - } - return S_OK; -} - -STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId) -{ - ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); - ITfReadingInformationUIElement *preading = 0; - ITfCandidateListUIElement *pcandlist = 0; - SDL_VideoData *videodata = (SDL_VideoData *)sink->data; - if (!element) { - return E_INVALIDARG; - } - - if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { - videodata->ime_readingstring[0] = 0; - IME_SendEditingEvent(videodata); - preading->lpVtbl->Release(preading); - } - if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { - videodata->ime_candref--; - if (videodata->ime_candref == 0) { - IME_CloseCandidateList(videodata); - } - - pcandlist->lpVtbl->Release(pcandlist); - } - return S_OK; -} - -STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) -{ - if (!ppv) { - return E_INVALIDARG; - } - - *ppv = 0; - if (WIN_IsEqualIID(riid, &IID_IUnknown)) { - *ppv = (IUnknown *)sink; - } else if (WIN_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink)) { - *ppv = (ITfInputProcessorProfileActivationSink *)sink; - } - - if (*ppv) { - TSFSink_AddRef(sink); - return S_OK; - } - return E_NOINTERFACE; -} - -STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags) -{ - static const GUID SDL_TF_PROFILE_DAYI = { 0x037B2C25, 0x480C, 0x4D7F, { 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A } }; - SDL_VideoData *videodata = (SDL_VideoData *)sink->data; - videodata->ime_candlistindexbase = WIN_IsEqualGUID(&SDL_TF_PROFILE_DAYI, guidProfile) ? 0 : 1; - if (WIN_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE)) { - IME_InputLangChanged((SDL_VideoData *)sink->data); - } - - IME_CloseCandidateList(videodata); - return S_OK; -} - -static void *vtUIElementSink[] = { - (void *)(UIElementSink_QueryInterface), - (void *)(TSFSink_AddRef), - (void *)(TSFSink_Release), - (void *)(UIElementSink_BeginUIElement), - (void *)(UIElementSink_UpdateUIElement), - (void *)(UIElementSink_EndUIElement) -}; - -static void *vtIPPASink[] = { - (void *)(IPPASink_QueryInterface), - (void *)(TSFSink_AddRef), - (void *)(TSFSink_Release), - (void *)(IPPASink_OnActivated) -}; - -static void UILess_EnableUIUpdates(SDL_VideoData *videodata) -{ - ITfSource *source = 0; - if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE) { - return; - } - - if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { - source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie); - source->lpVtbl->Release(source); - } -} - -static void UILess_DisableUIUpdates(SDL_VideoData *videodata) -{ - ITfSource *source = 0; - if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE) { - return; - } - - if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { - source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); - videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE; - source->lpVtbl->Release(source); - } -} - -static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata) -{ - TfClientId clientid = 0; - SDL_bool result = SDL_FALSE; - ITfSource *source = 0; - if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, (LPVOID *)&videodata->ime_threadmgrex))) { - return SDL_FALSE; - } - - if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY))) { - return SDL_FALSE; - } - - videodata->ime_uielemsink = (TSFSink *)SDL_malloc(sizeof(TSFSink)); - videodata->ime_ippasink = (TSFSink *)SDL_malloc(sizeof(TSFSink)); - - videodata->ime_uielemsink->lpVtbl = vtUIElementSink; - videodata->ime_uielemsink->refcount = 1; - videodata->ime_uielemsink->data = videodata; - - videodata->ime_ippasink->lpVtbl = vtIPPASink; - videodata->ime_ippasink->refcount = 1; - videodata->ime_ippasink->data = videodata; - - if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { - if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) { - if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) { - result = SDL_TRUE; - } - } - source->lpVtbl->Release(source); - } - return result; -} - -#define SAFE_RELEASE(p) \ - { \ - if (p) { \ - (p)->lpVtbl->Release((p)); \ - (p) = 0; \ - } \ - } - -static void UILess_ReleaseSinks(SDL_VideoData *videodata) -{ - ITfSource *source = 0; - if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { - source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); - source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie); - SAFE_RELEASE(source); - videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex); - SAFE_RELEASE(videodata->ime_threadmgrex); - TSFSink_Release(videodata->ime_uielemsink); - videodata->ime_uielemsink = 0; - TSFSink_Release(videodata->ime_ippasink); - videodata->ime_ippasink = 0; - } -} - -int WIN_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window) +void WIN_UpdateIMECandidates(SDL_VideoDevice *_this) { SDL_VideoData *videodata = _this->driverdata; - IME_ClearComposition(videodata); - return 0; + + if (videodata->ime_update_candidates) { + IME_GetCandidateList(videodata, videodata->ime_hwnd_current); + videodata->ime_update_candidates = SDL_FALSE; + } } #endif /* SDL_DISABLE_WINDOWS_IME */ diff --git a/src/video/windows/SDL_windowskeyboard.h b/src/video/windows/SDL_windowskeyboard.h index e62ce045f8..15de35f208 100644 --- a/src/video/windows/SDL_windowskeyboard.h +++ b/src/video/windows/SDL_windowskeyboard.h @@ -34,6 +34,7 @@ extern int WIN_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window); extern int WIN_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window); extern int WIN_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window); -extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata); +extern SDL_bool WIN_HandleIMEMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata); +extern void WIN_UpdateIMECandidates(SDL_VideoDevice *_this); #endif /* SDL_windowskeyboard_h_ */ diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index 3d078619ad..c2cf4677aa 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -423,7 +423,6 @@ struct SDL_VideoData #ifndef SDL_DISABLE_WINDOWS_IME SDL_bool ime_com_initialized; - struct ITfThreadMgr *ime_threadmgr; SDL_bool ime_initialized; SDL_bool ime_enabled; SDL_bool ime_available; @@ -440,6 +439,7 @@ struct SDL_VideoData int ime_selected_length; SDL_bool ime_candidates_open; + SDL_bool ime_update_candidates; char *ime_candidates[MAX_CANDLIST]; int ime_candcount; DWORD ime_candref; @@ -462,13 +462,6 @@ struct SDL_VideoData /* *INDENT-ON* */ /* clang-format on */ SDL_bool ime_uiless; - struct ITfThreadMgrEx *ime_threadmgrex; - DWORD ime_uielemsinkcookie; - DWORD ime_alpnsinkcookie; - DWORD ime_openmodesinkcookie; - DWORD ime_convmodesinkcookie; - TSFSink *ime_uielemsink; - TSFSink *ime_ippasink; #endif /* !SDL_DISABLE_WINDOWS_IME */ BYTE pre_hook_key_state[256];