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 /*********************************************************************** 353 * ImmIsUIMessageA (IMM32.@) 354 */ 355 BOOL WINAPI ImmIsUIMessageA(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 356 { 357 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 358 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE); 359 } 360 361 /*********************************************************************** 362 * ImmIsUIMessageW (IMM32.@) 363 */ 364 BOOL WINAPI ImmIsUIMessageW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 365 { 366 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 367 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE); 368 } 369 370 /*********************************************************************** 371 * ImmGetHotKey(IMM32.@) 372 */ 373 BOOL WINAPI 374 ImmGetHotKey(IN DWORD dwHotKey, OUT LPUINT lpuModifiers, OUT LPUINT lpuVKey, 375 OUT LPHKL lphKL) 376 { 377 TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL); 378 if (lpuModifiers && lpuVKey) 379 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL); 380 return FALSE; 381 } 382 383 /*********************************************************************** 384 * ImmWINNLSGetIMEHotkey (IMM32.@) 385 */ 386 UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme) 387 { 388 TRACE("(%p)\n", hwndIme); 389 UNREFERENCED_PARAMETER(hwndIme); 390 return 0; /* This is correct. This function of Windows just returns zero. */ 391 } 392 393 /*********************************************************************** 394 * ImmSimulateHotKey (IMM32.@) 395 */ 396 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) 397 { 398 HIMC hIMC; 399 DWORD dwThreadId; 400 HKL hKL; 401 BOOL ret; 402 403 TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID); 404 405 hIMC = ImmGetContext(hWnd); 406 dwThreadId = GetWindowThreadProcessId(hWnd, NULL); 407 hKL = GetKeyboardLayout(dwThreadId); 408 ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID); 409 ImmReleaseContext(hWnd, hIMC); 410 return ret; 411 } 412 413 /*********************************************************************** 414 * ImmGetVirtualKey (IMM32.@) 415 */ 416 UINT WINAPI ImmGetVirtualKey(HWND hWnd) 417 { 418 HIMC hIMC; 419 LPINPUTCONTEXTDX pIC; 420 UINT ret = VK_PROCESSKEY; 421 422 TRACE("(%p)\n", hWnd); 423 424 hIMC = ImmGetContext(hWnd); 425 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 426 if (!pIC) 427 return ret; 428 429 if (pIC->bNeedsTrans) 430 ret = pIC->nVKey; 431 432 ImmUnlockIMC(hIMC); 433 return ret; 434 } 435 436 /*********************************************************************** 437 * ImmProcessKey(IMM32.@) 438 * ( Undocumented, called from user32.dll ) 439 */ 440 DWORD WINAPI 441 ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID) 442 { 443 DWORD ret = 0; 444 HIMC hIMC; 445 PIMEDPI pImeDpi; 446 LPINPUTCONTEXTDX pIC; 447 BYTE KeyState[256]; 448 UINT vk; 449 BOOL bUseIme = TRUE, bSkipThisKey = FALSE, bLowWordOnly = FALSE; 450 451 TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID); 452 453 hIMC = ImmGetContext(hWnd); 454 pImeDpi = ImmLockImeDpi(hKL); 455 if (pImeDpi) 456 { 457 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 458 if (pIC) 459 { 460 if (LOBYTE(vKey) == VK_PACKET && 461 !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY)) 462 { 463 if (ImeDpi_IsUnicode(pImeDpi)) 464 { 465 bLowWordOnly = TRUE; 466 } 467 else 468 { 469 bUseIme = FALSE; 470 if (pIC->fOpen) 471 bSkipThisKey = TRUE; 472 } 473 } 474 475 if (bUseIme) 476 { 477 if (GetKeyboardState(KeyState)) 478 { 479 vk = (bLowWordOnly ? LOWORD(vKey) : vKey); 480 if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState)) 481 { 482 pIC->bNeedsTrans = TRUE; 483 pIC->nVKey = vKey; 484 ret |= IPHK_PROCESSBYIME; 485 } 486 } 487 } 488 else if (bSkipThisKey) 489 { 490 ret |= IPHK_SKIPTHISKEY; 491 } 492 493 ImmUnlockIMC(hIMC); 494 } 495 496 ImmUnlockImeDpi(pImeDpi); 497 } 498 499 if (dwHotKeyID != INVALID_HOTKEY_ID) 500 { 501 if (Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID)) 502 { 503 if (vKey != VK_KANJI || dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN) 504 ret |= IPHK_HOTKEY; 505 } 506 } 507 508 if (ret & IPHK_PROCESSBYIME) 509 { 510 FIXME("TODO: We have to do something here.\n"); 511 } 512 513 ImmReleaseContext(hWnd, hIMC); 514 return ret; 515 } 516 517 /*********************************************************************** 518 * ImmSystemHandler(IMM32.@) 519 */ 520 LRESULT WINAPI ImmSystemHandler(HIMC hIMC, WPARAM wParam, LPARAM lParam) 521 { 522 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); 523 524 switch (wParam) 525 { 526 case 0x1f: 527 Imm32SendChange((BOOL)lParam); 528 return 0; 529 530 case 0x20: 531 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 532 return 0; 533 534 case 0x23: case 0x24: 535 return Imm32UnknownProcess1((HWND)lParam, (wParam == 0x23)); 536 537 default: 538 return 0; 539 } 540 } 541 542 /*********************************************************************** 543 * ImmGenerateMessage(IMM32.@) 544 */ 545 BOOL WINAPI ImmGenerateMessage(HIMC hIMC) 546 { 547 PCLIENTIMC pClientImc; 548 LPINPUTCONTEXT pIC; 549 LPTRANSMSG pMsgs, pTrans = NULL, pItem; 550 HWND hWnd; 551 DWORD dwIndex, dwCount, cbTrans; 552 HIMCC hMsgBuf = NULL; 553 BOOL bAnsi; 554 555 TRACE("(%p)\n", hIMC); 556 557 if (Imm32IsCrossThreadAccess(hIMC)) 558 return FALSE; 559 560 pClientImc = ImmLockClientImc(hIMC); 561 if (pClientImc == NULL) 562 return FALSE; 563 564 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 565 ImmUnlockClientImc(pClientImc); 566 567 pIC = ImmLockIMC(hIMC); 568 if (pIC == NULL) 569 return FALSE; 570 571 dwCount = pIC->dwNumMsgBuf; 572 if (dwCount == 0) 573 goto Quit; 574 575 hMsgBuf = pIC->hMsgBuf; 576 pMsgs = ImmLockIMCC(hMsgBuf); 577 if (pMsgs == NULL) 578 goto Quit; 579 580 cbTrans = dwCount * sizeof(TRANSMSG); 581 pTrans = Imm32HeapAlloc(0, cbTrans); 582 if (pTrans == NULL) 583 goto Quit; 584 585 RtlCopyMemory(pTrans, pMsgs, cbTrans); 586 587 #ifdef IMM_WIN3_SUPPORT 588 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 589 { 590 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 591 WORD wLang = PRIMARYLANGID(LangID); 592 593 /* translate the messages if Japanese or Korean */ 594 if (wLang == LANG_JAPANESE || 595 (wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3)) 596 { 597 dwCount = ImmNt3Trans(dwCount, pTrans, hIMC, bAnsi, wLang); 598 } 599 } 600 #endif 601 602 /* send them */ 603 hWnd = pIC->hWnd; 604 pItem = pTrans; 605 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 606 { 607 if (bAnsi) 608 SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam); 609 else 610 SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam); 611 } 612 613 Quit: 614 Imm32HeapFree(pTrans); 615 if (hMsgBuf) 616 ImmUnlockIMCC(hMsgBuf); 617 pIC->dwNumMsgBuf = 0; /* done */ 618 ImmUnlockIMC(hIMC); 619 return TRUE; 620 } 621 622 VOID APIENTRY 623 Imm32PostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg) 624 { 625 DWORD dwIndex; 626 PCLIENTIMC pClientImc; 627 LPTRANSMSG pNewTransMsg = lpTransMsg, pItem; 628 BOOL bAnsi; 629 630 pClientImc = ImmLockClientImc(hIMC); 631 if (pClientImc == NULL) 632 return; 633 634 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 635 ImmUnlockClientImc(pClientImc); 636 637 #ifdef IMM_WIN3_SUPPORT 638 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 639 { 640 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 641 WORD Lang = PRIMARYLANGID(LangID); 642 643 /* translate the messages if Japanese or Korean */ 644 if (Lang == LANG_JAPANESE || 645 (Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3)) 646 { 647 DWORD cbTransMsg = dwCount * sizeof(TRANSMSG); 648 pNewTransMsg = Imm32HeapAlloc(0, cbTransMsg); 649 if (pNewTransMsg) 650 { 651 RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg); 652 dwCount = ImmNt3Trans(dwCount, pNewTransMsg, hIMC, bAnsi, Lang); 653 } 654 else 655 { 656 pNewTransMsg = lpTransMsg; 657 } 658 } 659 } 660 #endif 661 662 /* post them */ 663 pItem = pNewTransMsg; 664 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 665 { 666 if (bAnsi) 667 PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam); 668 else 669 PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam); 670 } 671 672 #ifdef IMM_WIN3_SUPPORT 673 if (pNewTransMsg != lpTransMsg) 674 Imm32HeapFree(pNewTransMsg); 675 #endif 676 } 677 678 /*********************************************************************** 679 * ImmTranslateMessage(IMM32.@) 680 * ( Undocumented, call internally and from user32.dll ) 681 */ 682 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) 683 { 684 #define MSG_COUNT 0x100 685 BOOL ret = FALSE; 686 INT kret; 687 LPINPUTCONTEXTDX pIC; 688 PIMEDPI pImeDpi = NULL; 689 LPTRANSMSGLIST pList = NULL; 690 LPTRANSMSG pTransMsg; 691 BYTE abKeyState[256]; 692 HIMC hIMC; 693 HKL hKL; 694 UINT vk; 695 DWORD dwThreadId, dwCount, cbList; 696 WCHAR wch; 697 WORD wChar; 698 699 TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData); 700 701 /* filter the message */ 702 switch (msg) 703 { 704 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: 705 break; 706 default: 707 return FALSE; 708 } 709 710 hIMC = ImmGetContext(hwnd); 711 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 712 if (pIC == NULL) 713 { 714 ImmReleaseContext(hwnd, hIMC); 715 return FALSE; 716 } 717 718 if (!pIC->bNeedsTrans) /* is translation needed? */ 719 { 720 /* directly post them */ 721 dwCount = pIC->dwNumMsgBuf; 722 if (dwCount == 0) 723 goto Quit; 724 725 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 726 if (pTransMsg) 727 { 728 Imm32PostMessages(hwnd, hIMC, dwCount, pTransMsg); 729 ImmUnlockIMCC(pIC->hMsgBuf); 730 ret = TRUE; 731 } 732 pIC->dwNumMsgBuf = 0; /* done */ 733 goto Quit; 734 } 735 pIC->bNeedsTrans = FALSE; /* clear the flag */ 736 737 dwThreadId = GetWindowThreadProcessId(hwnd, NULL); 738 hKL = GetKeyboardLayout(dwThreadId); 739 pImeDpi = ImmLockImeDpi(hKL); 740 if (pImeDpi == NULL) 741 goto Quit; 742 743 if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */ 744 goto Quit; 745 746 /* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */ 747 vk = pIC->nVKey; 748 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) 749 { 750 if (ImeDpi_IsUnicode(pImeDpi)) 751 { 752 wch = 0; 753 kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0); 754 if (kret == 1) 755 vk = MAKELONG(LOBYTE(vk), wch); 756 } 757 else 758 { 759 wChar = 0; 760 kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL); 761 if (kret > 0) 762 vk = MAKEWORD(vk, wChar); 763 } 764 } 765 766 /* allocate a list */ 767 cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG); 768 pList = Imm32HeapAlloc(0, cbList); 769 if (!pList) 770 goto Quit; 771 772 /* use IME conversion engine and convert the list */ 773 pList->uMsgCount = MSG_COUNT; 774 kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC); 775 if (kret <= 0) 776 goto Quit; 777 778 /* post them */ 779 if (kret <= MSG_COUNT) 780 { 781 Imm32PostMessages(hwnd, hIMC, kret, pList->TransMsg); 782 ret = TRUE; 783 } 784 else 785 { 786 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 787 if (pTransMsg == NULL) 788 goto Quit; 789 Imm32PostMessages(hwnd, hIMC, kret, pTransMsg); 790 ImmUnlockIMCC(pIC->hMsgBuf); 791 } 792 793 Quit: 794 Imm32HeapFree(pList); 795 ImmUnlockImeDpi(pImeDpi); 796 ImmUnlockIMC(hIMC); 797 ImmReleaseContext(hwnd, hIMC); 798 return ret; 799 #undef MSG_COUNT 800 } 801