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