[IMM32] Refactor about reconversion (#4031)
[reactos.git] / dll / win32 / imm32 / keymsg.c
1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing IMM32 keys and messages
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 BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID)
18 {
19 LPINPUTCONTEXT pIC;
20 BOOL fOpen;
21
22 if (hWnd != NULL)
23 return FALSE;
24
25 if (!IS_IME_HKL(hKL) || LOWORD(hKL) != LangID)
26 {
27 FIXME("We have to do something here\n");
28 return TRUE;
29 }
30
31 pIC = ImmLockIMC(hIMC);
32 if (pIC == NULL)
33 return TRUE;
34
35 fOpen = pIC->fOpen;
36 ImmUnlockIMC(hIMC);
37
38 if (!fOpen)
39 {
40 ImmSetOpenStatus(hIMC, TRUE);
41 return TRUE;
42 }
43
44 FIXME("We have to do something here\n");
45 return TRUE;
46 }
47
48 BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd)
49 {
50 LPINPUTCONTEXT pIC;
51 BOOL fOpen;
52 DWORD dwConversion, dwSentence;
53
54 if (hWnd == NULL || !IS_IME_HKL(hKL))
55 return FALSE;
56
57 pIC = ImmLockIMC(hIMC);
58 if (pIC == NULL)
59 return TRUE;
60
61 fOpen = pIC->fOpen;
62 if (fOpen)
63 {
64 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
65 dwSentence = pIC->fdwSentence;
66 }
67
68 ImmUnlockIMC(hIMC);
69
70 if (fOpen)
71 ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
72 else
73 ImmSetOpenStatus(hIMC, TRUE);
74
75 return TRUE;
76 }
77
78 BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd)
79 {
80 LPINPUTCONTEXT pIC;
81 BOOL fOpen;
82 DWORD dwConversion, dwSentence;
83
84 if (hWnd == NULL || !IS_IME_HKL(hKL))
85 return FALSE;
86
87 pIC = ImmLockIMC(hIMC);
88 if (pIC == NULL)
89 return TRUE;
90
91 fOpen = pIC->fOpen;
92 if (fOpen)
93 {
94 dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL);
95 dwSentence = pIC->fdwSentence;
96 }
97
98 ImmUnlockIMC(hIMC);
99
100 if (fOpen)
101 ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
102 else
103 ImmSetOpenStatus(hIMC, TRUE);
104
105 return TRUE;
106 }
107
108 BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd)
109 {
110 BOOL fOpen;
111
112 if (ImmIsIME(hKL) && LOWORD(hKL) == LANGID_JAPANESE)
113 {
114 fOpen = ImmGetOpenStatus(hIMC);
115 ImmSetOpenStatus(hIMC, !fOpen);
116 return TRUE;
117 }
118
119 FIXME("We have to do something here\n");
120 return TRUE;
121 }
122
123 BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC)
124 {
125 LPINPUTCONTEXT pIC;
126 DWORD dwConversion, dwSentence;
127
128 pIC = ImmLockIMC(hIMC);
129 if (pIC == NULL)
130 return FALSE;
131
132 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
133 dwSentence = pIC->fdwSentence;
134 ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
135
136 if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE))
137 ImmSetOpenStatus(hIMC, TRUE);
138 else
139 ImmSetOpenStatus(hIMC, FALSE);
140
141 ImmUnlockIMC(hIMC);
142 return TRUE;
143 }
144
145 BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC)
146 {
147 LPINPUTCONTEXT pIC;
148 DWORD dwConversion, dwSentence;
149
150 pIC = ImmLockIMC(hIMC);
151 if (!pIC)
152 return FALSE;
153
154 dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT);
155 dwSentence = pIC->fdwSentence;
156 ImmUnlockIMC(hIMC);
157
158 ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
159 return TRUE;
160 }
161
162 BOOL APIENTRY Imm32KEnglish(HIMC hIMC)
163 {
164 LPINPUTCONTEXT pIC;
165 DWORD dwConversion, dwSentence;
166 BOOL fOpen;
167
168 pIC = ImmLockIMC(hIMC);
169 if (pIC == NULL)
170 return FALSE;
171
172 dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE);
173 dwSentence = pIC->fdwSentence;
174 ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
175
176 fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0);
177 ImmSetOpenStatus(hIMC, fOpen);
178
179 ImmUnlockIMC(hIMC);
180 return TRUE;
181 }
182
183 BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID)
184 {
185 PIMEDPI pImeDpi;
186 BOOL ret;
187
188 if (hIMC && Imm32IsCrossThreadAccess(hIMC))
189 return FALSE;
190
191 switch (dwHotKeyID)
192 {
193 case IME_CHOTKEY_IME_NONIME_TOGGLE:
194 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED);
195
196 case IME_CHOTKEY_SHAPE_TOGGLE:
197 return Imm32CShapeToggle(hIMC, hKL, hWnd);
198
199 case IME_CHOTKEY_SYMBOL_TOGGLE:
200 return Imm32CSymbolToggle(hIMC, hKL, hWnd);
201
202 case IME_JHOTKEY_CLOSE_OPEN:
203 return Imm32JCloseOpen(hIMC, hKL, hWnd);
204
205 case IME_KHOTKEY_SHAPE_TOGGLE:
206 return Imm32KShapeToggle(hIMC);
207
208 case IME_KHOTKEY_HANJACONVERT:
209 return Imm32KHanjaConvert(hIMC);
210
211 case IME_KHOTKEY_ENGLISH:
212 return Imm32KEnglish(hIMC);
213
214 case IME_THOTKEY_IME_NONIME_TOGGLE:
215 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL);
216
217 case IME_THOTKEY_SHAPE_TOGGLE:
218 return Imm32CShapeToggle(hIMC, hKL, hWnd);
219
220 case IME_THOTKEY_SYMBOL_TOGGLE:
221 return Imm32CSymbolToggle(hIMC, hKL, hWnd);
222
223 default:
224 break;
225 }
226
227 if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID)
228 return FALSE;
229
230 pImeDpi = ImmLockImeDpi(hKL);
231 if (pImeDpi == NULL)
232 return FALSE;
233
234 ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID);
235 ImmUnlockImeDpi(pImeDpi);
236 return ret;
237 }
238
239 static BOOL APIENTRY
240 ImmIsUIMessageAW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAnsi)
241 {
242 switch (msg)
243 {
244 case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION:
245 case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY:
246 case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_SYSTEM:
247 break;
248 default:
249 return FALSE;
250 }
251
252 if (!hWndIME)
253 return TRUE;
254
255 if (bAnsi)
256 SendMessageA(hWndIME, msg, wParam, lParam);
257 else
258 SendMessageW(hWndIME, msg, wParam, lParam);
259
260 return TRUE;
261 }
262
263 typedef struct IMM_UNKNOWN_PROCESS1
264 {
265 HWND hWnd;
266 BOOL fFlag;
267 } IMM_UNKNOWN_PROCESS1, *PIMM_UNKNOWN_PROCESS1;
268
269 static DWORD WINAPI Imm32UnknownProcess1Proc(LPVOID arg)
270 {
271 HWND hwndDefIME;
272 UINT uValue;
273 DWORD_PTR lResult;
274 PIMM_UNKNOWN_PROCESS1 pUnknown = arg;
275
276 Sleep(3000);
277 hwndDefIME = ImmGetDefaultIMEWnd(pUnknown->hWnd);
278 if (hwndDefIME)
279 {
280 uValue = (pUnknown->fFlag ? 0x23 : 0x24);
281 SendMessageTimeoutW(hwndDefIME, WM_IME_SYSTEM, uValue, (LPARAM)pUnknown->hWnd,
282 SMTO_BLOCK | SMTO_ABORTIFHUNG, 5000, &lResult);
283 }
284 Imm32HeapFree(pUnknown);
285 return FALSE;
286 }
287
288 LRESULT APIENTRY Imm32UnknownProcess1(HWND hWnd, BOOL fFlag)
289 {
290 HANDLE hThread;
291 PWND pWnd = NULL;
292 PIMM_UNKNOWN_PROCESS1 pUnknown1;
293 DWORD_PTR lResult = 0;
294
295 if (hWnd && g_psi)
296 pWnd = ValidateHwndNoErr(hWnd);
297
298 if (!pWnd)
299 return 0;
300
301 if (pWnd->state2 & WNDS2_WMCREATEMSGPROCESSED)
302 {
303 SendMessageTimeoutW(hWnd, 0x505, 0, fFlag, 3, 5000, &lResult);
304 return lResult;
305 }
306
307 pUnknown1 = Imm32HeapAlloc(0, sizeof(IMM_UNKNOWN_PROCESS1));
308 if (!pUnknown1)
309 return 0;
310
311 pUnknown1->hWnd = hWnd;
312 pUnknown1->fFlag = fFlag;
313
314 hThread = CreateThread(NULL, 0, Imm32UnknownProcess1Proc, pUnknown1, 0, NULL);
315 if (hThread)
316 CloseHandle(hThread);
317 return 0;
318 }
319
320 static BOOL CALLBACK Imm32SendChangeProc(HIMC hIMC, LPARAM lParam)
321 {
322 HWND hWnd;
323 LPINPUTCONTEXTDX pIC;
324
325 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
326 if (!pIC)
327 return TRUE;
328
329 hWnd = pIC->hWnd;
330 if (!IsWindow(hWnd))
331 goto Quit;
332
333 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_OPEN)
334 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0);
335 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_CONVERSION)
336 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0);
337 if (pIC->dwChange & (INPUTCONTEXTDX_CHANGE_OPEN | INPUTCONTEXTDX_CHANGE_CONVERSION))
338 NtUserNotifyIMEStatus(hWnd, pIC->fOpen, pIC->fdwConversion);
339 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_SENTENCE)
340 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0);
341 Quit:
342 pIC->dwChange = 0;
343 ImmUnlockIMC(hIMC); // ??? Windows doesn't unlock here
344 return TRUE;
345 }
346
347 BOOL APIENTRY Imm32SendChange(BOOL bProcess)
348 {
349 return ImmEnumInputContext((bProcess ? -1 : 0), Imm32SendChangeProc, 0);
350 }
351
352 VOID APIENTRY Imm32RequestError(DWORD dwError)
353 {
354 FIXME("()\n");
355 SetLastError(dwError);
356 }
357
358 LRESULT APIENTRY
359 Imm32ProcessRequest(HIMC hIMC, PWND pWnd, DWORD dwCommand, LPVOID pData, BOOL bAnsiAPI)
360 {
361 HWND hWnd;
362 DWORD ret = 0, dwCharPos, cchCompStr;
363 LPVOID pCS, pTempData = pData;
364 LPRECONVERTSTRING pRS;
365 LPIMECHARPOSITION pICP;
366 PCLIENTIMC pClientImc;
367 UINT uCodePage = CP_ACP;
368 BOOL bAnsiWnd = !!(pWnd->state & WNDS_ANSIWINDOWPROC);
369 static const size_t acbData[7 * 2] =
370 {
371 /* UNICODE */
372 sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTW),
373 sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING),
374 sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING),
375 /* ANSI */
376 sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTA),
377 sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING),
378 sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING),
379 };
380
381 if (dwCommand == 0 || dwCommand > IMR_DOCUMENTFEED)
382 return 0; /* Out of range */
383
384 if (pData && IsBadWritePtr(pData, acbData[bAnsiAPI * 7 + dwCommand - 1]))
385 return 0; /* Invalid pointer */
386
387 /* Sanity check */
388 switch (dwCommand)
389 {
390 case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED:
391 pRS = pData;
392 if (pRS && (pRS->dwVersion != 0 || pRS->dwSize < sizeof(RECONVERTSTRING)))
393 {
394 Imm32RequestError(ERROR_INVALID_PARAMETER);
395 return 0;
396 }
397 break;
398
399 case IMR_CONFIRMRECONVERTSTRING:
400 pRS = pData;
401 if (!pRS || pRS->dwVersion != 0)
402 {
403 Imm32RequestError(ERROR_INVALID_PARAMETER);
404 return 0;
405 }
406 break;
407
408 default:
409 if (!pData)
410 {
411 Imm32RequestError(ERROR_INVALID_PARAMETER);
412 return 0;
413 }
414 break;
415 }
416
417 pClientImc = ImmLockClientImc(hIMC);
418 if (pClientImc)
419 {
420 uCodePage = pClientImc->uCodePage;
421 ImmUnlockClientImc(pClientImc);
422 }
423
424 /* Prepare */
425 switch (dwCommand)
426 {
427 case IMR_COMPOSITIONFONT:
428 if (bAnsiAPI == bAnsiWnd)
429 goto DoIt;
430 if (bAnsiWnd)
431 pTempData = Imm32HeapAlloc(0, sizeof(LOGFONTA));
432 else
433 pTempData = Imm32HeapAlloc(0, sizeof(LOGFONTW));
434 if (!pTempData)
435 return 0;
436 break;
437
438 case IMR_RECONVERTSTRING: case IMR_CONFIRMRECONVERTSTRING: case IMR_DOCUMENTFEED:
439 if (bAnsiAPI == bAnsiWnd || !pData)
440 goto DoIt;
441
442 if (bAnsiWnd)
443 ret = Imm32ReconvertAnsiFromWide(NULL, pData, uCodePage);
444 else
445 ret = Imm32ReconvertWideFromAnsi(NULL, pData, uCodePage);
446
447 pTempData = Imm32HeapAlloc(0, ret + sizeof(WCHAR));
448 if (!pTempData)
449 return 0;
450
451 pRS = pTempData;
452 pRS->dwSize = ret;
453 pRS->dwVersion = 0;
454
455 if (dwCommand == IMR_CONFIRMRECONVERTSTRING)
456 {
457 if (bAnsiWnd)
458 ret = Imm32ReconvertAnsiFromWide(pTempData, pData, uCodePage);
459 else
460 ret = Imm32ReconvertWideFromAnsi(pTempData, pData, uCodePage);
461 }
462 break;
463
464 case IMR_QUERYCHARPOSITION:
465 if (bAnsiAPI == bAnsiWnd)
466 goto DoIt;
467
468 pICP = pData;
469 dwCharPos = pICP->dwCharPos;
470
471 if (bAnsiAPI)
472 {
473 cchCompStr = ImmGetCompositionStringA(hIMC, GCS_COMPSTR, NULL, 0);
474 if (!cchCompStr)
475 return 0;
476
477 pCS = Imm32HeapAlloc(0, (cchCompStr + 1) * sizeof(CHAR));
478 if (!pCS)
479 return 0;
480
481 ImmGetCompositionStringA(hIMC, GCS_COMPSTR, pCS, cchCompStr);
482 pICP->dwCharPos = IchWideFromAnsi(pICP->dwCharPos, pCS, uCodePage);
483 }
484 else
485 {
486 cchCompStr = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
487 if (!cchCompStr)
488 return 0;
489
490 pCS = Imm32HeapAlloc(0, (cchCompStr + 1) * sizeof(WCHAR));
491 if (!pCS)
492 return 0;
493
494 ImmGetCompositionStringW(hIMC, GCS_COMPSTR, pCS, cchCompStr);
495 pICP->dwCharPos = IchAnsiFromWide(pICP->dwCharPos, pCS, uCodePage);
496 }
497
498 Imm32HeapFree(pCS);
499 break;
500
501 default:
502 break;
503 }
504
505 DoIt:
506 /* The main task */
507 hWnd = pWnd->head.h;
508 if (bAnsiWnd)
509 ret = SendMessageA(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData);
510 else
511 ret = SendMessageW(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData);
512
513 if (bAnsiAPI == bAnsiWnd)
514 goto Quit;
515
516 /* Get back to caller */
517 switch (dwCommand)
518 {
519 case IMR_COMPOSITIONFONT:
520 if (bAnsiAPI)
521 LogFontWideToAnsi(pTempData, pData);
522 else
523 LogFontAnsiToWide(pTempData, pData);
524 break;
525
526 case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED:
527 if (!ret)
528 break;
529
530 if (ret < sizeof(RECONVERTSTRING))
531 {
532 ret = 0;
533 break;
534 }
535
536 if (pTempData)
537 {
538 if (bAnsiWnd)
539 ret = Imm32ReconvertWideFromAnsi(pData, pTempData, uCodePage);
540 else
541 ret = Imm32ReconvertAnsiFromWide(pData, pTempData, uCodePage);
542 }
543 break;
544
545 case IMR_QUERYCHARPOSITION:
546 pICP->dwCharPos = dwCharPos;
547 break;
548
549 default:
550 break;
551 }
552
553 Quit:
554 if (pTempData != pData)
555 Imm32HeapFree(pTempData);
556 return ret;
557 }
558
559 LRESULT APIENTRY Imm32RequestMessageAW(HIMC hIMC, WPARAM wParam, LPARAM lParam, BOOL bAnsi)
560 {
561 LRESULT ret = 0;
562 LPINPUTCONTEXT pIC;
563 HWND hWnd;
564 PWND pWnd = NULL;
565
566 if (!hIMC || Imm32IsCrossThreadAccess(hIMC))
567 return FALSE;
568
569 pIC = ImmLockIMC(hIMC);
570 if (!pIC)
571 return FALSE;
572
573 hWnd = pIC->hWnd;
574 if (hWnd)
575 pWnd = ValidateHwndNoErr(hWnd);
576
577 if (pWnd && pWnd->head.pti == NtCurrentTeb()->Win32ThreadInfo)
578 ret = Imm32ProcessRequest(hIMC, pWnd, (DWORD)wParam, (LPVOID)lParam, bAnsi);
579
580 ImmUnlockIMC(hIMC);
581 return ret;
582 }
583
584 /***********************************************************************
585 * ImmIsUIMessageA (IMM32.@)
586 */
587 BOOL WINAPI ImmIsUIMessageA(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
588 {
589 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam);
590 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE);
591 }
592
593 /***********************************************************************
594 * ImmIsUIMessageW (IMM32.@)
595 */
596 BOOL WINAPI ImmIsUIMessageW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
597 {
598 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam);
599 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE);
600 }
601
602 /***********************************************************************
603 * ImmGetHotKey(IMM32.@)
604 */
605 BOOL WINAPI
606 ImmGetHotKey(IN DWORD dwHotKey, OUT LPUINT lpuModifiers, OUT LPUINT lpuVKey,
607 OUT LPHKL lphKL)
608 {
609 TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL);
610 if (lpuModifiers && lpuVKey)
611 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL);
612 return FALSE;
613 }
614
615 /***********************************************************************
616 * ImmWINNLSGetIMEHotkey (IMM32.@)
617 */
618 UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme)
619 {
620 TRACE("(%p)\n", hwndIme);
621 UNREFERENCED_PARAMETER(hwndIme);
622 return 0; /* This is correct. This function of Windows just returns zero. */
623 }
624
625 /***********************************************************************
626 * ImmSimulateHotKey (IMM32.@)
627 */
628 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
629 {
630 HIMC hIMC;
631 DWORD dwThreadId;
632 HKL hKL;
633 BOOL ret;
634
635 TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID);
636
637 hIMC = ImmGetContext(hWnd);
638 dwThreadId = GetWindowThreadProcessId(hWnd, NULL);
639 hKL = GetKeyboardLayout(dwThreadId);
640 ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID);
641 ImmReleaseContext(hWnd, hIMC);
642 return ret;
643 }
644
645 /***********************************************************************
646 * ImmGetVirtualKey (IMM32.@)
647 */
648 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
649 {
650 HIMC hIMC;
651 LPINPUTCONTEXTDX pIC;
652 UINT ret = VK_PROCESSKEY;
653
654 TRACE("(%p)\n", hWnd);
655
656 hIMC = ImmGetContext(hWnd);
657 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
658 if (!pIC)
659 return ret;
660
661 if (pIC->bNeedsTrans)
662 ret = pIC->nVKey;
663
664 ImmUnlockIMC(hIMC);
665 return ret;
666 }
667
668 /***********************************************************************
669 * ImmProcessKey(IMM32.@)
670 * ( Undocumented, called from user32.dll )
671 */
672 DWORD WINAPI
673 ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID)
674 {
675 DWORD ret = 0;
676 HIMC hIMC;
677 PIMEDPI pImeDpi;
678 LPINPUTCONTEXTDX pIC;
679 BYTE KeyState[256];
680 UINT vk;
681 BOOL bUseIme = TRUE, bSkipThisKey = FALSE, bLowWordOnly = FALSE;
682
683 TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID);
684
685 hIMC = ImmGetContext(hWnd);
686 pImeDpi = ImmLockImeDpi(hKL);
687 if (pImeDpi)
688 {
689 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
690 if (pIC)
691 {
692 if (LOBYTE(vKey) == VK_PACKET &&
693 !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY))
694 {
695 if (ImeDpi_IsUnicode(pImeDpi))
696 {
697 bLowWordOnly = TRUE;
698 }
699 else
700 {
701 bUseIme = FALSE;
702 if (pIC->fOpen)
703 bSkipThisKey = TRUE;
704 }
705 }
706
707 if (bUseIme)
708 {
709 if (GetKeyboardState(KeyState))
710 {
711 vk = (bLowWordOnly ? LOWORD(vKey) : vKey);
712 if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState))
713 {
714 pIC->bNeedsTrans = TRUE;
715 pIC->nVKey = vKey;
716 ret |= IPHK_PROCESSBYIME;
717 }
718 }
719 }
720 else if (bSkipThisKey)
721 {
722 ret |= IPHK_SKIPTHISKEY;
723 }
724
725 ImmUnlockIMC(hIMC);
726 }
727
728 ImmUnlockImeDpi(pImeDpi);
729 }
730
731 if (dwHotKeyID != INVALID_HOTKEY_ID)
732 {
733 if (Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID))
734 {
735 if (vKey != VK_KANJI || dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)
736 ret |= IPHK_HOTKEY;
737 }
738 }
739
740 if (ret & IPHK_PROCESSBYIME)
741 {
742 FIXME("TODO: We have to do something here.\n");
743 }
744
745 ImmReleaseContext(hWnd, hIMC);
746 return ret;
747 }
748
749 /***********************************************************************
750 * ImmSystemHandler(IMM32.@)
751 */
752 LRESULT WINAPI ImmSystemHandler(HIMC hIMC, WPARAM wParam, LPARAM lParam)
753 {
754 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam);
755
756 switch (wParam)
757 {
758 case 0x1f:
759 Imm32SendChange((BOOL)lParam);
760 return 0;
761
762 case 0x20:
763 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
764 return 0;
765
766 case 0x23: case 0x24:
767 return Imm32UnknownProcess1((HWND)lParam, (wParam == 0x23));
768
769 default:
770 return 0;
771 }
772 }
773
774 /***********************************************************************
775 * ImmGenerateMessage(IMM32.@)
776 */
777 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
778 {
779 PCLIENTIMC pClientImc;
780 LPINPUTCONTEXT pIC;
781 LPTRANSMSG pMsgs, pTrans = NULL, pItem;
782 HWND hWnd;
783 DWORD dwIndex, dwCount, cbTrans;
784 HIMCC hMsgBuf = NULL;
785 BOOL bAnsi;
786
787 TRACE("(%p)\n", hIMC);
788
789 if (Imm32IsCrossThreadAccess(hIMC))
790 return FALSE;
791
792 pClientImc = ImmLockClientImc(hIMC);
793 if (pClientImc == NULL)
794 return FALSE;
795
796 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
797 ImmUnlockClientImc(pClientImc);
798
799 pIC = ImmLockIMC(hIMC);
800 if (pIC == NULL)
801 return FALSE;
802
803 dwCount = pIC->dwNumMsgBuf;
804 if (dwCount == 0)
805 goto Quit;
806
807 hMsgBuf = pIC->hMsgBuf;
808 pMsgs = ImmLockIMCC(hMsgBuf);
809 if (pMsgs == NULL)
810 goto Quit;
811
812 cbTrans = dwCount * sizeof(TRANSMSG);
813 pTrans = Imm32HeapAlloc(0, cbTrans);
814 if (pTrans == NULL)
815 goto Quit;
816
817 RtlCopyMemory(pTrans, pMsgs, cbTrans);
818
819 #ifdef IMM_WIN3_SUPPORT
820 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
821 {
822 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
823 WORD wLang = PRIMARYLANGID(LangID);
824
825 /* translate the messages if Japanese or Korean */
826 if (wLang == LANG_JAPANESE ||
827 (wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3))
828 {
829 dwCount = ImmNt3Trans(dwCount, pTrans, hIMC, bAnsi, wLang);
830 }
831 }
832 #endif
833
834 /* send them */
835 hWnd = pIC->hWnd;
836 pItem = pTrans;
837 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem)
838 {
839 if (bAnsi)
840 SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam);
841 else
842 SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam);
843 }
844
845 Quit:
846 Imm32HeapFree(pTrans);
847 if (hMsgBuf)
848 ImmUnlockIMCC(hMsgBuf);
849 pIC->dwNumMsgBuf = 0; /* done */
850 ImmUnlockIMC(hIMC);
851 return TRUE;
852 }
853
854 VOID APIENTRY
855 Imm32PostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg)
856 {
857 DWORD dwIndex;
858 PCLIENTIMC pClientImc;
859 LPTRANSMSG pNewTransMsg = lpTransMsg, pItem;
860 BOOL bAnsi;
861
862 pClientImc = ImmLockClientImc(hIMC);
863 if (pClientImc == NULL)
864 return;
865
866 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
867 ImmUnlockClientImc(pClientImc);
868
869 #ifdef IMM_WIN3_SUPPORT
870 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
871 {
872 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
873 WORD Lang = PRIMARYLANGID(LangID);
874
875 /* translate the messages if Japanese or Korean */
876 if (Lang == LANG_JAPANESE ||
877 (Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3))
878 {
879 DWORD cbTransMsg = dwCount * sizeof(TRANSMSG);
880 pNewTransMsg = Imm32HeapAlloc(0, cbTransMsg);
881 if (pNewTransMsg)
882 {
883 RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg);
884 dwCount = ImmNt3Trans(dwCount, pNewTransMsg, hIMC, bAnsi, Lang);
885 }
886 else
887 {
888 pNewTransMsg = lpTransMsg;
889 }
890 }
891 }
892 #endif
893
894 /* post them */
895 pItem = pNewTransMsg;
896 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem)
897 {
898 if (bAnsi)
899 PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam);
900 else
901 PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam);
902 }
903
904 #ifdef IMM_WIN3_SUPPORT
905 if (pNewTransMsg != lpTransMsg)
906 Imm32HeapFree(pNewTransMsg);
907 #endif
908 }
909
910 /***********************************************************************
911 * ImmTranslateMessage(IMM32.@)
912 * ( Undocumented, call internally and from user32.dll )
913 */
914 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
915 {
916 #define MSG_COUNT 0x100
917 BOOL ret = FALSE;
918 INT kret;
919 LPINPUTCONTEXTDX pIC;
920 PIMEDPI pImeDpi = NULL;
921 LPTRANSMSGLIST pList = NULL;
922 LPTRANSMSG pTransMsg;
923 BYTE abKeyState[256];
924 HIMC hIMC;
925 HKL hKL;
926 UINT vk;
927 DWORD dwThreadId, dwCount, cbList;
928 WCHAR wch;
929 WORD wChar;
930
931 TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData);
932
933 /* filter the message */
934 switch (msg)
935 {
936 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP:
937 break;
938 default:
939 return FALSE;
940 }
941
942 hIMC = ImmGetContext(hwnd);
943 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
944 if (pIC == NULL)
945 {
946 ImmReleaseContext(hwnd, hIMC);
947 return FALSE;
948 }
949
950 if (!pIC->bNeedsTrans) /* is translation needed? */
951 {
952 /* directly post them */
953 dwCount = pIC->dwNumMsgBuf;
954 if (dwCount == 0)
955 goto Quit;
956
957 pTransMsg = ImmLockIMCC(pIC->hMsgBuf);
958 if (pTransMsg)
959 {
960 Imm32PostMessages(hwnd, hIMC, dwCount, pTransMsg);
961 ImmUnlockIMCC(pIC->hMsgBuf);
962 ret = TRUE;
963 }
964 pIC->dwNumMsgBuf = 0; /* done */
965 goto Quit;
966 }
967 pIC->bNeedsTrans = FALSE; /* clear the flag */
968
969 dwThreadId = GetWindowThreadProcessId(hwnd, NULL);
970 hKL = GetKeyboardLayout(dwThreadId);
971 pImeDpi = ImmLockImeDpi(hKL);
972 if (pImeDpi == NULL)
973 goto Quit;
974
975 if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */
976 goto Quit;
977
978 /* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */
979 vk = pIC->nVKey;
980 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
981 {
982 if (ImeDpi_IsUnicode(pImeDpi))
983 {
984 wch = 0;
985 kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0);
986 if (kret == 1)
987 vk = MAKELONG(LOBYTE(vk), wch);
988 }
989 else
990 {
991 wChar = 0;
992 kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL);
993 if (kret > 0)
994 vk = MAKEWORD(vk, wChar);
995 }
996 }
997
998 /* allocate a list */
999 cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG);
1000 pList = Imm32HeapAlloc(0, cbList);
1001 if (!pList)
1002 goto Quit;
1003
1004 /* use IME conversion engine and convert the list */
1005 pList->uMsgCount = MSG_COUNT;
1006 kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC);
1007 if (kret <= 0)
1008 goto Quit;
1009
1010 /* post them */
1011 if (kret <= MSG_COUNT)
1012 {
1013 Imm32PostMessages(hwnd, hIMC, kret, pList->TransMsg);
1014 ret = TRUE;
1015 }
1016 else
1017 {
1018 pTransMsg = ImmLockIMCC(pIC->hMsgBuf);
1019 if (pTransMsg == NULL)
1020 goto Quit;
1021 Imm32PostMessages(hwnd, hIMC, kret, pTransMsg);
1022 ImmUnlockIMCC(pIC->hMsgBuf);
1023 }
1024
1025 Quit:
1026 Imm32HeapFree(pList);
1027 ImmUnlockImeDpi(pImeDpi);
1028 ImmUnlockIMC(hIMC);
1029 ImmReleaseContext(hwnd, hIMC);
1030 return ret;
1031 #undef MSG_COUNT
1032 }
1033
1034 /***********************************************************************
1035 * ImmRequestMessageA(IMM32.@)
1036 */
1037 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
1038 {
1039 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam);
1040 return Imm32RequestMessageAW(hIMC, wParam, lParam, TRUE);
1041 }
1042
1043 /***********************************************************************
1044 * ImmRequestMessageW(IMM32.@)
1045 */
1046 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
1047 {
1048 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam);
1049 return Imm32RequestMessageAW(hIMC, wParam, lParam, FALSE);
1050 }