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