SDL  2.0
SDL_windowskeyboard.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
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.
8 
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:
12 
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.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_WINDOWS
24 
25 #include "SDL_windowsvideo.h"
26 
27 #include "../../events/SDL_keyboard_c.h"
28 #include "../../events/scancodes_windows.h"
29 
30 #include <imm.h>
31 #include <oleauto.h>
32 
33 #ifndef SDL_DISABLE_WINDOWS_IME
34 static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
35 static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
36 static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
37 static void IME_Quit(SDL_VideoData *videodata);
38 #endif /* !SDL_DISABLE_WINDOWS_IME */
39 
40 #ifndef MAPVK_VK_TO_VSC
41 #define MAPVK_VK_TO_VSC 0
42 #endif
43 #ifndef MAPVK_VSC_TO_VK
44 #define MAPVK_VSC_TO_VK 1
45 #endif
46 #ifndef MAPVK_VK_TO_CHAR
47 #define MAPVK_VK_TO_CHAR 2
48 #endif
49 
50 /* Alphabetic scancodes for PC keyboards */
51 void
53 {
55 
57  data->ime_threadmgr = 0;
58  data->ime_initialized = SDL_FALSE;
59  data->ime_enabled = SDL_FALSE;
60  data->ime_available = SDL_FALSE;
61  data->ime_hwnd_main = 0;
62  data->ime_hwnd_current = 0;
63  data->ime_himc = 0;
64  data->ime_composition[0] = 0;
65  data->ime_readingstring[0] = 0;
66  data->ime_cursor = 0;
67 
68  data->ime_candlist = SDL_FALSE;
69  SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates));
70  data->ime_candcount = 0;
71  data->ime_candref = 0;
72  data->ime_candsel = 0;
73  data->ime_candpgsize = 0;
74  data->ime_candlistindexbase = 0;
75  data->ime_candvertical = SDL_TRUE;
76 
77  data->ime_dirty = SDL_FALSE;
78  SDL_memset(&data->ime_rect, 0, sizeof(data->ime_rect));
79  SDL_memset(&data->ime_candlistrect, 0, sizeof(data->ime_candlistrect));
80  data->ime_winwidth = 0;
81  data->ime_winheight = 0;
82 
83  data->ime_hkl = 0;
84  data->ime_himm32 = 0;
85  data->GetReadingString = 0;
86  data->ShowReadingWindow = 0;
87  data->ImmLockIMC = 0;
88  data->ImmUnlockIMC = 0;
89  data->ImmLockIMCC = 0;
90  data->ImmUnlockIMCC = 0;
91  data->ime_uiless = SDL_FALSE;
92  data->ime_threadmgrex = 0;
97  data->ime_uielemsink = 0;
98  data->ime_ippasink = 0;
99 
101 
103  SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
104  SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows");
105 
106  /* Are system caps/num/scroll lock active? Set our state to match. */
107  SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
108  SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
109 }
110 
111 void
113 {
114  int i;
115  SDL_Scancode scancode;
117 
118  SDL_GetDefaultKeymap(keymap);
119 
120  for (i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
121  int vk;
122  /* Make sure this scancode is a valid character scancode */
123  scancode = windows_scancode_table[i];
124  if (scancode == SDL_SCANCODE_UNKNOWN ) {
125  continue;
126  }
127 
128  /* If this key is one of the non-mappable keys, ignore it */
129  /* Not mapping numbers fixes the French layout, giving numeric keycodes for the number keys, which is the expected behavior */
130  if ((keymap[scancode] & SDLK_SCANCODE_MASK) ||
131  /* scancode == SDL_SCANCODE_GRAVE || */ /* Uncomment this line to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */
132  (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0) ) {
133  continue;
134  }
135 
136  vk = MapVirtualKey(i, MAPVK_VSC_TO_VK);
137  if ( vk ) {
138  int ch = (MapVirtualKey( vk, MAPVK_VK_TO_CHAR ) & 0x7FFF);
139  if ( ch ) {
140  if ( ch >= 'A' && ch <= 'Z' ) {
141  keymap[scancode] = SDLK_a + ( ch - 'A' );
142  } else {
143  keymap[scancode] = ch;
144  }
145  }
146  }
147  }
148 
149  SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
150 }
151 
152 void
154 {
155 #ifndef SDL_DISABLE_WINDOWS_IME
156  IME_Quit((SDL_VideoData *)_this->driverdata);
157 #endif
158 }
159 
160 void
162 {
163 #ifndef SDL_DISABLE_WINDOWS_IME
165  if (window) {
166  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
167  SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
168  SDL_GetWindowSize(window, &videodata->ime_winwidth, &videodata->ime_winheight);
169  IME_Init(videodata, hwnd);
170  IME_Enable(videodata, hwnd);
171  }
172 #endif /* !SDL_DISABLE_WINDOWS_IME */
173 }
174 
175 void
177 {
178 #ifndef SDL_DISABLE_WINDOWS_IME
179  SDL_Window *window = SDL_GetKeyboardFocus();
180  if (window) {
181  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
182  SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
183  IME_Init(videodata, hwnd);
184  IME_Disable(videodata, hwnd);
185  }
186 #endif /* !SDL_DISABLE_WINDOWS_IME */
187 }
188 
189 void
191 {
192  SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
193  HIMC himc = 0;
194 
195  if (!rect) {
196  SDL_InvalidParamError("rect");
197  return;
198  }
199 
200  videodata->ime_rect = *rect;
201 
202  himc = ImmGetContext(videodata->ime_hwnd_current);
203  if (himc)
204  {
205  COMPOSITIONFORM cf;
206  cf.ptCurrentPos.x = videodata->ime_rect.x;
207  cf.ptCurrentPos.y = videodata->ime_rect.y;
208  cf.dwStyle = CFS_FORCE_POSITION;
209  ImmSetCompositionWindow(himc, &cf);
210  ImmReleaseContext(videodata->ime_hwnd_current, himc);
211  }
212 }
213 
214 #ifdef SDL_DISABLE_WINDOWS_IME
215 
216 
217 SDL_bool
218 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
219 {
220  return SDL_FALSE;
221 }
222 
223 void IME_Present(SDL_VideoData *videodata)
224 {
225 }
226 
227 #else
228 
229 #ifdef _SDL_msctf_h
230 #define USE_INIT_GUID
231 #elif defined(__GNUC__)
232 #define USE_INIT_GUID
233 #endif
234 #ifdef USE_INIT_GUID
235 #undef DEFINE_GUID
236 #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}}
237 DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E,0x0F28,0x11D8,0xA8,0x2A,0x00,0x06,0x5B,0x84,0x43,0x5C);
238 DEFINE_GUID(IID_ITfUIElementSink, 0xEA1EA136,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
239 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63,0xB2F0,0x4784,0x8B,0x67,0x5E,0x12,0xC8,0x70,0x1A,0x31);
240 DEFINE_GUID(IID_ITfSource, 0x4EA48A35,0x60AE,0x446F,0x8F,0xD6,0xE6,0xA8,0xD8,0x24,0x59,0xF7);
241 DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
242 DEFINE_GUID(IID_ITfCandidateListUIElement, 0xEA1EA138,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
243 DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
244 DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801,0x2021,0x11D2,0x93,0xE0,0x00,0x60,0xB0,0x67,0xB8,0x6E);
245 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B,0x6587,0x4F23,0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50);
246 DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3,0x7594,0x4CB0,0xBB,0x58,0x69,0x62,0x8F,0x5F,0x45,0x8C);
247 #endif
248 
249 #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
250 #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
251 
252 #define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) ))
253 #define IMEID_VER(id) ((id) & 0xffff0000)
254 #define IMEID_LANG(id) ((id) & 0x0000ffff)
255 
256 #define CHT_HKL_DAYI ((HKL)0xE0060404)
257 #define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404)
258 #define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404)
259 #define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404)
260 #define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404)
261 #define CHT_IMEFILENAME1 "TINTLGNT.IME"
262 #define CHT_IMEFILENAME2 "CINTLGNT.IME"
263 #define CHT_IMEFILENAME3 "MSTCIPHA.IME"
264 #define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2))
265 #define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3))
266 #define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4))
267 #define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0))
268 #define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1))
269 #define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2))
270 #define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0))
271 #define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0))
272 
273 #define CHS_HKL ((HKL)0xE00E0804)
274 #define CHS_IMEFILENAME1 "PINTLGNT.IME"
275 #define CHS_IMEFILENAME2 "MSSCIPYA.IME"
276 #define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1))
277 #define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2))
278 #define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3))
279 
280 #define LANG() LOWORD((videodata->ime_hkl))
281 #define PRIMLANG() ((WORD)PRIMARYLANGID(LANG()))
282 #define SUBLANG() SUBLANGID(LANG())
283 
284 static void IME_UpdateInputLocale(SDL_VideoData *videodata);
285 static void IME_ClearComposition(SDL_VideoData *videodata);
286 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
287 static void IME_SetupAPI(SDL_VideoData *videodata);
288 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
289 static void IME_SendEditingEvent(SDL_VideoData *videodata);
290 static void IME_DestroyTextures(SDL_VideoData *videodata);
291 
292 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
293 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
294 
295 static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata);
296 static void UILess_ReleaseSinks(SDL_VideoData *videodata);
297 static void UILess_EnableUIUpdates(SDL_VideoData *videodata);
298 static void UILess_DisableUIUpdates(SDL_VideoData *videodata);
299 
300 static void
301 IME_Init(SDL_VideoData *videodata, HWND hwnd)
302 {
303  if (videodata->ime_initialized)
304  return;
305 
306  videodata->ime_hwnd_main = hwnd;
307  if (SUCCEEDED(WIN_CoInitialize())) {
308  videodata->ime_com_initialized = SDL_TRUE;
309  CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (LPVOID *)&videodata->ime_threadmgr);
310  }
311  videodata->ime_initialized = SDL_TRUE;
312  videodata->ime_himm32 = SDL_LoadObject("imm32.dll");
313  if (!videodata->ime_himm32) {
314  videodata->ime_available = SDL_FALSE;
315  return;
316  }
317  videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))SDL_LoadFunction(videodata->ime_himm32, "ImmLockIMC");
318  videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))SDL_LoadFunction(videodata->ime_himm32, "ImmUnlockIMC");
319  videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))SDL_LoadFunction(videodata->ime_himm32, "ImmLockIMCC");
320  videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))SDL_LoadFunction(videodata->ime_himm32, "ImmUnlockIMCC");
321 
322  IME_SetWindow(videodata, hwnd);
323  videodata->ime_himc = ImmGetContext(hwnd);
324  ImmReleaseContext(hwnd, videodata->ime_himc);
325  if (!videodata->ime_himc) {
326  videodata->ime_available = SDL_FALSE;
327  IME_Disable(videodata, hwnd);
328  return;
329  }
330  videodata->ime_available = SDL_TRUE;
331  IME_UpdateInputLocale(videodata);
332  IME_SetupAPI(videodata);
333  videodata->ime_uiless = UILess_SetupSinks(videodata);
334  IME_UpdateInputLocale(videodata);
335  IME_Disable(videodata, hwnd);
336 }
337 
338 static void
339 IME_Enable(SDL_VideoData *videodata, HWND hwnd)
340 {
341  if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
342  return;
343 
344  if (!videodata->ime_available) {
345  IME_Disable(videodata, hwnd);
346  return;
347  }
348  if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
349  ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
350 
351  videodata->ime_enabled = SDL_TRUE;
352  IME_UpdateInputLocale(videodata);
353  UILess_EnableUIUpdates(videodata);
354 }
355 
356 static void
357 IME_Disable(SDL_VideoData *videodata, HWND hwnd)
358 {
359  if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
360  return;
361 
362  IME_ClearComposition(videodata);
363  if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
364  ImmAssociateContext(videodata->ime_hwnd_current, (HIMC)0);
365 
366  videodata->ime_enabled = SDL_FALSE;
367  UILess_DisableUIUpdates(videodata);
368 }
369 
370 static void
371 IME_Quit(SDL_VideoData *videodata)
372 {
373  if (!videodata->ime_initialized)
374  return;
375 
376  UILess_ReleaseSinks(videodata);
377  if (videodata->ime_hwnd_main)
378  ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
379 
380  videodata->ime_hwnd_main = 0;
381  videodata->ime_himc = 0;
382  if (videodata->ime_himm32) {
383  SDL_UnloadObject(videodata->ime_himm32);
384  videodata->ime_himm32 = 0;
385  }
386  if (videodata->ime_threadmgr) {
387  videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr);
388  videodata->ime_threadmgr = 0;
389  }
390  if (videodata->ime_com_initialized) {
392  videodata->ime_com_initialized = SDL_FALSE;
393  }
394  IME_DestroyTextures(videodata);
395  videodata->ime_initialized = SDL_FALSE;
396 }
397 
398 static void
399 IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd)
400 {
401  DWORD id = 0;
402  HIMC himc = 0;
403  WCHAR buffer[16];
404  WCHAR *s = buffer;
405  DWORD len = 0;
406  INT err = 0;
407  BOOL vertical = FALSE;
408  UINT maxuilen = 0;
409  static OSVERSIONINFOA osversion;
410 
411  if (videodata->ime_uiless)
412  return;
413 
414  videodata->ime_readingstring[0] = 0;
415  if (!osversion.dwOSVersionInfoSize) {
416  osversion.dwOSVersionInfoSize = sizeof(osversion);
417  GetVersionExA(&osversion);
418  }
419  id = IME_GetId(videodata, 0);
420  if (!id)
421  return;
422 
423  himc = ImmGetContext(hwnd);
424  if (!himc)
425  return;
426 
427  if (videodata->GetReadingString) {
428  len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen);
429  if (len) {
430  if (len > SDL_arraysize(buffer))
431  len = SDL_arraysize(buffer);
432 
433  len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen);
434  }
435  SDL_wcslcpy(videodata->ime_readingstring, s, len);
436  }
437  else {
438  LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc);
439  LPBYTE p = 0;
440  s = 0;
441  switch (id)
442  {
443  case IMEID_CHT_VER42:
444  case IMEID_CHT_VER43:
445  case IMEID_CHT_VER44:
446  p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24);
447  if (!p)
448  break;
449 
450  len = *(DWORD *)(p + 7*4 + 32*4);
451  s = (WCHAR *)(p + 56);
452  break;
453  case IMEID_CHT_VER51:
454  case IMEID_CHT_VER52:
455  case IMEID_CHS_VER53:
456  p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4);
457  if (!p)
458  break;
459 
460  p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
461  if (!p)
462  break;
463 
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);
466  break;
467  case IMEID_CHS_VER41:
468  {
469  int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7;
470  p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4);
471  if (!p)
472  break;
473 
474  len = *(DWORD *)(p + 7*4 + 16*2*4);
475  s = (WCHAR *)(p + 6*4 + 16*2*1);
476  }
477  break;
478  case IMEID_CHS_VER42:
479  if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT)
480  break;
481 
482  p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4);
483  if (!p)
484  break;
485 
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);
488  break;
489  }
490  if (s) {
491  size_t size = SDL_min((size_t)(len + 1), SDL_arraysize(videodata->ime_readingstring));
492  SDL_wcslcpy(videodata->ime_readingstring, s, size);
493  }
494 
495  videodata->ImmUnlockIMCC(lpimc->hPrivate);
496  videodata->ImmUnlockIMC(himc);
497  }
498  ImmReleaseContext(hwnd, himc);
499  IME_SendEditingEvent(videodata);
500 }
501 
502 static void
503 IME_InputLangChanged(SDL_VideoData *videodata)
504 {
505  UINT lang = PRIMLANG();
506  IME_UpdateInputLocale(videodata);
507  if (!videodata->ime_uiless)
508  videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1;
509 
510  IME_SetupAPI(videodata);
511  if (lang != PRIMLANG()) {
512  IME_ClearComposition(videodata);
513  }
514 }
515 
516 static DWORD
517 IME_GetId(SDL_VideoData *videodata, UINT uIndex)
518 {
519  static HKL hklprev = 0;
520  static DWORD dwRet[2] = {0};
521  DWORD dwVerSize = 0;
522  DWORD dwVerHandle = 0;
523  LPVOID lpVerBuffer = 0;
524  LPVOID lpVerData = 0;
525  UINT cbVerData = 0;
526  char szTemp[256];
527  HKL hkl = 0;
528  DWORD dwLang = 0;
529  if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0]))
530  return 0;
531 
532  hkl = videodata->ime_hkl;
533  if (hklprev == hkl)
534  return dwRet[uIndex];
535 
536  hklprev = hkl;
537  dwLang = ((DWORD_PTR)hkl & 0xffff);
538  if (videodata->ime_uiless && LANG() == LANG_CHT) {
539  dwRet[0] = IMEID_CHT_VER_VISTA;
540  dwRet[1] = 0;
541  return dwRet[0];
542  }
543  if (hkl != CHT_HKL_NEW_PHONETIC
544  && hkl != CHT_HKL_NEW_CHANG_JIE
545  && hkl != CHT_HKL_NEW_QUICK
546  && hkl != CHT_HKL_HK_CANTONESE
547  && hkl != CHS_HKL) {
548  dwRet[0] = dwRet[1] = 0;
549  return dwRet[uIndex];
550  }
551  if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) {
552  dwRet[0] = dwRet[1] = 0;
553  return dwRet[uIndex];
554  }
555  if (!videodata->GetReadingString) {
556  #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
557  if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2
558  && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2
559  && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2
560  && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2
561  && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) {
562  dwRet[0] = dwRet[1] = 0;
563  return dwRet[uIndex];
564  }
565  #undef LCID_INVARIANT
566  dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle);
567  if (dwVerSize) {
568  lpVerBuffer = SDL_malloc(dwVerSize);
569  if (lpVerBuffer) {
570  if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) {
571  if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) {
572  #define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData)
573  DWORD dwVer = pVerFixedInfo->dwFileVersionMS;
574  dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
575  if ((videodata->GetReadingString) ||
576  ((dwLang == LANG_CHT) && (
577  dwVer == MAKEIMEVERSION(4, 2) ||
578  dwVer == MAKEIMEVERSION(4, 3) ||
579  dwVer == MAKEIMEVERSION(4, 4) ||
580  dwVer == MAKEIMEVERSION(5, 0) ||
581  dwVer == MAKEIMEVERSION(5, 1) ||
582  dwVer == MAKEIMEVERSION(5, 2) ||
583  dwVer == MAKEIMEVERSION(6, 0)))
584  ||
585  ((dwLang == LANG_CHS) && (
586  dwVer == MAKEIMEVERSION(4, 1) ||
587  dwVer == MAKEIMEVERSION(4, 2) ||
588  dwVer == MAKEIMEVERSION(5, 3)))) {
589  dwRet[0] = dwVer | dwLang;
590  dwRet[1] = pVerFixedInfo->dwFileVersionLS;
591  SDL_free(lpVerBuffer);
592  return dwRet[0];
593  }
594  #undef pVerFixedInfo
595  }
596  }
597  }
598  SDL_free(lpVerBuffer);
599  }
600  }
601  dwRet[0] = dwRet[1] = 0;
602  return dwRet[uIndex];
603 }
604 
605 static void
606 IME_SetupAPI(SDL_VideoData *videodata)
607 {
608  char ime_file[MAX_PATH + 1];
609  void* hime = 0;
610  HKL hkl = 0;
611  videodata->GetReadingString = 0;
612  videodata->ShowReadingWindow = 0;
613  if (videodata->ime_uiless)
614  return;
615 
616  hkl = videodata->ime_hkl;
617  if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0)
618  return;
619 
620  hime = SDL_LoadObject(ime_file);
621  if (!hime)
622  return;
623 
624  videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
625  SDL_LoadFunction(hime, "GetReadingString");
626  videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL))
627  SDL_LoadFunction(hime, "ShowReadingWindow");
628 
629  if (videodata->ShowReadingWindow) {
630  HIMC himc = ImmGetContext(videodata->ime_hwnd_current);
631  if (himc) {
632  videodata->ShowReadingWindow(himc, FALSE);
633  ImmReleaseContext(videodata->ime_hwnd_current, himc);
634  }
635  }
636 }
637 
638 static void
639 IME_SetWindow(SDL_VideoData* videodata, HWND hwnd)
640 {
641  videodata->ime_hwnd_current = hwnd;
642  if (videodata->ime_threadmgr) {
643  struct ITfDocumentMgr *document_mgr = 0;
644  if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) {
645  if (document_mgr)
646  document_mgr->lpVtbl->Release(document_mgr);
647  }
648  }
649 }
650 
651 static void
652 IME_UpdateInputLocale(SDL_VideoData *videodata)
653 {
654  static HKL hklprev = 0;
655  videodata->ime_hkl = GetKeyboardLayout(0);
656  if (hklprev == videodata->ime_hkl)
657  return;
658 
659  hklprev = videodata->ime_hkl;
660  switch (PRIMLANG()) {
661  case LANG_CHINESE:
662  videodata->ime_candvertical = SDL_TRUE;
663  if (SUBLANG() == SUBLANG_CHINESE_SIMPLIFIED)
664  videodata->ime_candvertical = SDL_FALSE;
665 
666  break;
667  case LANG_JAPANESE:
668  videodata->ime_candvertical = SDL_TRUE;
669  break;
670  case LANG_KOREAN:
671  videodata->ime_candvertical = SDL_FALSE;
672  break;
673  }
674 }
675 
676 static void
677 IME_ClearComposition(SDL_VideoData *videodata)
678 {
679  HIMC himc = 0;
680  if (!videodata->ime_initialized)
681  return;
682 
683  himc = ImmGetContext(videodata->ime_hwnd_current);
684  if (!himc)
685  return;
686 
687  ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
688  if (videodata->ime_uiless)
689  ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR));
690 
691  ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0);
692  ImmReleaseContext(videodata->ime_hwnd_current, himc);
693  SDL_SendEditingText("", 0, 0);
694 }
695 
696 static void
697 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
698 {
699  LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition) - sizeof(videodata->ime_composition[0]));
700  if (length < 0)
701  length = 0;
702 
703  length /= sizeof(videodata->ime_composition[0]);
704  videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
705  if (videodata->ime_cursor < SDL_arraysize(videodata->ime_composition) && videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
706  int i;
707  for (i = videodata->ime_cursor + 1; i < length; ++i)
708  videodata->ime_composition[i - 1] = videodata->ime_composition[i];
709 
710  --length;
711  }
712  videodata->ime_composition[length] = 0;
713 }
714 
715 static void
716 IME_SendInputEvent(SDL_VideoData *videodata)
717 {
718  char *s = 0;
719  s = WIN_StringToUTF8(videodata->ime_composition);
721  SDL_free(s);
722 
723  videodata->ime_composition[0] = 0;
724  videodata->ime_readingstring[0] = 0;
725  videodata->ime_cursor = 0;
726 }
727 
728 static void
729 IME_SendEditingEvent(SDL_VideoData *videodata)
730 {
731  char *s = 0;
732  WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
733  const size_t size = SDL_arraysize(buffer);
734  buffer[0] = 0;
735  if (videodata->ime_readingstring[0]) {
736  size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
737  SDL_wcslcpy(buffer, videodata->ime_composition, len + 1);
738  SDL_wcslcat(buffer, videodata->ime_readingstring, size);
739  SDL_wcslcat(buffer, &videodata->ime_composition[len], size);
740  }
741  else {
742  SDL_wcslcpy(buffer, videodata->ime_composition, size);
743  }
744  s = WIN_StringToUTF8(buffer);
745  SDL_SendEditingText(s, videodata->ime_cursor + (int)SDL_wcslen(videodata->ime_readingstring), 0);
746  SDL_free(s);
747 }
748 
749 static void
750 IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate)
751 {
752  LPWSTR dst = videodata->ime_candidates[i];
753  *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10));
754  if (videodata->ime_candvertical)
755  *dst++ = TEXT(' ');
756 
757  while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i])))
758  *dst++ = *candidate++;
759 
760  *dst = (WCHAR)'\0';
761 }
762 
763 static void
764 IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata)
765 {
766  LPCANDIDATELIST cand_list = 0;
767  DWORD size = ImmGetCandidateListW(himc, 0, 0, 0);
768  if (size) {
769  cand_list = (LPCANDIDATELIST)SDL_malloc(size);
770  if (cand_list) {
771  size = ImmGetCandidateListW(himc, 0, cand_list, size);
772  if (size) {
773  UINT i, j;
774  UINT page_start = 0;
775  videodata->ime_candsel = cand_list->dwSelection;
776  videodata->ime_candcount = cand_list->dwCount;
777 
778  if (LANG() == LANG_CHS && IME_GetId(videodata, 0)) {
779  const UINT maxcandchar = 18;
780  size_t cchars = 0;
781 
782  for (i = 0; i < videodata->ime_candcount; ++i) {
783  size_t len = SDL_wcslen((LPWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i])) + 1;
784  if (len + cchars > maxcandchar) {
785  if (i > cand_list->dwSelection)
786  break;
787 
788  page_start = i;
789  cchars = len;
790  }
791  else {
792  cchars += len;
793  }
794  }
795  videodata->ime_candpgsize = i - page_start;
796  } else {
797  videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize, MAX_CANDLIST);
798  page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize;
799  }
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);
804  }
805  if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0)))
806  videodata->ime_candsel = -1;
807 
808  }
809  SDL_free(cand_list);
810  }
811  }
812 }
813 
814 static void
815 IME_ShowCandidateList(SDL_VideoData *videodata)
816 {
817  videodata->ime_dirty = SDL_TRUE;
818  videodata->ime_candlist = SDL_TRUE;
819  IME_DestroyTextures(videodata);
820  IME_SendEditingEvent(videodata);
821 }
822 
823 static void
824 IME_HideCandidateList(SDL_VideoData *videodata)
825 {
826  videodata->ime_dirty = SDL_FALSE;
827  videodata->ime_candlist = SDL_FALSE;
828  IME_DestroyTextures(videodata);
829  IME_SendEditingEvent(videodata);
830 }
831 
832 SDL_bool
833 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
834 {
835  SDL_bool trap = SDL_FALSE;
836  HIMC himc = 0;
837  if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
838  return SDL_FALSE;
839 
840  switch (msg) {
841  case WM_INPUTLANGCHANGE:
842  IME_InputLangChanged(videodata);
843  break;
844  case WM_IME_SETCONTEXT:
845  *lParam = 0;
846  break;
847  case WM_IME_STARTCOMPOSITION:
848  trap = SDL_TRUE;
849  break;
850  case WM_IME_COMPOSITION:
851  trap = SDL_TRUE;
852  himc = ImmGetContext(hwnd);
853  if (*lParam & GCS_RESULTSTR) {
854  IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
855  IME_SendInputEvent(videodata);
856  }
857  if (*lParam & GCS_COMPSTR) {
858  if (!videodata->ime_uiless)
859  videodata->ime_readingstring[0] = 0;
860 
861  IME_GetCompositionString(videodata, himc, GCS_COMPSTR);
862  IME_SendEditingEvent(videodata);
863  }
864  ImmReleaseContext(hwnd, himc);
865  break;
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);
871  break;
872  case WM_IME_NOTIFY:
873  switch (wParam) {
874  case IMN_SETCONVERSIONMODE:
875  case IMN_SETOPENSTATUS:
876  IME_UpdateInputLocale(videodata);
877  break;
878  case IMN_OPENCANDIDATE:
879  case IMN_CHANGECANDIDATE:
880  if (videodata->ime_uiless)
881  break;
882 
883  trap = SDL_TRUE;
884  IME_ShowCandidateList(videodata);
885  himc = ImmGetContext(hwnd);
886  if (!himc)
887  break;
888 
889  IME_GetCandidateList(himc, videodata);
890  ImmReleaseContext(hwnd, himc);
891  break;
892  case IMN_CLOSECANDIDATE:
893  trap = SDL_TRUE;
894  IME_HideCandidateList(videodata);
895  break;
896  case IMN_PRIVATE:
897  {
898  DWORD dwId = IME_GetId(videodata, 0);
899  IME_GetReadingString(videodata, hwnd);
900  switch (dwId)
901  {
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)
908  trap = SDL_TRUE;
909 
910  break;
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:
916  if (*lParam == 16
917  || *lParam == 17
918  || *lParam == 26
919  || *lParam == 27
920  || *lParam == 28)
921  trap = SDL_TRUE;
922  break;
923  }
924  }
925  break;
926  default:
927  trap = SDL_TRUE;
928  break;
929  }
930  break;
931  }
932  return trap;
933 }
934 
935 static void
936 IME_CloseCandidateList(SDL_VideoData *videodata)
937 {
938  IME_HideCandidateList(videodata);
939  videodata->ime_candcount = 0;
940  SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
941 }
942 
943 static void
944 UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pcandlist)
945 {
946  UINT selection = 0;
947  UINT count = 0;
948  UINT page = 0;
949  UINT pgcount = 0;
950  DWORD pgstart = 0;
951  DWORD pgsize = 0;
952  UINT i, j;
953  pcandlist->lpVtbl->GetSelection(pcandlist, &selection);
954  pcandlist->lpVtbl->GetCount(pcandlist, &count);
955  pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page);
956 
957  videodata->ime_candsel = selection;
958  videodata->ime_candcount = count;
959  IME_ShowCandidateList(videodata);
960 
961  pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount);
962  if (pgcount > 0) {
963  UINT *idxlist = SDL_malloc(sizeof(UINT) * pgcount);
964  if (idxlist) {
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;
969  else
970  pgsize = count - pgstart;
971 
972  SDL_free(idxlist);
973  }
974  }
975  videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST);
976  videodata->ime_candsel = videodata->ime_candsel - pgstart;
977 
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++) {
980  BSTR bstr;
981  if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) {
982  if (bstr) {
983  IME_AddCandidate(videodata, j, bstr);
984  SysFreeString(bstr);
985  }
986  }
987  }
988  if (PRIMLANG() == LANG_KOREAN)
989  videodata->ime_candsel = -1;
990 }
991 
992 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
993 {
994  return ++sink->refcount;
995 }
996 
997 STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink)
998 {
999  --sink->refcount;
1000  if (sink->refcount == 0) {
1001  SDL_free(sink);
1002  return 0;
1003  }
1004  return sink->refcount;
1005 }
1006 
1007 STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
1008 {
1009  if (!ppv)
1010  return E_INVALIDARG;
1011 
1012  *ppv = 0;
1013  if (SDL_IsEqualIID(riid, &IID_IUnknown))
1014  *ppv = (IUnknown *)sink;
1015  else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink))
1016  *ppv = (ITfUIElementSink *)sink;
1017 
1018  if (*ppv) {
1019  TSFSink_AddRef(sink);
1020  return S_OK;
1021  }
1022  return E_NOINTERFACE;
1023 }
1024 
1025 ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId)
1026 {
1027  ITfUIElementMgr *puiem = 0;
1028  ITfUIElement *pelem = 0;
1029  ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex;
1030 
1031  if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) {
1032  puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem);
1033  puiem->lpVtbl->Release(puiem);
1034  }
1035  return pelem;
1036 }
1037 
1038 STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow)
1039 {
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;
1044  if (!element)
1045  return E_INVALIDARG;
1046 
1047  *pbShow = FALSE;
1048  if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1049  BSTR bstr;
1050  if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
1051  SysFreeString(bstr);
1052  }
1053  preading->lpVtbl->Release(preading);
1054  }
1055  else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1056  videodata->ime_candref++;
1057  UILess_GetCandidateList(videodata, pcandlist);
1058  pcandlist->lpVtbl->Release(pcandlist);
1059  }
1060  return S_OK;
1061 }
1062 
1063 STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId)
1064 {
1065  ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
1066  ITfReadingInformationUIElement *preading = 0;
1067  ITfCandidateListUIElement *pcandlist = 0;
1068  SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1069  if (!element)
1070  return E_INVALIDARG;
1071 
1072  if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1073  BSTR bstr;
1074  if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
1075  WCHAR *s = (WCHAR *)bstr;
1076  SDL_wcslcpy(videodata->ime_readingstring, s, SDL_arraysize(videodata->ime_readingstring));
1077  IME_SendEditingEvent(videodata);
1078  SysFreeString(bstr);
1079  }
1080  preading->lpVtbl->Release(preading);
1081  }
1082  else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1083  UILess_GetCandidateList(videodata, pcandlist);
1084  pcandlist->lpVtbl->Release(pcandlist);
1085  }
1086  return S_OK;
1087 }
1088 
1089 STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId)
1090 {
1091  ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
1092  ITfReadingInformationUIElement *preading = 0;
1093  ITfCandidateListUIElement *pcandlist = 0;
1094  SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1095  if (!element)
1096  return E_INVALIDARG;
1097 
1098  if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
1099  videodata->ime_readingstring[0] = 0;
1100  IME_SendEditingEvent(videodata);
1101  preading->lpVtbl->Release(preading);
1102  }
1103  if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
1104  videodata->ime_candref--;
1105  if (videodata->ime_candref == 0)
1106  IME_CloseCandidateList(videodata);
1107 
1108  pcandlist->lpVtbl->Release(pcandlist);
1109  }
1110  return S_OK;
1111 }
1112 
1113 STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
1114 {
1115  if (!ppv)
1116  return E_INVALIDARG;
1117 
1118  *ppv = 0;
1119  if (SDL_IsEqualIID(riid, &IID_IUnknown))
1120  *ppv = (IUnknown *)sink;
1121  else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink))
1123 
1124  if (*ppv) {
1125  TSFSink_AddRef(sink);
1126  return S_OK;
1127  }
1128  return E_NOINTERFACE;
1129 }
1130 
1131 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
1132 {
1133  static const GUID TF_PROFILE_DAYI = { 0x037B2C25, 0x480C, 0x4D7F, { 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A } };
1134  SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
1135  videodata->ime_candlistindexbase = SDL_IsEqualGUID(&TF_PROFILE_DAYI, guidProfile) ? 0 : 1;
1136  if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
1137  IME_InputLangChanged((SDL_VideoData *)sink->data);
1138 
1139  IME_HideCandidateList(videodata);
1140  return S_OK;
1141 }
1142 
1143 static void *vtUIElementSink[] = {
1144  (void *)(UIElementSink_QueryInterface),
1145  (void *)(TSFSink_AddRef),
1146  (void *)(TSFSink_Release),
1147  (void *)(UIElementSink_BeginUIElement),
1148  (void *)(UIElementSink_UpdateUIElement),
1149  (void *)(UIElementSink_EndUIElement)
1150 };
1151 
1152 static void *vtIPPASink[] = {
1153  (void *)(IPPASink_QueryInterface),
1154  (void *)(TSFSink_AddRef),
1155  (void *)(TSFSink_Release),
1156  (void *)(IPPASink_OnActivated)
1157 };
1158 
1159 static void
1160 UILess_EnableUIUpdates(SDL_VideoData *videodata)
1161 {
1162  ITfSource *source = 0;
1163  if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE)
1164  return;
1165 
1166  if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1167  source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie);
1168  source->lpVtbl->Release(source);
1169  }
1170 }
1171 
1172 static void
1173 UILess_DisableUIUpdates(SDL_VideoData *videodata)
1174 {
1175  ITfSource *source = 0;
1176  if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE)
1177  return;
1178 
1179  if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1180  source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
1182  source->lpVtbl->Release(source);
1183  }
1184 }
1185 
1186 static SDL_bool
1187 UILess_SetupSinks(SDL_VideoData *videodata)
1188 {
1189  TfClientId clientid = 0;
1191  ITfSource *source = 0;
1192  if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, (LPVOID *)&videodata->ime_threadmgrex)))
1193  return SDL_FALSE;
1194 
1195  if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY)))
1196  return SDL_FALSE;
1197 
1198  videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink));
1199  videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink));
1200 
1201  videodata->ime_uielemsink->lpVtbl = vtUIElementSink;
1202  videodata->ime_uielemsink->refcount = 1;
1203  videodata->ime_uielemsink->data = videodata;
1204 
1205  videodata->ime_ippasink->lpVtbl = vtIPPASink;
1206  videodata->ime_ippasink->refcount = 1;
1207  videodata->ime_ippasink->data = videodata;
1208 
1209  if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1210  if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) {
1211  if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) {
1212  result = SDL_TRUE;
1213  }
1214  }
1215  source->lpVtbl->Release(source);
1216  }
1217  return result;
1218 }
1219 
1220 #define SAFE_RELEASE(p) \
1221 { \
1222  if (p) { \
1223  (p)->lpVtbl->Release((p)); \
1224  (p) = 0; \
1225  } \
1226 }
1227 
1228 static void
1229 UILess_ReleaseSinks(SDL_VideoData *videodata)
1230 {
1231  ITfSource *source = 0;
1232  if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
1233  source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
1234  source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie);
1235  SAFE_RELEASE(source);
1236  videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex);
1237  SAFE_RELEASE(videodata->ime_threadmgrex);
1238  TSFSink_Release(videodata->ime_uielemsink);
1239  videodata->ime_uielemsink = 0;
1240  TSFSink_Release(videodata->ime_ippasink);
1241  videodata->ime_ippasink = 0;
1242  }
1243 }
1244 
1245 static void *
1246 StartDrawToBitmap(HDC hdc, HBITMAP *hhbm, int width, int height)
1247 {
1248  BITMAPINFO info;
1249  BITMAPINFOHEADER *infoHeader = &info.bmiHeader;
1250  BYTE *bits = NULL;
1251  if (hhbm) {
1252  SDL_zero(info);
1253  infoHeader->biSize = sizeof(BITMAPINFOHEADER);
1254  infoHeader->biWidth = width;
1255  infoHeader->biHeight = -1 * SDL_abs(height);
1256  infoHeader->biPlanes = 1;
1257  infoHeader->biBitCount = 32;
1258  infoHeader->biCompression = BI_RGB;
1259  *hhbm = CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void **)&bits, 0, 0);
1260  if (*hhbm)
1261  SelectObject(hdc, *hhbm);
1262  }
1263  return bits;
1264 }
1265 
1266 static void
1267 StopDrawToBitmap(HDC hdc, HBITMAP *hhbm)
1268 {
1269  if (hhbm && *hhbm) {
1270  DeleteObject(*hhbm);
1271  *hhbm = NULL;
1272  }
1273 }
1274 
1275 /* This draws only within the specified area and fills the entire region. */
1276 static void
1277 DrawRect(HDC hdc, int left, int top, int right, int bottom, int pensize)
1278 {
1279  /* The case of no pen (PenSize = 0) is automatically taken care of. */
1280  const int penadjust = (int)SDL_floor(pensize / 2.0f - 0.5f);
1281  left += pensize / 2;
1282  top += pensize / 2;
1283  right -= penadjust;
1284  bottom -= penadjust;
1285  Rectangle(hdc, left, top, right, bottom);
1286 }
1287 
1288 static void
1289 IME_DestroyTextures(SDL_VideoData *videodata)
1290 {
1291 }
1292 
1293 #define SDL_swap(a,b) { \
1294  int c = (a); \
1295  (a) = (b); \
1296  (b) = c; \
1297  }
1298 
1299 static void
1300 IME_PositionCandidateList(SDL_VideoData *videodata, SIZE size)
1301 {
1302  int left, top, right, bottom;
1303  SDL_bool ok = SDL_FALSE;
1304  int winw = videodata->ime_winwidth;
1305  int winh = videodata->ime_winheight;
1306 
1307  /* Bottom */
1308  left = videodata->ime_rect.x;
1309  top = videodata->ime_rect.y + videodata->ime_rect.h;
1310  right = left + size.cx;
1311  bottom = top + size.cy;
1312  if (right >= winw) {
1313  left -= right - winw;
1314  right = winw;
1315  }
1316  if (bottom < winh)
1317  ok = SDL_TRUE;
1318 
1319  /* Top */
1320  if (!ok) {
1321  left = videodata->ime_rect.x;
1322  top = videodata->ime_rect.y - size.cy;
1323  right = left + size.cx;
1324  bottom = videodata->ime_rect.y;
1325  if (right >= winw) {
1326  left -= right - winw;
1327  right = winw;
1328  }
1329  if (top >= 0)
1330  ok = SDL_TRUE;
1331  }
1332 
1333  /* Right */
1334  if (!ok) {
1335  left = videodata->ime_rect.x + size.cx;
1336  top = 0;
1337  right = left + size.cx;
1338  bottom = size.cy;
1339  if (right < winw)
1340  ok = SDL_TRUE;
1341  }
1342 
1343  /* Left */
1344  if (!ok) {
1345  left = videodata->ime_rect.x - size.cx;
1346  top = 0;
1347  right = videodata->ime_rect.x;
1348  bottom = size.cy;
1349  if (right >= 0)
1350  ok = SDL_TRUE;
1351  }
1352 
1353  /* Window too small, show at (0,0) */
1354  if (!ok) {
1355  left = 0;
1356  top = 0;
1357  right = size.cx;
1358  bottom = size.cy;
1359  }
1360 
1361  videodata->ime_candlistrect.x = left;
1362  videodata->ime_candlistrect.y = top;
1363  videodata->ime_candlistrect.w = right - left;
1364  videodata->ime_candlistrect.h = bottom - top;
1365 }
1366 
1367 static void
1368 IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc)
1369 {
1370  int i, j;
1371  SIZE size = {0};
1372  SIZE candsizes[MAX_CANDLIST];
1373  SIZE maxcandsize = {0};
1374  HBITMAP hbm = NULL;
1375  const int candcount = SDL_min(SDL_min(MAX_CANDLIST, videodata->ime_candcount), videodata->ime_candpgsize);
1376  SDL_bool vertical = videodata->ime_candvertical;
1377 
1378  const int listborder = 1;
1379  const int listpadding = 0;
1380  const int listbordercolor = RGB(0xB4, 0xC7, 0xAA);
1381  const int listfillcolor = RGB(255, 255, 255);
1382 
1383  const int candborder = 1;
1384  const int candpadding = 0;
1385  const int candmargin = 1;
1386  const COLORREF candbordercolor = RGB(255, 255, 255);
1387  const COLORREF candfillcolor = RGB(255, 255, 255);
1388  const COLORREF candtextcolor = RGB(0, 0, 0);
1389  const COLORREF selbordercolor = RGB(0x84, 0xAC, 0xDD);
1390  const COLORREF selfillcolor = RGB(0xD2, 0xE6, 0xFF);
1391  const COLORREF seltextcolor = RGB(0, 0, 0);
1392  const int horzcandspacing = 5;
1393 
1394  HPEN listpen = listborder != 0 ? CreatePen(PS_SOLID, listborder, listbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1395  HBRUSH listbrush = CreateSolidBrush(listfillcolor);
1396  HPEN candpen = candborder != 0 ? CreatePen(PS_SOLID, candborder, candbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1397  HBRUSH candbrush = CreateSolidBrush(candfillcolor);
1398  HPEN selpen = candborder != 0 ? CreatePen(PS_DOT, candborder, selbordercolor) : (HPEN)GetStockObject(NULL_PEN);
1399  HBRUSH selbrush = CreateSolidBrush(selfillcolor);
1400  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"));
1401 
1402  SetBkMode(hdc, TRANSPARENT);
1403  SelectObject(hdc, font);
1404 
1405  for (i = 0; i < candcount; ++i) {
1406  const WCHAR *s = videodata->ime_candidates[i];
1407  if (!*s)
1408  break;
1409 
1410  GetTextExtentPoint32W(hdc, s, (int)SDL_wcslen(s), &candsizes[i]);
1411  maxcandsize.cx = SDL_max(maxcandsize.cx, candsizes[i].cx);
1412  maxcandsize.cy = SDL_max(maxcandsize.cy, candsizes[i].cy);
1413 
1414  }
1415  if (vertical) {
1416  size.cx =
1417  (listborder * 2) +
1418  (listpadding * 2) +
1419  (candmargin * 2) +
1420  (candborder * 2) +
1421  (candpadding * 2) +
1422  (maxcandsize.cx)
1423  ;
1424  size.cy =
1425  (listborder * 2) +
1426  (listpadding * 2) +
1427  ((candcount + 1) * candmargin) +
1428  (candcount * candborder * 2) +
1429  (candcount * candpadding * 2) +
1430  (candcount * maxcandsize.cy)
1431  ;
1432  }
1433  else {
1434  size.cx =
1435  (listborder * 2) +
1436  (listpadding * 2) +
1437  ((candcount + 1) * candmargin) +
1438  (candcount * candborder * 2) +
1439  (candcount * candpadding * 2) +
1440  ((candcount - 1) * horzcandspacing);
1441  ;
1442 
1443  for (i = 0; i < candcount; ++i)
1444  size.cx += candsizes[i].cx;
1445 
1446  size.cy =
1447  (listborder * 2) +
1448  (listpadding * 2) +
1449  (candmargin * 2) +
1450  (candborder * 2) +
1451  (candpadding * 2) +
1452  (maxcandsize.cy)
1453  ;
1454  }
1455 
1456  StartDrawToBitmap(hdc, &hbm, size.cx, size.cy);
1457 
1458  SelectObject(hdc, listpen);
1459  SelectObject(hdc, listbrush);
1460  DrawRect(hdc, 0, 0, size.cx, size.cy, listborder);
1461 
1462  SelectObject(hdc, candpen);
1463  SelectObject(hdc, candbrush);
1464  SetTextColor(hdc, candtextcolor);
1465  SetBkMode(hdc, TRANSPARENT);
1466 
1467  for (i = 0; i < candcount; ++i) {
1468  const WCHAR *s = videodata->ime_candidates[i];
1469  int left, top, right, bottom;
1470  if (!*s)
1471  break;
1472 
1473  if (vertical) {
1474  left = listborder + listpadding + candmargin;
1475  top = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * maxcandsize.cy);
1476  right = size.cx - listborder - listpadding - candmargin;
1477  bottom = top + maxcandsize.cy + (candpadding * 2) + (candborder * 2);
1478  }
1479  else {
1480  left = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * horzcandspacing);
1481 
1482  for (j = 0; j < i; ++j)
1483  left += candsizes[j].cx;
1484 
1485  top = listborder + listpadding + candmargin;
1486  right = left + candsizes[i].cx + (candpadding * 2) + (candborder * 2);
1487  bottom = size.cy - listborder - listpadding - candmargin;
1488  }
1489 
1490  if (i == videodata->ime_candsel) {
1491  SelectObject(hdc, selpen);
1492  SelectObject(hdc, selbrush);
1493  SetTextColor(hdc, seltextcolor);
1494  }
1495  else {
1496  SelectObject(hdc, candpen);
1497  SelectObject(hdc, candbrush);
1498  SetTextColor(hdc, candtextcolor);
1499  }
1500 
1501  DrawRect(hdc, left, top, right, bottom, candborder);
1502  ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, (int)SDL_wcslen(s), NULL);
1503  }
1504  StopDrawToBitmap(hdc, &hbm);
1505 
1506  DeleteObject(listpen);
1507  DeleteObject(listbrush);
1508  DeleteObject(candpen);
1509  DeleteObject(candbrush);
1510  DeleteObject(selpen);
1511  DeleteObject(selbrush);
1512  DeleteObject(font);
1513 
1514  IME_PositionCandidateList(videodata, size);
1515 }
1516 
1517 static void
1518 IME_Render(SDL_VideoData *videodata)
1519 {
1520  HDC hdc = CreateCompatibleDC(NULL);
1521 
1522  if (videodata->ime_candlist)
1523  IME_RenderCandidateList(videodata, hdc);
1524 
1525  DeleteDC(hdc);
1526 
1527  videodata->ime_dirty = SDL_FALSE;
1528 }
1529 
1530 void IME_Present(SDL_VideoData *videodata)
1531 {
1532  if (videodata->ime_dirty)
1533  IME_Render(videodata);
1534 
1535  /* FIXME: Need to show the IME bitmap */
1536 }
1537 
1538 #endif /* SDL_DISABLE_WINDOWS_IME */
1539 
1540 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
1541 
1542 /* vi: set ts=4 sw=4 expandtab: */
void * data
void SDL_GetDefaultKeymap(SDL_Keycode *keymap)
Definition: SDL_keyboard.c:580
#define BI_RGB
Definition: SDL_bmp.c:44
GLenum GLenum dst
#define SDL_abs
Definition: edid.h:20
GLsizei GLenum GLboolean sink
#define MAX_CANDLIST
LPINPUTCONTEXT2(WINAPI *ImmLockIMC)(HIMC himc)
#define SDL_min(x, y)
Definition: SDL_stdinc.h:345
GLuint64EXT * result
TSFSink * ime_uielemsink
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Rect rect
Definition: testrelative.c:27
SDL_Window * window
const struct ITfThreadMgrExVtbl * lpVtbl
Definition: SDL_msctf.h:99
GLfloat GLfloat p
const struct ITfSourceVtbl * lpVtbl
Definition: SDL_msctf.h:239
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
void ** lpVtbl
static void DrawRect(SDL_Renderer *r, const int x, const int y, const int w, const int h)
Definition: testjoystick.c:40
#define SDLK_SCANCODE_MASK
Definition: SDL_keycode.h:44
GLint GLint GLsizei width
Definition: SDL_opengl.h:1565
GLfloat f
const struct ITfThreadMgrVtbl * lpVtbl
Definition: SDL_msctf.h:74
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define TF_INVALID_COOKIE
Definition: SDL_msctf.h:27
#define SDL_GetKeyboardFocus
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
#define SDL_LoadObject
DWORD ime_openmodesinkcookie
#define SDL_UnloadObject
#define SDL_floor
Sint32 SDL_Keycode
The SDL virtual key representation.
Definition: SDL_keycode.h:42
GLsizeiptr size
#define SDL_max(x, y)
Definition: SDL_stdinc.h:346
GLenum GLsizei len
const struct ITfDocumentMgrVtbl * lpVtbl
Definition: SDL_msctf.h:117
LPVOID(WINAPI *ImmLockIMCC)(HIMCC himcc)
#define E_NOINTERFACE
Definition: SDL_directx.h:61
GLdouble GLdouble right
DWORD TfClientId
Definition: SDL_msctf.h:51
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_bool
Definition: SDL_stdinc.h:126
SDL_bool ime_candlist
DWORD ime_uielemsinkcookie
void SDL_SetKeymap(int start, SDL_Keycode *keys, int length)
Definition: SDL_keyboard.c:586
#define SDL_GetWindowSize
#define FAILED(x)
Definition: SDL_directx.h:54
GLdouble s
Definition: SDL_opengl.h:2056
void WIN_StartTextInput(_THIS)
#define E_INVALIDARG
Definition: SDL_directx.h:67
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
#define SDL_wcslen
HRESULT WIN_CoInitialize(void)
#define _THIS
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
void SDL_free(void *mem)
SDL_bool ime_initialized
#define TF_IPSINK_FLAG_ACTIVE
Definition: SDL_msctf.h:28
void WIN_StopTextInput(_THIS)
const struct ITfCandidateListUIElementVtbl * lpVtbl
Definition: SDL_msctf.h:173
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:45
GLsizei GLsizei GLchar * source
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
#define SDL_wcslcat
GLint GLint bottom
void WIN_InitKeyboard(_THIS)
int x
Definition: SDL_rect.h:66
TSFSink * ime_ippasink
void WIN_QuitKeyboard(_THIS)
#define SDL_wcslcpy
#define S_OK
Definition: SDL_directx.h:47
void SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
Definition: SDL_keyboard.c:598
SDL_bool ime_enabled
int w
Definition: SDL_rect.h:67
const struct ITfUIElementVtbl * lpVtbl
Definition: SDL_msctf.h:211
BOOL(WINAPI *CloseTouchInputHandle)(HTOUCHINPUT)
DWORD ime_convmodesinkcookie
SDL_bool ime_available
SDL_bool ime_com_initialized
GLint left
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
Definition: SDL_keyboard.c:850
WCHAR ime_readingstring[16]
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define NULL
Definition: begin_code.h:143
void WIN_CoUninitialize(void)
GLintptr offset
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
void WIN_UpdateKeymap(void)
void WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
static const SDL_Scancode windows_scancode_table[]
int h
Definition: SDL_rect.h:67
The type used to identify a window.
Definition: SDL_sysvideo.h:71
SDL_bool ime_candvertical
GLuint buffer
WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE]
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
SDL_Rect ime_candlistrect
void * SDL_LoadFunction(void *handle, const char *name)
void * driverdata
Definition: SDL_sysvideo.h:106
#define TF_TMAE_UIELEMENTENABLEDONLY
Definition: SDL_msctf.h:29
GLuint GLsizei GLsizei * length
#define FALSE
Definition: edid-parse.c:32
int y
Definition: SDL_rect.h:66
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
const struct ITfReadingInformationUIElementVtbl * lpVtbl
Definition: SDL_msctf.h:195
int SDL_SendEditingText(const char *text, int start, int length)
Definition: SDL_keyboard.c:797
WCHAR ime_candidates[MAX_CANDLIST][MAX_CANDLENGTH]
GLdouble GLdouble GLdouble GLdouble top
#define SDL_memset
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata)
#define SDL_TEXTEDITINGEVENT_TEXT_SIZE
Definition: SDL_events.h:199
struct ITfThreadMgrEx * ime_threadmgrex
struct ITfThreadMgr * ime_threadmgr
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:42
const struct ITfUIElementMgrVtbl * lpVtbl
Definition: SDL_msctf.h:149