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