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
This commit is contained in:
Sam Lantinga 2024-06-28 15:10:19 -07:00
parent bdd531986b
commit d9d7104feb
4 changed files with 116 additions and 415 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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_ */

View File

@ -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];