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