xref: /reactos/dll/win32/imm32/ime.c (revision 53221834)
1 /*
2  * PROJECT:     ReactOS IMM32
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Implementing IME manipulation of IMM32
5  * COPYRIGHT:   Copyright 1998 Patrik Stridvall
6  *              Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7  *              Copyright 2017 James Tabor <james.tabor@reactos.org>
8  *              Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9  *              Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10  *              Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11  */
12 
13 #include "precomp.h"
14 
15 WINE_DEFAULT_DEBUG_CHANNEL(imm);
16 
17 RTL_CRITICAL_SECTION g_csImeDpi;
18 PIMEDPI g_pImeDpiList = NULL;
19 
20 PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL)
21 {
22     PIMEDPI pImeDpi;
23 
24     RtlEnterCriticalSection(&g_csImeDpi);
25     for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext)
26     {
27         if (pImeDpi->hKL == hKL)
28             break;
29     }
30     RtlLeaveCriticalSection(&g_csImeDpi);
31 
32     return pImeDpi;
33 }
34 
35 VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy)
36 {
37     if (pImeDpi->hInst == NULL)
38         return;
39     if (bDestroy)
40         pImeDpi->ImeDestroy(0);
41     FreeLibrary(pImeDpi->hInst);
42     pImeDpi->hInst = NULL;
43 }
44 
45 BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi)
46 {
47     WCHAR szUIClass[64];
48     WNDCLASSW wcW;
49     DWORD dwSysInfoFlags = 0; // TODO: ???
50     LPIMEINFO pImeInfo = &pImeDpi->ImeInfo;
51 
52     // TODO: NtUserGetThreadState(16);
53 
54     if (!IS_IME_HKL(pImeDpi->hKL))
55     {
56         if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) &&
57             pImeDpi->CtfImeInquireExW)
58         {
59             // TODO:
60             return FALSE;
61         }
62     }
63 
64     if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags))
65         return FALSE;
66 
67     szUIClass[_countof(szUIClass) - 1] = 0;
68 
69     if (pImeInfo->dwPrivateDataSize == 0)
70         pImeInfo->dwPrivateDataSize = 4;
71 
72 #define VALID_IME_PROP (IME_PROP_AT_CARET              | \
73                         IME_PROP_SPECIAL_UI            | \
74                         IME_PROP_CANDLIST_START_FROM_1 | \
75                         IME_PROP_UNICODE               | \
76                         IME_PROP_COMPLETE_ON_UNSELECT  | \
77                         IME_PROP_END_UNLOAD            | \
78                         IME_PROP_KBD_CHAR_FIRST        | \
79                         IME_PROP_IGNORE_UPKEYS         | \
80                         IME_PROP_NEED_ALTKEY           | \
81                         IME_PROP_NO_KEYS_ON_CLOSE      | \
82                         IME_PROP_ACCEPT_WIDE_VKEY)
83 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \
84                           IME_CMODE_NATIVE       | \
85                           IME_CMODE_KATAKANA     | \
86                           IME_CMODE_LANGUAGE     | \
87                           IME_CMODE_FULLSHAPE    | \
88                           IME_CMODE_ROMAN        | \
89                           IME_CMODE_CHARCODE     | \
90                           IME_CMODE_HANJACONVERT | \
91                           IME_CMODE_SOFTKBD      | \
92                           IME_CMODE_NOCONVERSION | \
93                           IME_CMODE_EUDC         | \
94                           IME_CMODE_SYMBOL       | \
95                           IME_CMODE_FIXED)
96 #define VALID_SMODE_CAPS (IME_SMODE_NONE          | \
97                           IME_SMODE_PLAURALCLAUSE | \
98                           IME_SMODE_SINGLECONVERT | \
99                           IME_SMODE_AUTOMATIC     | \
100                           IME_SMODE_PHRASEPREDICT | \
101                           IME_SMODE_CONVERSATION)
102 #define VALID_UI_CAPS (UI_CAP_2700    | \
103                        UI_CAP_ROT90   | \
104                        UI_CAP_ROTANY  | \
105                        UI_CAP_SOFTKBD)
106 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR            | \
107                         SCS_CAP_MAKEREAD           | \
108                         SCS_CAP_SETRECONVERTSTRING)
109 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE)
110 
111     if (pImeInfo->fdwProperty & ~VALID_IME_PROP)
112         return FALSE;
113     if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS)
114         return FALSE;
115     if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS)
116         return FALSE;
117     if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS)
118         return FALSE;
119     if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS)
120         return FALSE;
121     if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS)
122         return FALSE;
123 
124 #undef VALID_IME_PROP
125 #undef VALID_CMODE_CAPS
126 #undef VALID_SMODE_CAPS
127 #undef VALID_UI_CAPS
128 #undef VALID_SCS_CAPS
129 #undef VALID_SELECT_CAPS
130 
131     if (pImeInfo->fdwProperty & IME_PROP_UNICODE)
132     {
133         StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass);
134     }
135     else
136     {
137         if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage)
138             return FALSE;
139 
140         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1,
141                             pImeDpi->szUIClass, _countof(pImeDpi->szUIClass));
142     }
143 
144     return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW);
145 }
146 
147 BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
148 {
149     WCHAR szPath[MAX_PATH];
150     HINSTANCE hIME;
151     FARPROC fn;
152 
153     if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
154         return FALSE;
155 
156     hIME = GetModuleHandleW(szPath);
157     if (hIME == NULL)
158     {
159         hIME = LoadLibraryW(szPath);
160         if (hIME == NULL)
161         {
162             ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath);
163             return FALSE;
164         }
165     }
166     pImeDpi->hInst = hIME;
167 
168 #define DEFINE_IME_ENTRY(type, name, params, extended) \
169     do { \
170         fn = GetProcAddress(hIME, #name); \
171         if (fn) pImeDpi->name = (FN_##name)fn; \
172         else if (!extended) goto Failed; \
173     } while (0);
174 #include "../../../win32ss/include/imetable.h"
175 #undef DEFINE_IME_ENTRY
176 
177     if (!Imm32InquireIme(pImeDpi))
178     {
179         ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n");
180         goto Failed;
181     }
182 
183     if (pImeInfoEx->fLoadFlag)
184         return TRUE;
185 
186     NtUserSetImeOwnerWindow(pImeInfoEx, TRUE);
187     return TRUE;
188 
189 Failed:
190     FreeLibrary(pImeDpi->hInst);
191     pImeDpi->hInst = NULL;
192     return FALSE;
193 }
194 
195 PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock)
196 {
197     IMEINFOEX ImeInfoEx;
198     CHARSETINFO ci;
199     PIMEDPI pImeDpiNew, pImeDpiFound;
200     UINT uCodePage;
201     LCID lcid;
202 
203     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) ||
204         ImeInfoEx.fLoadFlag == 1)
205     {
206         return NULL;
207     }
208 
209     pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
210     if (pImeDpiNew == NULL)
211         return NULL;
212 
213     pImeDpiNew->hKL = hKL;
214 
215     lcid = LOWORD(hKL);
216     if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE))
217         uCodePage = ci.ciACP;
218     else
219         uCodePage = CP_ACP;
220     pImeDpiNew->uCodePage = uCodePage;
221 
222     if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew))
223     {
224         HeapFree(g_hImm32Heap, 0, pImeDpiNew);
225         return FALSE;
226     }
227 
228     RtlEnterCriticalSection(&g_csImeDpi);
229 
230     pImeDpiFound = Imm32FindImeDpi(hKL);
231     if (pImeDpiFound)
232     {
233         if (!bLock)
234             pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED;
235 
236         RtlLeaveCriticalSection(&g_csImeDpi);
237 
238         Imm32FreeImeDpi(pImeDpiNew, FALSE);
239         HeapFree(g_hImm32Heap, 0, pImeDpiNew);
240         return pImeDpiFound;
241     }
242     else
243     {
244         if (bLock)
245         {
246             pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED;
247             pImeDpiNew->cLockObj = 1;
248         }
249 
250         pImeDpiNew->pNext = g_pImeDpiList;
251         g_pImeDpiList = pImeDpiNew;
252 
253         RtlLeaveCriticalSection(&g_csImeDpi);
254         return pImeDpiNew;
255     }
256 }
257 
258 PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL)
259 {
260     PW32CLIENTINFO pInfo;
261     PIMEDPI pImeDpi;
262 
263     if (!IS_IME_HKL(hKL))
264     {
265         if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
266             return NULL;
267 
268         pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
269         if ((pInfo->W32ClientInfo[0] & 2))
270             return NULL;
271     }
272 
273     pImeDpi = ImmLockImeDpi(hKL);
274     if (pImeDpi == NULL)
275         pImeDpi = Ime32LoadImeDpi(hKL, TRUE);
276     return pImeDpi;
277 }
278 
279 /***********************************************************************
280  *		ImmIsIME (IMM32.@)
281  */
282 BOOL WINAPI ImmIsIME(HKL hKL)
283 {
284     IMEINFOEX info;
285     TRACE("(%p)\n", hKL);
286     return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL);
287 }
288 
289 /***********************************************************************
290  *		ImmGetDefaultIMEWnd (IMM32.@)
291  */
292 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
293 {
294     if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
295         return NULL;
296 
297     // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
298     if (hWnd == NULL)
299         return (HWND)NtUserGetThreadState(3);
300 
301     return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME);
302 }
303 
304 /***********************************************************************
305  *		ImmNotifyIME (IMM32.@)
306  */
307 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
308 {
309     HKL hKL;
310     PIMEDPI pImeDpi;
311     BOOL ret;
312 
313     TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue);
314 
315     if (hIMC && Imm32IsCrossThreadAccess(hIMC))
316         return FALSE;
317 
318     hKL = GetKeyboardLayout(0);
319     pImeDpi = ImmLockImeDpi(hKL);
320     if (pImeDpi == NULL)
321         return FALSE;
322 
323     ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
324     ImmUnlockImeDpi(pImeDpi);
325     return ret;
326 }
327 
328 /***********************************************************************
329  *              ImmDisableLegacyIME(IMM32.@)
330  */
331 BOOL WINAPI ImmDisableLegacyIME(void)
332 {
333     FIXME("stub\n");
334     return TRUE;
335 }
336 
337 /***********************************************************************
338  *		CtfImmIsTextFrameServiceDisabled(IMM32.@)
339  */
340 BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID)
341 {
342     PTEB pTeb = NtCurrentTeb();
343     if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED)
344         return TRUE;
345     return FALSE;
346 }
347 
348 /***********************************************************************
349  *              ImmGetImeInfoEx (IMM32.@)
350  */
351 BOOL WINAPI
352 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey)
353 {
354     BOOL bDisabled = FALSE;
355     HKL hKL;
356     PTEB pTeb;
357 
358     switch (SearchType)
359     {
360         case ImeInfoExKeyboardLayout:
361             break;
362 
363         case ImeInfoExImeWindow:
364             bDisabled = CtfImmIsTextFrameServiceDisabled();
365             SearchType = ImeInfoExKeyboardLayout;
366             break;
367 
368         case ImeInfoExImeFileName:
369             StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
370                            pvSearchKey);
371             goto Quit;
372     }
373 
374     hKL = *(HKL*)pvSearchKey;
375     pImeInfoEx->hkl = hKL;
376 
377     if (!IS_IME_HKL(hKL))
378     {
379         if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
380         {
381             pTeb = NtCurrentTeb();
382             if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2)
383                 return FALSE;
384             if (!bDisabled)
385                 goto Quit;
386         }
387         return FALSE;
388     }
389 
390 Quit:
391     return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
392 }
393 
394 /***********************************************************************
395  *		ImmLockImeDpi (IMM32.@)
396  */
397 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
398 {
399     PIMEDPI pImeDpi = NULL;
400 
401     TRACE("(%p)\n", hKL);
402 
403     RtlEnterCriticalSection(&g_csImeDpi);
404 
405     /* Find by hKL */
406     for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
407     {
408         if (pImeDpi->hKL == hKL) /* found */
409         {
410             /* lock if possible */
411             if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN)
412                 pImeDpi = NULL;
413             else
414                 ++(pImeDpi->cLockObj);
415             break;
416         }
417     }
418 
419     RtlLeaveCriticalSection(&g_csImeDpi);
420     return pImeDpi;
421 }
422 
423 /***********************************************************************
424  *		ImmUnlockImeDpi (IMM32.@)
425  */
426 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
427 {
428     PIMEDPI *ppEntry;
429 
430     TRACE("(%p)\n", pImeDpi);
431 
432     if (pImeDpi == NULL)
433         return;
434 
435     RtlEnterCriticalSection(&g_csImeDpi);
436 
437     /* unlock */
438     --(pImeDpi->cLockObj);
439     if (pImeDpi->cLockObj != 0)
440     {
441         RtlLeaveCriticalSection(&g_csImeDpi);
442         return;
443     }
444 
445     if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0)
446     {
447         if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
448             (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
449         {
450             RtlLeaveCriticalSection(&g_csImeDpi);
451             return;
452         }
453     }
454 
455     /* Remove from list */
456     for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
457     {
458         if (*ppEntry == pImeDpi) /* found */
459         {
460             *ppEntry = pImeDpi->pNext;
461             break;
462         }
463     }
464 
465     Imm32FreeImeDpi(pImeDpi, TRUE);
466     HeapFree(g_hImm32Heap, 0, pImeDpi);
467 
468     RtlLeaveCriticalSection(&g_csImeDpi);
469 }
470 
471 /***********************************************************************
472  *		ImmLoadIME (IMM32.@)
473  */
474 BOOL WINAPI ImmLoadIME(HKL hKL)
475 {
476     PW32CLIENTINFO pInfo;
477     PIMEDPI pImeDpi;
478 
479     if (!IS_IME_HKL(hKL))
480     {
481         if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
482             return FALSE;
483 
484         pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
485         if ((pInfo->W32ClientInfo[0] & 2))
486             return FALSE;
487     }
488 
489     pImeDpi = Imm32FindImeDpi(hKL);
490     if (pImeDpi == NULL)
491         pImeDpi = Ime32LoadImeDpi(hKL, FALSE);
492     return (pImeDpi != NULL);
493 }
494 
495 /***********************************************************************
496  *		ImmDisableIME (IMM32.@)
497  */
498 BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
499 {
500     return NtUserDisableThreadIme(dwThreadId);
501 }
502 
503 /***********************************************************************
504  *		ImmGetDescriptionA (IMM32.@)
505  */
506 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen)
507 {
508     IMEINFOEX info;
509     size_t cch;
510 
511     TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
512 
513     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
514         return 0;
515 
516     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
517     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
518                               lpszDescription, uBufLen, NULL, NULL);
519     if (uBufLen)
520         lpszDescription[cch] = 0;
521     return (UINT)cch;
522 }
523 
524 /***********************************************************************
525  *		ImmGetDescriptionW (IMM32.@)
526  */
527 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
528 {
529     IMEINFOEX info;
530     size_t cch;
531 
532     TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
533 
534     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
535         return 0;
536 
537     if (uBufLen != 0)
538         StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
539 
540     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
541     return (UINT)cch;
542 }
543 
544 /***********************************************************************
545  *		ImmGetIMEFileNameA (IMM32.@)
546  */
547 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
548 {
549     BOOL bDefUsed;
550     IMEINFOEX info;
551     size_t cch;
552 
553     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
554 
555     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
556     {
557         if (uBufLen > 0)
558             lpszFileName[0] = 0;
559         return 0;
560     }
561 
562     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
563 
564     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
565                               lpszFileName, uBufLen, NULL, &bDefUsed);
566     if (uBufLen == 0)
567         return (UINT)cch;
568 
569     if (cch > uBufLen - 1)
570         cch = uBufLen - 1;
571 
572     lpszFileName[cch] = 0;
573     return (UINT)cch;
574 }
575 
576 /***********************************************************************
577  *		ImmGetIMEFileNameW (IMM32.@)
578  */
579 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
580 {
581     IMEINFOEX info;
582     size_t cch;
583 
584     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
585 
586     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
587     {
588         if (uBufLen > 0)
589             lpszFileName[0] = 0;
590         return 0;
591     }
592 
593     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
594     if (uBufLen == 0)
595         return (UINT)cch;
596 
597     StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
598 
599     if (cch > uBufLen - 1)
600         cch = uBufLen - 1;
601 
602     lpszFileName[cch] = 0;
603     return (UINT)cch;
604 }
605 
606 /***********************************************************************
607  *		ImmGetProperty (IMM32.@)
608  */
609 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
610 {
611     IMEINFOEX ImeInfoEx;
612     LPIMEINFO pImeInfo;
613     DWORD dwValue;
614     PIMEDPI pImeDpi = NULL;
615 
616     TRACE("(%p, %lu)\n", hKL, fdwIndex);
617 
618     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
619         return FALSE;
620 
621     if (fdwIndex == IGP_GETIMEVERSION)
622         return ImeInfoEx.dwImeWinVersion;
623 
624     if (ImeInfoEx.fLoadFlag != 2)
625     {
626         pImeDpi = ImmLockOrLoadImeDpi(hKL);
627         if (pImeDpi == NULL)
628             return FALSE;
629 
630         pImeInfo = &pImeDpi->ImeInfo;
631     }
632     else
633     {
634         pImeInfo = &ImeInfoEx.ImeInfo;
635     }
636 
637     switch (fdwIndex)
638     {
639         case IGP_PROPERTY:      dwValue = pImeInfo->fdwProperty; break;
640         case IGP_CONVERSION:    dwValue = pImeInfo->fdwConversionCaps; break;
641         case IGP_SENTENCE:      dwValue = pImeInfo->fdwSentenceCaps; break;
642         case IGP_UI:            dwValue = pImeInfo->fdwUICaps; break;
643         case IGP_SETCOMPSTR:    dwValue = pImeInfo->fdwSCSCaps; break;
644         case IGP_SELECT:        dwValue = pImeInfo->fdwSelectCaps; break;
645         default:                dwValue = 0; break;
646     }
647 
648     if (pImeDpi)
649         ImmUnlockImeDpi(pImeDpi);
650     return dwValue;
651 }
652 
653 /***********************************************************************
654  *		ImmGetOpenStatus (IMM32.@)
655  */
656 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
657 {
658     BOOL ret;
659     LPINPUTCONTEXT pIC;
660 
661     TRACE("(%p)\n", hIMC);
662 
663     if (!hIMC)
664         return FALSE;
665 
666     pIC = ImmLockIMC(hIMC);
667     if (!pIC)
668         return FALSE;
669 
670     ret = pIC->fOpen;
671 
672     ImmUnlockIMC(hIMC);
673     return ret;
674 }
675 
676 /***********************************************************************
677  *		ImmSetOpenStatus (IMM32.@)
678  */
679 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
680 {
681     DWORD dwConversion;
682     LPINPUTCONTEXT pIC;
683     HWND hWnd;
684     BOOL bHasChange = FALSE;
685 
686     TRACE("(%p, %d)\n", hIMC, fOpen);
687 
688     if (Imm32IsCrossThreadAccess(hIMC))
689         return FALSE;
690 
691     pIC = ImmLockIMC(hIMC);
692     if (pIC == NULL)
693         return FALSE;
694 
695     if (pIC->fOpen != fOpen)
696     {
697         pIC->fOpen = fOpen;
698         hWnd = pIC->hWnd;
699         dwConversion = pIC->fdwConversion;
700         bHasChange = TRUE;
701     }
702 
703     ImmUnlockIMC(hIMC);
704 
705     if (bHasChange)
706     {
707         Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
708                           IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
709         NtUserNotifyIMEStatus(hWnd, hIMC, dwConversion);
710     }
711 
712     return TRUE;
713 }
714 
715 /***********************************************************************
716  *		ImmGetStatusWindowPos (IMM32.@)
717  */
718 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
719 {
720     LPINPUTCONTEXT pIC;
721     BOOL ret;
722 
723     TRACE("(%p, %p)\n", hIMC, lpptPos);
724 
725     pIC = ImmLockIMC(hIMC);
726     if (pIC == NULL)
727         return FALSE;
728 
729     ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
730     if (ret)
731         *lpptPos = pIC->ptStatusWndPos;
732 
733     ImmUnlockIMC(hIMC);
734     return ret;
735 }
736 
737 /***********************************************************************
738  *		ImmSetStatusWindowPos (IMM32.@)
739  */
740 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
741 {
742     LPINPUTCONTEXT pIC;
743     HWND hWnd;
744 
745     TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
746 
747     if (Imm32IsCrossThreadAccess(hIMC))
748         return FALSE;
749 
750     pIC = ImmLockIMC(hIMC);
751     if (!pIC)
752         return FALSE;
753 
754     hWnd = pIC->hWnd;
755     pIC->ptStatusWndPos = *lpptPos;
756     pIC->fdwInit |= INIT_STATUSWNDPOS;
757 
758     ImmUnlockIMC(hIMC);
759 
760     Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
761                       IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
762     return TRUE;
763 }
764 
765 /***********************************************************************
766  *		ImmGetCompositionWindow (IMM32.@)
767  */
768 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
769 {
770     LPINPUTCONTEXT pIC;
771     BOOL ret = FALSE;
772 
773     TRACE("(%p, %p)\n", hIMC, lpCompForm);
774 
775     pIC = ImmLockIMC(hIMC);
776     if (!pIC)
777         return FALSE;
778 
779     if (pIC->fdwInit & INIT_COMPFORM)
780     {
781         *lpCompForm = pIC->cfCompForm;
782         ret = TRUE;
783     }
784 
785     ImmUnlockIMC(hIMC);
786     return ret;
787 }
788 
789 /***********************************************************************
790  *		ImmSetCompositionWindow (IMM32.@)
791  */
792 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
793 {
794     LPINPUTCONTEXT pIC;
795     HWND hWnd;
796 
797     if (Imm32IsCrossThreadAccess(hIMC))
798         return FALSE;
799 
800     pIC = ImmLockIMC(hIMC);
801     if (pIC == NULL)
802         return FALSE;
803 
804     pIC->cfCompForm = *lpCompForm;
805     pIC->fdwInit |= INIT_COMPFORM;
806 
807     hWnd = pIC->hWnd;
808 
809     ImmUnlockIMC(hIMC);
810 
811     Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
812                       IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
813     return TRUE;
814 }
815 
816 /***********************************************************************
817  *		ImmGetCompositionFontA (IMM32.@)
818  */
819 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
820 {
821     PCLIENTIMC pClientImc;
822     BOOL ret = FALSE, bWide;
823     LPINPUTCONTEXT pIC;
824 
825     TRACE("(%p, %p)\n", hIMC, lplf);
826 
827     pClientImc = ImmLockClientImc(hIMC);
828     if (pClientImc == NULL)
829         return FALSE;
830 
831     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
832     ImmUnlockClientImc(pClientImc);
833 
834     pIC = ImmLockIMC(hIMC);
835     if (pIC == NULL)
836         return FALSE;
837 
838     if (pIC->fdwInit & INIT_LOGFONT)
839     {
840         if (bWide)
841             LogFontWideToAnsi(&pIC->lfFont.W, lplf);
842         else
843             *lplf = pIC->lfFont.A;
844 
845         ret = TRUE;
846     }
847 
848     ImmUnlockIMC(hIMC);
849     return ret;
850 }
851 
852 /***********************************************************************
853  *		ImmGetCompositionFontW (IMM32.@)
854  */
855 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
856 {
857     PCLIENTIMC pClientImc;
858     BOOL bWide;
859     LPINPUTCONTEXT pIC;
860     BOOL ret = FALSE;
861 
862     TRACE("(%p, %p)\n", hIMC, lplf);
863 
864     pClientImc = ImmLockClientImc(hIMC);
865     if (pClientImc == NULL)
866         return FALSE;
867 
868     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
869     ImmUnlockClientImc(pClientImc);
870 
871     pIC = ImmLockIMC(hIMC);
872     if (pIC == NULL)
873         return FALSE;
874 
875     if (pIC->fdwInit & INIT_LOGFONT)
876     {
877         if (bWide)
878             *lplf = pIC->lfFont.W;
879         else
880             LogFontAnsiToWide(&pIC->lfFont.A, lplf);
881 
882         ret = TRUE;
883     }
884 
885     ImmUnlockIMC(hIMC);
886     return ret;
887 }
888 
889 /***********************************************************************
890  *		ImmSetCompositionFontA (IMM32.@)
891  */
892 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
893 {
894     LOGFONTW lfW;
895     PCLIENTIMC pClientImc;
896     BOOL bWide;
897     LPINPUTCONTEXTDX pIC;
898     LCID lcid;
899     HWND hWnd;
900     PTEB pTeb;
901 
902     TRACE("(%p, %p)\n", hIMC, lplf);
903 
904     if (Imm32IsCrossThreadAccess(hIMC))
905         return FALSE;
906 
907     pClientImc = ImmLockClientImc(hIMC);
908     if (pClientImc == NULL)
909         return FALSE;
910 
911     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
912     ImmUnlockClientImc(pClientImc);
913 
914     if (bWide)
915     {
916         LogFontAnsiToWide(lplf, &lfW);
917         return ImmSetCompositionFontW(hIMC, &lfW);
918     }
919 
920     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
921     if (pIC == NULL)
922         return FALSE;
923 
924     pTeb = NtCurrentTeb();
925     if (pTeb->Win32ClientInfo[2] < 0x400)
926     {
927         lcid = GetSystemDefaultLCID();
928         if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) &&
929             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
930         {
931             PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
932         }
933     }
934 
935     pIC->lfFont.A = *lplf;
936     pIC->fdwInit |= INIT_LOGFONT;
937     hWnd = pIC->hWnd;
938 
939     ImmUnlockIMC(hIMC);
940 
941     Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
942                       IMN_SETCOMPOSITIONFONT, 0);
943     return TRUE;
944 }
945 
946 /***********************************************************************
947  *		ImmSetCompositionFontW (IMM32.@)
948  */
949 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
950 {
951     LOGFONTA lfA;
952     PCLIENTIMC pClientImc;
953     BOOL bWide;
954     HWND hWnd;
955     LPINPUTCONTEXTDX pIC;
956     PTEB pTeb;
957     LCID lcid;
958 
959     TRACE("(%p, %p)\n", hIMC, lplf);
960 
961     if (Imm32IsCrossThreadAccess(hIMC))
962         return FALSE;
963 
964     pClientImc = ImmLockClientImc(hIMC);
965     if (pClientImc == NULL)
966         return FALSE;
967 
968     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
969     ImmUnlockClientImc(pClientImc);
970 
971     if (!bWide)
972     {
973         LogFontWideToAnsi(lplf, &lfA);
974         return ImmSetCompositionFontA(hIMC, &lfA);
975     }
976 
977     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
978     if (pIC == NULL)
979         return FALSE;
980 
981     pTeb = NtCurrentTeb();
982     if (pTeb->Win32ClientInfo[2] < 0x400)
983     {
984         lcid = GetSystemDefaultLCID();
985         if (PRIMARYLANGID(lcid) == LANG_JAPANESE &&
986             !(pIC->dwUIFlags & 2) &&
987             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
988         {
989             PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
990         }
991     }
992 
993     pIC->lfFont.W = *lplf;
994     pIC->fdwInit |= INIT_LOGFONT;
995     hWnd = pIC->hWnd;
996 
997     ImmUnlockIMC(hIMC);
998 
999     Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1000                       IMN_SETCOMPOSITIONFONT, 0);
1001     return TRUE;
1002 }
1003 
1004 /***********************************************************************
1005  *		ImmGetConversionListA (IMM32.@)
1006  */
1007 DWORD WINAPI
1008 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst,
1009                       DWORD dwBufLen, UINT uFlag)
1010 {
1011     DWORD ret = 0;
1012     UINT cb;
1013     LPWSTR pszSrcW = NULL;
1014     LPCANDIDATELIST pCL = NULL;
1015     PIMEDPI pImeDpi;
1016 
1017     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc),
1018           lpDst, dwBufLen, uFlag);
1019 
1020     pImeDpi = ImmLockOrLoadImeDpi(hKL);
1021     if (pImeDpi == NULL)
1022         return 0;
1023 
1024     if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
1025     {
1026         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1027         ImmUnlockImeDpi(pImeDpi);
1028         return ret;
1029     }
1030 
1031     if (pSrc)
1032     {
1033         pszSrcW = Imm32WideFromAnsi(pSrc);
1034         if (pszSrcW == NULL)
1035             goto Quit;
1036     }
1037 
1038     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag);
1039     if (cb == 0)
1040         goto Quit;
1041 
1042     pCL = Imm32HeapAlloc(0, cb);
1043     if (pCL == NULL)
1044         goto Quit;
1045 
1046     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag);
1047     if (cb == 0)
1048         goto Quit;
1049 
1050     ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP);
1051 
1052 Quit:
1053     if (pszSrcW)
1054         HeapFree(g_hImm32Heap, 0, pszSrcW);
1055     if (pCL)
1056         HeapFree(g_hImm32Heap, 0, pCL);
1057     ImmUnlockImeDpi(pImeDpi);
1058     return ret;
1059 }
1060 
1061 /***********************************************************************
1062  *		ImmGetConversionListW (IMM32.@)
1063  */
1064 DWORD WINAPI
1065 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1066                       DWORD dwBufLen, UINT uFlag)
1067 {
1068     DWORD ret = 0;
1069     INT cb;
1070     PIMEDPI pImeDpi;
1071     LPCANDIDATELIST pCL = NULL;
1072     LPSTR pszSrcA = NULL;
1073 
1074     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc),
1075           lpDst, dwBufLen, uFlag);
1076 
1077     pImeDpi = ImmLockOrLoadImeDpi(hKL);
1078     if (!pImeDpi)
1079         return 0;
1080 
1081     if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
1082     {
1083         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1084         ImmUnlockImeDpi(pImeDpi);
1085         return ret;
1086     }
1087 
1088     if (pSrc)
1089     {
1090         pszSrcA = Imm32AnsiFromWide(pSrc);
1091         if (pszSrcA == NULL)
1092             goto Quit;
1093     }
1094 
1095     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag);
1096     if (cb == 0)
1097         goto Quit;
1098 
1099     pCL = Imm32HeapAlloc(0, cb);
1100     if (!pCL)
1101         goto Quit;
1102 
1103     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag);
1104     if (!cb)
1105         goto Quit;
1106 
1107     ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP);
1108 
1109 Quit:
1110     if (pszSrcA)
1111         HeapFree(g_hImm32Heap, 0, pszSrcA);
1112     if (pCL)
1113         HeapFree(g_hImm32Heap, 0, pCL);
1114     ImmUnlockImeDpi(pImeDpi);
1115     return ret;
1116 }
1117 
1118 /***********************************************************************
1119  *		ImmGetConversionStatus (IMM32.@)
1120  */
1121 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1122 {
1123     LPINPUTCONTEXT pIC;
1124 
1125     TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1126 
1127     pIC = ImmLockIMC(hIMC);
1128     if (!pIC)
1129         return FALSE;
1130 
1131     if (lpfdwConversion)
1132         *lpfdwConversion = pIC->fdwConversion;
1133     if (lpfdwSentence)
1134         *lpfdwSentence = pIC->fdwSentence;
1135 
1136     ImmUnlockIMC(hIMC);
1137     return TRUE;
1138 }
1139 
1140 /***********************************************************************
1141  *		ImmSetConversionStatus (IMM32.@)
1142  */
1143 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1144 {
1145     HKL hKL;
1146     LPINPUTCONTEXT pIC;
1147     DWORD dwOldConversion, dwOldSentence;
1148     BOOL fConversionChange = FALSE, fSentenceChange = FALSE;
1149     HWND hWnd;
1150 
1151     TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
1152 
1153     hKL = GetKeyboardLayout(0);
1154     if (!IS_IME_HKL(hKL))
1155     {
1156         if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
1157         {
1158             FIXME("Cicero\n");
1159             return FALSE;
1160         }
1161     }
1162 
1163     if (Imm32IsCrossThreadAccess(hIMC))
1164         return FALSE;
1165 
1166     pIC = ImmLockIMC(hIMC);
1167     if (pIC == NULL)
1168         return FALSE;
1169 
1170     if (pIC->fdwConversion != fdwConversion)
1171     {
1172         dwOldConversion = pIC->fdwConversion;
1173         pIC->fdwConversion = fdwConversion;
1174         fConversionChange = TRUE;
1175     }
1176 
1177     if (pIC->fdwSentence != fdwSentence)
1178     {
1179         dwOldSentence = pIC->fdwSentence;
1180         pIC->fdwSentence = fdwSentence;
1181         fSentenceChange = TRUE;
1182     }
1183 
1184     hWnd = pIC->hWnd;
1185     ImmUnlockIMC(hIMC);
1186 
1187     if (fConversionChange)
1188     {
1189         Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
1190                           IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
1191         NtUserNotifyIMEStatus(hWnd, hIMC, fdwConversion);
1192     }
1193 
1194     if (fSentenceChange)
1195     {
1196         Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
1197                           IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
1198     }
1199 
1200     return TRUE;
1201 }
1202