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