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