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 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(hwnd, 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) 943 { 944 if (IS_CICERO_MODE()) 945 { 946 ret = IMM_FN(CtfImmDispatchDefImeMessage)(hwnd, msg, wParam, lParam); 947 if (ret) 948 return ret; 949 } 950 951 if (!pWnd->fnid) 952 { 953 if (msg != WM_NCCREATE) 954 { 955 if (unicode) 956 return DefWindowProcW(hwnd, msg, wParam, lParam); 957 return DefWindowProcA(hwnd, msg, wParam, lParam); 958 } 959 NtUserSetWindowFNID(hwnd, FNID_IME); 960 pimeui = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMEUI)); 961 pimeui->spwnd = pWnd; 962 } 963 else 964 { 965 if (pWnd->fnid != FNID_IME) 966 { 967 ERR("Wrong window class for Ime! fnId 0x%x\n",pWnd->fnid); 968 return 0; 969 } 970 pimeui = ((PIMEWND)pWnd)->pimeui; 971 if (pimeui == NULL) 972 { 973 ERR("Window is not set to IME!\n"); 974 return 0; 975 } 976 } 977 } 978 979 if (pimeui->nCntInIMEProc > 0) 980 { 981 switch (msg) 982 { 983 case WM_IME_CHAR: 984 case WM_IME_COMPOSITIONFULL: 985 case WM_IME_CONTROL: 986 case WM_IME_REQUEST: 987 case WM_IME_SELECT: 988 case WM_IME_SETCONTEXT: 989 case WM_IME_STARTCOMPOSITION: 990 case WM_IME_COMPOSITION: 991 case WM_IME_ENDCOMPOSITION: 992 return 0; 993 994 case WM_IME_NOTIFY: 995 if (wParam < IMN_PRIVATE || IS_IME_HKL(pimeui->hKL) || !IS_CICERO_MODE()) 996 return 0; 997 break; 998 999 case WM_IME_SYSTEM: 1000 switch (wParam) 1001 { 1002 case 0x03: 1003 case 0x10: 1004 case 0x13: 1005 break; 1006 1007 default: 1008 return 0; 1009 } 1010 break; 1011 1012 default: 1013 { 1014 if (unicode) 1015 return DefWindowProcW(hwnd, msg, wParam, lParam); 1016 return DefWindowProcA(hwnd, msg, wParam, lParam); 1017 } 1018 } 1019 } 1020 1021 switch (msg) 1022 { 1023 case WM_CREATE: 1024 return ImeWnd_OnCreate(pimeui, (LPCREATESTRUCT)lParam); 1025 1026 case WM_DESTROY: 1027 User32DestroyImeUIWindow(pimeui); 1028 break; 1029 1030 case WM_NCDESTROY: 1031 HeapFree(GetProcessHeap(), 0, pimeui); 1032 NtUserSetWindowFNID(hwnd, FNID_DESTROY); 1033 break; 1034 1035 case WM_ERASEBKGND: 1036 return TRUE; 1037 1038 case WM_PAINT: 1039 break; 1040 1041 case WM_COPYDATA: 1042 // TODO: 1043 break; 1044 1045 case WM_IME_STARTCOMPOSITION: 1046 case WM_IME_COMPOSITION: 1047 case WM_IME_ENDCOMPOSITION: 1048 return User32SendImeUIMessage(pimeui, msg, wParam, lParam, unicode); 1049 1050 case WM_IME_CONTROL: 1051 return ImeWnd_OnImeControl(pimeui, wParam, lParam, unicode); 1052 1053 case WM_IME_NOTIFY: 1054 return ImeWnd_OnImeNotify(pimeui, wParam, lParam); 1055 1056 case WM_IME_REQUEST: 1057 break; 1058 1059 case WM_IME_SELECT: 1060 ImeWnd_OnImeSelect(pimeui, wParam, lParam); 1061 break; 1062 1063 case WM_IME_SETCONTEXT: 1064 return ImeWnd_OnImeSetContext(pimeui, wParam, lParam); 1065 1066 case WM_IME_SYSTEM: 1067 return ImeWnd_OnImeSystem(pimeui, wParam, lParam); 1068 1069 default: 1070 { 1071 if (unicode) 1072 return DefWindowProcW(hwnd, msg, wParam, lParam); 1073 return DefWindowProcA(hwnd, msg, wParam, lParam); 1074 } 1075 } 1076 1077 return 0; 1078 } 1079 1080 // Win: ImeWndProcA 1081 LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 1082 { 1083 return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE); 1084 } 1085 1086 // Win: ImeWndProcW 1087 LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 1088 { 1089 return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE); 1090 } 1091 1092 // Win: UpdatePerUserImmEnabling 1093 BOOL WINAPI UpdatePerUserImmEnabling(VOID) 1094 { 1095 HMODULE imm32; 1096 BOOL ret; 1097 1098 ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING); 1099 if (!ret || !(gpsi->dwSRVIFlags & SRVINFO_IMM32)) 1100 return FALSE; 1101 1102 imm32 = GetModuleHandleW(L"imm32.dll"); 1103 if (imm32) 1104 return TRUE; 1105 1106 imm32 = LoadLibraryW(L"imm32.dll"); 1107 if (imm32) 1108 { 1109 ERR("UPUIE: Imm32 not installed!\n"); 1110 ret = FALSE; 1111 } 1112 1113 return ret; 1114 } 1115 1116 BOOL 1117 WINAPI 1118 RegisterIMEClass(VOID) 1119 { 1120 ATOM atom; 1121 WNDCLASSEXW WndClass = { sizeof(WndClass) }; 1122 1123 WndClass.lpszClassName = L"IME"; 1124 WndClass.style = CS_GLOBALCLASS; 1125 WndClass.lpfnWndProc = ImeWndProcW; 1126 WndClass.cbWndExtra = sizeof(LONG_PTR); 1127 WndClass.hCursor = LoadCursorW(NULL, IDC_ARROW); 1128 1129 atom = RegisterClassExWOWW(&WndClass, 0, FNID_IME, 0, FALSE); 1130 if (!atom) 1131 { 1132 ERR("Failed to register IME Class!\n"); 1133 return FALSE; 1134 } 1135 1136 RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME); 1137 TRACE("RegisterIMEClass atom = %u\n", atom); 1138 return TRUE; 1139 } 1140 1141 /* 1142 * @implemented 1143 */ 1144 BOOL 1145 WINAPI 1146 IMPSetIMEW(HWND hwnd, LPIMEPROW ime) 1147 { 1148 return IMM_FN(ImmIMPSetIMEW)(hwnd, ime); 1149 } 1150 1151 /* 1152 * @implemented 1153 */ 1154 BOOL 1155 WINAPI 1156 IMPQueryIMEW(LPIMEPROW ime) 1157 { 1158 return IMM_FN(ImmIMPQueryIMEW)(ime); 1159 } 1160 1161 /* 1162 * @implemented 1163 */ 1164 BOOL 1165 WINAPI 1166 IMPGetIMEW(HWND hwnd, LPIMEPROW ime) 1167 { 1168 return IMM_FN(ImmIMPGetIMEW)(hwnd, ime); 1169 } 1170 1171 /* 1172 * @implemented 1173 */ 1174 BOOL 1175 WINAPI 1176 IMPSetIMEA(HWND hwnd, LPIMEPROA ime) 1177 { 1178 return IMM_FN(ImmIMPSetIMEA)(hwnd, ime); 1179 } 1180 1181 /* 1182 * @implemented 1183 */ 1184 BOOL 1185 WINAPI 1186 IMPQueryIMEA(LPIMEPROA ime) 1187 { 1188 return IMM_FN(ImmIMPQueryIMEA)(ime); 1189 } 1190 1191 /* 1192 * @implemented 1193 */ 1194 BOOL 1195 WINAPI 1196 IMPGetIMEA(HWND hwnd, LPIMEPROA ime) 1197 { 1198 return IMM_FN(ImmIMPGetIMEA)(hwnd, ime); 1199 } 1200 1201 /* 1202 * @implemented 1203 */ 1204 LRESULT 1205 WINAPI 1206 SendIMEMessageExW(HWND hwnd, LPARAM lParam) 1207 { 1208 return IMM_FN(ImmSendIMEMessageExW)(hwnd, lParam); 1209 } 1210 1211 /* 1212 * @implemented 1213 */ 1214 LRESULT 1215 WINAPI 1216 SendIMEMessageExA(HWND hwnd, LPARAM lParam) 1217 { 1218 return IMM_FN(ImmSendIMEMessageExA)(hwnd, lParam); 1219 } 1220 1221 /* 1222 * @implemented 1223 */ 1224 BOOL 1225 WINAPI 1226 WINNLSEnableIME(HWND hwnd, BOOL enable) 1227 { 1228 return IMM_FN(ImmWINNLSEnableIME)(hwnd, enable); 1229 } 1230 1231 /* 1232 * @implemented 1233 */ 1234 BOOL 1235 WINAPI 1236 WINNLSGetEnableStatus(HWND hwnd) 1237 { 1238 return IMM_FN(ImmWINNLSGetEnableStatus)(hwnd); 1239 } 1240 1241 /* 1242 * @implemented 1243 */ 1244 UINT 1245 WINAPI 1246 WINNLSGetIMEHotkey(HWND hwnd) 1247 { 1248 return FALSE; 1249 } 1250