comparison src/video/win32/SDL_win32keyboard.c @ 4759:863ba7d1f029

Large commit with initial reading string support, TSF UILess code, etc.
author dewyatt
date Tue, 03 Aug 2010 16:57:49 -0400
parents 11b0a6a3eb4d
children c40027ee6d47
comparison
equal deleted inserted replaced
4758:e2f4e31b41fc 4759:863ba7d1f029
24 #include "SDL_win32video.h" 24 #include "SDL_win32video.h"
25 25
26 #include "../../events/SDL_keyboard_c.h" 26 #include "../../events/SDL_keyboard_c.h"
27 #include "../../events/scancodes_win32.h" 27 #include "../../events/scancodes_win32.h"
28 28
29 #include <msctf.h>
30 #include <imm.h> 29 #include <imm.h>
30 #include <oleauto.h>
31
32 static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
33 static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
34 static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
35 static void IME_Quit(SDL_VideoData *videodata);
31 36
32 #ifndef MAPVK_VK_TO_VSC 37 #ifndef MAPVK_VK_TO_VSC
33 #define MAPVK_VK_TO_VSC 0 38 #define MAPVK_VK_TO_VSC 0
34 #endif 39 #endif
35 #ifndef MAPVK_VSC_TO_VK 40 #ifndef MAPVK_VSC_TO_VK
46 }; 51 };
47 52
48 BYTE keypad_scancodes[10] = { 53 BYTE keypad_scancodes[10] = {
49 82, 79, 80, 81, 75, 76, 77, 71, 72, 73 54 82, 79, 80, 81, 75, 76, 77, 71, 72, 73
50 }; 55 };
51
52 void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
53 void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
54 void IME_Init(SDL_VideoData *videodata, HWND hwnd);
55 void IME_Quit(SDL_VideoData *videodata);
56 56
57 void 57 void
58 WIN_InitKeyboard(_THIS) 58 WIN_InitKeyboard(_THIS)
59 { 59 {
60 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 60 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
88 } 88 }
89 89
90 data->key_layout = win32_scancode_table; 90 data->key_layout = win32_scancode_table;
91 91
92 data->ime_com_initialized = SDL_FALSE; 92 data->ime_com_initialized = SDL_FALSE;
93 data->ime_thread_mgr = 0; 93 data->ime_threadmgr = 0;
94 data->ime_initialized = SDL_FALSE; 94 data->ime_initialized = SDL_FALSE;
95 data->ime_enabled = SDL_FALSE; 95 data->ime_enabled = SDL_FALSE;
96 data->ime_available = SDL_FALSE; 96 data->ime_available = SDL_FALSE;
97 data->ime_hwnd_main = 0; 97 data->ime_hwnd_main = 0;
98 data->ime_hwnd_current = 0; 98 data->ime_hwnd_current = 0;
99 data->ime_himc = 0; 99 data->ime_himc = 0;
100 data->ime_composition[0] = 0;
101 data->ime_readingstring[0] = 0;
102 data->ime_cursor = 0;
103 data->ime_hkl = 0;
104 data->ime_himm32 = 0;
105 data->GetReadingString = 0;
106 data->ShowReadingWindow = 0;
107 data->ImmLockIMC = 0;
108 data->ImmUnlockIMC = 0;
109 data->ImmLockIMCC = 0;
110 data->ImmUnlockIMCC = 0;
111 data->ime_uiless = SDL_FALSE;
112 data->ime_threadmgrex = 0;
113 data->ime_uielemsinkcookie = TF_INVALID_COOKIE;
114 data->ime_alpnsinkcookie = TF_INVALID_COOKIE;
115 data->ime_openmodesinkcookie = TF_INVALID_COOKIE;
116 data->ime_convmodesinkcookie = TF_INVALID_COOKIE;
117 data->ime_uielemsink = 0;
118 data->ime_ippasink = 0;
100 119
101 WIN_UpdateKeymap(); 120 WIN_UpdateKeymap();
102 121
103 SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); 122 SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
104 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows"); 123 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
142 161
143 void 162 void
144 WIN_StartTextInput(_THIS) 163 WIN_StartTextInput(_THIS)
145 { 164 {
146 SDL_Window *window = SDL_GetKeyboardFocus(); 165 SDL_Window *window = SDL_GetKeyboardFocus();
147 if (window) 166 if (window) {
148 {
149 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 167 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
150 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; 168 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
151 IME_Init(videodata, hwnd); 169 IME_Init(videodata, hwnd);
152 IME_Enable(videodata, hwnd); 170 IME_Enable(videodata, hwnd);
153 } 171 }
155 173
156 void 174 void
157 WIN_StopTextInput(_THIS) 175 WIN_StopTextInput(_THIS)
158 { 176 {
159 SDL_Window *window = SDL_GetKeyboardFocus(); 177 SDL_Window *window = SDL_GetKeyboardFocus();
160 if (window) 178 if (window) {
161 {
162 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 179 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
163 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; 180 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
164 IME_Init(videodata, hwnd); 181 IME_Init(videodata, hwnd);
165 IME_Disable(videodata, hwnd); 182 IME_Disable(videodata, hwnd);
166 } 183 }
170 WIN_SetTextInputRect(_THIS, SDL_Rect *rect) 187 WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
171 { 188 {
172 189
173 } 190 }
174 191
175 void 192 #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
176 IME_Disable(SDL_VideoData *videodata, HWND hwnd) 193 #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
177 { 194
178 if (!videodata->ime_initialized || !videodata->ime_hwnd_current) 195 #define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) ))
179 return; 196 #define IMEID_VER(id) ((id) & 0xffff0000)
180 197 #define IMEID_LANG(id) ((id) & 0x0000ffff)
181 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) 198
182 ImmAssociateContext(videodata->ime_hwnd_current, NULL); 199 #define CHT_HKL_DAYI ((HKL)0xE0060404)
183 200 #define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404)
184 videodata->ime_enabled = SDL_FALSE; 201 #define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404)
185 } 202 #define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404)
186 203 #define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404)
187 void 204 #define CHT_IMEFILENAME1 "TINTLGNT.IME"
188 IME_Enable(SDL_VideoData *videodata, HWND hwnd) 205 #define CHT_IMEFILENAME2 "CINTLGNT.IME"
189 { 206 #define CHT_IMEFILENAME3 "MSTCIPHA.IME"
190 if (!videodata->ime_initialized || !videodata->ime_hwnd_current) 207 #define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2))
191 return; 208 #define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3))
192 209 #define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4))
193 if (!videodata->ime_available) { 210 #define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0))
194 IME_Disable(videodata, hwnd); 211 #define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1))
195 return; 212 #define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2))
196 } 213 #define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0))
197 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) 214 #define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0))
198 ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc); 215
199 216 #define CHS_HKL ((HKL)0xE00E0804)
200 videodata->ime_enabled = SDL_TRUE; 217 #define CHS_IMEFILENAME1 "PINTLGNT.IME"
201 } 218 #define CHS_IMEFILENAME2 "MSSCIPYA.IME"
202 219 #define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1))
203 void 220 #define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2))
221 #define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3))
222
223 #define LANG() LOWORD((videodata->ime_hkl))
224 #define PRIMLANG() ((WORD)PRIMARYLANGID(LANG()))
225 #define SUBLANG() SUBLANGID(LANG())
226
227 static void IME_UpdateInputLocale(SDL_VideoData *videodata);
228 static void IME_ClearComposition(SDL_VideoData *videodata);
229 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
230 static void IME_SetupAPI(SDL_VideoData *videodata);
231 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
232 static void IME_SendEditingEvent(SDL_VideoData *videodata);
233 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
234 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
235
236 static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata);
237 static void UILess_ReleaseSinks(SDL_VideoData *videodata);
238 static void UILess_EnableUIUpdates(SDL_VideoData *videodata);
239 static void UILess_DisableUIUpdates(SDL_VideoData *videodata);
240
241 static void
204 IME_Init(SDL_VideoData *videodata, HWND hwnd) 242 IME_Init(SDL_VideoData *videodata, HWND hwnd)
205 { 243 {
206 if (videodata->ime_initialized) 244 if (videodata->ime_initialized)
207 return; 245 return;
208 246
209 videodata->ime_hwnd_main = hwnd; 247 videodata->ime_hwnd_main = hwnd;
210 if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { 248 if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
211 videodata->ime_com_initialized = SDL_TRUE; 249 videodata->ime_com_initialized = SDL_TRUE;
212 CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_thread_mgr); 250 CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_threadmgr);
213 } 251 }
214 videodata->ime_initialized = SDL_TRUE; 252 videodata->ime_initialized = SDL_TRUE;
215 videodata->ime_hwnd_current = videodata->ime_hwnd_main; 253 videodata->ime_himm32 = LoadLibraryA("imm32.dll");
216 if (videodata->ime_thread_mgr) { 254 if (!videodata->ime_himm32) {
217 struct ITfDocumentMgr *document_mgr = 0; 255 videodata->ime_available = SDL_FALSE;
218 if (SUCCEEDED(videodata->ime_thread_mgr->lpVtbl->AssociateFocus(videodata->ime_thread_mgr, hwnd, NULL, &document_mgr))) { 256 return;
219 if (document_mgr) 257 }
220 document_mgr->lpVtbl->Release(document_mgr); 258 videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmLockIMC");
221 } 259 videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMC");
222 } 260 videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmLockIMCC");
261 videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMCC");
262
263 IME_SetWindow(videodata, hwnd);
223 videodata->ime_himc = ImmGetContext(hwnd); 264 videodata->ime_himc = ImmGetContext(hwnd);
224 ImmReleaseContext(hwnd, videodata->ime_himc); 265 ImmReleaseContext(hwnd, videodata->ime_himc);
225 if (!videodata->ime_himc) { 266 if (!videodata->ime_himc) {
226 videodata->ime_available = SDL_FALSE; 267 videodata->ime_available = SDL_FALSE;
227 IME_Disable(videodata, hwnd); 268 IME_Disable(videodata, hwnd);
228 return; 269 return;
229 } 270 }
230 videodata->ime_available = SDL_TRUE; 271 videodata->ime_available = SDL_TRUE;
272 IME_UpdateInputLocale(videodata);
273 IME_SetupAPI(videodata);
274 videodata->ime_uiless = UILess_SetupSinks(videodata);
275 IME_UpdateInputLocale(videodata);
231 IME_Disable(videodata, hwnd); 276 IME_Disable(videodata, hwnd);
232 } 277 }
233 278
234 void 279 static void
280 IME_Enable(SDL_VideoData *videodata, HWND hwnd)
281 {
282 if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
283 return;
284
285 if (!videodata->ime_available) {
286 IME_Disable(videodata, hwnd);
287 return;
288 }
289 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
290 ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
291
292 videodata->ime_enabled = SDL_TRUE;
293 IME_UpdateInputLocale(videodata);
294 UILess_EnableUIUpdates(videodata);
295 }
296
297 static void
298 IME_Disable(SDL_VideoData *videodata, HWND hwnd)
299 {
300 if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
301 return;
302
303 IME_ClearComposition(videodata);
304 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
305 ImmAssociateContext(videodata->ime_hwnd_current, NULL);
306
307 videodata->ime_enabled = SDL_FALSE;
308 UILess_DisableUIUpdates(videodata);
309 }
310
311 static void
235 IME_Quit(SDL_VideoData *videodata) 312 IME_Quit(SDL_VideoData *videodata)
236 { 313 {
237 if (!videodata->ime_initialized) 314 if (!videodata->ime_initialized)
238 return; 315 return;
239 316
317 UILess_ReleaseSinks(videodata);
240 if (videodata->ime_hwnd_main) 318 if (videodata->ime_hwnd_main)
241 ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc); 319 ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
242 320
243 videodata->ime_hwnd_main = 0; 321 videodata->ime_hwnd_main = 0;
244 videodata->ime_himc = 0; 322 videodata->ime_himc = 0;
245 if (videodata->ime_thread_mgr) 323 if (videodata->ime_himm32)
246 { 324 {
247 videodata->ime_thread_mgr->lpVtbl->Release(videodata->ime_thread_mgr); 325 FreeLibrary(videodata->ime_himm32);
248 videodata->ime_thread_mgr = 0; 326 videodata->ime_himm32 = 0;
327 }
328 if (videodata->ime_threadmgr)
329 {
330 videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr);
331 videodata->ime_threadmgr = 0;
249 } 332 }
250 if (videodata->ime_com_initialized) 333 if (videodata->ime_com_initialized)
251 { 334 {
252 CoUninitialize(); 335 CoUninitialize();
253 videodata->ime_com_initialized = SDL_FALSE; 336 videodata->ime_com_initialized = SDL_FALSE;
254 } 337 }
255 videodata->ime_initialized = SDL_FALSE; 338 videodata->ime_initialized = SDL_FALSE;
256 } 339 }
257 340
341 static void
342 IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd)
343 {
344 DWORD id = 0;
345 HIMC himc = 0;
346 WCHAR buffer[16];
347 WCHAR *s = buffer;
348 DWORD len = 0;
349 DWORD err = 0;
350 BOOL vertical = FALSE;
351 UINT maxuilen = 0;
352 static OSVERSIONINFOA osversion = {0};
353 if (videodata->ime_uiless)
354 return;
355
356 videodata->ime_readingstring[0] = 0;
357 if (!osversion.dwOSVersionInfoSize)
358 {
359 osversion.dwOSVersionInfoSize = sizeof(osversion);
360 GetVersionExA(&osversion);
361 }
362 id = IME_GetId(videodata, 0);
363 if (!id)
364 return;
365
366 himc = ImmGetContext(hwnd);
367 if (!himc)
368 return;
369
370 if (videodata->GetReadingString)
371 {
372 len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen);
373 if (len)
374 {
375 if (len > SDL_arraysize(buffer))
376 len = SDL_arraysize(buffer);
377
378 len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen);
379 }
380 SDL_wcslcpy(videodata->ime_readingstring, s, len);
381 }
382 else
383 {
384 LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc);
385 LPBYTE p = 0;
386 s = 0;
387 switch (id)
388 {
389 case IMEID_CHT_VER42:
390 case IMEID_CHT_VER43:
391 case IMEID_CHT_VER44:
392 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24);
393 if (!p)
394 break;
395
396 len = *(DWORD *)(p + 7*4 + 32*4);
397 s = (WCHAR *)(p + 56);
398 break;
399 case IMEID_CHT_VER51:
400 case IMEID_CHT_VER52:
401 case IMEID_CHS_VER53:
402 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4);
403 if (!p)
404 break;
405
406 p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
407 if (!p)
408 break;
409
410 len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
411 s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
412 break;
413 case IMEID_CHS_VER41:
414 {
415 int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7;
416 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4);
417 if (!p)
418 break;
419
420 len = *(DWORD *)(p + 7*4 + 16*2*4);
421 s = (WCHAR *)(p + 6*4 + 16*2*1);
422 }
423 break;
424 case IMEID_CHS_VER42:
425 if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT)
426 break;
427
428 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4);
429 if (!p)
430 break;
431
432 len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
433 s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
434 break;
435 }
436 if (s)
437 {
438 SDL_wcslcpy(videodata->ime_readingstring, s, len + 1);
439 }
440 videodata->ImmUnlockIMCC(lpimc->hPrivate);
441 videodata->ImmUnlockIMC(himc);
442 }
443 ImmReleaseContext(hwnd, himc);
444 IME_SendEditingEvent(videodata);
445 }
446
447 static void
448 IME_InputLangChanged(SDL_VideoData *videodata)
449 {
450 UINT uLang = PRIMLANG();
451 HWND hwndime = 0;
452 IME_UpdateInputLocale(videodata);
453 IME_SetupAPI(videodata);
454 if (uLang != PRIMLANG())
455 {
456 IME_ClearComposition(videodata);
457 }
458 hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current);
459 if (hwndime)
460 {
461 SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
462 SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
463 }
464 }
465
466 static DWORD
467 IME_GetId(SDL_VideoData *videodata, UINT uIndex)
468 {
469 static HKL hklprev = 0;
470 static DWORD dwRet[2] = {0};
471 DWORD dwVerSize = 0;
472 DWORD dwVerHandle = 0;
473 LPVOID lpVerBuffer = 0;
474 LPVOID lpVerData = 0;
475 UINT cbVerData = 0;
476 char szTemp[256];
477 HKL hkl = 0;
478 DWORD dwLang = 0;
479 if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0]))
480 return 0;
481
482 hkl = videodata->ime_hkl;
483 if (hklprev == hkl)
484 return dwRet[uIndex];
485
486 hklprev = hkl;
487 dwLang = ((DWORD)hkl & 0xffff);
488 if (videodata->ime_uiless && LANG() == LANG_CHT)
489 {
490 dwRet[0] = IMEID_CHT_VER_VISTA;
491 dwRet[1] = 0;
492 return dwRet[0];
493 }
494 if (hkl != CHT_HKL_NEW_PHONETIC
495 && hkl != CHT_HKL_NEW_CHANG_JIE
496 && hkl != CHT_HKL_NEW_QUICK
497 && hkl != CHT_HKL_HK_CANTONESE
498 && hkl != CHS_HKL)
499 {
500 dwRet[0] = dwRet[1] = 0;
501 return dwRet[uIndex];
502 }
503 if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0)
504 {
505 dwRet[0] = dwRet[1] = 0;
506 return dwRet[uIndex];
507 }
508 if (!videodata->GetReadingString)
509 {
510 #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
511 if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2
512 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2
513 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2
514 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2
515 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2
516 )
517 {
518 dwRet[0] = dwRet[1] = 0;
519 return dwRet[uIndex];
520 }
521 #undef LCID_INVARIANT
522 dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle);
523 if (dwVerSize)
524 {
525 lpVerBuffer = SDL_malloc(dwVerSize);
526 if (lpVerBuffer)
527 {
528 if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer))
529 {
530 if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData))
531 {
532 #define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData)
533 DWORD dwVer = pVerFixedInfo->dwFileVersionMS;
534 dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
535 if (videodata->GetReadingString ||
536 dwLang == LANG_CHT && (
537 dwVer == MAKEIMEVERSION(4, 2) ||
538 dwVer == MAKEIMEVERSION(4, 3) ||
539 dwVer == MAKEIMEVERSION(4, 4) ||
540 dwVer == MAKEIMEVERSION(5, 0) ||
541 dwVer == MAKEIMEVERSION(5, 1) ||
542 dwVer == MAKEIMEVERSION(5, 2) ||
543 dwVer == MAKEIMEVERSION(6, 0))
544 ||
545 dwLang == LANG_CHS && (
546 dwVer == MAKEIMEVERSION(4, 1) ||
547 dwVer == MAKEIMEVERSION(4, 2) ||
548 dwVer == MAKEIMEVERSION(5, 3))
549 )
550 {
551 dwRet[0] = dwVer | dwLang;
552 dwRet[1] = pVerFixedInfo->dwFileVersionLS;
553 SDL_free(lpVerBuffer);
554 return dwRet[0];
555 }
556 #undef pVerFixedInfo
557 }
558 }
559 }
560 SDL_free(lpVerBuffer);
561 }
562 }
563 dwRet[0] = dwRet[1] = 0;
564 return dwRet[uIndex];
565 }
566
567 static void
568 IME_SetupAPI(SDL_VideoData *videodata)
569 {
570 char ime_file[MAX_PATH + 1];
571 HMODULE hime = 0;
572 HKL hkl = 0;
573 videodata->GetReadingString = 0;
574 videodata->ShowReadingWindow = 0;
575 if (videodata->ime_uiless)
576 return;
577
578 hkl = videodata->ime_hkl;
579 if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0)
580 return;
581
582 hime = LoadLibraryA(ime_file);
583 if (!hime)
584 return;
585
586 videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
587 GetProcAddress(hime, "GetReadingString");
588 videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL))
589 GetProcAddress(hime, "ShowReadingWindow");
590
591 if (videodata->ShowReadingWindow)
592 {
593 HIMC himc = ImmGetContext(videodata->ime_hwnd_current);
594 if (himc)
595 {
596 videodata->ShowReadingWindow(himc, FALSE);
597 ImmReleaseContext(videodata->ime_hwnd_current, himc);
598 }
599 }
600 }
601
602 static void
603 IME_SetWindow(SDL_VideoData* videodata, HWND hwnd)
604 {
605 videodata->ime_hwnd_current = hwnd;
606 if (videodata->ime_threadmgr) {
607 struct ITfDocumentMgr *document_mgr = 0;
608 if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) {
609 if (document_mgr)
610 document_mgr->lpVtbl->Release(document_mgr);
611 }
612 }
613 }
614
615 static void
616 IME_UpdateInputLocale(SDL_VideoData *videodata)
617 {
618 static HKL hklPrevious = 0;
619 videodata->ime_hkl = GetKeyboardLayout(0);
620 if (hklPrevious == videodata->ime_hkl)
621 return;
622
623 hklPrevious = videodata->ime_hkl;
624 }
625
626 static void
627 IME_ClearComposition(SDL_VideoData *videodata)
628 {
629 HIMC himc = 0;
630 if (!videodata->ime_initialized)
631 return;
632
633 himc = ImmGetContext(videodata->ime_hwnd_current);
634 if (!himc)
635 return;
636
637 ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
638 if (videodata->ime_uiless)
639 ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR));
640
641 ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0);
642 ImmReleaseContext(videodata->ime_hwnd_current, himc);
643 SDL_SendEditingText("", 0, 0);
644 }
645
646 static void
647 IME_ClearEditing(SDL_VideoData *videodata)
648 {
649
650 }
651
652 static void
653 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
654 {
655 LONG Length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition));
656 if (Length < 0)
657 Length = 0;
658
659 Length /= sizeof(videodata->ime_composition[0]);
660 videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
661 if (videodata->ime_composition[videodata->ime_cursor] == 0x3000)
662 {
663 int i;
664 for (i = videodata->ime_cursor + 1; i < Length; ++i)
665 videodata->ime_composition[i - 1] = videodata->ime_composition[i];
666
667 --Length;
668 }
669 videodata->ime_composition[Length] = 0;
670 }
671
672 static void
673 IME_SendInputEvent(SDL_VideoData *videodata)
674 {
675 char *s = 0;
676 s = WIN_StringToUTF8(videodata->ime_composition);
677 SDL_SendKeyboardText(s);
678 SDL_free(s);
679
680 videodata->ime_composition[0] = 0;
681 videodata->ime_readingstring[0] = 0;
682 videodata->ime_cursor = 0;
683 }
684
685 static void
686 IME_SendEditingEvent(SDL_VideoData *videodata)
687 {
688 char *s = 0;
689 WCHAR wBuffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
690 wBuffer[0] = 0;
691 if (videodata->ime_readingstring[0])
692 {
693 size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
694 SDL_wcslcpy(wBuffer, videodata->ime_composition, len + 1);
695 SDL_wcslcat(wBuffer, videodata->ime_readingstring, sizeof(wBuffer));
696 SDL_wcslcat(wBuffer, &videodata->ime_composition[len], sizeof(wBuffer) - len);
697 }
698 else
699 {
700 SDL_wcslcpy(wBuffer, videodata->ime_composition, sizeof(videodata->ime_composition));
701 }
702 s = WIN_StringToUTF8(wBuffer);
703 SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0);
704 SDL_free(s);
705 }
706
258 SDL_bool 707 SDL_bool
259 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) 708 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
260 { 709 {
261 SDL_bool trap = SDL_FALSE; 710 SDL_bool trap = SDL_FALSE;
262 HIMC himc = 0; 711 HIMC himc = 0;
263 WCHAR Buffer[SDL_TEXTINPUTEVENT_TEXT_SIZE / 2];
264 if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled) 712 if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
265 return SDL_FALSE; 713 return SDL_FALSE;
266 714
267 switch (msg) 715 switch (msg)
268 { 716 {
269 case WM_INPUTLANGCHANGE: 717 case WM_INPUTLANGCHANGE:
718 //IME_InputLangChanged(videodata);
270 break; 719 break;
271 case WM_IME_SETCONTEXT: 720 case WM_IME_SETCONTEXT:
272 *lParam = 0; 721 *lParam = 0;
273 break; 722 break;
274 case WM_IME_STARTCOMPOSITION: 723 case WM_IME_STARTCOMPOSITION:
277 case WM_IME_COMPOSITION: 726 case WM_IME_COMPOSITION:
278 trap = SDL_TRUE; 727 trap = SDL_TRUE;
279 himc = ImmGetContext(hwnd); 728 himc = ImmGetContext(hwnd);
280 if (*lParam & GCS_RESULTSTR) 729 if (*lParam & GCS_RESULTSTR)
281 { 730 {
282 LONG Length = 0; 731 IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
283 char *s = 0; 732 IME_SendInputEvent(videodata);
284 Length = ImmGetCompositionStringW(himc, GCS_RESULTSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
285 Buffer[Length / sizeof(Buffer[0])] = 0;
286 s = WIN_StringToUTF8(Buffer);
287 SDL_SendKeyboardText(s);
288 SDL_free(s);
289 } 733 }
290 if (*lParam & GCS_COMPSTR) 734 if (*lParam & GCS_COMPSTR)
291 { 735 {
292 LONG Length = 0; 736 if (!videodata->ime_uiless)
293 DWORD Cursor = 0; 737 videodata->ime_readingstring[0] = 0;
294 char *s = 0; 738
295 Length = ImmGetCompositionStringW(himc, GCS_COMPSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0])); 739 IME_GetCompositionString(videodata, himc, GCS_COMPSTR);
296 Buffer[Length / sizeof(Buffer[0])] = 0; 740 IME_SendEditingEvent(videodata);
297 s = WIN_StringToUTF8(Buffer);
298 Cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
299 SDL_SendEditingText(s, Cursor, 0);
300 SDL_free(s);
301 } 741 }
302 ImmReleaseContext(hwnd, himc); 742 ImmReleaseContext(hwnd, himc);
303 break; 743 break;
304 case WM_IME_ENDCOMPOSITION: 744 case WM_IME_ENDCOMPOSITION:
305 SDL_SendKeyboardText(""); 745 videodata->ime_composition[0] = 0;
746 videodata->ime_readingstring[0] = 0;
747 videodata->ime_cursor = 0;
748 SDL_SendEditingText("", 0, 0);
306 break; 749 break;
307 case WM_IME_NOTIFY: 750 case WM_IME_NOTIFY:
308 switch (wParam) 751 switch (wParam)
309 { 752 {
310 case IMN_SETCONVERSIONMODE: 753 case IMN_SETCONVERSIONMODE:
311 break;
312 case IMN_SETOPENSTATUS: 754 case IMN_SETOPENSTATUS:
755 IME_UpdateInputLocale(videodata);
313 break; 756 break;
314 case IMN_OPENCANDIDATE: 757 case IMN_OPENCANDIDATE:
315 case IMN_CHANGECANDIDATE: 758 case IMN_CHANGECANDIDATE:
316 trap = SDL_TRUE; 759 trap = SDL_TRUE;
317 break; 760 break;
318 case IMN_CLOSECANDIDATE: 761 case IMN_CLOSECANDIDATE:
319 trap = SDL_TRUE; 762 trap = SDL_TRUE;
320 break; 763 break;
321 case IMN_PRIVATE: 764 case IMN_PRIVATE:
765 {
766 DWORD dwId = IME_GetId(videodata, 0);
767 IME_GetReadingString(videodata, hwnd);
768 switch (dwId)
769 {
770 case IMEID_CHT_VER42:
771 case IMEID_CHT_VER43:
772 case IMEID_CHT_VER44:
773 case IMEID_CHS_VER41:
774 case IMEID_CHS_VER42:
775 if (*lParam == 1 || *lParam == 2)
776 trap = SDL_TRUE;
777
778 break;
779 case IMEID_CHT_VER50:
780 case IMEID_CHT_VER51:
781 case IMEID_CHT_VER52:
782 case IMEID_CHT_VER60:
783 case IMEID_CHS_VER53:
784 if (*lParam == 16
785 || *lParam == 17
786 || *lParam == 26
787 || *lParam == 27
788 || *lParam == 28)
789 trap = SDL_TRUE;
790 break;
791 }
792 }
322 break; 793 break;
323 default: 794 default:
324 trap = SDL_TRUE; 795 trap = SDL_TRUE;
325 break; 796 break;
326 } 797 }
327 break; 798 break;
328 } 799 }
329 return trap; 800 return trap;
330 } 801 }
331 802
803 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
804 {
805 return ++sink->refcount;
806 }
807
808 STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink)
809 {
810 --sink->refcount;
811 if (sink->refcount == 0)
812 {
813 SDL_free(sink);
814 return 0;
815 }
816 return sink->refcount;
817 }
818
819 STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
820 {
821 if (!ppv)
822 return E_INVALIDARG;
823
824 *ppv = 0;
825 if (SDL_IsEqualIID(riid, &IID_IUnknown))
826 *ppv = (IUnknown *)sink;
827 else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink))
828 *ppv = (ITfUIElementSink *)sink;
829
830 if (*ppv)
831 {
832 TSFSink_AddRef(sink);
833 return S_OK;
834 }
835 return E_NOINTERFACE;
836 }
837
838 ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId)
839 {
840 ITfUIElementMgr *puiem = 0;
841 ITfUIElement *pelem = 0;
842 ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex;
843
844 if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem)))
845 {
846 puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem);
847 puiem->lpVtbl->Release(puiem);
848 }
849 return pelem;
850 }
851
852 STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow)
853 {
854 ITfUIElement *pElement = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
855 ITfReadingInformationUIElement *preading = 0;
856 ITfCandidateListUIElement *pcandidates = 0;
857 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
858 if (!pElement)
859 return E_INVALIDARG;
860
861 *pbShow = FALSE;
862 if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading)))
863 {
864 BSTR bstr;
865 if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr)
866 {
867 WCHAR *s = (WCHAR *)bstr;
868 SysFreeString(bstr);
869 }
870 preading->lpVtbl->Release(preading);
871 }
872 else if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfCandidateListUIElement, (PVOID *)&pcandidates)))
873 {
874 pcandidates->lpVtbl->Release(pcandidates);
875 }
876 return S_OK;
877 }
878
879 STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId)
880 {
881 ITfUIElement *pElement = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
882 ITfReadingInformationUIElement *preading = 0;
883 ITfCandidateListUIElement *pcandidates = 0;
884 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
885 if (!pElement)
886 return E_INVALIDARG;
887
888 if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading)))
889 {
890 BSTR bstr;
891 if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr)
892 {
893 WCHAR *s = (WCHAR *)bstr;
894 SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring));
895 IME_SendEditingEvent(videodata);
896 SysFreeString(bstr);
897 }
898 preading->lpVtbl->Release(preading);
899 }
900 else if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfCandidateListUIElement, (PVOID *)&pcandidates)))
901 {
902 pcandidates->lpVtbl->Release(pcandidates);
903 }
904 return S_OK;
905 }
906
907 STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId)
908 {
909 ITfUIElement *pElement = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
910 ITfReadingInformationUIElement *preading = 0;
911 ITfCandidateListUIElement *pcandidates = 0;
912 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
913 if (!pElement)
914 return E_INVALIDARG;
915
916 if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading)))
917 {
918 videodata->ime_readingstring[0] = 0;
919 IME_SendEditingEvent(videodata);
920 preading->lpVtbl->Release(preading);
921 }
922 else if (SUCCEEDED(pElement->lpVtbl->QueryInterface(pElement, &IID_ITfCandidateListUIElement, (PVOID *)&pcandidates)))
923 {
924 pcandidates->lpVtbl->Release(pcandidates);
925 }
926 return S_OK;
927 }
928
929 STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
930 {
931 if (!ppv)
932 return E_INVALIDARG;
933
934 *ppv = 0;
935 if (SDL_IsEqualIID(riid, &IID_IUnknown))
936 *ppv = (IUnknown *)sink;
937 else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink))
938 *ppv = (ITfInputProcessorProfileActivationSink *)sink;
939
940 if (*ppv)
941 {
942 TSFSink_AddRef(sink);
943 return S_OK;
944 }
945 return E_NOINTERFACE;
946 }
947
948 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
949 {
950 if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
951 IME_InputLangChanged((SDL_VideoData *)sink->data);
952
953 return S_OK;
954 }
955
956 static void *vtUIElementSink[] = {
957 (void *)(UIElementSink_QueryInterface),
958 (void *)(TSFSink_AddRef),
959 (void *)(TSFSink_Release),
960 (void *)(UIElementSink_BeginUIElement),
961 (void *)(UIElementSink_UpdateUIElement),
962 (void *)(UIElementSink_EndUIElement)
963 };
964
965 static void *vtIPPASink[] = {
966 (void *)(IPPASink_QueryInterface),
967 (void *)(TSFSink_AddRef),
968 (void *)(TSFSink_Release),
969 (void *)(IPPASink_OnActivated)
970 };
971
972 static void
973 UILess_EnableUIUpdates(SDL_VideoData *videodata)
974 {
975 ITfSource *source = 0;
976 if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE)
977 return;
978
979 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source)))
980 {
981 source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie);
982 source->lpVtbl->Release(source);
983 }
984 }
985
986 static void
987 UILess_DisableUIUpdates(SDL_VideoData *videodata)
988 {
989 ITfSource *source = 0;
990 if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE)
991 return;
992
993 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source)))
994 {
995 source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
996 videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE;
997 source->lpVtbl->Release(source);
998 }
999 }
1000
1001 static SDL_bool
1002 UILess_SetupSinks(SDL_VideoData *videodata)
1003 {
1004 TfClientId clientid = 0;
1005 SDL_bool result = SDL_FALSE;
1006 ITfSource *source = 0;
1007 if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, &videodata->ime_threadmgrex)))
1008 return SDL_FALSE;
1009
1010 if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY)))
1011 return SDL_FALSE;
1012
1013 videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink));
1014 videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink));
1015
1016 videodata->ime_uielemsink->lpVtbl = vtUIElementSink;
1017 videodata->ime_uielemsink->refcount = 1;
1018 videodata->ime_uielemsink->data = videodata;
1019
1020 videodata->ime_ippasink->lpVtbl = vtIPPASink;
1021 videodata->ime_ippasink->refcount = 1;
1022 videodata->ime_ippasink->data = videodata;
1023
1024 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source)))
1025 {
1026 if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie)))
1027 {
1028 if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie)))
1029 {
1030 result = SDL_TRUE;
1031 }
1032 }
1033 source->lpVtbl->Release(source);
1034 }
1035 return result;
1036 }
1037
1038 #define SAFE_RELEASE(p) \
1039 { \
1040 if (p) { \
1041 (p)->lpVtbl->Release((p)); \
1042 (p) = 0; \
1043 } \
1044 }
1045
1046 static void
1047 UILess_ReleaseSinks(SDL_VideoData *videodata)
1048 {
1049 ITfSource *Source = 0;
1050 if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, &Source)))
1051 {
1052 Source->lpVtbl->UnadviseSink(Source, videodata->ime_uielemsinkcookie);
1053 Source->lpVtbl->UnadviseSink(Source, videodata->ime_alpnsinkcookie);
1054 SAFE_RELEASE(Source);
1055 videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex);
1056 SAFE_RELEASE(videodata->ime_threadmgrex);
1057 TSFSink_Release(videodata->ime_uielemsink);
1058 videodata->ime_uielemsink = 0;
1059 TSFSink_Release(videodata->ime_ippasink);
1060 videodata->ime_ippasink = 0;
1061 }
1062 }
1063
332 /* vi: set ts=4 sw=4 expandtab: */ 1064 /* vi: set ts=4 sw=4 expandtab: */