1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: win32ss/user/user32/misc/imm.c
5 * PURPOSE: User32.dll Imm functions
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8 */
9
10 #include <user32.h>
11 #include <strsafe.h>
12 #include <immdev.h>
13
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15
16 #define IMM_INIT_MAGIC 0x19650412
17 #define MAX_CANDIDATEFORM 4
18
19 /* Is != NULL when we have loaded the IMM ourselves */
20 HINSTANCE ghImm32 = NULL; // Win: ghImm32
21
22 BOOL gbImmInitializing = FALSE; // Win: bImmInitializing
23
24 INT gfConIme = -1; // Win: gfConIme
25
IntGetTopLevelWindow(HWND hWnd)26 HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
27 {
28 DWORD style;
29
30 for (; hWnd; hWnd = GetParent(hWnd))
31 {
32 style = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE);
33 if (!(style & WS_CHILD))
34 break;
35 }
36
37 return hWnd;
38 }
39
40 /* define stub functions */
41 #undef DEFINE_IMM_ENTRY
42 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
43 static type WINAPI IMMSTUB_##name params { IMM_RETURN_##retkind((type)retval); }
44 #include "immtable.h"
45
46 // Win: gImmApiEntries
47 Imm32ApiTable gImmApiEntries = {
48 /* initialize by stubs */
49 #undef DEFINE_IMM_ENTRY
50 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
51 IMMSTUB_##name,
52 #include "immtable.h"
53 };
54
55 // Win: GetImmFileName
56 HRESULT
User32GetImmFileName(_Out_ LPWSTR lpBuffer,_In_ size_t cchBuffer)57 User32GetImmFileName(_Out_ LPWSTR lpBuffer, _In_ size_t cchBuffer)
58 {
59 UINT length = GetSystemDirectoryW(lpBuffer, cchBuffer);
60 if (length && length < cchBuffer)
61 {
62 StringCchCatW(lpBuffer, cchBuffer, L"\\");
63 return StringCchCatW(lpBuffer, cchBuffer, L"imm32.dll");
64 }
65 return StringCchCopyW(lpBuffer, cchBuffer, L"imm32.dll");
66 }
67
68 // @unimplemented
69 // Win: _InitializeImmEntryTable
IntInitializeImmEntryTable(VOID)70 static BOOL IntInitializeImmEntryTable(VOID)
71 {
72 WCHAR ImmFile[MAX_PATH];
73 HMODULE imm32 = ghImm32;
74
75 /* Check whether the IMM table has already been initialized */
76 if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME)
77 return TRUE;
78
79 User32GetImmFileName(ImmFile, _countof(ImmFile));
80 TRACE("File %S\n", ImmFile);
81
82 /* If IMM32 is already loaded, use it without increasing reference count. */
83 if (imm32 == NULL)
84 imm32 = GetModuleHandleW(ImmFile);
85
86 /*
87 * Loading imm32.dll will call imm32!DllMain function.
88 * imm32!DllMain calls User32InitializeImmEntryTable.
89 * Thus, if imm32.dll was loaded, the table has been loaded.
90 */
91 if (imm32 == NULL)
92 {
93 imm32 = ghImm32 = LoadLibraryW(ImmFile);
94 if (imm32 == NULL)
95 {
96 ERR("Did not load imm32.dll!\n");
97 return FALSE;
98 }
99 return TRUE;
100 }
101
102 /* load imm procedures */
103 #undef DEFINE_IMM_ENTRY
104 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
105 do { \
106 FN_##name proc = (FN_##name)GetProcAddress(imm32, #name); \
107 if (!proc) { \
108 ERR("Could not load %s\n", #name); \
109 return FALSE; \
110 } \
111 IMM_FN(name) = proc; \
112 } while (0);
113 #include "immtable.h"
114
115 return TRUE;
116 }
117
118 // Win: InitializeImmEntryTable
InitializeImmEntryTable(VOID)119 BOOL WINAPI InitializeImmEntryTable(VOID)
120 {
121 gbImmInitializing = TRUE;
122 return IntInitializeImmEntryTable();
123 }
124
125 // Win: User32InitializeImmEntryTable
User32InitializeImmEntryTable(DWORD magic)126 BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
127 {
128 TRACE("Imm (%x)\n", magic);
129
130 if (magic != IMM_INIT_MAGIC)
131 return FALSE;
132
133 /* Check whether the IMM table has already been initialized */
134 if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME)
135 return TRUE;
136
137 IntInitializeImmEntryTable();
138
139 if (ghImm32 == NULL && !gbImmInitializing)
140 {
141 WCHAR ImmFile[MAX_PATH];
142 User32GetImmFileName(ImmFile, _countof(ImmFile));
143 ghImm32 = LoadLibraryW(ImmFile);
144 if (ghImm32 == NULL)
145 {
146 ERR("Did not load imm32.dll!\n");
147 return FALSE;
148 }
149 }
150
151 return IMM_FN(ImmRegisterClient)(&gSharedInfo, ghImm32);
152 }
153
154 // Win: ImeIsUsableContext
User32CanSetImeWindowToImc(HIMC hIMC,HWND hImeWnd)155 static BOOL User32CanSetImeWindowToImc(HIMC hIMC, HWND hImeWnd)
156 {
157 PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
158 return pIMC && (!pIMC->hImeWnd || pIMC->hImeWnd == hImeWnd || !ValidateHwnd(pIMC->hImeWnd));
159 }
160
161 // Win: GetIMEShowStatus
User32GetImeShowStatus(VOID)162 static BOOL User32GetImeShowStatus(VOID)
163 {
164 return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_GETIMESHOWSTATUS);
165 }
166
167 /* Sends a message to the IME UI window. */
168 /* Win: SendMessageToUI(pimeui, uMsg, wParam, lParam, !unicode) */
169 static LRESULT
User32SendImeUIMessage(PIMEUI pimeui,UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL unicode)170 User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode)
171 {
172 LRESULT ret = 0;
173 HWND hwndUI = pimeui->hwndUI;
174 PWND pwnd, pwndUI;
175
176 ASSERT(pimeui->spwnd != NULL);
177
178 pwnd = pimeui->spwnd;
179 pwndUI = ValidateHwnd(hwndUI);
180 if (!pwnd || (pwnd->state & WNDS_DESTROYED) || (pwnd->state2 & WNDS2_INDESTROY) ||
181 !pwndUI || (pwndUI->state & WNDS_DESTROYED) || (pwndUI->state2 & WNDS2_INDESTROY))
182 {
183 return 0;
184 }
185
186 InterlockedIncrement(&pimeui->nCntInIMEProc);
187
188 if (unicode)
189 ret = SendMessageW(hwndUI, uMsg, wParam, lParam);
190 else
191 ret = SendMessageA(hwndUI, uMsg, wParam, lParam);
192
193 InterlockedDecrement(&pimeui->nCntInIMEProc);
194
195 return ret;
196 }
197
198 // Win: SendOpenStatusNotify
User32NotifyOpenStatus(PIMEUI pimeui,HWND hwndIMC,BOOL bOpen)199 static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen)
200 {
201 WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW);
202
203 ASSERT(pimeui->spwnd != NULL);
204
205 pimeui->fShowStatus = bOpen;
206
207 if (LOWORD(GetWin32ClientInfo()->dwExpWinVer) >= 0x400)
208 SendMessageW(hwndIMC, WM_IME_NOTIFY, wParam, 0);
209 else
210 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, 0, TRUE);
211 }
212
213 // Win: ImeMarkUsedContext
User32SetImeWindowOfImc(HIMC hIMC,HWND hImeWnd)214 static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd)
215 {
216 PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
217 if (!pIMC || pIMC->hImeWnd == hImeWnd)
218 return;
219
220 NtUserUpdateInputContext(hIMC, UIC_IMEWINDOW, (ULONG_PTR)hImeWnd);
221 }
222
223 // Win: ImeSetImc
User32UpdateImcOfImeUI(PIMEUI pimeui,HIMC hNewIMC)224 static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC)
225 {
226 HWND hImeWnd;
227 HIMC hOldIMC = pimeui->hIMC;
228
229 ASSERT(pimeui->spwnd != NULL);
230 hImeWnd = UserHMGetHandle(pimeui->spwnd);
231
232 if (hNewIMC == hOldIMC)
233 return;
234
235 if (hOldIMC)
236 User32SetImeWindowOfImc(hOldIMC, NULL);
237
238 pimeui->hIMC = hNewIMC;
239
240 if (hNewIMC)
241 User32SetImeWindowOfImc(hNewIMC, hImeWnd);
242 }
243
244 /* Handles WM_IME_NOTIFY message of the default IME window. */
245 /* Win: ImeNotifyHandler */
ImeWnd_OnImeNotify(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)246 static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
247 {
248 LRESULT ret = 0;
249 HIMC hIMC;
250 LPINPUTCONTEXT pIC;
251 HWND hwndUI, hwndIMC, hImeWnd, hwndOwner;
252
253 ASSERT(pimeui->spwnd != NULL);
254
255 switch (wParam)
256 {
257 case IMN_SETCONVERSIONMODE:
258 case IMN_SETOPENSTATUS:
259 hIMC = pimeui->hIMC;
260 pIC = IMM_FN(ImmLockIMC)(hIMC);
261 if (pIC)
262 {
263 hwndIMC = pimeui->hwndIMC;
264 if (IsWindow(hwndIMC))
265 {
266 NtUserNotifyIMEStatus(hwndIMC, pIC->fOpen, pIC->fdwConversion);
267 }
268 else if (gfConIme == TRUE && pimeui->spwnd)
269 {
270 hImeWnd = UserHMGetHandle(pimeui->spwnd);
271 hwndOwner = GetWindow(hImeWnd, GW_OWNER);
272 if (hwndOwner)
273 {
274 NtUserNotifyIMEStatus(hwndOwner, pIC->fOpen, pIC->fdwConversion);
275 }
276 }
277
278 IMM_FN(ImmUnlockIMC)(hIMC);
279 }
280 /* FALL THROUGH */
281 default:
282 ret = User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, lParam, TRUE);
283 break;
284
285 case IMN_PRIVATE:
286 hwndUI = pimeui->hwndUI;
287 if (IsWindow(hwndUI))
288 ret = SendMessageW(hwndUI, WM_IME_NOTIFY, wParam, lParam);
289 break;
290 }
291
292 return ret;
293 }
294
295 /* Creates the IME UI window. */
296 /* Win: CreateIMEUI */
User32CreateImeUIWindow(PIMEUI pimeui,HKL hKL)297 static HWND User32CreateImeUIWindow(PIMEUI pimeui, HKL hKL)
298 {
299 IMEINFOEX ImeInfoEx;
300 PIMEDPI pImeDpi;
301 WNDCLASSW wc;
302 HWND hwndUI = NULL;
303 CHAR szUIClass[32];
304 PWND pwnd = pimeui->spwnd;
305
306 ASSERT(pimeui->spwnd != NULL);
307
308 if (!pwnd || !IMM_FN(ImmGetImeInfoEx)(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
309 return NULL;
310
311 pImeDpi = IMM_FN(ImmLockImeDpi)(hKL);
312 if (!pImeDpi)
313 return NULL;
314
315 if (!GetClassInfoW(pImeDpi->hInst, ImeInfoEx.wszUIClass, &wc))
316 goto Quit;
317
318 if (ImeInfoEx.ImeInfo.fdwProperty & IME_PROP_UNICODE)
319 {
320 hwndUI = CreateWindowW(ImeInfoEx.wszUIClass, ImeInfoEx.wszUIClass, WS_POPUP | WS_DISABLED,
321 0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL);
322 }
323 else
324 {
325 WideCharToMultiByte(CP_ACP, 0, ImeInfoEx.wszUIClass, -1,
326 szUIClass, _countof(szUIClass), NULL, NULL);
327 szUIClass[_countof(szUIClass) - 1] = 0;
328
329 hwndUI = CreateWindowA(szUIClass, szUIClass, WS_POPUP | WS_DISABLED,
330 0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL);
331 }
332
333 if (hwndUI)
334 NtUserSetWindowLongPtr(hwndUI, IMMGWLP_IMC, (LONG_PTR)pimeui->hIMC, FALSE);
335
336 Quit:
337 IMM_FN(ImmUnlockImeDpi)(pImeDpi);
338 return hwndUI;
339 }
340
341 /* Initializes the default IME window. */
342 /* Win: ImeWndCreateHandler */
ImeWnd_OnCreate(PIMEUI pimeui,LPCREATESTRUCT lpCS)343 static INT ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS)
344 {
345 PWND pParentWnd, pWnd = pimeui->spwnd;
346 HIMC hIMC = NULL;
347
348 if (!pWnd || (pWnd->style & (WS_DISABLED | WS_POPUP)) != (WS_DISABLED | WS_POPUP))
349 return -1;
350
351 pParentWnd = ValidateHwnd(lpCS->hwndParent);
352 if (pParentWnd)
353 {
354 hIMC = pParentWnd->hImc;
355 if (hIMC && !User32CanSetImeWindowToImc(hIMC, UserHMGetHandle(pWnd)))
356 hIMC = NULL;
357 }
358
359 User32UpdateImcOfImeUI(pimeui, hIMC);
360
361 pimeui->fShowStatus = FALSE;
362 pimeui->nCntInIMEProc = 0;
363 pimeui->fActivate = FALSE;
364 pimeui->fDestroy = FALSE;
365 pimeui->hwndIMC = NULL;
366 pimeui->hKL = GetWin32ClientInfo()->hKL;
367 pimeui->fCtrlShowStatus = TRUE;
368 pimeui->dwLastStatus = 0;
369
370 return 0;
371 }
372
373 /* Destroys the IME UI window. */
374 /* Win: DestroyIMEUI */
User32DestroyImeUIWindow(PIMEUI pimeui)375 static VOID User32DestroyImeUIWindow(PIMEUI pimeui)
376 {
377 HWND hwndUI = pimeui->hwndUI;
378
379 if (IsWindow(hwndUI))
380 {
381 pimeui->fDestroy = TRUE;
382 NtUserDestroyWindow(hwndUI);
383 }
384
385 pimeui->fShowStatus = pimeui->fDestroy = FALSE;
386 pimeui->hwndUI = NULL;
387 }
388
389 /* Handles WM_IME_SELECT message of the default IME window. */
390 /* Win: ImeSelectHandler */
ImeWnd_OnImeSelect(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)391 static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
392 {
393 HKL hKL;
394 HWND hwndUI, hwndIMC = pimeui->hwndIMC;
395
396 if (wParam)
397 {
398 pimeui->hKL = hKL = (HKL)lParam;
399
400 if (!pimeui->fActivate)
401 return;
402
403 pimeui->hwndUI = hwndUI = User32CreateImeUIWindow(pimeui, hKL);
404 if (hwndUI)
405 User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE);
406
407 if (User32GetImeShowStatus() && pimeui->fCtrlShowStatus)
408 {
409 if (!pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC))
410 User32NotifyOpenStatus(pimeui, hwndIMC, TRUE);
411 }
412 }
413 else
414 {
415 if (pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC))
416 User32NotifyOpenStatus(pimeui, hwndIMC, FALSE);
417
418 User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE);
419 User32DestroyImeUIWindow(pimeui);
420 pimeui->hKL = NULL;
421 }
422 }
423
424 /* Handles WM_IME_CONTROL message of the default IME window. */
425 /* Win: ImeControlHandler(pimeui, wParam, lParam, !unicode) */
426 static LRESULT
ImeWnd_OnImeControl(PIMEUI pimeui,WPARAM wParam,LPARAM lParam,BOOL unicode)427 ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode)
428 {
429 HIMC hIMC = pimeui->hIMC;
430 DWORD dwConversion, dwSentence;
431 POINT pt;
432
433 if (IS_CICERO_MODE())
434 {
435 if (wParam == IMC_OPENSTATUSWINDOW)
436 {
437 IMM_FN(CtfImmRestoreToolbarWnd)(pimeui->dwLastStatus);
438 pimeui->dwLastStatus = 0;
439 }
440 else if (wParam == IMC_CLOSESTATUSWINDOW)
441 {
442 pimeui->dwLastStatus = IMM_FN(CtfImmHideToolbarWnd)();
443 }
444 }
445
446 if (!hIMC)
447 return 0;
448
449 switch (wParam)
450 {
451 case IMC_GETCONVERSIONMODE:
452 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence))
453 return 1;
454 return dwConversion;
455
456 case IMC_GETSENTENCEMODE:
457 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence))
458 return 1;
459 return dwSentence;
460
461 case IMC_GETOPENSTATUS:
462 return IMM_FN(ImmGetOpenStatus)(hIMC);
463
464 case IMC_SETCONVERSIONMODE:
465 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) ||
466 !IMM_FN(ImmSetConversionStatus)(hIMC, (DWORD)lParam, dwSentence))
467 {
468 return 1;
469 }
470 break;
471
472 case IMC_SETSENTENCEMODE:
473 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) ||
474 !IMM_FN(ImmSetConversionStatus)(hIMC, dwConversion, (DWORD)lParam))
475 {
476 return 1;
477 }
478 break;
479
480 case IMC_SETOPENSTATUS:
481 if (!IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam))
482 return 1;
483 break;
484
485 case IMC_GETCANDIDATEPOS:
486 case IMC_GETCOMPOSITIONWINDOW:
487 case IMC_GETSOFTKBDPOS:
488 case IMC_SETSOFTKBDPOS:
489 case IMC_GETSTATUSWINDOWPOS:
490 return User32SendImeUIMessage(pimeui, WM_IME_CONTROL, wParam, lParam, unicode);
491
492 case IMC_SETCANDIDATEPOS:
493 if (!IMM_FN(ImmSetCandidateWindow)(hIMC, (LPCANDIDATEFORM)lParam))
494 return 1;
495 break;
496
497 case IMC_GETCOMPOSITIONFONT:
498 if (unicode)
499 {
500 if (!IMM_FN(ImmGetCompositionFontW)(hIMC, (LPLOGFONTW)lParam))
501 return 1;
502 }
503 else
504 {
505 if (!IMM_FN(ImmGetCompositionFontA)(hIMC, (LPLOGFONTA)lParam))
506 return 1;
507 }
508 break;
509
510 case IMC_SETCOMPOSITIONFONT:
511 if (unicode)
512 {
513 if (!IMM_FN(ImmSetCompositionFontW)(hIMC, (LPLOGFONTW)lParam))
514 return 1;
515 }
516 else
517 {
518 if (!IMM_FN(ImmSetCompositionFontA)(hIMC, (LPLOGFONTA)lParam))
519 return 1;
520 }
521 break;
522
523 case IMC_SETCOMPOSITIONWINDOW:
524 if (!IMM_FN(ImmSetCompositionWindow)(hIMC, (LPCOMPOSITIONFORM)lParam))
525 return 1;
526 break;
527
528 case IMC_SETSTATUSWINDOWPOS:
529 pt.x = GET_X_LPARAM(lParam);
530 pt.y = GET_Y_LPARAM(lParam);
531 if (!IMM_FN(ImmSetStatusWindowPos)(hIMC, &pt))
532 return 1;
533 break;
534
535 case IMC_CLOSESTATUSWINDOW:
536 if (pimeui->fShowStatus && User32GetImeShowStatus())
537 {
538 pimeui->fShowStatus = FALSE;
539 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE);
540 }
541 pimeui->fCtrlShowStatus = FALSE;
542 break;
543
544 case IMC_OPENSTATUSWINDOW:
545 if (!pimeui->fShowStatus && User32GetImeShowStatus())
546 {
547 pimeui->fShowStatus = TRUE;
548 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_OPENSTATUSWINDOW, 0, TRUE);
549 }
550 pimeui->fCtrlShowStatus = TRUE;
551 break;
552
553 default:
554 break;
555 }
556
557 return 0;
558 }
559
560 /* Modify the IME activation status. */
561 /* Win: FocusSetIMCContext */
User32SetImeActivenessOfWindow(HWND hWnd,BOOL bActive)562 static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive)
563 {
564 HIMC hIMC;
565
566 if (!hWnd || !IsWindow(hWnd))
567 {
568 IMM_FN(ImmSetActiveContext)(NULL, NULL, bActive);
569 return;
570 }
571
572 hIMC = IMM_FN(ImmGetContext)(hWnd);
573 IMM_FN(ImmSetActiveContext)(hWnd, hIMC, bActive);
574 IMM_FN(ImmReleaseContext)(hWnd, hIMC);
575 }
576
577 /* Win: CtfLoadThreadLayout */
CtfLoadThreadLayout(PIMEUI pimeui)578 VOID FASTCALL CtfLoadThreadLayout(PIMEUI pimeui)
579 {
580 IMM_FN(CtfImmTIMActivate)(pimeui->hKL);
581 pimeui->hKL = GetWin32ClientInfo()->hKL;
582 IMM_FN(ImmLoadIME)(pimeui->hKL);
583 pimeui->hwndUI = NULL;
584 }
585
586 /* Open the IME help or check the existence of the IME help. */
587 static LRESULT FASTCALL
User32DoImeHelp(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)588 User32DoImeHelp(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
589 {
590 WCHAR szHelpFile[MAX_PATH];
591 DWORD ret, dwEsc = IME_ESC_GETHELPFILENAME;
592 size_t cch;
593
594 /* Is there any IME help file? */
595 ret = IMM_FN(ImmEscapeW)(pimeui->hKL, pimeui->hIMC, IME_ESC_QUERY_SUPPORT, &dwEsc);
596 if (!ret || !lParam)
597 return ret;
598
599 /* Get the help filename */
600 if (IMM_FN(ImmEscapeW)(pimeui->hKL, pimeui->hIMC, IME_ESC_GETHELPFILENAME, szHelpFile))
601 {
602 /* Check filename extension */
603 cch = wcslen(szHelpFile);
604 if (cch > 4 && _wcsicmp(&szHelpFile[cch - 4], L".HLP") == 0)
605 {
606 /* Open the old-style help */
607 TRACE("szHelpFile: %s\n", debugstr_w(szHelpFile));
608 WinHelpW(NULL, szHelpFile, HELP_FINDER, 0);
609 }
610 else
611 {
612 /* Open the new-style help */
613 FIXME("(%p, %p, %p): %s\n", pimeui, wParam, lParam, debugstr_w(szHelpFile));
614 ret = FALSE;
615 }
616 }
617
618 return ret;
619 }
620
621 /* Handles WM_IME_SYSTEM message of the default IME window. */
622 /* Win: ImeSystemHandler */
ImeWnd_OnImeSystem(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)623 static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
624 {
625 LRESULT ret = 0;
626 LPINPUTCONTEXTDX pIC;
627 HIMC hIMC = pimeui->hIMC;
628 LPCANDIDATEFORM pCandForm;
629 LPCOMPOSITIONFORM pCompForm;
630 DWORD dwConversion, dwSentence;
631 HWND hImeWnd;
632 BOOL bCompForm;
633 CANDIDATEFORM CandForm;
634 COMPOSITIONFORM CompForm;
635 UINT iCandForm;
636
637 ASSERT(pimeui->spwnd != NULL);
638
639 switch (wParam)
640 {
641 case IMS_NOTIFYIMESHOW:
642 if (User32GetImeShowStatus() == !lParam)
643 {
644 hImeWnd = UserHMGetHandle(pimeui->spwnd);
645 NtUserCallHwndParamLock(hImeWnd, lParam, TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE);
646 }
647 break;
648
649 case IMS_UPDATEIMEUI:
650 if (!hIMC)
651 break;
652
653 bCompForm = TRUE;
654 pIC = IMM_FN(ImmLockIMC)(hIMC);
655 if (pIC)
656 {
657 bCompForm = !(pIC->dwUIFlags & 0x2);
658 IMM_FN(ImmUnlockIMC)(hIMC);
659 }
660
661 if (!IsWindow(pimeui->hwndIMC))
662 break;
663
664 if (bCompForm && IMM_FN(ImmGetCompositionWindow)(hIMC, &CompForm))
665 {
666 if (CompForm.dwStyle)
667 IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm);
668 }
669
670 for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm)
671 {
672 if (IMM_FN(ImmGetCandidateWindow)(hIMC, iCandForm, &CandForm))
673 {
674 if (CandForm.dwStyle)
675 IMM_FN(ImmSetCandidateWindow)(hIMC, &CandForm);
676 }
677 }
678 break;
679
680 case IMS_SETCANDFORM:
681 pIC = IMM_FN(ImmLockIMC)(hIMC);
682 if (!pIC)
683 break;
684
685 pCandForm = &pIC->cfCandForm[lParam];
686 IMM_FN(ImmSetCandidateWindow)(hIMC, pCandForm);
687 IMM_FN(ImmUnlockIMC)(hIMC);
688 break;
689
690 case IMS_SETCOMPFONT:
691 pIC = IMM_FN(ImmLockIMC)(hIMC);
692 if (!pIC)
693 break;
694
695 IMM_FN(ImmSetCompositionFontW)(hIMC, &pIC->lfFont.W);
696 IMM_FN(ImmUnlockIMC)(hIMC);
697 break;
698
699 case IMS_SETCOMPFORM:
700 pIC = IMM_FN(ImmLockIMC)(hIMC);
701 if (!pIC)
702 break;
703
704 pCompForm = &pIC->cfCompForm;
705 pIC->dwUIFlags |= 0x8;
706 IMM_FN(ImmSetCompositionWindow)(hIMC, pCompForm);
707 IMM_FN(ImmUnlockIMC)(hIMC);
708 break;
709
710 case IMS_CONFIGURE:
711 IMM_FN(ImmConfigureIMEW)((HKL)lParam, pimeui->hwndIMC, IME_CONFIG_GENERAL, NULL);
712 break;
713
714 case IMS_SETOPENSTATUS:
715 if (hIMC)
716 IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam);
717 break;
718
719 case IMS_FREELAYOUT:
720 ret = IMM_FN(ImmFreeLayout)((HKL)lParam);
721 break;
722
723 case 0x13:
724 FIXME("\n");
725 break;
726
727 case IMS_GETCONVSTATUS:
728 IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence);
729 ret = dwConversion;
730 break;
731
732 case IMS_IMEHELP:
733 return User32DoImeHelp(pimeui, wParam, lParam);
734
735 case IMS_IMEACTIVATE:
736 User32SetImeActivenessOfWindow((HWND)lParam, TRUE);
737 break;
738
739 case IMS_IMEDEACTIVATE:
740 User32SetImeActivenessOfWindow((HWND)lParam, FALSE);
741 break;
742
743 case IMS_ACTIVATELAYOUT:
744 ret = IMM_FN(ImmActivateLayout)((HKL)lParam);
745 break;
746
747 case IMS_GETIMEMENU:
748 ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam);
749 break;
750
751 case 0x1D:
752 FIXME("\n");
753 break;
754
755 case IMS_GETCONTEXT:
756 ret = (ULONG_PTR)IMM_FN(ImmGetContext)((HWND)lParam);
757 break;
758
759 case IMS_SENDNOTIFICATION:
760 case IMS_COMPLETECOMPSTR:
761 case IMS_SETLANGBAND:
762 case IMS_UNSETLANGBAND:
763 ret = IMM_FN(ImmSystemHandler)(hIMC, wParam, lParam);
764 break;
765
766 case IMS_LOADTHREADLAYOUT:
767 CtfLoadThreadLayout(pimeui);
768 break;
769
770 default:
771 break;
772 }
773
774 return ret;
775 }
776
777 /* Handles WM_IME_SETCONTEXT message of the default IME window. */
778 /* Win: ImeSetContextHandler */
ImeWnd_OnImeSetContext(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)779 LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
780 {
781 LRESULT ret;
782 HIMC hIMC;
783 LPINPUTCONTEXTDX pIC;
784 HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner;
785 PWND pwndFocus, pImeWnd, pwndOwner;
786 COMPOSITIONFORM CompForm;
787
788 pimeui->fActivate = !!wParam;
789 hwndOldImc = pimeui->hwndIMC;
790 ASSERT(pimeui->spwnd != NULL);
791
792 if (wParam)
793 {
794 if (!pimeui->hwndUI)
795 pimeui->hwndUI = User32CreateImeUIWindow(pimeui, pimeui->hKL);
796
797 if (gfConIme == -1)
798 {
799 gfConIme = (INT)NtUserGetThreadState(THREADSTATE_CHECKCONIME);
800 if (gfConIme)
801 pimeui->fCtrlShowStatus = FALSE;
802 }
803
804 hImeWnd = UserHMGetHandle(pimeui->spwnd);
805
806 if (gfConIme)
807 {
808 hwndOwner = GetWindow(hImeWnd, GW_OWNER);
809 pwndOwner = ValidateHwnd(hwndOwner);
810 if (pwndOwner)
811 {
812 User32UpdateImcOfImeUI(pimeui, pwndOwner->hImc);
813
814 if (pimeui->hwndUI)
815 SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)pwndOwner->hImc);
816 }
817
818 return User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE);
819 }
820
821 hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
822
823 hIMC = IMM_FN(ImmGetContext)(hwndFocus);
824
825 if (hIMC && !User32CanSetImeWindowToImc(hIMC, hImeWnd))
826 {
827 User32UpdateImcOfImeUI(pimeui, NULL);
828 return 0;
829 }
830
831 User32UpdateImcOfImeUI(pimeui, hIMC);
832
833 if (pimeui->hwndUI)
834 SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)hIMC);
835
836 if (hIMC)
837 {
838 pIC = IMM_FN(ImmLockIMC)(hIMC);
839 if (!pIC)
840 return 0;
841
842 if (hwndFocus != pIC->hWnd)
843 {
844 IMM_FN(ImmUnlockIMC)(hIMC);
845 return 0;
846 }
847
848 if ((pIC->dwUIFlags & 0x40000) && hwndOldImc != hwndFocus)
849 {
850 RtlZeroMemory(&CompForm, sizeof(CompForm));
851 IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm);
852
853 pIC->dwUIFlags &= ~0x40000;
854 }
855
856 IMM_FN(ImmUnlockIMC)(hIMC);
857
858 hImeWnd = UserHMGetHandle(pimeui->spwnd);
859 if (NtUserSetImeOwnerWindow(hImeWnd, hwndFocus))
860 pimeui->hwndIMC = hwndFocus;
861 }
862 else
863 {
864 pimeui->hwndIMC = hwndFocus;
865
866 hImeWnd = UserHMGetHandle(pimeui->spwnd);
867 NtUserSetImeOwnerWindow(hImeWnd, NULL);
868 }
869 }
870
871 ret = User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE);
872
873 if (!pimeui->spwnd)
874 return 0;
875
876 if (!pimeui->fCtrlShowStatus || !User32GetImeShowStatus())
877 return ret;
878
879 hImeWnd = UserHMGetHandle(pimeui->spwnd);
880 hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
881 pwndFocus = ValidateHwnd(hwndFocus);
882
883 if (wParam)
884 {
885 pImeWnd = ValidateHwnd(hImeWnd);
886 if (pwndFocus && pImeWnd && pImeWnd->head.pti == pwndFocus->head.pti)
887 {
888 hwndNewImc = pimeui->hwndIMC;
889 if (pimeui->fShowStatus)
890 {
891 if (hwndOldImc && hwndNewImc && hwndOldImc != hwndNewImc &&
892 IntGetTopLevelWindow(hwndOldImc) != IntGetTopLevelWindow(hwndNewImc))
893 {
894 User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
895 User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
896 }
897 }
898 else
899 {
900 if (ValidateHwnd(hwndNewImc))
901 User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
902 }
903 }
904
905 pImeWnd = pimeui->spwnd;
906 hImeWnd = (pImeWnd ? UserHMGetHandle(pImeWnd) : NULL);
907 if (hImeWnd)
908 NtUserCallHwndLock(hImeWnd, HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD);
909 }
910 else
911 {
912 pImeWnd = pimeui->spwnd;
913 hImeWnd = UserHMGetHandle(pImeWnd);
914 hwndActive = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_ACTIVE);
915 if (!pwndFocus || !hwndActive || pImeWnd->head.pti != pwndFocus->head.pti)
916 {
917 if (IsWindow(hwndOldImc))
918 {
919 User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
920 }
921 else
922 {
923 pimeui->fShowStatus = FALSE;
924 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE);
925 }
926 }
927 }
928
929 return ret;
930 }
931
932 /* The window procedure of the default IME window */
933 /* Win: ImeWndProcWorker(pWnd, msg, wParam, lParam, !unicode) */
934 LRESULT WINAPI
ImeWndProc_common(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,BOOL unicode)935 ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode) // ReactOS
936 {
937 PWND pWnd;
938 PIMEUI pimeui;
939 LRESULT ret;
940
941 pWnd = ValidateHwnd(hwnd);
942 if (pWnd == NULL)
943 {
944 ERR("hwnd was %p\n", hwnd);
945 return 0;
946 }
947
948 if (!pWnd->fnid)
949 {
950 NtUserSetWindowFNID(hwnd, FNID_IME);
951 }
952 else if (pWnd->fnid != FNID_IME)
953 {
954 ERR("fnid was 0x%x\n", pWnd->fnid);
955 return 0;
956 }
957
958 pimeui = (PIMEUI)GetWindowLongPtrW(hwnd, 0);
959 if (pimeui == NULL)
960 {
961 pimeui = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMEUI));
962 if (pimeui == NULL)
963 {
964 ERR("HeapAlloc failed\n");
965 NtUserSetWindowFNID(hwnd, FNID_DESTROY);
966 DestroyWindow(hwnd);
967 return 0;
968 }
969
970 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)pimeui);
971 pimeui->spwnd = pWnd;
972 }
973
974 if (IS_CICERO_MODE())
975 {
976 ret = IMM_FN(CtfImmDispatchDefImeMessage)(hwnd, msg, wParam, lParam);
977 if (ret)
978 return ret;
979 }
980
981 if (pimeui->nCntInIMEProc > 0)
982 {
983 switch (msg)
984 {
985 case WM_IME_CHAR:
986 case WM_IME_COMPOSITIONFULL:
987 case WM_IME_CONTROL:
988 case WM_IME_REQUEST:
989 case WM_IME_SELECT:
990 case WM_IME_SETCONTEXT:
991 case WM_IME_STARTCOMPOSITION:
992 case WM_IME_COMPOSITION:
993 case WM_IME_ENDCOMPOSITION:
994 return 0;
995
996 case WM_IME_NOTIFY:
997 if (wParam < IMN_PRIVATE || IS_IME_HKL(pimeui->hKL) || !IS_CICERO_MODE())
998 return 0;
999 break;
1000
1001 case WM_IME_SYSTEM:
1002 switch (wParam)
1003 {
1004 case 0x03:
1005 case 0x10:
1006 case 0x13:
1007 break;
1008
1009 default:
1010 return 0;
1011 }
1012 break;
1013
1014 default:
1015 goto Finish;
1016 }
1017 }
1018
1019 if ((pWnd->state2 & WNDS2_INDESTROY) || (pWnd->state & WNDS_DESTROYED))
1020 {
1021 switch (msg)
1022 {
1023 case WM_DESTROY:
1024 case WM_NCDESTROY:
1025 case WM_FINALDESTROY:
1026 break;
1027
1028 default:
1029 return 0;
1030 }
1031 }
1032
1033 switch (msg)
1034 {
1035 case WM_CREATE:
1036 return ImeWnd_OnCreate(pimeui, (LPCREATESTRUCT)lParam);
1037
1038 case WM_DESTROY:
1039 User32DestroyImeUIWindow(pimeui);
1040 return 0;
1041
1042 case WM_NCDESTROY:
1043 case WM_FINALDESTROY:
1044 pimeui->spwnd = NULL;
1045 HeapFree(GetProcessHeap(), 0, pimeui);
1046 NtUserSetWindowFNID(hwnd, FNID_DESTROY);
1047 break;
1048
1049 case WM_ERASEBKGND:
1050 return TRUE;
1051
1052 case WM_PAINT:
1053 return 0;
1054
1055 case WM_IME_STARTCOMPOSITION:
1056 case WM_IME_COMPOSITION:
1057 case WM_IME_ENDCOMPOSITION:
1058 return User32SendImeUIMessage(pimeui, msg, wParam, lParam, unicode);
1059
1060 case WM_IME_CONTROL:
1061 return ImeWnd_OnImeControl(pimeui, wParam, lParam, unicode);
1062
1063 case WM_IME_NOTIFY:
1064 return ImeWnd_OnImeNotify(pimeui, wParam, lParam);
1065
1066 case WM_IME_REQUEST:
1067 return 0;
1068
1069 case WM_IME_SELECT:
1070 ImeWnd_OnImeSelect(pimeui, wParam, lParam);
1071 return (LRESULT)pimeui;
1072
1073 case WM_IME_SETCONTEXT:
1074 return ImeWnd_OnImeSetContext(pimeui, wParam, lParam);
1075
1076 case WM_IME_SYSTEM:
1077 return ImeWnd_OnImeSystem(pimeui, wParam, lParam);
1078
1079 default:
1080 break;
1081 }
1082
1083 Finish:
1084 if (unicode)
1085 return DefWindowProcW(hwnd, msg, wParam, lParam);
1086 return DefWindowProcA(hwnd, msg, wParam, lParam);
1087 }
1088
1089 // Win: ImeWndProcA
ImeWndProcA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1090 LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1091 {
1092 return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE);
1093 }
1094
1095 // Win: ImeWndProcW
ImeWndProcW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1096 LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1097 {
1098 return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE);
1099 }
1100
1101 // Win: UpdatePerUserImmEnabling
UpdatePerUserImmEnabling(VOID)1102 BOOL WINAPI UpdatePerUserImmEnabling(VOID)
1103 {
1104 HMODULE imm32;
1105 BOOL ret;
1106
1107 ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING);
1108 if (!ret || !(gpsi->dwSRVIFlags & SRVINFO_IMM32))
1109 return FALSE;
1110
1111 imm32 = GetModuleHandleW(L"imm32.dll");
1112 if (imm32)
1113 return TRUE;
1114
1115 imm32 = LoadLibraryW(L"imm32.dll");
1116 if (imm32 == NULL)
1117 {
1118 ERR("Imm32 not installed!\n");
1119 ret = FALSE;
1120 }
1121
1122 return ret;
1123 }
1124
1125 BOOL
1126 WINAPI
RegisterIMEClass(VOID)1127 RegisterIMEClass(VOID)
1128 {
1129 ATOM atom;
1130 WNDCLASSEXW WndClass = { sizeof(WndClass) };
1131
1132 WndClass.lpszClassName = L"IME";
1133 WndClass.style = CS_GLOBALCLASS;
1134 WndClass.lpfnWndProc = ImeWndProcW;
1135 WndClass.cbWndExtra = sizeof(LONG_PTR);
1136 WndClass.hCursor = LoadCursorW(NULL, IDC_ARROW);
1137
1138 atom = RegisterClassExWOWW(&WndClass, 0, FNID_IME, 0, FALSE);
1139 if (!atom)
1140 {
1141 ERR("Failed to register IME Class!\n");
1142 return FALSE;
1143 }
1144
1145 RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME);
1146 TRACE("RegisterIMEClass atom = %u\n", atom);
1147 return TRUE;
1148 }
1149
1150 /*
1151 * @implemented
1152 */
1153 BOOL
1154 WINAPI
IMPSetIMEW(HWND hwnd,LPIMEPROW ime)1155 IMPSetIMEW(HWND hwnd, LPIMEPROW ime)
1156 {
1157 return IMM_FN(ImmIMPSetIMEW)(hwnd, ime);
1158 }
1159
1160 /*
1161 * @implemented
1162 */
1163 BOOL
1164 WINAPI
IMPQueryIMEW(LPIMEPROW ime)1165 IMPQueryIMEW(LPIMEPROW ime)
1166 {
1167 return IMM_FN(ImmIMPQueryIMEW)(ime);
1168 }
1169
1170 /*
1171 * @implemented
1172 */
1173 BOOL
1174 WINAPI
IMPGetIMEW(HWND hwnd,LPIMEPROW ime)1175 IMPGetIMEW(HWND hwnd, LPIMEPROW ime)
1176 {
1177 return IMM_FN(ImmIMPGetIMEW)(hwnd, ime);
1178 }
1179
1180 /*
1181 * @implemented
1182 */
1183 BOOL
1184 WINAPI
IMPSetIMEA(HWND hwnd,LPIMEPROA ime)1185 IMPSetIMEA(HWND hwnd, LPIMEPROA ime)
1186 {
1187 return IMM_FN(ImmIMPSetIMEA)(hwnd, ime);
1188 }
1189
1190 /*
1191 * @implemented
1192 */
1193 BOOL
1194 WINAPI
IMPQueryIMEA(LPIMEPROA ime)1195 IMPQueryIMEA(LPIMEPROA ime)
1196 {
1197 return IMM_FN(ImmIMPQueryIMEA)(ime);
1198 }
1199
1200 /*
1201 * @implemented
1202 */
1203 BOOL
1204 WINAPI
IMPGetIMEA(HWND hwnd,LPIMEPROA ime)1205 IMPGetIMEA(HWND hwnd, LPIMEPROA ime)
1206 {
1207 return IMM_FN(ImmIMPGetIMEA)(hwnd, ime);
1208 }
1209
1210 /*
1211 * @implemented
1212 */
1213 LRESULT
1214 WINAPI
SendIMEMessageExW(HWND hwnd,LPARAM lParam)1215 SendIMEMessageExW(HWND hwnd, LPARAM lParam)
1216 {
1217 return IMM_FN(ImmSendIMEMessageExW)(hwnd, lParam);
1218 }
1219
1220 /*
1221 * @implemented
1222 */
1223 LRESULT
1224 WINAPI
SendIMEMessageExA(HWND hwnd,LPARAM lParam)1225 SendIMEMessageExA(HWND hwnd, LPARAM lParam)
1226 {
1227 return IMM_FN(ImmSendIMEMessageExA)(hwnd, lParam);
1228 }
1229
1230 /*
1231 * @implemented
1232 */
1233 BOOL
1234 WINAPI
WINNLSEnableIME(HWND hwnd,BOOL enable)1235 WINNLSEnableIME(HWND hwnd, BOOL enable)
1236 {
1237 return IMM_FN(ImmWINNLSEnableIME)(hwnd, enable);
1238 }
1239
1240 /*
1241 * @implemented
1242 */
1243 BOOL
1244 WINAPI
WINNLSGetEnableStatus(HWND hwnd)1245 WINNLSGetEnableStatus(HWND hwnd)
1246 {
1247 return IMM_FN(ImmWINNLSGetEnableStatus)(hwnd);
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 UINT
1254 WINAPI
WINNLSGetIMEHotkey(HWND hwnd)1255 WINNLSGetIMEHotkey(HWND hwnd)
1256 {
1257 return FALSE;
1258 }
1259