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