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