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-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 10 */ 11 12 #include "precomp.h" 13 #include <jpnvkeys.h> 14 15 WINE_DEFAULT_DEBUG_CHANNEL(imm); 16 17 /* Win: IMENonIMEToggle */ 18 BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, BOOL bNowIME, LANGID LangID) 19 { 20 HKL hOldKL, LayoutList[32], hFoundKL = NULL; 21 UINT iLayout, nLayoutCount; 22 23 /* Get the previous layout */ 24 hOldKL = (HKL)NtUserGetThreadState(THREADSTATE_OLDKEYBOARDLAYOUT); 25 26 /* Get the layout list */ 27 nLayoutCount = GetKeyboardLayoutList(_countof(LayoutList), LayoutList); 28 29 /* Is there hOldKL in the list in the specified language ID? */ 30 if (hOldKL && (LangID == 0 || LOWORD(hOldKL) == LangID)) 31 { 32 for (iLayout = 0; iLayout < nLayoutCount; ++iLayout) 33 { 34 if (LayoutList[iLayout] == hOldKL) 35 { 36 hFoundKL = hOldKL; 37 break; 38 } 39 } 40 } 41 42 if (hFoundKL == NULL) /* Not found? */ 43 { 44 /* Is there the keyboard layout of another kind in LangID? */ 45 for (iLayout = 0; iLayout < nLayoutCount; ++iLayout) 46 { 47 if (bNowIME == ImmIsIME(LayoutList[iLayout])) /* Same kind? */ 48 continue; 49 50 if (LangID == 0 || LangID == LOWORD(LayoutList[iLayout])) 51 { 52 hFoundKL = LayoutList[iLayout]; 53 break; 54 } 55 } 56 } 57 58 if (hFoundKL && hKL != hFoundKL) /* Found and different layout */ 59 { 60 PostMessageW(hWnd, WM_INPUTLANGCHANGEREQUEST, 1, (LPARAM)hFoundKL); 61 } 62 63 return ImmIsIME(hFoundKL); 64 } 65 66 /* Open or close the IME on Chinese or Taiwanese */ 67 /* Win: CIMENonIMEToggle */ 68 BOOL APIENTRY Imm32CImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID) 69 { 70 LPINPUTCONTEXT pIC; 71 BOOL fOpen; 72 73 if (IS_NULL_UNEXPECTEDLY(hWnd)) 74 return FALSE; 75 76 if (LOWORD(hKL) != LangID || !ImmIsIME(hKL)) 77 { 78 Imm32ImeNonImeToggle(hIMC, hKL, hWnd, FALSE, LangID); 79 return TRUE; 80 } 81 82 pIC = ImmLockIMC(hIMC); 83 if (IS_NULL_UNEXPECTEDLY(pIC)) 84 return TRUE; 85 86 fOpen = pIC->fOpen; 87 ImmUnlockIMC(hIMC); 88 89 if (fOpen) 90 Imm32ImeNonImeToggle(hIMC, hKL, hWnd, TRUE, 0); 91 else 92 ImmSetOpenStatus(hIMC, TRUE); 93 94 return TRUE; 95 } 96 97 /* Toggle shape mode on Chinese or Taiwanese */ 98 /* Win: TShapeToggle */ 99 BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd) 100 { 101 LPINPUTCONTEXT pIC; 102 BOOL fOpen; 103 DWORD dwConversion, dwSentence; 104 105 if (hWnd == NULL || !ImmIsIME(hKL)) 106 return FALSE; 107 108 pIC = ImmLockIMC(hIMC); 109 if (IS_NULL_UNEXPECTEDLY(pIC)) 110 return TRUE; 111 112 fOpen = pIC->fOpen; 113 if (fOpen) 114 { 115 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 116 dwSentence = pIC->fdwSentence; 117 } 118 119 ImmUnlockIMC(hIMC); 120 121 if (fOpen) 122 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 123 else 124 ImmSetOpenStatus(hIMC, TRUE); 125 126 return TRUE; 127 } 128 129 /* Win: CSymbolToggle */ 130 BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd) 131 { 132 LPINPUTCONTEXT pIC; 133 BOOL fOpen; 134 DWORD dwConversion, dwSentence; 135 136 if (hWnd == NULL || !ImmIsIME(hKL)) 137 return FALSE; 138 139 pIC = ImmLockIMC(hIMC); 140 if (IS_NULL_UNEXPECTEDLY(pIC)) 141 return TRUE; 142 143 fOpen = pIC->fOpen; 144 if (fOpen) 145 { 146 dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL); 147 dwSentence = pIC->fdwSentence; 148 } 149 150 ImmUnlockIMC(hIMC); 151 152 if (fOpen) 153 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 154 else 155 ImmSetOpenStatus(hIMC, TRUE); 156 157 return TRUE; 158 } 159 160 /* Open or close Japanese IME */ 161 BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd) 162 { 163 BOOL fOpen; 164 LPINPUTCONTEXTDX pIC; 165 166 if (LOWORD(hKL) == LANGID_JAPANESE && ImmIsIME(hKL)) /* Japanese IME is selected */ 167 { 168 fOpen = ImmGetOpenStatus(hIMC); 169 ImmSetOpenStatus(hIMC, !fOpen); 170 return TRUE; 171 } 172 173 /* Japanese IME is not selected. Select now */ 174 if (Imm32ImeNonImeToggle(hIMC, hKL, hWnd, FALSE, LANGID_JAPANESE)) 175 { 176 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 177 if (pIC) 178 { 179 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_FORCE_OPEN; 180 ImmUnlockIMC(hIMC); 181 } 182 } 183 184 return TRUE; 185 } 186 187 /* Win: KShapeToggle */ 188 BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC) 189 { 190 LPINPUTCONTEXT pIC; 191 DWORD dwConversion, dwSentence; 192 193 pIC = ImmLockIMC(hIMC); 194 if (IS_NULL_UNEXPECTEDLY(pIC)) 195 return FALSE; 196 197 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 198 dwSentence = pIC->fdwSentence; 199 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 200 201 if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) 202 ImmSetOpenStatus(hIMC, TRUE); 203 else 204 ImmSetOpenStatus(hIMC, FALSE); 205 206 ImmUnlockIMC(hIMC); 207 return TRUE; 208 } 209 210 /* Win: KHanjaConvert */ 211 BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC) 212 { 213 LPINPUTCONTEXT pIC; 214 DWORD dwConversion, dwSentence; 215 216 pIC = ImmLockIMC(hIMC); 217 if (IS_NULL_UNEXPECTEDLY(pIC)) 218 return FALSE; 219 220 dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT); 221 dwSentence = pIC->fdwSentence; 222 ImmUnlockIMC(hIMC); 223 224 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 225 return TRUE; 226 } 227 228 /* Win: KEnglishHangul */ 229 BOOL APIENTRY Imm32KEnglish(HIMC hIMC) 230 { 231 LPINPUTCONTEXT pIC; 232 DWORD dwConversion, dwSentence; 233 BOOL fOpen; 234 235 pIC = ImmLockIMC(hIMC); 236 if (IS_NULL_UNEXPECTEDLY(pIC)) 237 return FALSE; 238 239 dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE); 240 dwSentence = pIC->fdwSentence; 241 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 242 243 fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0); 244 ImmSetOpenStatus(hIMC, fOpen); 245 246 ImmUnlockIMC(hIMC); 247 return TRUE; 248 } 249 250 /* Win: HotKeyIDDispatcher */ 251 BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID) 252 { 253 PIMEDPI pImeDpi; 254 BOOL ret; 255 256 if (hIMC && IS_CROSS_THREAD_HIMC(hIMC)) 257 return FALSE; 258 259 switch (dwHotKeyID) 260 { 261 case IME_CHOTKEY_IME_NONIME_TOGGLE: 262 return Imm32CImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED); 263 264 case IME_CHOTKEY_SHAPE_TOGGLE: 265 return Imm32CShapeToggle(hIMC, hKL, hWnd); 266 267 case IME_CHOTKEY_SYMBOL_TOGGLE: 268 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 269 270 case IME_JHOTKEY_CLOSE_OPEN: 271 return Imm32JCloseOpen(hIMC, hKL, hWnd); 272 273 case IME_KHOTKEY_SHAPE_TOGGLE: 274 return Imm32KShapeToggle(hIMC); 275 276 case IME_KHOTKEY_HANJACONVERT: 277 return Imm32KHanjaConvert(hIMC); 278 279 case IME_KHOTKEY_ENGLISH: 280 return Imm32KEnglish(hIMC); 281 282 case IME_THOTKEY_IME_NONIME_TOGGLE: 283 return Imm32CImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL); 284 285 case IME_THOTKEY_SHAPE_TOGGLE: 286 return Imm32CShapeToggle(hIMC, hKL, hWnd); 287 288 case IME_THOTKEY_SYMBOL_TOGGLE: 289 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 290 291 default: 292 WARN("0x%X\n", dwHotKeyID); 293 break; 294 } 295 296 if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID) 297 return FALSE; 298 299 pImeDpi = ImmLockImeDpi(hKL); 300 if (IS_NULL_UNEXPECTEDLY(pImeDpi)) 301 return FALSE; 302 303 ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID); 304 ImmUnlockImeDpi(pImeDpi); 305 return ret; 306 } 307 308 /* Win: ImmIsUIMessageWorker */ 309 static BOOL APIENTRY 310 ImmIsUIMessageAW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAnsi) 311 { 312 switch (msg) 313 { 314 case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: 315 case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: 316 case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_SYSTEM: 317 break; 318 default: 319 return FALSE; 320 } 321 322 if (IS_NULL_UNEXPECTEDLY(hWndIME)) 323 return TRUE; 324 325 if (bAnsi) 326 SendMessageA(hWndIME, msg, wParam, lParam); 327 else 328 SendMessageW(hWndIME, msg, wParam, lParam); 329 330 return TRUE; 331 } 332 333 static BOOL CALLBACK 334 Imm32SendNotificationProc( 335 _In_ HIMC hIMC, 336 _In_ LPARAM lParam) 337 { 338 HWND hWnd; 339 LPINPUTCONTEXTDX pIC; 340 341 UNREFERENCED_PARAMETER(lParam); 342 343 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 344 if (IS_NULL_UNEXPECTEDLY(pIC)) 345 return TRUE; 346 347 hWnd = pIC->hWnd; 348 if (!IsWindow(hWnd)) 349 goto Quit; 350 351 TRACE("dwChange: 0x%08X\n", pIC->dwChange); 352 353 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_OPEN) 354 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0); 355 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_CONVERSION) 356 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0); 357 if (pIC->dwChange & (INPUTCONTEXTDX_CHANGE_OPEN | INPUTCONTEXTDX_CHANGE_CONVERSION)) 358 NtUserNotifyIMEStatus(hWnd, pIC->fOpen, pIC->fdwConversion); 359 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_SENTENCE) 360 SendMessageW(hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0); 361 Quit: 362 pIC->dwChange = 0; 363 ImmUnlockIMC(hIMC); // ??? Windows doesn't unlock here 364 return TRUE; 365 } 366 367 BOOL APIENTRY Imm32SendNotification(BOOL bProcess) 368 { 369 return ImmEnumInputContext((bProcess ? -1 : 0), Imm32SendNotificationProc, 0); 370 } 371 372 LRESULT APIENTRY 373 Imm32ProcessRequest(HIMC hIMC, PWND pWnd, DWORD dwCommand, LPVOID pData, BOOL bAnsiAPI) 374 { 375 HWND hWnd; 376 DWORD ret = 0, dwCharPos, cchCompStr, dwSize; 377 LPVOID pCS, pTempData = pData; 378 LPRECONVERTSTRING pRS; 379 LPIMECHARPOSITION pICP; 380 PCLIENTIMC pClientImc; 381 UINT uCodePage = CP_ACP; 382 BOOL bAnsiWnd = !!(pWnd->state & WNDS_ANSIWINDOWPROC); 383 static const size_t acbData[7 * 2] = 384 { 385 /* UNICODE */ 386 sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTW), 387 sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING), 388 sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING), 389 /* ANSI */ 390 sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTA), 391 sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING), 392 sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING), 393 }; 394 395 if (dwCommand == 0 || dwCommand > IMR_DOCUMENTFEED) 396 { 397 ERR("Out of boundary\n"); 398 return 0; /* Out of range */ 399 } 400 401 dwSize = acbData[bAnsiAPI * 7 + dwCommand - 1]; 402 if (pData && IsBadWritePtr(pData, dwSize)) 403 { 404 ERR("\n"); 405 return 0; /* Invalid pointer */ 406 } 407 408 /* Sanity check */ 409 switch (dwCommand) 410 { 411 case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: 412 pRS = pData; 413 if (pRS && (pRS->dwVersion != 0 || pRS->dwSize < sizeof(RECONVERTSTRING))) 414 { 415 ERR("Invalid pRS\n"); 416 return 0; 417 } 418 break; 419 420 case IMR_CONFIRMRECONVERTSTRING: 421 pRS = pData; 422 if (!pRS || pRS->dwVersion != 0) 423 { 424 ERR("Invalid pRS\n"); 425 return 0; 426 } 427 break; 428 429 default: 430 if (IS_NULL_UNEXPECTEDLY(pData)) 431 return 0; 432 break; 433 } 434 435 pClientImc = ImmLockClientImc(hIMC); 436 if (pClientImc) 437 { 438 uCodePage = pClientImc->uCodePage; 439 ImmUnlockClientImc(pClientImc); 440 } 441 442 /* Prepare */ 443 switch (dwCommand) 444 { 445 case IMR_COMPOSITIONFONT: 446 if (bAnsiAPI == bAnsiWnd) 447 goto DoIt; /* No conversion needed */ 448 449 if (bAnsiWnd) 450 pTempData = ImmLocalAlloc(0, sizeof(LOGFONTA)); 451 else 452 pTempData = ImmLocalAlloc(0, sizeof(LOGFONTW)); 453 454 if (IS_NULL_UNEXPECTEDLY(pTempData)) 455 return 0; 456 break; 457 458 case IMR_RECONVERTSTRING: case IMR_CONFIRMRECONVERTSTRING: case IMR_DOCUMENTFEED: 459 if (bAnsiAPI == bAnsiWnd || !pData) 460 goto DoIt; /* No conversion needed */ 461 462 if (bAnsiWnd) 463 ret = Imm32ReconvertAnsiFromWide(NULL, pData, uCodePage); 464 else 465 ret = Imm32ReconvertWideFromAnsi(NULL, pData, uCodePage); 466 467 pTempData = ImmLocalAlloc(0, ret + sizeof(WCHAR)); 468 if (IS_NULL_UNEXPECTEDLY(pTempData)) 469 return 0; 470 471 pRS = pTempData; 472 pRS->dwSize = ret; 473 pRS->dwVersion = 0; 474 475 if (dwCommand == IMR_CONFIRMRECONVERTSTRING) 476 { 477 if (bAnsiWnd) 478 ret = Imm32ReconvertAnsiFromWide(pTempData, pData, uCodePage); 479 else 480 ret = Imm32ReconvertWideFromAnsi(pTempData, pData, uCodePage); 481 } 482 break; 483 484 case IMR_QUERYCHARPOSITION: 485 if (bAnsiAPI == bAnsiWnd) 486 goto DoIt; /* No conversion needed */ 487 488 pICP = pData; 489 dwCharPos = pICP->dwCharPos; 490 491 if (bAnsiAPI) 492 { 493 cchCompStr = ImmGetCompositionStringA(hIMC, GCS_COMPSTR, NULL, 0); 494 if (IS_ZERO_UNEXPECTEDLY(cchCompStr)) 495 return 0; 496 497 pCS = ImmLocalAlloc(0, (cchCompStr + 1) * sizeof(CHAR)); 498 if (IS_NULL_UNEXPECTEDLY(pCS)) 499 return 0; 500 501 ImmGetCompositionStringA(hIMC, GCS_COMPSTR, pCS, cchCompStr); 502 pICP->dwCharPos = IchWideFromAnsi(pICP->dwCharPos, pCS, uCodePage); 503 } 504 else 505 { 506 cchCompStr = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); 507 if (IS_ZERO_UNEXPECTEDLY(cchCompStr)) 508 return 0; 509 510 pCS = ImmLocalAlloc(0, (cchCompStr + 1) * sizeof(WCHAR)); 511 if (IS_NULL_UNEXPECTEDLY(pCS)) 512 return 0; 513 514 ImmGetCompositionStringW(hIMC, GCS_COMPSTR, pCS, cchCompStr); 515 pICP->dwCharPos = IchAnsiFromWide(pICP->dwCharPos, pCS, uCodePage); 516 } 517 518 ImmLocalFree(pCS); 519 break; 520 521 default: 522 WARN("0x%X\n", dwCommand); 523 break; 524 } 525 526 DoIt: 527 /* The main task */ 528 hWnd = pWnd->head.h; 529 if (bAnsiWnd) 530 ret = SendMessageA(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData); 531 else 532 ret = SendMessageW(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData); 533 534 if (bAnsiAPI == bAnsiWnd) 535 goto Quit; /* No conversion needed */ 536 537 /* Get back to caller */ 538 switch (dwCommand) 539 { 540 case IMR_COMPOSITIONFONT: 541 if (bAnsiAPI) 542 LogFontWideToAnsi(pTempData, pData); 543 else 544 LogFontAnsiToWide(pTempData, pData); 545 break; 546 547 case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: 548 if (!ret) 549 break; 550 551 if (ret < sizeof(RECONVERTSTRING)) 552 { 553 ret = 0; 554 break; 555 } 556 557 if (pTempData) 558 { 559 if (bAnsiWnd) 560 ret = Imm32ReconvertWideFromAnsi(pData, pTempData, uCodePage); 561 else 562 ret = Imm32ReconvertAnsiFromWide(pData, pTempData, uCodePage); 563 } 564 break; 565 566 case IMR_QUERYCHARPOSITION: 567 pICP->dwCharPos = dwCharPos; 568 break; 569 570 default: 571 WARN("0x%X\n", dwCommand); 572 break; 573 } 574 575 Quit: 576 if (pTempData != pData) 577 ImmLocalFree(pTempData); 578 return ret; 579 } 580 581 /* Win: ImmRequestMessageWorker */ 582 LRESULT APIENTRY ImmRequestMessageAW(HIMC hIMC, WPARAM wParam, LPARAM lParam, BOOL bAnsi) 583 { 584 LRESULT ret = 0; 585 LPINPUTCONTEXT pIC; 586 HWND hWnd; 587 PWND pWnd = NULL; 588 589 if (IS_NULL_UNEXPECTEDLY(hIMC) || IS_CROSS_THREAD_HIMC(hIMC)) 590 return FALSE; 591 592 pIC = ImmLockIMC(hIMC); 593 if (IS_NULL_UNEXPECTEDLY(pIC)) 594 return FALSE; 595 596 hWnd = pIC->hWnd; 597 if (hWnd) 598 pWnd = ValidateHwnd(hWnd); 599 600 if (pWnd && pWnd->head.pti == Imm32CurrentPti()) 601 ret = Imm32ProcessRequest(hIMC, pWnd, (DWORD)wParam, (LPVOID)lParam, bAnsi); 602 603 ImmUnlockIMC(hIMC); 604 return ret; 605 } 606 607 /*********************************************************************** 608 * ImmIsUIMessageA (IMM32.@) 609 */ 610 BOOL WINAPI ImmIsUIMessageA(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 611 { 612 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 613 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE); 614 } 615 616 /*********************************************************************** 617 * ImmIsUIMessageW (IMM32.@) 618 */ 619 BOOL WINAPI ImmIsUIMessageW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 620 { 621 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 622 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE); 623 } 624 625 /*********************************************************************** 626 * ImmGetHotKey(IMM32.@) 627 */ 628 BOOL WINAPI 629 ImmGetHotKey(IN DWORD dwHotKey, OUT LPUINT lpuModifiers, OUT LPUINT lpuVKey, 630 OUT LPHKL lphKL) 631 { 632 TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL); 633 if (lpuModifiers && lpuVKey) 634 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL); 635 return FALSE; 636 } 637 638 /*********************************************************************** 639 * ImmWINNLSGetIMEHotkey (IMM32.@) 640 */ 641 UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme) 642 { 643 TRACE("(%p)\n", hwndIme); 644 UNREFERENCED_PARAMETER(hwndIme); 645 return 0; /* This is correct. This function of Windows just returns zero. */ 646 } 647 648 /*********************************************************************** 649 * ImmSimulateHotKey (IMM32.@) 650 */ 651 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) 652 { 653 HIMC hIMC; 654 DWORD dwThreadId; 655 HKL hKL; 656 BOOL ret; 657 658 TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID); 659 660 hIMC = ImmGetContext(hWnd); 661 dwThreadId = GetWindowThreadProcessId(hWnd, NULL); 662 hKL = GetKeyboardLayout(dwThreadId); 663 ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID); 664 ImmReleaseContext(hWnd, hIMC); 665 return ret; 666 } 667 668 /*********************************************************************** 669 * ImmGetVirtualKey (IMM32.@) 670 */ 671 UINT WINAPI ImmGetVirtualKey(HWND hWnd) 672 { 673 HIMC hIMC; 674 LPINPUTCONTEXTDX pIC; 675 UINT ret = VK_PROCESSKEY; 676 677 TRACE("(%p)\n", hWnd); 678 679 hIMC = ImmGetContext(hWnd); 680 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 681 if (IS_NULL_UNEXPECTEDLY(pIC)) 682 return ret; 683 684 if (pIC->bNeedsTrans) 685 ret = pIC->nVKey; 686 687 ImmUnlockIMC(hIMC); 688 return ret; 689 } 690 691 /*********************************************************************** 692 * ImmGetAppCompatFlags (IMM32.@) 693 */ 694 DWORD WINAPI ImmGetAppCompatFlags(HIMC hIMC) 695 { 696 PCLIENTIMC pClientIMC; 697 DWORD dwFlags; 698 699 TRACE("(%p)\n", hIMC); 700 701 pClientIMC = ImmLockClientImc(hIMC); 702 if (IS_NULL_UNEXPECTEDLY(pClientIMC)) 703 return 0; 704 705 dwFlags = pClientIMC->dwCompatFlags; 706 ImmUnlockClientImc(pClientIMC); 707 return (dwFlags | g_aimm_compat_flags); 708 } 709 710 /*********************************************************************** 711 * ImmProcessKey(IMM32.@) 712 * ( Undocumented, called from user32.dll ) 713 */ 714 DWORD WINAPI 715 ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID) 716 { 717 DWORD ret = 0; 718 HIMC hIMC; 719 PIMEDPI pImeDpi; 720 LPINPUTCONTEXTDX pIC; 721 BYTE KeyState[256]; 722 BOOL bLowWordOnly = FALSE, bSkipThisKey = FALSE, bHotKeyDone = TRUE; 723 724 TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID); 725 726 /* Process the key by the IME */ 727 hIMC = ImmGetContext(hWnd); 728 pImeDpi = ImmLockImeDpi(hKL); 729 if (pImeDpi) 730 { 731 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 732 if (pIC) 733 { 734 if ((LOBYTE(vKey) == VK_PACKET) && 735 !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY)) 736 { 737 if (ImeDpi_IsUnicode(pImeDpi)) 738 { 739 bLowWordOnly = TRUE; 740 } 741 else 742 { 743 if (pIC->fOpen) 744 ret |= IPHK_SKIPTHISKEY; 745 746 bSkipThisKey = TRUE; 747 } 748 } 749 750 if (!bSkipThisKey && GetKeyboardState(KeyState)) 751 { 752 UINT vk = (bLowWordOnly ? LOWORD(vKey) : vKey); 753 if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState)) 754 { 755 pIC->bNeedsTrans = TRUE; 756 pIC->nVKey = vKey; 757 ret |= IPHK_PROCESSBYIME; 758 } 759 } 760 761 ImmUnlockIMC(hIMC); 762 } 763 764 ImmUnlockImeDpi(pImeDpi); 765 } 766 767 /* Process the hot-key if necessary */ 768 if (!CtfImmIsCiceroStartedInThread()) /* Not Cicero? */ 769 { 770 /* Process IMM IME hotkey */ 771 if ((dwHotKeyID == INVALID_HOTKEY_ID) || !Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID)) 772 bHotKeyDone = FALSE; 773 } 774 else if (!CtfImeProcessCicHotkey(hIMC, vKey, lParam)) /* CTF IME not processed the hotkey? */ 775 { 776 /* Process IMM IME hotkey */ 777 if (!IS_IME_HKL(hKL) || 778 ((dwHotKeyID == INVALID_HOTKEY_ID) || !Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID))) 779 { 780 bHotKeyDone = FALSE; 781 } 782 } 783 784 if (bHotKeyDone && ((vKey != VK_KANJI) || (dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN))) 785 ret |= IPHK_HOTKEY; 786 787 if ((ret & IPHK_PROCESSBYIME) && (ImmGetAppCompatFlags(hIMC) & 0x10000)) 788 { 789 /* The key has been processed by IME's ImeProcessKey */ 790 LANGID wLangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 791 if ((PRIMARYLANGID(wLangID) == LANG_KOREAN) && 792 ((vKey == VK_PROCESSKEY) || (ret & IPHK_HOTKEY))) 793 { 794 /* Korean don't want VK_PROCESSKEY and IME hot-keys */ 795 } 796 else 797 { 798 /* Add WM_KEYDOWN:VK_PROCESSKEY message */ 799 ImmTranslateMessage(hWnd, WM_KEYDOWN, VK_PROCESSKEY, lParam); 800 801 ret &= ~IPHK_PROCESSBYIME; 802 ret |= IPHK_SKIPTHISKEY; 803 } 804 } 805 806 ImmReleaseContext(hWnd, hIMC); 807 return ret; /* Returns IPHK_... flags */ 808 } 809 810 /*********************************************************************** 811 * ImmSystemHandler(IMM32.@) 812 */ 813 LRESULT WINAPI ImmSystemHandler(HIMC hIMC, WPARAM wParam, LPARAM lParam) 814 { 815 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); 816 817 switch (wParam) 818 { 819 case IMS_SENDNOTIFICATION: 820 Imm32SendNotification((BOOL)lParam); 821 return 0; 822 823 case IMS_COMPLETECOMPSTR: 824 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 825 return 0; 826 827 case IMS_SETLANGBAND: 828 case IMS_UNSETLANGBAND: 829 return CtfImmSetLangBand((HWND)lParam, (wParam == IMS_SETLANGBAND)); 830 831 default: 832 WARN("%p\n", wParam); 833 return 0; 834 } 835 } 836 837 /*********************************************************************** 838 * ImmGenerateMessage(IMM32.@) 839 */ 840 BOOL WINAPI ImmGenerateMessage(HIMC hIMC) 841 { 842 PCLIENTIMC pClientImc; 843 LPINPUTCONTEXT pIC; 844 LPTRANSMSG pMsgs, pTrans = NULL, pItem; 845 HWND hWnd; 846 DWORD dwIndex, dwCount, cbTrans; 847 HIMCC hMsgBuf = NULL; 848 BOOL bAnsi; 849 850 TRACE("(%p)\n", hIMC); 851 852 if (IS_CROSS_THREAD_HIMC(hIMC)) 853 return FALSE; 854 855 pClientImc = ImmLockClientImc(hIMC); 856 if (IS_NULL_UNEXPECTEDLY(pClientImc)) 857 return FALSE; 858 859 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 860 ImmUnlockClientImc(pClientImc); 861 862 pIC = ImmLockIMC(hIMC); 863 if (IS_NULL_UNEXPECTEDLY(pIC)) 864 return FALSE; 865 866 dwCount = pIC->dwNumMsgBuf; 867 if (dwCount == 0) 868 goto Quit; 869 870 hMsgBuf = pIC->hMsgBuf; 871 pMsgs = ImmLockIMCC(hMsgBuf); 872 if (IS_NULL_UNEXPECTEDLY(pMsgs)) 873 goto Quit; 874 875 cbTrans = dwCount * sizeof(TRANSMSG); 876 pTrans = ImmLocalAlloc(0, cbTrans); 877 if (IS_NULL_UNEXPECTEDLY(pTrans)) 878 goto Quit; 879 880 RtlCopyMemory(pTrans, pMsgs, cbTrans); 881 882 #ifdef IMM_WIN3_SUPPORT 883 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 884 { 885 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 886 WORD wLang = PRIMARYLANGID(LangID); 887 888 /* translate the messages if Japanese or Korean */ 889 if (wLang == LANG_JAPANESE || 890 (wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3)) 891 { 892 dwCount = WINNLSTranslateMessage(dwCount, pTrans, hIMC, bAnsi, wLang); 893 } 894 } 895 #endif 896 897 /* send them */ 898 hWnd = pIC->hWnd; 899 pItem = pTrans; 900 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 901 { 902 if (bAnsi) 903 SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam); 904 else 905 SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam); 906 } 907 908 Quit: 909 ImmLocalFree(pTrans); 910 if (hMsgBuf) 911 ImmUnlockIMCC(hMsgBuf); 912 pIC->dwNumMsgBuf = 0; /* done */ 913 ImmUnlockIMC(hIMC); 914 return TRUE; 915 } 916 917 VOID APIENTRY 918 ImmPostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg) 919 { 920 DWORD dwIndex; 921 PCLIENTIMC pClientImc; 922 LPTRANSMSG pNewTransMsg = lpTransMsg, pItem; 923 BOOL bAnsi; 924 925 pClientImc = ImmLockClientImc(hIMC); 926 if (IS_NULL_UNEXPECTEDLY(pClientImc)) 927 return; 928 929 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 930 ImmUnlockClientImc(pClientImc); 931 932 #ifdef IMM_WIN3_SUPPORT 933 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 934 { 935 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 936 WORD Lang = PRIMARYLANGID(LangID); 937 938 /* translate the messages if Japanese or Korean */ 939 if (Lang == LANG_JAPANESE || 940 (Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3)) 941 { 942 DWORD cbTransMsg = dwCount * sizeof(TRANSMSG); 943 pNewTransMsg = ImmLocalAlloc(0, cbTransMsg); 944 if (pNewTransMsg) 945 { 946 RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg); 947 dwCount = WINNLSTranslateMessage(dwCount, pNewTransMsg, hIMC, bAnsi, Lang); 948 } 949 else 950 { 951 pNewTransMsg = lpTransMsg; 952 } 953 } 954 } 955 #endif 956 957 /* post them */ 958 pItem = pNewTransMsg; 959 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 960 { 961 if (bAnsi) 962 PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam); 963 else 964 PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam); 965 } 966 967 #ifdef IMM_WIN3_SUPPORT 968 if (pNewTransMsg != lpTransMsg) 969 ImmLocalFree(pNewTransMsg); 970 #endif 971 } 972 973 /*********************************************************************** 974 * ImmTranslateMessage(IMM32.@) 975 * ( Undocumented, call internally and from user32.dll ) 976 */ 977 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) 978 { 979 #define MSG_COUNT 0x100 980 BOOL ret = FALSE; 981 INT kret; 982 LPINPUTCONTEXTDX pIC; 983 PIMEDPI pImeDpi = NULL; 984 LPTRANSMSGLIST pList = NULL; 985 LPTRANSMSG pTransMsg; 986 BYTE abKeyState[256]; 987 HIMC hIMC; 988 HKL hKL; 989 UINT vk; 990 DWORD dwThreadId, dwCount, cbList; 991 WCHAR wch; 992 WORD wChar; 993 994 TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData); 995 996 /* filter the message */ 997 switch (msg) 998 { 999 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: 1000 break; 1001 default: 1002 return FALSE; 1003 } 1004 1005 hIMC = ImmGetContext(hwnd); 1006 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 1007 if (IS_NULL_UNEXPECTEDLY(pIC)) 1008 { 1009 ImmReleaseContext(hwnd, hIMC); 1010 return FALSE; 1011 } 1012 1013 if (!pIC->bNeedsTrans) /* is translation needed? */ 1014 { 1015 /* directly post them */ 1016 dwCount = pIC->dwNumMsgBuf; 1017 if (dwCount == 0) 1018 goto Quit; 1019 1020 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 1021 if (pTransMsg) 1022 { 1023 ImmPostMessages(hwnd, hIMC, dwCount, pTransMsg); 1024 ImmUnlockIMCC(pIC->hMsgBuf); 1025 ret = TRUE; 1026 } 1027 pIC->dwNumMsgBuf = 0; /* done */ 1028 goto Quit; 1029 } 1030 pIC->bNeedsTrans = FALSE; /* clear the flag */ 1031 1032 dwThreadId = GetWindowThreadProcessId(hwnd, NULL); 1033 hKL = GetKeyboardLayout(dwThreadId); 1034 pImeDpi = ImmLockImeDpi(hKL); 1035 if (IS_NULL_UNEXPECTEDLY(pImeDpi)) 1036 goto Quit; 1037 1038 if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */ 1039 { 1040 WARN("\n"); 1041 goto Quit; 1042 } 1043 1044 /* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */ 1045 vk = pIC->nVKey; 1046 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) 1047 { 1048 if (ImeDpi_IsUnicode(pImeDpi)) 1049 { 1050 wch = 0; 1051 kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0); 1052 if (kret == 1) 1053 vk = MAKELONG(LOBYTE(vk), wch); 1054 } 1055 else 1056 { 1057 wChar = 0; 1058 kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL); 1059 if (kret > 0) 1060 { 1061 if ((BYTE)vk == VK_PACKET) 1062 { 1063 vk &= 0xFF; 1064 vk |= (wChar << 8); 1065 } 1066 else 1067 { 1068 vk = MAKEWORD(vk, wChar); 1069 } 1070 } 1071 } 1072 } 1073 1074 /* allocate a list */ 1075 cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG); 1076 pList = ImmLocalAlloc(0, cbList); 1077 if (IS_NULL_UNEXPECTEDLY(pList)) 1078 goto Quit; 1079 1080 /* use IME conversion engine and convert the list */ 1081 pList->uMsgCount = MSG_COUNT; 1082 kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC); 1083 if (kret <= 0) 1084 goto Quit; 1085 1086 /* post them */ 1087 if (kret <= MSG_COUNT) 1088 { 1089 ImmPostMessages(hwnd, hIMC, kret, pList->TransMsg); 1090 ret = TRUE; 1091 } 1092 else 1093 { 1094 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 1095 if (IS_NULL_UNEXPECTEDLY(pTransMsg)) 1096 goto Quit; 1097 ImmPostMessages(hwnd, hIMC, kret, pTransMsg); 1098 ImmUnlockIMCC(pIC->hMsgBuf); 1099 } 1100 1101 Quit: 1102 ImmLocalFree(pList); 1103 ImmUnlockImeDpi(pImeDpi); 1104 ImmUnlockIMC(hIMC); 1105 ImmReleaseContext(hwnd, hIMC); 1106 TRACE("ret: %d\n", ret); 1107 return ret; 1108 #undef MSG_COUNT 1109 } 1110 1111 /*********************************************************************** 1112 * ImmRequestMessageA(IMM32.@) 1113 */ 1114 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) 1115 { 1116 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); 1117 return ImmRequestMessageAW(hIMC, wParam, lParam, TRUE); 1118 } 1119 1120 /*********************************************************************** 1121 * ImmRequestMessageW(IMM32.@) 1122 */ 1123 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) 1124 { 1125 TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); 1126 return ImmRequestMessageAW(hIMC, wParam, lParam, FALSE); 1127 } 1128 1129 /*********************************************************************** 1130 * ImmCallImeConsoleIME (IMM32.@) 1131 */ 1132 DWORD WINAPI 1133 ImmCallImeConsoleIME( 1134 _In_ HWND hWnd, 1135 _In_ UINT uMsg, 1136 _In_ WPARAM wParam, 1137 _In_ LPARAM lParam, 1138 _Out_ LPUINT puVK) 1139 { 1140 DWORD dwThreadId, ret = 0; 1141 HKL hKL; 1142 PWND pWnd = NULL; 1143 HIMC hIMC; 1144 PIMEDPI pImeDpi; 1145 UINT uVK; 1146 PIMC pIMC; 1147 1148 switch (uMsg) 1149 { 1150 case WM_KEYDOWN: 1151 case WM_KEYUP: 1152 case WM_SYSKEYDOWN: 1153 case WM_SYSKEYUP: 1154 break; 1155 1156 default: 1157 return 0; 1158 } 1159 1160 dwThreadId = GetWindowThreadProcessId(hWnd, NULL); 1161 hKL = GetKeyboardLayout(dwThreadId); 1162 1163 if (hWnd && gpsi) 1164 pWnd = ValidateHwndNoErr(hWnd); 1165 if (IS_NULL_UNEXPECTEDLY(pWnd)) 1166 return 0; 1167 1168 hIMC = ImmGetContext(hWnd); 1169 if (IS_NULL_UNEXPECTEDLY(hIMC)) 1170 return 0; 1171 1172 uVK = *puVK = (wParam & 0xFF); 1173 1174 pIMC = ValidateHandleNoErr(hIMC, TYPE_INPUTCONTEXT); 1175 if (IS_NULL_UNEXPECTEDLY(pIMC)) 1176 return 0; 1177 1178 pImeDpi = ImmLockImeDpi(hKL); 1179 if (IS_NULL_UNEXPECTEDLY(pImeDpi)) 1180 return 0; 1181 1182 if ((lParam & MAKELPARAM(0, KF_UP)) && (pImeDpi->ImeInfo.fdwProperty & IME_PROP_IGNORE_UPKEYS)) 1183 goto Quit; 1184 1185 switch (uVK) 1186 { 1187 case VK_DBE_ROMAN: 1188 case VK_DBE_NOROMAN: 1189 case VK_DBE_HIRAGANA: 1190 case VK_DBE_KATAKANA: 1191 case VK_DBE_CODEINPUT: 1192 case VK_DBE_NOCODEINPUT: 1193 case VK_DBE_ENTERWORDREGISTERMODE: 1194 case VK_DBE_ENTERCONFIGMODE: 1195 break; 1196 1197 default: 1198 { 1199 if (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) 1200 { 1201 if (uVK != VK_MENU && uVK != VK_F10) 1202 goto Quit; 1203 } 1204 1205 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_NEED_ALTKEY)) 1206 { 1207 if (uVK == VK_MENU || (lParam & MAKELPARAM(0, KF_ALTDOWN))) 1208 goto Quit; 1209 } 1210 } 1211 } 1212 1213 ret = ImmProcessKey(hWnd, hKL, uVK, lParam, INVALID_HOTKEY_ID); 1214 1215 Quit: 1216 ImmUnlockImeDpi(pImeDpi); 1217 return ret; 1218 } 1219