1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS user32.dll 4 * FILE: win32ss/user/user32/misc/imm.c 5 * PURPOSE: User32.dll Imm functions 6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org) 7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 8 */ 9 10 #include <user32.h> 11 #include <strsafe.h> 12 #include <ddk/immdev.h> 13 14 WINE_DEFAULT_DEBUG_CHANNEL(user32); 15 16 #define IMM_INIT_MAGIC 0x19650412 17 #define MAX_CANDIDATEFORM 4 18 19 /* Is != NULL when we have loaded the IMM ourselves */ 20 HINSTANCE ghImm32 = NULL; // Win: ghImm32 21 22 BOOL gbImmInitializing = FALSE; // Win: bImmInitializing 23 24 INT gfConIme = -1; // Win: gfConIme 25 26 // Win: GetTopLevelWindow 27 PWND FASTCALL User32GetTopLevelWindow(PWND pwnd) 28 { 29 if (!pwnd) 30 return NULL; 31 32 while (pwnd->style & WS_CHILD) 33 pwnd = pwnd->spwndParent; 34 35 return pwnd; 36 } 37 38 /* define stub functions */ 39 #undef DEFINE_IMM_ENTRY 40 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \ 41 static type WINAPI IMMSTUB_##name params { IMM_RETURN_##retkind((type)retval); } 42 #include "immtable.h" 43 44 // Win: gImmApiEntries 45 Imm32ApiTable gImmApiEntries = { 46 /* initialize by stubs */ 47 #undef DEFINE_IMM_ENTRY 48 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \ 49 IMMSTUB_##name, 50 #include "immtable.h" 51 }; 52 53 // Win: GetImmFileName 54 HRESULT 55 User32GetImmFileName(_Out_ LPWSTR lpBuffer, _In_ size_t cchBuffer) 56 { 57 UINT length = GetSystemDirectoryW(lpBuffer, cchBuffer); 58 if (length && length < cchBuffer) 59 { 60 StringCchCatW(lpBuffer, cchBuffer, L"\\"); 61 return StringCchCatW(lpBuffer, cchBuffer, L"imm32.dll"); 62 } 63 return StringCchCopyW(lpBuffer, cchBuffer, L"imm32.dll"); 64 } 65 66 // @unimplemented 67 // Win: _InitializeImmEntryTable 68 static BOOL IntInitializeImmEntryTable(VOID) 69 { 70 WCHAR ImmFile[MAX_PATH]; 71 HMODULE imm32 = ghImm32; 72 73 /* Check whether the IMM table has already been initialized */ 74 if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME) 75 return TRUE; 76 77 User32GetImmFileName(ImmFile, _countof(ImmFile)); 78 TRACE("File %S\n", ImmFile); 79 80 /* If IMM32 is already loaded, use it without increasing reference count. */ 81 if (imm32 == NULL) 82 imm32 = GetModuleHandleW(ImmFile); 83 84 /* 85 * Loading imm32.dll will call imm32!DllMain function. 86 * imm32!DllMain calls User32InitializeImmEntryTable. 87 * Thus, if imm32.dll was loaded, the table has been loaded. 88 */ 89 if (imm32 == NULL) 90 { 91 imm32 = ghImm32 = LoadLibraryW(ImmFile); 92 if (imm32 == NULL) 93 { 94 ERR("Did not load imm32.dll!\n"); 95 return FALSE; 96 } 97 return TRUE; 98 } 99 100 /* load imm procedures */ 101 #undef DEFINE_IMM_ENTRY 102 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \ 103 do { \ 104 FN_##name proc = (FN_##name)GetProcAddress(imm32, #name); \ 105 if (!proc) { \ 106 ERR("Could not load %s\n", #name); \ 107 return FALSE; \ 108 } \ 109 IMM_FN(name) = proc; \ 110 } while (0); 111 #include "immtable.h" 112 113 return TRUE; 114 } 115 116 // Win: InitializeImmEntryTable 117 BOOL WINAPI InitializeImmEntryTable(VOID) 118 { 119 gbImmInitializing = TRUE; 120 return IntInitializeImmEntryTable(); 121 } 122 123 // Win: User32InitializeImmEntryTable 124 BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) 125 { 126 TRACE("Imm (%x)\n", magic); 127 128 if (magic != IMM_INIT_MAGIC) 129 return FALSE; 130 131 /* Check whether the IMM table has already been initialized */ 132 if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME) 133 return TRUE; 134 135 IntInitializeImmEntryTable(); 136 137 if (ghImm32 == NULL && !gbImmInitializing) 138 { 139 WCHAR ImmFile[MAX_PATH]; 140 User32GetImmFileName(ImmFile, _countof(ImmFile)); 141 ghImm32 = LoadLibraryW(ImmFile); 142 if (ghImm32 == NULL) 143 { 144 ERR("Did not load imm32.dll!\n"); 145 return FALSE; 146 } 147 } 148 149 return IMM_FN(ImmRegisterClient)(&gSharedInfo, ghImm32); 150 } 151 152 // Win: ImeIsUsableContext 153 static BOOL User32CanSetImeWindowToImc(HIMC hIMC, HWND hImeWnd) 154 { 155 PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT); 156 return pIMC && (!pIMC->hImeWnd || pIMC->hImeWnd == hImeWnd || !ValidateHwnd(pIMC->hImeWnd)); 157 } 158 159 // Win: GetIMEShowStatus 160 static BOOL User32GetImeShowStatus(VOID) 161 { 162 return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_GETIMESHOWSTATUS); 163 } 164 165 // Win: SendMessageToUI(pimeui, uMsg, wParam, lParam, !unicode) 166 static LRESULT 167 User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode) 168 { 169 LRESULT ret = 0; 170 HWND hwndUI = pimeui->hwndUI; 171 PWND pwnd, pwndUI; 172 173 ASSERT(pimeui->spwnd != NULL); 174 175 pwnd = pimeui->spwnd; 176 pwndUI = ValidateHwnd(hwndUI); 177 if (!pwnd || (pwnd->state & WNDS_DESTROYED) || (pwnd->state2 & WNDS2_INDESTROY) || 178 !pwndUI || (pwndUI->state & WNDS_DESTROYED) || (pwndUI->state2 & WNDS2_INDESTROY)) 179 { 180 return 0; 181 } 182 183 InterlockedIncrement(&pimeui->nCntInIMEProc); 184 185 if (unicode) 186 ret = SendMessageW(hwndUI, uMsg, wParam, lParam); 187 else 188 ret = SendMessageA(hwndUI, uMsg, wParam, lParam); 189 190 InterlockedDecrement(&pimeui->nCntInIMEProc); 191 192 return ret; 193 } 194 195 // Win: SendOpenStatusNotify 196 static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen) 197 { 198 WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW); 199 200 ASSERT(pimeui->spwnd != NULL); 201 202 pimeui->fShowStatus = bOpen; 203 204 if (LOWORD(GetWin32ClientInfo()->dwExpWinVer) >= 0x400) 205 SendMessageW(hwndIMC, WM_IME_NOTIFY, wParam, 0); 206 else 207 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, 0, TRUE); 208 } 209 210 // Win: ImeMarkUsedContext 211 static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd) 212 { 213 PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT); 214 if (!pIMC || pIMC->hImeWnd == hImeWnd) 215 return; 216 217 NtUserUpdateInputContext(hIMC, UIC_IMEWINDOW, (ULONG_PTR)hImeWnd); 218 } 219 220 // Win: ImeSetImc 221 static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC) 222 { 223 HWND hImeWnd; 224 HIMC hOldIMC = pimeui->hIMC; 225 226 ASSERT(pimeui->spwnd != NULL); 227 hImeWnd = UserHMGetHandle(pimeui->spwnd); 228 229 if (hNewIMC == hOldIMC) 230 return; 231 232 if (hOldIMC) 233 User32SetImeWindowOfImc(hOldIMC, NULL); 234 235 pimeui->hIMC = hNewIMC; 236 237 if (hNewIMC) 238 User32SetImeWindowOfImc(hNewIMC, hImeWnd); 239 } 240 241 // Win: ImeNotifyHandler 242 static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) 243 { 244 LRESULT ret = 0; 245 HIMC hIMC; 246 LPINPUTCONTEXT pIC; 247 HWND hwndUI, hwndIMC, hImeWnd, hwndOwner; 248 249 ASSERT(pimeui->spwnd != NULL); 250 251 switch (wParam) 252 { 253 case IMN_SETCONVERSIONMODE: 254 case IMN_SETOPENSTATUS: 255 hIMC = pimeui->hIMC; 256 pIC = IMM_FN(ImmLockIMC)(hIMC); 257 if (pIC) 258 { 259 hwndIMC = pimeui->hwndIMC; 260 if (IsWindow(hwndIMC)) 261 { 262 NtUserNotifyIMEStatus(hwndIMC, pIC->fOpen, pIC->fdwConversion); 263 } 264 else if (gfConIme == TRUE && pimeui->spwnd) 265 { 266 hImeWnd = UserHMGetHandle(pimeui->spwnd); 267 hwndOwner = GetWindow(hImeWnd, GW_OWNER); 268 if (hwndOwner) 269 { 270 NtUserNotifyIMEStatus(hwndOwner, pIC->fOpen, pIC->fdwConversion); 271 } 272 } 273 274 IMM_FN(ImmUnlockIMC)(hIMC); 275 } 276 /* FALL THROUGH */ 277 default: 278 ret = User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, lParam, TRUE); 279 break; 280 281 case IMN_PRIVATE: 282 hwndUI = pimeui->hwndUI; 283 if (IsWindow(hwndUI)) 284 ret = SendMessageW(hwndUI, WM_IME_NOTIFY, wParam, lParam); 285 break; 286 } 287 288 return ret; 289 } 290 291 // Win: CreateIMEUI 292 static HWND User32CreateImeUIWindow(PIMEUI pimeui, HKL hKL) 293 { 294 IMEINFOEX ImeInfoEx; 295 PIMEDPI pImeDpi; 296 WNDCLASSW wc; 297 HWND hwndUI = NULL; 298 CHAR szUIClass[32]; 299 PWND pwnd = pimeui->spwnd; 300 301 ASSERT(pimeui->spwnd != NULL); 302 303 if (!pwnd || !IMM_FN(ImmGetImeInfoEx)(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL)) 304 return NULL; 305 306 pImeDpi = IMM_FN(ImmLockImeDpi)(hKL); 307 if (!pImeDpi) 308 return NULL; 309 310 if (!GetClassInfoW(pImeDpi->hInst, ImeInfoEx.wszUIClass, &wc)) 311 goto Quit; 312 313 if (ImeInfoEx.ImeInfo.fdwProperty & IME_PROP_UNICODE) 314 { 315 hwndUI = CreateWindowW(ImeInfoEx.wszUIClass, ImeInfoEx.wszUIClass, WS_POPUP | WS_DISABLED, 316 0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL); 317 } 318 else 319 { 320 WideCharToMultiByte(CP_ACP, 0, ImeInfoEx.wszUIClass, -1, 321 szUIClass, _countof(szUIClass), NULL, NULL); 322 szUIClass[_countof(szUIClass) - 1] = 0; 323 324 hwndUI = CreateWindowA(szUIClass, szUIClass, WS_POPUP | WS_DISABLED, 325 0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL); 326 } 327 328 if (hwndUI) 329 NtUserSetWindowLong(hwndUI, IMMGWL_IMC, (LONG_PTR)pimeui->hIMC, FALSE); 330 331 Quit: 332 IMM_FN(ImmUnlockImeDpi)(pImeDpi); 333 return hwndUI; 334 } 335 336 // Win: ImeWndCreateHandler 337 static BOOL ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS) 338 { 339 PWND pParentWnd, pWnd = pimeui->spwnd; 340 HIMC hIMC = NULL; 341 342 if (!pWnd || (pWnd->style & (WS_DISABLED | WS_POPUP)) != (WS_DISABLED | WS_POPUP)) 343 return FALSE; 344 345 pParentWnd = ValidateHwnd(lpCS->hwndParent); 346 if (pParentWnd) 347 { 348 hIMC = pParentWnd->hImc; 349 if (hIMC && !User32CanSetImeWindowToImc(hIMC, UserHMGetHandle(pWnd))) 350 hIMC = NULL; 351 } 352 353 User32UpdateImcOfImeUI(pimeui, hIMC); 354 355 pimeui->fShowStatus = FALSE; 356 pimeui->nCntInIMEProc = 0; 357 pimeui->fActivate = FALSE; 358 pimeui->fDestroy = FALSE; 359 pimeui->hwndIMC = NULL; 360 pimeui->hKL = GetWin32ClientInfo()->hKL; 361 pimeui->fCtrlShowStatus = TRUE; 362 363 IMM_FN(ImmLoadIME)(pimeui->hKL); 364 365 pimeui->hwndUI = NULL; 366 367 return TRUE; 368 } 369 370 // Win: DestroyIMEUI 371 static VOID User32DestroyImeUIWindow(PIMEUI pimeui) 372 { 373 HWND hwndUI = pimeui->hwndUI; 374 375 if (IsWindow(hwndUI)) 376 { 377 pimeui->fDestroy = TRUE; 378 NtUserDestroyWindow(hwndUI); 379 } 380 381 pimeui->fShowStatus = pimeui->fDestroy = FALSE; 382 pimeui->hwndUI = NULL; 383 } 384 385 // Win: ImeSelectHandler 386 static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) 387 { 388 HKL hKL; 389 HWND hwndUI, hwndIMC = pimeui->hwndIMC; 390 391 if (wParam) 392 { 393 pimeui->hKL = hKL = (HKL)lParam; 394 pimeui->hwndUI = hwndUI = User32CreateImeUIWindow(pimeui, hKL); 395 if (hwndUI) 396 User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE); 397 398 if (User32GetImeShowStatus() && pimeui->fCtrlShowStatus) 399 { 400 if (!pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC)) 401 User32NotifyOpenStatus(pimeui, hwndIMC, TRUE); 402 } 403 } 404 else 405 { 406 if (pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC)) 407 User32NotifyOpenStatus(pimeui, hwndIMC, FALSE); 408 409 User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE); 410 User32DestroyImeUIWindow(pimeui); 411 pimeui->hKL = NULL; 412 } 413 } 414 415 // Win: ImeControlHandler(pimeui, wParam, lParam, !unicode) 416 static LRESULT 417 ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode) 418 { 419 HIMC hIMC = pimeui->hIMC; 420 DWORD dwConversion, dwSentence; 421 POINT pt; 422 423 if (!hIMC) 424 return 0; 425 426 switch (wParam) 427 { 428 case IMC_GETCONVERSIONMODE: 429 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence)) 430 return 1; 431 return dwConversion; 432 433 case IMC_GETSENTENCEMODE: 434 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence)) 435 return 1; 436 return dwSentence; 437 438 case IMC_GETOPENSTATUS: 439 return IMM_FN(ImmGetOpenStatus)(hIMC); 440 441 case IMC_SETCONVERSIONMODE: 442 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) || 443 !IMM_FN(ImmSetConversionStatus)(hIMC, (DWORD)lParam, dwSentence)) 444 { 445 return 1; 446 } 447 break; 448 449 case IMC_SETSENTENCEMODE: 450 if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) || 451 !IMM_FN(ImmSetConversionStatus)(hIMC, dwConversion, (DWORD)lParam)) 452 { 453 return 1; 454 } 455 break; 456 457 case IMC_SETOPENSTATUS: 458 if (!IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam)) 459 return 1; 460 break; 461 462 case IMC_GETCANDIDATEPOS: 463 case IMC_GETCOMPOSITIONWINDOW: 464 case IMC_GETSOFTKBDPOS: 465 case IMC_SETSOFTKBDPOS: 466 case IMC_GETSTATUSWINDOWPOS: 467 return User32SendImeUIMessage(pimeui, WM_IME_CONTROL, wParam, lParam, unicode); 468 469 case IMC_SETCANDIDATEPOS: 470 if (!IMM_FN(ImmSetCandidateWindow)(hIMC, (LPCANDIDATEFORM)lParam)) 471 return 1; 472 break; 473 474 case IMC_GETCOMPOSITIONFONT: 475 if (unicode) 476 { 477 if (!IMM_FN(ImmGetCompositionFontW)(hIMC, (LPLOGFONTW)lParam)) 478 return 1; 479 } 480 else 481 { 482 if (!IMM_FN(ImmGetCompositionFontA)(hIMC, (LPLOGFONTA)lParam)) 483 return 1; 484 } 485 break; 486 487 case IMC_SETCOMPOSITIONFONT: 488 if (unicode) 489 { 490 if (!IMM_FN(ImmSetCompositionFontW)(hIMC, (LPLOGFONTW)lParam)) 491 return 1; 492 } 493 else 494 { 495 if (!IMM_FN(ImmSetCompositionFontA)(hIMC, (LPLOGFONTA)lParam)) 496 return 1; 497 } 498 break; 499 500 case IMC_SETCOMPOSITIONWINDOW: 501 if (!IMM_FN(ImmSetCompositionWindow)(hIMC, (LPCOMPOSITIONFORM)lParam)) 502 return 1; 503 break; 504 505 case IMC_SETSTATUSWINDOWPOS: 506 pt.x = GET_X_LPARAM(lParam); 507 pt.y = GET_Y_LPARAM(lParam); 508 if (!IMM_FN(ImmSetStatusWindowPos)(hIMC, &pt)) 509 return 1; 510 break; 511 512 case IMC_CLOSESTATUSWINDOW: 513 if (pimeui->fShowStatus && User32GetImeShowStatus()) 514 { 515 pimeui->fShowStatus = FALSE; 516 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE); 517 } 518 pimeui->fCtrlShowStatus = FALSE; 519 break; 520 521 case IMC_OPENSTATUSWINDOW: 522 if (!pimeui->fShowStatus && User32GetImeShowStatus()) 523 { 524 pimeui->fShowStatus = TRUE; 525 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_OPENSTATUSWINDOW, 0, TRUE); 526 } 527 pimeui->fCtrlShowStatus = TRUE; 528 break; 529 530 default: 531 break; 532 } 533 534 return 0; 535 } 536 537 // Win: FocusSetIMCContext 538 static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive) 539 { 540 HIMC hIMC; 541 542 if (!hWnd || !IsWindow(hWnd)) 543 { 544 IMM_FN(ImmSetActiveContext)(NULL, NULL, bActive); 545 return; 546 } 547 548 hIMC = IMM_FN(ImmGetContext)(hWnd); 549 IMM_FN(ImmSetActiveContext)(hWnd, hIMC, bActive); 550 IMM_FN(ImmReleaseContext)(hWnd, hIMC); 551 } 552 553 // Win: ImeSystemHandler 554 static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) 555 { 556 LRESULT ret = 0; 557 LPINPUTCONTEXTDX pIC; 558 HIMC hIMC = pimeui->hIMC; 559 LPCANDIDATEFORM pCandForm; 560 LPCOMPOSITIONFORM pCompForm; 561 DWORD dwConversion, dwSentence; 562 HWND hImeWnd; 563 BOOL bCompForm; 564 CANDIDATEFORM CandForm; 565 COMPOSITIONFORM CompForm; 566 UINT iCandForm; 567 568 ASSERT(pimeui->spwnd != NULL); 569 570 switch (wParam) 571 { 572 case 0x05: 573 if (User32GetImeShowStatus() == !lParam) 574 { 575 hImeWnd = UserHMGetHandle(pimeui->spwnd); 576 NtUserCallHwndParamLock(hImeWnd, lParam, X_ROUTINE_IMESHOWSTATUSCHANGE); 577 } 578 break; 579 580 case 0x06: 581 if (!hIMC) 582 break; 583 584 bCompForm = TRUE; 585 pIC = IMM_FN(ImmLockIMC)(hIMC); 586 if (pIC) 587 { 588 bCompForm = !(pIC->dwUIFlags & 0x2); 589 IMM_FN(ImmUnlockIMC)(hIMC); 590 } 591 592 if (!IsWindow(pimeui->hwndIMC)) 593 break; 594 595 if (bCompForm && IMM_FN(ImmGetCompositionWindow)(hIMC, &CompForm)) 596 { 597 if (CompForm.dwStyle) 598 IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm); 599 } 600 601 for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm) 602 { 603 if (IMM_FN(ImmGetCandidateWindow)(hIMC, iCandForm, &CandForm)) 604 { 605 if (CandForm.dwStyle) 606 IMM_FN(ImmSetCandidateWindow)(hIMC, &CandForm); 607 } 608 } 609 break; 610 611 case 0x09: 612 pIC = IMM_FN(ImmLockIMC)(hIMC); 613 if (!pIC) 614 break; 615 616 pCandForm = &pIC->cfCandForm[lParam]; 617 IMM_FN(ImmSetCandidateWindow)(hIMC, pCandForm); 618 IMM_FN(ImmUnlockIMC)(hIMC); 619 break; 620 621 case 0x0A: 622 pIC = IMM_FN(ImmLockIMC)(hIMC); 623 if (!pIC) 624 break; 625 626 IMM_FN(ImmSetCompositionFontW)(hIMC, &pIC->lfFont.W); 627 IMM_FN(ImmUnlockIMC)(hIMC); 628 break; 629 630 case 0x0B: 631 pIC = IMM_FN(ImmLockIMC)(hIMC); 632 if (!pIC) 633 break; 634 635 pCompForm = &pIC->cfCompForm; 636 pIC->dwUIFlags |= 0x8; 637 IMM_FN(ImmSetCompositionWindow)(hIMC, pCompForm); 638 IMM_FN(ImmUnlockIMC)(hIMC); 639 break; 640 641 case 0x0D: 642 IMM_FN(ImmConfigureIMEW)((HKL)lParam, pimeui->hwndIMC, IME_CONFIG_GENERAL, NULL); 643 break; 644 645 case 0x0F: 646 if (hIMC) 647 IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam); 648 break; 649 650 case 0x11: 651 ret = IMM_FN(ImmFreeLayout)((DWORD)lParam); 652 break; 653 654 case 0x13: 655 // TODO: 656 break; 657 658 case 0x14: 659 IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence); 660 ret = dwConversion; 661 break; 662 663 case 0x15: 664 // TODO: 665 break; 666 667 case IMS_IMEACTIVATE: 668 User32SetImeActivenessOfWindow((HWND)lParam, TRUE); 669 break; 670 671 case IMS_IMEDEACTIVATE: 672 User32SetImeActivenessOfWindow((HWND)lParam, FALSE); 673 break; 674 675 case IMS_ACTIVATELAYOUT: 676 ret = IMM_FN(ImmActivateLayout)((HKL)lParam); 677 break; 678 679 case 0x1C: 680 ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam); 681 break; 682 683 case 0x1D: 684 // TODO: 685 break; 686 687 case 0x1E: 688 ret = (ULONG_PTR)IMM_FN(ImmGetContext)((HWND)lParam); 689 break; 690 691 case 0x1F: 692 case 0x20: 693 ret = IMM_FN(ImmSystemHandler)(hIMC, wParam, lParam); 694 break; 695 696 default: 697 break; 698 } 699 700 return ret; 701 } 702 703 // Win: ImeSetContextHandler 704 LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) 705 { 706 LRESULT ret; 707 HIMC hIMC; 708 LPINPUTCONTEXTDX pIC; 709 HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner; 710 PWND pwndFocus, pwndOldImc, pwndNewImc, pImeWnd, pwndOwner; 711 COMPOSITIONFORM CompForm; 712 713 pimeui->fActivate = !!wParam; 714 hwndOldImc = pimeui->hwndIMC; 715 ASSERT(pimeui->spwnd != NULL); 716 717 if (wParam) 718 { 719 if (!pimeui->hwndUI) 720 pimeui->hwndUI = User32CreateImeUIWindow(pimeui, pimeui->hKL); 721 722 if (gfConIme == -1) 723 { 724 gfConIme = (INT)NtUserGetThreadState(THREADSTATE_CHECKCONIME); 725 if (gfConIme) 726 pimeui->fCtrlShowStatus = FALSE; 727 } 728 729 hImeWnd = UserHMGetHandle(pimeui->spwnd); 730 731 if (gfConIme) 732 { 733 hwndOwner = GetWindow(hImeWnd, GW_OWNER); 734 pwndOwner = ValidateHwnd(hwndOwner); 735 if (pwndOwner) 736 { 737 User32UpdateImcOfImeUI(pimeui, pwndOwner->hImc); 738 739 if (pimeui->hwndUI) 740 SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)pwndOwner->hImc); 741 } 742 743 return User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE); 744 } 745 746 hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS); 747 748 hIMC = IMM_FN(ImmGetContext)(hwndFocus); 749 750 if (hIMC && !User32CanSetImeWindowToImc(hIMC, hImeWnd)) 751 { 752 User32UpdateImcOfImeUI(pimeui, NULL); 753 return 0; 754 } 755 756 User32UpdateImcOfImeUI(pimeui, hIMC); 757 758 if (pimeui->hwndUI) 759 SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)hIMC); 760 761 if (hIMC) 762 { 763 pIC = IMM_FN(ImmLockIMC)(hIMC); 764 if (!pIC) 765 return 0; 766 767 if (hwndFocus != pIC->hWnd) 768 { 769 IMM_FN(ImmUnlockIMC)(hIMC); 770 return 0; 771 } 772 773 if ((pIC->dwUIFlags & 0x40000) && hwndOldImc != hwndFocus) 774 { 775 RtlZeroMemory(&CompForm, sizeof(CompForm)); 776 IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm); 777 778 pIC->dwUIFlags &= ~0x40000; 779 } 780 781 IMM_FN(ImmUnlockIMC)(hIMC); 782 783 hImeWnd = UserHMGetHandle(pimeui->spwnd); 784 if (NtUserSetImeOwnerWindow(hImeWnd, hwndFocus)) 785 pimeui->hwndIMC = hwndFocus; 786 } 787 else 788 { 789 pimeui->hwndIMC = hwndFocus; 790 791 hImeWnd = UserHMGetHandle(pimeui->spwnd); 792 NtUserSetImeOwnerWindow(hImeWnd, NULL); 793 } 794 } 795 796 ret = User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE); 797 798 if (!pimeui->spwnd) 799 return 0; 800 801 if (!pimeui->fCtrlShowStatus || !User32GetImeShowStatus()) 802 return ret; 803 804 hImeWnd = UserHMGetHandle(pimeui->spwnd); 805 hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS); 806 pwndFocus = ValidateHwnd(hwndFocus); 807 808 if (wParam) 809 { 810 pImeWnd = ValidateHwnd(hImeWnd); 811 if (pwndFocus && pImeWnd && pImeWnd->head.pti == pwndFocus->head.pti) 812 { 813 hwndNewImc = pimeui->hwndIMC; 814 if (pimeui->fShowStatus) 815 { 816 pwndNewImc = ValidateHwnd(hwndNewImc); 817 pwndOldImc = ValidateHwnd(hwndOldImc); 818 if (pwndNewImc && pwndOldImc && pwndNewImc != pwndOldImc && 819 User32GetTopLevelWindow(pwndNewImc) != User32GetTopLevelWindow(pwndOldImc)) 820 { 821 User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE); 822 User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE); 823 } 824 } 825 else 826 { 827 if (ValidateHwnd(hwndNewImc)) 828 User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE); 829 } 830 } 831 832 pImeWnd = pimeui->spwnd; 833 hImeWnd = (pImeWnd ? UserHMGetHandle(pImeWnd) : NULL); 834 if (hImeWnd) 835 NtUserCallHwndLock(hImeWnd, HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD); 836 } 837 else 838 { 839 pImeWnd = pimeui->spwnd; 840 hImeWnd = UserHMGetHandle(pImeWnd); 841 hwndActive = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_ACTIVE); 842 if (!pwndFocus || !hwndActive || pImeWnd->head.pti != pwndFocus->head.pti) 843 { 844 if (IsWindow(hwndOldImc)) 845 { 846 User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE); 847 } 848 else 849 { 850 pimeui->fShowStatus = FALSE; 851 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE); 852 } 853 } 854 } 855 856 return ret; 857 } 858 859 // Win: ImeWndProcWorker(hwnd, msg, wParam, lParam, !unicode) 860 LRESULT WINAPI 861 ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode) // ReactOS 862 { 863 PWND pWnd; 864 PIMEUI pimeui; 865 866 pWnd = ValidateHwnd(hwnd); 867 if (pWnd) 868 { 869 if (!pWnd->fnid) 870 { 871 if (msg != WM_NCCREATE) 872 { 873 if (unicode) 874 return DefWindowProcW(hwnd, msg, wParam, lParam); 875 return DefWindowProcA(hwnd, msg, wParam, lParam); 876 } 877 NtUserSetWindowFNID(hwnd, FNID_IME); 878 pimeui = HeapAlloc( GetProcessHeap(), 0, sizeof(IMEUI) ); 879 pimeui->spwnd = pWnd; 880 SetWindowLongPtrW(hwnd, IMMGWLP_IMC, (LONG_PTR)pimeui); 881 } 882 else 883 { 884 if (pWnd->fnid != FNID_IME) 885 { 886 ERR("Wrong window class for Ime! fnId 0x%x\n",pWnd->fnid); 887 return 0; 888 } 889 pimeui = ((PIMEWND)pWnd)->pimeui; 890 if (pimeui == NULL) 891 { 892 ERR("Window is not set to IME!\n"); 893 return 0; 894 } 895 } 896 } 897 898 if (pimeui->nCntInIMEProc > 0) 899 { 900 switch (msg) 901 { 902 case WM_IME_CHAR: 903 case WM_IME_COMPOSITIONFULL: 904 case WM_IME_CONTROL: 905 case WM_IME_NOTIFY: 906 case WM_IME_REQUEST: 907 case WM_IME_SELECT: 908 case WM_IME_SETCONTEXT: 909 case WM_IME_STARTCOMPOSITION: 910 case WM_IME_COMPOSITION: 911 case WM_IME_ENDCOMPOSITION: 912 return 0; 913 914 case WM_IME_SYSTEM: 915 switch (wParam) 916 { 917 case 0x03: 918 case 0x10: 919 case 0x13: 920 break; 921 922 default: 923 return 0; 924 } 925 break; 926 927 default: 928 { 929 if (unicode) 930 return DefWindowProcW(hwnd, msg, wParam, lParam); 931 return DefWindowProcA(hwnd, msg, wParam, lParam); 932 } 933 } 934 } 935 936 switch (msg) 937 { 938 case WM_CREATE: 939 return (ImeWnd_OnCreate(pimeui, (LPCREATESTRUCT)lParam) ? 0 : -1); 940 941 case WM_DESTROY: 942 User32DestroyImeUIWindow(pimeui); 943 break; 944 945 case WM_NCDESTROY: 946 HeapFree(GetProcessHeap(), 0, pimeui); 947 SetWindowLongPtrW(hwnd, IMMGWLP_IMC, 0); 948 NtUserSetWindowFNID(hwnd, FNID_DESTROY); 949 break; 950 951 case WM_ERASEBKGND: 952 return TRUE; 953 954 case WM_PAINT: 955 break; 956 957 case WM_COPYDATA: 958 // TODO: 959 break; 960 961 case WM_IME_STARTCOMPOSITION: 962 case WM_IME_COMPOSITION: 963 case WM_IME_ENDCOMPOSITION: 964 return User32SendImeUIMessage(pimeui, msg, wParam, lParam, unicode); 965 966 case WM_IME_CONTROL: 967 return ImeWnd_OnImeControl(pimeui, wParam, lParam, unicode); 968 969 case WM_IME_NOTIFY: 970 return ImeWnd_OnImeNotify(pimeui, wParam, lParam); 971 972 case WM_IME_REQUEST: 973 break; 974 975 case WM_IME_SELECT: 976 ImeWnd_OnImeSelect(pimeui, wParam, lParam); 977 break; 978 979 case WM_IME_SETCONTEXT: 980 return ImeWnd_OnImeSetContext(pimeui, wParam, lParam); 981 982 case WM_IME_SYSTEM: 983 return ImeWnd_OnImeSystem(pimeui, wParam, lParam); 984 985 default: 986 { 987 if (unicode) 988 return DefWindowProcW(hwnd, msg, wParam, lParam); 989 return DefWindowProcA(hwnd, msg, wParam, lParam); 990 } 991 } 992 993 return 0; 994 } 995 996 // Win: ImeWndProcA 997 LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 998 { 999 return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE); 1000 } 1001 1002 // Win: ImeWndProcW 1003 LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 1004 { 1005 return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE); 1006 } 1007 1008 // Win: UpdatePerUserImmEnabling 1009 BOOL WINAPI UpdatePerUserImmEnabling(VOID) 1010 { 1011 HMODULE imm32; 1012 BOOL ret; 1013 1014 ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING); 1015 if (!ret || !(gpsi->dwSRVIFlags & SRVINFO_IMM32)) 1016 return FALSE; 1017 1018 imm32 = GetModuleHandleW(L"imm32.dll"); 1019 if (imm32) 1020 return TRUE; 1021 1022 imm32 = LoadLibraryW(L"imm32.dll"); 1023 if (imm32) 1024 { 1025 ERR("UPUIE: Imm32 not installed!\n"); 1026 ret = FALSE; 1027 } 1028 1029 return ret; 1030 } 1031 1032 BOOL 1033 WINAPI 1034 RegisterIMEClass(VOID) 1035 { 1036 ATOM atom; 1037 WNDCLASSEXW WndClass = { sizeof(WndClass) }; 1038 1039 WndClass.lpszClassName = L"IME"; 1040 WndClass.style = CS_GLOBALCLASS; 1041 WndClass.lpfnWndProc = ImeWndProcW; 1042 WndClass.cbWndExtra = sizeof(LONG_PTR); 1043 WndClass.hCursor = LoadCursorW(NULL, IDC_ARROW); 1044 1045 atom = RegisterClassExWOWW(&WndClass, 0, FNID_IME, 0, FALSE); 1046 if (!atom) 1047 { 1048 ERR("Failed to register IME Class!\n"); 1049 return FALSE; 1050 } 1051 1052 RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME); 1053 TRACE("RegisterIMEClass atom = %u\n", atom); 1054 return TRUE; 1055 } 1056 1057 /* 1058 * @unimplemented 1059 */ 1060 BOOL WINAPI CliImmSetHotKey(DWORD dwID, UINT uModifiers, UINT uVirtualKey, HKL hKl) 1061 { 1062 UNIMPLEMENTED; 1063 return FALSE; 1064 } 1065 1066 /* 1067 * @implemented 1068 */ 1069 BOOL 1070 WINAPI 1071 IMPSetIMEW(HWND hwnd, LPIMEPROW ime) 1072 { 1073 return IMM_FN(ImmIMPSetIMEW)(hwnd, ime); 1074 } 1075 1076 /* 1077 * @implemented 1078 */ 1079 BOOL 1080 WINAPI 1081 IMPQueryIMEW(LPIMEPROW ime) 1082 { 1083 return IMM_FN(ImmIMPQueryIMEW)(ime); 1084 } 1085 1086 /* 1087 * @implemented 1088 */ 1089 BOOL 1090 WINAPI 1091 IMPGetIMEW(HWND hwnd, LPIMEPROW ime) 1092 { 1093 return IMM_FN(ImmIMPGetIMEW)(hwnd, ime); 1094 } 1095 1096 /* 1097 * @implemented 1098 */ 1099 BOOL 1100 WINAPI 1101 IMPSetIMEA(HWND hwnd, LPIMEPROA ime) 1102 { 1103 return IMM_FN(ImmIMPSetIMEA)(hwnd, ime); 1104 } 1105 1106 /* 1107 * @implemented 1108 */ 1109 BOOL 1110 WINAPI 1111 IMPQueryIMEA(LPIMEPROA ime) 1112 { 1113 return IMM_FN(ImmIMPQueryIMEA)(ime); 1114 } 1115 1116 /* 1117 * @implemented 1118 */ 1119 BOOL 1120 WINAPI 1121 IMPGetIMEA(HWND hwnd, LPIMEPROA ime) 1122 { 1123 return IMM_FN(ImmIMPGetIMEA)(hwnd, ime); 1124 } 1125 1126 /* 1127 * @implemented 1128 */ 1129 LRESULT 1130 WINAPI 1131 SendIMEMessageExW(HWND hwnd, LPARAM lParam) 1132 { 1133 return IMM_FN(ImmSendIMEMessageExW)(hwnd, lParam); 1134 } 1135 1136 /* 1137 * @implemented 1138 */ 1139 LRESULT 1140 WINAPI 1141 SendIMEMessageExA(HWND hwnd, LPARAM lParam) 1142 { 1143 return IMM_FN(ImmSendIMEMessageExA)(hwnd, lParam); 1144 } 1145 1146 /* 1147 * @implemented 1148 */ 1149 BOOL 1150 WINAPI 1151 WINNLSEnableIME(HWND hwnd, BOOL enable) 1152 { 1153 return IMM_FN(ImmWINNLSEnableIME)(hwnd, enable); 1154 } 1155 1156 /* 1157 * @implemented 1158 */ 1159 BOOL 1160 WINAPI 1161 WINNLSGetEnableStatus(HWND hwnd) 1162 { 1163 return IMM_FN(ImmWINNLSGetEnableStatus)(hwnd); 1164 } 1165 1166 /* 1167 * @implemented 1168 */ 1169 UINT 1170 WINAPI 1171 WINNLSGetIMEHotkey(HWND hwnd) 1172 { 1173 return FALSE; 1174 } 1175