SDL 1.3 is now under the zlib license.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_config.h"
24 #define SDL_DISABLE_WINDOWS_IME
27 #include "SDL_windowsvideo.h"
29 #include "../../events/SDL_keyboard_c.h"
30 #include "../../events/scancodes_windows.h"
35 #ifndef SDL_DISABLE_WINDOWS_IME
36 static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
37 static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
38 static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
39 static void IME_Quit(SDL_VideoData *videodata);
40 #endif /* !SDL_DISABLE_WINDOWS_IME */
42 #ifndef MAPVK_VK_TO_VSC
43 #define MAPVK_VK_TO_VSC 0
45 #ifndef MAPVK_VSC_TO_VK
46 #define MAPVK_VSC_TO_VK 1
48 #ifndef MAPVK_VK_TO_CHAR
49 #define MAPVK_VK_TO_CHAR 2
52 /* Alphabetic scancodes for PC keyboards */
53 BYTE alpha_scancodes[26] = {
54 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24,
55 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44
58 BYTE keypad_scancodes[10] = {
59 82, 79, 80, 81, 75, 76, 77, 71, 72, 73
63 WIN_InitKeyboard(_THIS)
65 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
68 /* Make sure the alpha scancodes are correct. T isn't usually remapped */
69 if (MapVirtualKey('T', MAPVK_VK_TO_VSC) != alpha_scancodes['T' - 'A']) {
72 ("Fixing alpha scancode map, assuming US QWERTY layout!\nPlease send the following 26 lines of output to the SDL mailing list <sdl@libsdl.org>, including a description of your keyboard hardware.\n");
74 for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) {
75 alpha_scancodes[i] = MapVirtualKey('A' + i, MAPVK_VK_TO_VSC);
77 printf("%d = %d\n", i, alpha_scancodes[i]);
81 if (MapVirtualKey(VK_NUMPAD0, MAPVK_VK_TO_VSC) != keypad_scancodes[0]) {
84 ("Fixing keypad scancode map!\nPlease send the following 10 lines of output to the SDL mailing list <sdl@libsdl.org>, including a description of your keyboard hardware.\n");
86 for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
88 MapVirtualKey(VK_NUMPAD0 + i, MAPVK_VK_TO_VSC);
90 printf("%d = %d\n", i, keypad_scancodes[i]);
95 data->key_layout = windows_scancode_table;
97 data->ime_com_initialized = SDL_FALSE;
98 data->ime_threadmgr = 0;
99 data->ime_initialized = SDL_FALSE;
100 data->ime_enabled = SDL_FALSE;
101 data->ime_available = SDL_FALSE;
102 data->ime_hwnd_main = 0;
103 data->ime_hwnd_current = 0;
105 data->ime_composition[0] = 0;
106 data->ime_readingstring[0] = 0;
107 data->ime_cursor = 0;
109 data->ime_candlist = SDL_FALSE;
110 SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates));
111 data->ime_candcount = 0;
112 data->ime_candref = 0;
113 data->ime_candsel = 0;
114 data->ime_candpgsize = 0;
115 data->ime_candlistindexbase = 0;
116 data->ime_candvertical = SDL_TRUE;
118 data->ime_dirty = SDL_FALSE;
119 SDL_memset(&data->ime_rect, 0, sizeof(data->ime_rect));
120 SDL_memset(&data->ime_candlistrect, 0, sizeof(data->ime_candlistrect));
121 data->ime_winwidth = 0;
122 data->ime_winheight = 0;
125 data->ime_himm32 = 0;
126 data->GetReadingString = 0;
127 data->ShowReadingWindow = 0;
128 data->ImmLockIMC = 0;
129 data->ImmUnlockIMC = 0;
130 data->ImmLockIMCC = 0;
131 data->ImmUnlockIMCC = 0;
132 data->ime_uiless = SDL_FALSE;
133 data->ime_threadmgrex = 0;
134 data->ime_uielemsinkcookie = TF_INVALID_COOKIE;
135 data->ime_alpnsinkcookie = TF_INVALID_COOKIE;
136 data->ime_openmodesinkcookie = TF_INVALID_COOKIE;
137 data->ime_convmodesinkcookie = TF_INVALID_COOKIE;
138 data->ime_uielemsink = 0;
139 data->ime_ippasink = 0;
143 SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
144 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
145 SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows");
152 SDL_Scancode scancode;
153 SDL_Keycode keymap[SDL_NUM_SCANCODES];
155 SDL_GetDefaultKeymap(keymap);
157 for (i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
159 /* Make sure this scancode is a valid character scancode */
160 scancode = windows_scancode_table[i];
161 if (scancode == SDL_SCANCODE_UNKNOWN || keymap[scancode] >= 127) {
165 /* Alphabetic keys are handled specially, since Windows remaps them */
166 if (i >= 'A' && i <= 'Z') {
167 BYTE vsc = alpha_scancodes[i - 'A'];
168 keymap[scancode] = MapVirtualKey(vsc, MAPVK_VSC_TO_VK) + 0x20;
170 keymap[scancode] = (MapVirtualKey(i, MAPVK_VK_TO_CHAR) & 0x7FFF);
173 SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
177 WIN_QuitKeyboard(_THIS)
179 #ifndef SDL_DISABLE_WINDOWS_IME
180 IME_Quit((SDL_VideoData *)_this->driverdata);
185 WIN_StartTextInput(_THIS)
187 #ifndef SDL_DISABLE_WINDOWS_IME
188 SDL_Window *window = SDL_GetKeyboardFocus();
190 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
191 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
192 SDL_GetWindowSize(window, &videodata->ime_winwidth, &videodata->ime_winheight);
193 IME_Init(videodata, hwnd);
194 IME_Enable(videodata, hwnd);
196 #endif /* !SDL_DISABLE_WINDOWS_IME */
200 WIN_StopTextInput(_THIS)
202 #ifndef SDL_DISABLE_WINDOWS_IME
203 SDL_Window *window = SDL_GetKeyboardFocus();
205 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
206 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
207 IME_Init(videodata, hwnd);
208 IME_Disable(videodata, hwnd);
210 #endif /* !SDL_DISABLE_WINDOWS_IME */
214 WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
216 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
217 videodata->ime_rect = *rect;
220 #ifdef SDL_DISABLE_WINDOWS_IME
224 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
229 void IME_Present(SDL_VideoData *videodata)
237 #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}}
238 DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E,0x0F28,0x11D8,0xA8,0x2A,0x00,0x06,0x5B,0x84,0x43,0x5C);
239 DEFINE_GUID(IID_ITfUIElementSink, 0xEA1EA136,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
240 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63,0xB2F0,0x4784,0x8B,0x67,0x5E,0x12,0xC8,0x70,0x1A,0x31);
241 DEFINE_GUID(IID_ITfSource, 0x4EA48A35,0x60AE,0x446F,0x8F,0xD6,0xE6,0xA8,0xD8,0x24,0x59,0xF7);
242 DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
243 DEFINE_GUID(IID_ITfCandidateListUIElement, 0xEA1EA138,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
244 DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
245 DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801,0x2021,0x11D2,0x93,0xE0,0x00,0x60,0xB0,0x67,0xB8,0x6E);
246 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B,0x6587,0x4F23,0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50);
247 DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3,0x7594,0x4CB0,0xBB,0x58,0x69,0x62,0x8F,0x5F,0x45,0x8C);
250 #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
251 #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
253 #define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) ))
254 #define IMEID_VER(id) ((id) & 0xffff0000)
255 #define IMEID_LANG(id) ((id) & 0x0000ffff)
257 #define CHT_HKL_DAYI ((HKL)0xE0060404)
258 #define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404)
259 #define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404)
260 #define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404)
261 #define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404)
262 #define CHT_IMEFILENAME1 "TINTLGNT.IME"
263 #define CHT_IMEFILENAME2 "CINTLGNT.IME"
264 #define CHT_IMEFILENAME3 "MSTCIPHA.IME"
265 #define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2))
266 #define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3))
267 #define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4))
268 #define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0))
269 #define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1))
270 #define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2))
271 #define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0))
272 #define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0))
274 #define CHS_HKL ((HKL)0xE00E0804)
275 #define CHS_IMEFILENAME1 "PINTLGNT.IME"
276 #define CHS_IMEFILENAME2 "MSSCIPYA.IME"
277 #define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1))
278 #define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2))
279 #define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3))
281 #define LANG() LOWORD((videodata->ime_hkl))
282 #define PRIMLANG() ((WORD)PRIMARYLANGID(LANG()))
283 #define SUBLANG() SUBLANGID(LANG())
285 static void IME_UpdateInputLocale(SDL_VideoData *videodata);
286 static void IME_ClearComposition(SDL_VideoData *videodata);
287 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
288 static void IME_SetupAPI(SDL_VideoData *videodata);
289 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
290 static void IME_SendEditingEvent(SDL_VideoData *videodata);
291 static void IME_DestroyTextures(SDL_VideoData *videodata);
293 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
294 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
296 static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata);
297 static void UILess_ReleaseSinks(SDL_VideoData *videodata);
298 static void UILess_EnableUIUpdates(SDL_VideoData *videodata);
299 static void UILess_DisableUIUpdates(SDL_VideoData *videodata);
302 IME_Init(SDL_VideoData *videodata, HWND hwnd)
304 if (videodata->ime_initialized)
307 videodata->ime_hwnd_main = hwnd;
308 if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
309 videodata->ime_com_initialized = SDL_TRUE;
310 CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (LPVOID *)&videodata->ime_threadmgr);
312 videodata->ime_initialized = SDL_TRUE;
313 videodata->ime_himm32 = SDL_LoadObject("imm32.dll");
314 if (!videodata->ime_himm32) {
315 videodata->ime_available = SDL_FALSE;
318 videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))SDL_LoadFunction(videodata->ime_himm32, "ImmLockIMC");
319 videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))SDL_LoadFunction(videodata->ime_himm32, "ImmUnlockIMC");
320 videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))SDL_LoadFunction(videodata->ime_himm32, "ImmLockIMCC");
321 videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))SDL_LoadFunction(videodata->ime_himm32, "ImmUnlockIMCC");
323 IME_SetWindow(videodata, hwnd);
324 videodata->ime_himc = ImmGetContext(hwnd);
325 ImmReleaseContext(hwnd, videodata->ime_himc);
326 if (!videodata->ime_himc) {
327 videodata->ime_available = SDL_FALSE;
328 IME_Disable(videodata, hwnd);
331 videodata->ime_available = SDL_TRUE;
332 IME_UpdateInputLocale(videodata);
333 IME_SetupAPI(videodata);
334 videodata->ime_uiless = UILess_SetupSinks(videodata);
335 IME_UpdateInputLocale(videodata);
336 IME_Disable(videodata, hwnd);
340 IME_Enable(SDL_VideoData *videodata, HWND hwnd)
342 if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
345 if (!videodata->ime_available) {
346 IME_Disable(videodata, hwnd);
349 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
350 ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
352 videodata->ime_enabled = SDL_TRUE;
353 IME_UpdateInputLocale(videodata);
354 UILess_EnableUIUpdates(videodata);
358 IME_Disable(SDL_VideoData *videodata, HWND hwnd)
360 if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
363 IME_ClearComposition(videodata);
364 if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
365 ImmAssociateContext(videodata->ime_hwnd_current, (HIMC)0);
367 videodata->ime_enabled = SDL_FALSE;
368 UILess_DisableUIUpdates(videodata);
372 IME_Quit(SDL_VideoData *videodata)
374 if (!videodata->ime_initialized)
377 UILess_ReleaseSinks(videodata);
378 if (videodata->ime_hwnd_main)
379 ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
381 videodata->ime_hwnd_main = 0;
382 videodata->ime_himc = 0;
383 if (videodata->ime_himm32) {
384 SDL_UnloadObject(videodata->ime_himm32);
385 videodata->ime_himm32 = 0;
387 if (videodata->ime_threadmgr) {
388 videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr);
389 videodata->ime_threadmgr = 0;
391 if (videodata->ime_com_initialized) {
393 videodata->ime_com_initialized = SDL_FALSE;
395 IME_DestroyTextures(videodata);
396 videodata->ime_initialized = SDL_FALSE;
400 IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd)
408 BOOL vertical = FALSE;
410 static OSVERSIONINFOA osversion = {0};
411 if (videodata->ime_uiless)
414 videodata->ime_readingstring[0] = 0;
415 if (!osversion.dwOSVersionInfoSize) {
416 osversion.dwOSVersionInfoSize = sizeof(osversion);
417 GetVersionExA(&osversion);
419 id = IME_GetId(videodata, 0);
423 himc = ImmGetContext(hwnd);
427 if (videodata->GetReadingString) {
428 len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen);
430 if (len > SDL_arraysize(buffer))
431 len = SDL_arraysize(buffer);
433 len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen);
435 SDL_wcslcpy(videodata->ime_readingstring, s, len);
438 LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc);
443 case IMEID_CHT_VER42:
444 case IMEID_CHT_VER43:
445 case IMEID_CHT_VER44:
446 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24);
450 len = *(DWORD *)(p + 7*4 + 32*4);
451 s = (WCHAR *)(p + 56);
453 case IMEID_CHT_VER51:
454 case IMEID_CHT_VER52:
455 case IMEID_CHS_VER53:
456 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4);
460 p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
464 len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
465 s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
467 case IMEID_CHS_VER41:
469 int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7;
470 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4);
474 len = *(DWORD *)(p + 7*4 + 16*2*4);
475 s = (WCHAR *)(p + 6*4 + 16*2*1);
478 case IMEID_CHS_VER42:
479 if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT)
482 p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4);
486 len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
487 s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
491 SDL_wcslcpy(videodata->ime_readingstring, s, len + 1);
493 videodata->ImmUnlockIMCC(lpimc->hPrivate);
494 videodata->ImmUnlockIMC(himc);
496 ImmReleaseContext(hwnd, himc);
497 IME_SendEditingEvent(videodata);
501 IME_InputLangChanged(SDL_VideoData *videodata)
503 UINT lang = PRIMLANG();
504 IME_UpdateInputLocale(videodata);
505 if (!videodata->ime_uiless)
506 videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1;
508 IME_SetupAPI(videodata);
509 if (lang != PRIMLANG()) {
510 IME_ClearComposition(videodata);
515 IME_GetId(SDL_VideoData *videodata, UINT uIndex)
517 static HKL hklprev = 0;
518 static DWORD dwRet[2] = {0};
520 DWORD dwVerHandle = 0;
521 LPVOID lpVerBuffer = 0;
522 LPVOID lpVerData = 0;
527 if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0]))
530 hkl = videodata->ime_hkl;
532 return dwRet[uIndex];
535 dwLang = ((DWORD_PTR)hkl & 0xffff);
536 if (videodata->ime_uiless && LANG() == LANG_CHT) {
537 dwRet[0] = IMEID_CHT_VER_VISTA;
541 if (hkl != CHT_HKL_NEW_PHONETIC
542 && hkl != CHT_HKL_NEW_CHANG_JIE
543 && hkl != CHT_HKL_NEW_QUICK
544 && hkl != CHT_HKL_HK_CANTONESE
546 dwRet[0] = dwRet[1] = 0;
547 return dwRet[uIndex];
549 if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) {
550 dwRet[0] = dwRet[1] = 0;
551 return dwRet[uIndex];
553 if (!videodata->GetReadingString) {
554 #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
555 if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2
556 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2
557 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2
558 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2
559 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) {
560 dwRet[0] = dwRet[1] = 0;
561 return dwRet[uIndex];
563 #undef LCID_INVARIANT
564 dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle);
566 lpVerBuffer = SDL_malloc(dwVerSize);
568 if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) {
569 if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) {
570 #define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData)
571 DWORD dwVer = pVerFixedInfo->dwFileVersionMS;
572 dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
573 if (videodata->GetReadingString ||
574 dwLang == LANG_CHT && (
575 dwVer == MAKEIMEVERSION(4, 2) ||
576 dwVer == MAKEIMEVERSION(4, 3) ||
577 dwVer == MAKEIMEVERSION(4, 4) ||
578 dwVer == MAKEIMEVERSION(5, 0) ||
579 dwVer == MAKEIMEVERSION(5, 1) ||
580 dwVer == MAKEIMEVERSION(5, 2) ||
581 dwVer == MAKEIMEVERSION(6, 0))
583 dwLang == LANG_CHS && (
584 dwVer == MAKEIMEVERSION(4, 1) ||
585 dwVer == MAKEIMEVERSION(4, 2) ||
586 dwVer == MAKEIMEVERSION(5, 3))) {
587 dwRet[0] = dwVer | dwLang;
588 dwRet[1] = pVerFixedInfo->dwFileVersionLS;
589 SDL_free(lpVerBuffer);
596 SDL_free(lpVerBuffer);
599 dwRet[0] = dwRet[1] = 0;
600 return dwRet[uIndex];
604 IME_SetupAPI(SDL_VideoData *videodata)
606 char ime_file[MAX_PATH + 1];
609 videodata->GetReadingString = 0;
610 videodata->ShowReadingWindow = 0;
611 if (videodata->ime_uiless)
614 hkl = videodata->ime_hkl;
615 if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0)
618 hime = SDL_LoadObject(ime_file);
622 videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
623 SDL_LoadFunction(hime, "GetReadingString");
624 videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL))
625 SDL_LoadFunction(hime, "ShowReadingWindow");
627 if (videodata->ShowReadingWindow) {
628 HIMC himc = ImmGetContext(videodata->ime_hwnd_current);
630 videodata->ShowReadingWindow(himc, FALSE);
631 ImmReleaseContext(videodata->ime_hwnd_current, himc);
637 IME_SetWindow(SDL_VideoData* videodata, HWND hwnd)
639 videodata->ime_hwnd_current = hwnd;
640 if (videodata->ime_threadmgr) {
641 struct ITfDocumentMgr *document_mgr = 0;
642 if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) {
644 document_mgr->lpVtbl->Release(document_mgr);
650 IME_UpdateInputLocale(SDL_VideoData *videodata)
652 static HKL hklprev = 0;
653 videodata->ime_hkl = GetKeyboardLayout(0);
654 if (hklprev == videodata->ime_hkl)
657 hklprev = videodata->ime_hkl;
658 switch (PRIMLANG()) {
660 videodata->ime_candvertical = SDL_TRUE;
661 if (SUBLANG() == SUBLANG_CHINESE_SIMPLIFIED)
662 videodata->ime_candvertical = SDL_FALSE;
666 videodata->ime_candvertical = SDL_TRUE;
669 videodata->ime_candvertical = SDL_FALSE;
675 IME_ClearComposition(SDL_VideoData *videodata)
678 if (!videodata->ime_initialized)
681 himc = ImmGetContext(videodata->ime_hwnd_current);
685 ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
686 if (videodata->ime_uiless)
687 ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR));
689 ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0);
690 ImmReleaseContext(videodata->ime_hwnd_current, himc);
691 SDL_SendEditingText("", 0, 0);
695 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
697 LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition));
701 length /= sizeof(videodata->ime_composition[0]);
702 videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
703 if (videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
705 for (i = videodata->ime_cursor + 1; i < length; ++i)
706 videodata->ime_composition[i - 1] = videodata->ime_composition[i];
710 videodata->ime_composition[length] = 0;
714 IME_SendInputEvent(SDL_VideoData *videodata)
717 s = WIN_StringToUTF8(videodata->ime_composition);
718 SDL_SendKeyboardText(s);
721 videodata->ime_composition[0] = 0;
722 videodata->ime_readingstring[0] = 0;
723 videodata->ime_cursor = 0;
727 IME_SendEditingEvent(SDL_VideoData *videodata)
730 WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
732 if (videodata->ime_readingstring[0]) {
733 size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
734 SDL_wcslcpy(buffer, videodata->ime_composition, len + 1);
735 SDL_wcslcat(buffer, videodata->ime_readingstring, sizeof(buffer));
736 SDL_wcslcat(buffer, &videodata->ime_composition[len], sizeof(buffer) - len);
739 SDL_wcslcpy(buffer, videodata->ime_composition, sizeof(videodata->ime_composition));
741 s = WIN_StringToUTF8(buffer);
742 SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0);
747 IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate)
749 LPWSTR dst = videodata->ime_candidates[i];
750 *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10));
751 if (videodata->ime_candvertical)
754 while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i])))
755 *dst++ = *candidate++;
761 IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata)
763 LPCANDIDATELIST cand_list = 0;
764 DWORD size = ImmGetCandidateListW(himc, 0, 0, 0);
766 cand_list = (LPCANDIDATELIST)SDL_malloc(size);
768 size = ImmGetCandidateListW(himc, 0, cand_list, size);
773 videodata->ime_candsel = cand_list->dwSelection;
774 videodata->ime_candcount = cand_list->dwCount;
776 if (LANG() == LANG_CHS && IME_GetId(videodata, 0)) {
777 const UINT maxcandchar = 18;
781 for (; i < videodata->ime_candcount; ++i) {
782 UINT len = SDL_wcslen((LPWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i])) + 1;
783 if (len + cchars > maxcandchar) {
784 if (i > cand_list->dwSelection)
794 videodata->ime_candpgsize = i - page_start;
797 videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize, MAX_CANDLIST);
798 page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize;
800 SDL_memset(&videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
801 for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < (int)videodata->ime_candpgsize; i++, j++) {
802 LPCWSTR candidate = (LPCWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i]);
803 IME_AddCandidate(videodata, j, candidate);
805 if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0)))
806 videodata->ime_candsel = -1;
815 IME_ShowCandidateList(SDL_VideoData *videodata)
817 videodata->ime_dirty = SDL_TRUE;
818 videodata->ime_candlist = SDL_TRUE;
819 IME_DestroyTextures(videodata);
820 IME_SendEditingEvent(videodata);
824 IME_HideCandidateList(SDL_VideoData *videodata)
826 videodata->ime_dirty = SDL_FALSE;
827 videodata->ime_candlist = SDL_FALSE;
828 IME_DestroyTextures(videodata);
829 IME_SendEditingEvent(videodata);
833 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
835 SDL_bool trap = SDL_FALSE;
837 if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
841 case WM_INPUTLANGCHANGE:
842 IME_InputLangChanged(videodata);
844 case WM_IME_SETCONTEXT:
847 case WM_IME_STARTCOMPOSITION:
850 case WM_IME_COMPOSITION:
852 himc = ImmGetContext(hwnd);
853 if (*lParam & GCS_RESULTSTR) {
854 IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
855 IME_SendInputEvent(videodata);
857 if (*lParam & GCS_COMPSTR) {
858 if (!videodata->ime_uiless)
859 videodata->ime_readingstring[0] = 0;
861 IME_GetCompositionString(videodata, himc, GCS_COMPSTR);
862 IME_SendEditingEvent(videodata);
864 ImmReleaseContext(hwnd, himc);
866 case WM_IME_ENDCOMPOSITION:
867 videodata->ime_composition[0] = 0;
868 videodata->ime_readingstring[0] = 0;
869 videodata->ime_cursor = 0;
870 SDL_SendEditingText("", 0, 0);
874 case IMN_SETCONVERSIONMODE:
875 case IMN_SETOPENSTATUS:
876 IME_UpdateInputLocale(videodata);
878 case IMN_OPENCANDIDATE:
879 case IMN_CHANGECANDIDATE:
880 if (videodata->ime_uiless)
884 IME_ShowCandidateList(videodata);
885 himc = ImmGetContext(hwnd);
889 IME_GetCandidateList(himc, videodata);
890 ImmReleaseContext(hwnd, himc);
892 case IMN_CLOSECANDIDATE:
894 IME_HideCandidateList(videodata);
898 DWORD dwId = IME_GetId(videodata, 0);
899 IME_GetReadingString(videodata, hwnd);
902 case IMEID_CHT_VER42:
903 case IMEID_CHT_VER43:
904 case IMEID_CHT_VER44:
905 case IMEID_CHS_VER41:
906 case IMEID_CHS_VER42:
907 if (*lParam == 1 || *lParam == 2)
911 case IMEID_CHT_VER50:
912 case IMEID_CHT_VER51:
913 case IMEID_CHT_VER52:
914 case IMEID_CHT_VER60:
915 case IMEID_CHS_VER53:
936 IME_CloseCandidateList(SDL_VideoData *videodata)
938 IME_HideCandidateList(videodata);
939 videodata->ime_candcount = 0;
940 SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
944 UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pcandlist)
953 pcandlist->lpVtbl->GetSelection(pcandlist, &selection);
954 pcandlist->lpVtbl->GetCount(pcandlist, &count);
955 pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page);
957 videodata->ime_candsel = selection;
958 videodata->ime_candcount = count;
959 IME_ShowCandidateList(videodata);
961 pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount);
963 UINT *idxlist = SDL_malloc(sizeof(UINT) * pgcount);
965 pcandlist->lpVtbl->GetPageIndex(pcandlist, idxlist, pgcount, &pgcount);
966 pgstart = idxlist[page];
967 if (page < pgcount - 1)
968 pgsize = SDL_min(count, idxlist[page + 1]) - pgstart;
970 pgsize = count - pgstart;
975 videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST);
976 videodata->ime_candsel = videodata->ime_candsel - pgstart;
978 SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
979 for (i = pgstart, j = 0; (DWORD)i < count && j < videodata->ime_candpgsize; i++, j++) {
981 if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) {
983 IME_AddCandidate(videodata, j, bstr);
988 if (PRIMLANG() == LANG_KOREAN)
989 videodata->ime_candsel = -1;
992 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
994 return ++sink->refcount;
997 STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink)
1000 if (sink->refcount == 0) {
1004 return sink->refcount;
1007 STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
1010 return E_INVALIDARG;
1013 if (SDL_IsEqualIID(riid, &IID_IUnknown))
1014 *ppv = (IUnknown *)sink;
1015 else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink))
1016 *ppv = (ITfUIElementSink *)sink;
1019 TSFSink_AddRef(sink);
1022 return E_NOINTERFACE;
1025 ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId)
1027 ITfUIElementMgr *puiem = 0;
1028 ITfUIElement *pelem = 0;
1029 ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex;
1031 if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) {
1032 puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem);
1033 puiem->lpVtbl->Release(puiem);
1038 STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow)
1040 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
1041 ITfReadingInformationUIElement *preading = 0;
1042 ITfCandidateListUIElement *pcandlist = 0;
1043 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1045 return E_INVALIDARG;
1048 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1050 if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
1051 WCHAR *s = (WCHAR *)bstr;
1052 SysFreeString(bstr);
1054 preading->lpVtbl->Release(preading);
1056 else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1057 videodata->ime_candref++;
1058 UILess_GetCandidateList(videodata, pcandlist);
1059 pcandlist->lpVtbl->Release(pcandlist);
1064 STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId)
1066 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
1067 ITfReadingInformationUIElement *preading = 0;
1068 ITfCandidateListUIElement *pcandlist = 0;
1069 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1071 return E_INVALIDARG;
1073 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1075 if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
1076 WCHAR *s = (WCHAR *)bstr;
1077 SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring));
1078 IME_SendEditingEvent(videodata);
1079 SysFreeString(bstr);
1081 preading->lpVtbl->Release(preading);
1083 else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1084 UILess_GetCandidateList(videodata, pcandlist);
1085 pcandlist->lpVtbl->Release(pcandlist);
1090 STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId)
1092 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
1093 ITfReadingInformationUIElement *preading = 0;
1094 ITfCandidateListUIElement *pcandlist = 0;
1095 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1097 return E_INVALIDARG;
1099 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1100 videodata->ime_readingstring[0] = 0;
1101 IME_SendEditingEvent(videodata);
1102 preading->lpVtbl->Release(preading);
1104 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1105 videodata->ime_candref--;
1106 if (videodata->ime_candref == 0)
1107 IME_CloseCandidateList(videodata);
1109 pcandlist->lpVtbl->Release(pcandlist);
1114 STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
1117 return E_INVALIDARG;
1120 if (SDL_IsEqualIID(riid, &IID_IUnknown))
1121 *ppv = (IUnknown *)sink;
1122 else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink))
1123 *ppv = (ITfInputProcessorProfileActivationSink *)sink;
1126 TSFSink_AddRef(sink);
1129 return E_NOINTERFACE;
1132 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
1134 static GUID TF_PROFILE_DAYI = {0x037B2C25, 0x480C, 0x4D7F, 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A};
1135 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1136 videodata->ime_candlistindexbase = SDL_IsEqualGUID(&TF_PROFILE_DAYI, guidProfile) ? 0 : 1;
1137 if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
1138 IME_InputLangChanged((SDL_VideoData *)sink->data);
1140 IME_HideCandidateList(videodata);
1144 static void *vtUIElementSink[] = {
1145 (void *)(UIElementSink_QueryInterface),
1146 (void *)(TSFSink_AddRef),
1147 (void *)(TSFSink_Release),
1148 (void *)(UIElementSink_BeginUIElement),
1149 (void *)(UIElementSink_UpdateUIElement),
1150 (void *)(UIElementSink_EndUIElement)
1153 static void *vtIPPASink[] = {
1154 (void *)(IPPASink_QueryInterface),
1155 (void *)(TSFSink_AddRef),
1156 (void *)(TSFSink_Release),
1157 (void *)(IPPASink_OnActivated)
1161 UILess_EnableUIUpdates(SDL_VideoData *videodata)
1163 ITfSource *source = 0;
1164 if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE)
1167 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1168 source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie);
1169 source->lpVtbl->Release(source);
1174 UILess_DisableUIUpdates(SDL_VideoData *videodata)
1176 ITfSource *source = 0;
1177 if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE)
1180 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1181 source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
1182 videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE;
1183 source->lpVtbl->Release(source);
1188 UILess_SetupSinks(SDL_VideoData *videodata)
1190 TfClientId clientid = 0;
1191 SDL_bool result = SDL_FALSE;
1192 ITfSource *source = 0;
1193 if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, (LPVOID *)&videodata->ime_threadmgrex)))
1196 if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY)))
1199 videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink));
1200 videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink));
1202 videodata->ime_uielemsink->lpVtbl = vtUIElementSink;
1203 videodata->ime_uielemsink->refcount = 1;
1204 videodata->ime_uielemsink->data = videodata;
1206 videodata->ime_ippasink->lpVtbl = vtIPPASink;
1207 videodata->ime_ippasink->refcount = 1;
1208 videodata->ime_ippasink->data = videodata;
1210 if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1211 if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) {
1212 if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) {
1216 source->lpVtbl->Release(source);
1221 #define SAFE_RELEASE(p) \
1224 (p)->lpVtbl->Release((p)); \
1230 UILess_ReleaseSinks(SDL_VideoData *videodata)
1232 ITfSource *source = 0;
1233 if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1234 source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
1235 source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie);
1236 SAFE_RELEASE(source);
1237 videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex);
1238 SAFE_RELEASE(videodata->ime_threadmgrex);
1239 TSFSink_Release(videodata->ime_uielemsink);
1240 videodata->ime_uielemsink = 0;
1241 TSFSink_Release(videodata->ime_ippasink);
1242 videodata->ime_ippasink = 0;
1247 StartDrawToBitmap(HDC hdc, HBITMAP *hhbm, int width, int height)
1250 BITMAPINFOHEADER *infoHeader = &info.bmiHeader;
1254 infoHeader->biSize = sizeof(BITMAPINFOHEADER);
1255 infoHeader->biWidth = width;
1256 infoHeader->biHeight = -1 * SDL_abs(height);
1257 infoHeader->biPlanes = 1;
1258 infoHeader->biBitCount = 32;
1259 infoHeader->biCompression = BI_RGB;
1260 *hhbm = CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void **)&bits, 0, 0);
1262 SelectObject(hdc, *hhbm);
1268 StopDrawToBitmap(HDC hdc, HBITMAP *hhbm)
1270 if (hhbm && *hhbm) {
1271 DeleteObject(*hhbm);
1276 /* This draws only within the specified area and fills the entire region. */
1278 DrawRect(HDC hdc, int left, int top, int right, int bottom, int pensize)
1280 /* The case of no pen (PenSize = 0) is automatically taken care of. */
1281 const int penadjust = (int)SDL_floor(pensize / 2.0f - 0.5f);
1282 left += pensize / 2;
1285 bottom -= penadjust;
1286 Rectangle(hdc, left, top, right, bottom);
1290 IME_DestroyTextures(SDL_VideoData *videodata)
1294 #define SDL_swap(a,b) { \
1301 IME_PositionCandidateList(SDL_VideoData *videodata, SIZE size)
1303 int left, top, right, bottom;
1304 SDL_bool ok = SDL_FALSE;
1305 int winw = videodata->ime_winwidth;
1306 int winh = videodata->ime_winheight;
1309 left = videodata->ime_rect.x;
1310 top = videodata->ime_rect.y + videodata->ime_rect.h;
1311 right = left + size.cx;
1312 bottom = top + size.cy;
1313 if (right >= winw) {
1314 left -= right - winw;
1322 left = videodata->ime_rect.x;
1323 top = videodata->ime_rect.y - size.cy;
1324 right = left + size.cx;
1325 bottom = videodata->ime_rect.y;
1326 if (right >= winw) {
1327 left -= right - winw;
1336 left = videodata->ime_rect.x + size.cx;
1338 right = left + size.cx;
1346 left = videodata->ime_rect.x - size.cx;
1348 right = videodata->ime_rect.x;
1354 /* Window too small, show at (0,0) */
1362 videodata->ime_candlistrect.x = left;
1363 videodata->ime_candlistrect.y = top;
1364 videodata->ime_candlistrect.w = right - left;
1365 videodata->ime_candlistrect.h = bottom - top;
1369 IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc)
1373 SIZE candsizes[MAX_CANDLIST];
1374 SIZE maxcandsize = {0};
1377 const int candcount = SDL_min(SDL_min(MAX_CANDLIST, videodata->ime_candcount), videodata->ime_candpgsize);
1378 SDL_bool vertical = videodata->ime_candvertical;
1380 const int listborder = 1;
1381 const int listpadding = 0;
1382 const int listbordercolor = RGB(0xB4, 0xC7, 0xAA);
1383 const int listfillcolor = RGB(255, 255, 255);
1385 const int candborder = 1;
1386 const int candpadding = 0;
1387 const int candmargin = 1;
1388 const COLORREF candbordercolor = RGB(255, 255, 255);
1389 const COLORREF candfillcolor = RGB(255, 255, 255);
1390 const COLORREF candtextcolor = RGB(0, 0, 0);
1391 const COLORREF selbordercolor = RGB(0x84, 0xAC, 0xDD);
1392 const COLORREF selfillcolor = RGB(0xD2, 0xE6, 0xFF);
1393 const COLORREF seltextcolor = RGB(0, 0, 0);
1394 const int horzcandspacing = 5;
1396 HPEN listpen = listborder != 0 ? CreatePen(PS_SOLID, listborder, listbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1397 HBRUSH listbrush = CreateSolidBrush(listfillcolor);
1398 HPEN candpen = candborder != 0 ? CreatePen(PS_SOLID, candborder, candbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1399 HBRUSH candbrush = CreateSolidBrush(candfillcolor);
1400 HPEN selpen = candborder != 0 ? CreatePen(PS_DOT, candborder, selbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1401 HBRUSH selbrush = CreateSolidBrush(selfillcolor);
1402 HFONT font = CreateFont((int)(1 + videodata->ime_rect.h * 0.75f), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("Microsoft Sans Serif"));
1404 SetBkMode(hdc, TRANSPARENT);
1405 SelectObject(hdc, font);
1407 for (i = 0; i < candcount; ++i) {
1408 const WCHAR *s = videodata->ime_candidates[i];
1412 GetTextExtentPoint32W(hdc, s, SDL_wcslen(s), &candsizes[i]);
1413 maxcandsize.cx = SDL_max(maxcandsize.cx, candsizes[i].cx);
1414 maxcandsize.cy = SDL_max(maxcandsize.cy, candsizes[i].cy);
1429 ((candcount + 1) * candmargin) +
1430 (candcount * candborder * 2) +
1431 (candcount * candpadding * 2) +
1432 (candcount * maxcandsize.cy)
1439 ((candcount + 1) * candmargin) +
1440 (candcount * candborder * 2) +
1441 (candcount * candpadding * 2) +
1442 ((candcount - 1) * horzcandspacing);
1445 for (i = 0; i < candcount; ++i)
1446 size.cx += candsizes[i].cx;
1458 bits = StartDrawToBitmap(hdc, &hbm, size.cx, size.cy);
1460 SelectObject(hdc, listpen);
1461 SelectObject(hdc, listbrush);
1462 DrawRect(hdc, 0, 0, size.cx, size.cy, listborder);
1464 SelectObject(hdc, candpen);
1465 SelectObject(hdc, candbrush);
1466 SetTextColor(hdc, candtextcolor);
1467 SetBkMode(hdc, TRANSPARENT);
1469 for (i = 0; i < candcount; ++i) {
1470 const WCHAR *s = videodata->ime_candidates[i];
1471 int left, top, right, bottom;
1476 left = listborder + listpadding + candmargin;
1477 top = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * maxcandsize.cy);
1478 right = size.cx - listborder - listpadding - candmargin;
1479 bottom = top + maxcandsize.cy + (candpadding * 2) + (candborder * 2);
1482 left = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * horzcandspacing);
1484 for (j = 0; j < i; ++j)
1485 left += candsizes[j].cx;
1487 top = listborder + listpadding + candmargin;
1488 right = left + candsizes[i].cx + (candpadding * 2) + (candborder * 2);
1489 bottom = size.cy - listborder - listpadding - candmargin;
1492 if (i == videodata->ime_candsel) {
1493 SelectObject(hdc, selpen);
1494 SelectObject(hdc, selbrush);
1495 SetTextColor(hdc, seltextcolor);
1498 SelectObject(hdc, candpen);
1499 SelectObject(hdc, candbrush);
1500 SetTextColor(hdc, candtextcolor);
1503 DrawRect(hdc, left, top, right, bottom, candborder);
1504 ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, SDL_wcslen(s), NULL);
1506 StopDrawToBitmap(hdc, &hbm);
1508 DeleteObject(listpen);
1509 DeleteObject(listbrush);
1510 DeleteObject(candpen);
1511 DeleteObject(candbrush);
1512 DeleteObject(selpen);
1513 DeleteObject(selbrush);
1516 IME_PositionCandidateList(videodata, size);
1520 IME_Render(SDL_VideoData *videodata)
1522 HDC hdc = CreateCompatibleDC(NULL);
1524 if (videodata->ime_candlist)
1525 IME_RenderCandidateList(videodata, hdc);
1529 videodata->ime_dirty = SDL_FALSE;
1532 void IME_Present(SDL_VideoData *videodata)
1534 if (videodata->ime_dirty)
1535 IME_Render(videodata);
1537 // FIXME: Need to show the IME bitmap
1540 #endif /* SDL_DISABLE_WINDOWS_IME */
1542 /* vi: set ts=4 sw=4 expandtab: */