1 /* 2 * PROJECT: ReactOS msctfime.ime 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: The bridge of msctfime.ime 5 * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #include "msctfime.h" 9 10 WINE_DEFAULT_DEBUG_CHANNEL(msctfime); 11 12 /// @implemented 13 CicBridge::CicBridge() 14 { 15 m_bImmxInited = FALSE; 16 m_bUnknown1 = FALSE; 17 m_bDeactivating = FALSE; 18 m_bUnknown2 = FALSE; 19 m_pKeystrokeMgr = NULL; 20 m_pDocMgr = NULL; 21 m_pThreadMgrEventSink = NULL; 22 m_cliendId = 0; 23 m_cRefs = 1; 24 } 25 26 /// @implemented 27 STDMETHODIMP CicBridge::QueryInterface(REFIID riid, LPVOID* ppvObj) 28 { 29 static const QITAB c_tab[] = 30 { 31 QITABENT(CicBridge, ITfSysHookSink), 32 { NULL } 33 }; 34 return ::QISearch(this, c_tab, riid, ppvObj); 35 } 36 37 /// @implemented 38 STDMETHODIMP_(ULONG) CicBridge::AddRef() 39 { 40 return ::InterlockedIncrement(&m_cRefs); 41 } 42 43 /// @implemented 44 STDMETHODIMP_(ULONG) CicBridge::Release() 45 { 46 if (::InterlockedDecrement(&m_cRefs) == 0) 47 { 48 delete this; 49 return 0; 50 } 51 return m_cRefs; 52 } 53 54 /// @implemented 55 CicBridge::~CicBridge() 56 { 57 TLS *pTLS = TLS::PeekTLS(); 58 if (!pTLS || !pTLS->m_pThreadMgr) 59 return; 60 61 if (SUCCEEDED(DeactivateIMMX(pTLS, pTLS->m_pThreadMgr))) 62 UnInitIMMX(pTLS); 63 } 64 65 /// @implemented 66 ITfDocumentMgr* 67 CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext) 68 { 69 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 70 if (!pCicIC) 71 return NULL; 72 73 pCicIC->m_pDocumentMgr->AddRef(); 74 return pCicIC->m_pDocumentMgr; 75 } 76 77 /// @implemented 78 HRESULT 79 CicBridge::CreateInputContext( 80 _Inout_ TLS *pTLS, 81 _In_ HIMC hIMC) 82 { 83 CicIMCLock imcLock(hIMC); 84 if (FAILED(imcLock.m_hr)) 85 return imcLock.m_hr; 86 87 if (!imcLock.get().hCtfImeContext) 88 { 89 HIMCC hCtfImeContext = ImmCreateIMCC(sizeof(CTFIMECONTEXT)); 90 if (!hCtfImeContext) 91 return E_OUTOFMEMORY; 92 imcLock.get().hCtfImeContext = hCtfImeContext; 93 } 94 95 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 96 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 97 if (pCicIC) 98 return S_OK; 99 100 pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, hIMC); 101 if (!pCicIC) 102 { 103 imeContext.unlock(); 104 imcLock.unlock(); 105 DestroyInputContext(pTLS, hIMC); 106 return E_OUTOFMEMORY; 107 } 108 109 if (!pTLS->m_pThreadMgr) 110 { 111 pCicIC->Release(); 112 imeContext.unlock(); 113 imcLock.unlock(); 114 DestroyInputContext(pTLS, hIMC); 115 return E_NOINTERFACE; 116 } 117 118 imeContext.get().m_pCicIC = pCicIC; 119 120 HRESULT hr = pCicIC->CreateInputContext(pTLS->m_pThreadMgr, imcLock); 121 if (FAILED(hr)) 122 { 123 pCicIC->Release(); 124 imeContext.get().m_pCicIC = NULL; 125 return hr; 126 } 127 128 HWND hWnd = imcLock.get().hWnd; 129 if (hWnd && hWnd == ::GetFocus()) 130 { 131 ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext); 132 if (pDocMgr) 133 { 134 SetAssociate(pTLS, hWnd, hIMC, pTLS->m_pThreadMgr, pDocMgr); 135 pDocMgr->Release(); 136 } 137 } 138 139 return hr; 140 } 141 142 /// @implemented 143 HRESULT CicBridge::DestroyInputContext(TLS *pTLS, HIMC hIMC) 144 { 145 CicIMCLock imcLock(hIMC); 146 HRESULT hr = imcLock.m_hr; 147 if (FAILED(hr)) 148 return hr; 149 150 hr = E_FAIL; 151 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 152 if (imeContext) 153 hr = imeContext.m_hr; 154 155 if (SUCCEEDED(hr) && !(imeContext.get().m_dwCicFlags & 1)) 156 { 157 imeContext.get().m_dwCicFlags |= 1; 158 159 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 160 if (pCicIC) 161 { 162 imeContext.get().m_pCicIC = NULL; 163 hr = pCicIC->DestroyInputContext(); 164 pCicIC->Release(); 165 imeContext.get().m_pCicIC = NULL; 166 } 167 } 168 169 if (imcLock.get().hCtfImeContext) 170 { 171 ImmDestroyIMCC(imcLock.get().hCtfImeContext); 172 imcLock.get().hCtfImeContext = NULL; 173 hr = S_OK; 174 } 175 176 return hr; 177 } 178 179 /// @implemented 180 ITfContext * 181 CicBridge::GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext) 182 { 183 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 184 if (!pCicIC) 185 return NULL; 186 return pCicIC->m_pContext; 187 } 188 189 /// @implemented 190 HRESULT CicBridge::OnSetOpenStatus( 191 TLS *pTLS, 192 ITfThreadMgr_P *pThreadMgr, 193 CicIMCLock& imcLock, 194 CicInputContext *pCicIC) 195 { 196 if (!imcLock.get().fOpen && imcLock.ValidCompositionString()) 197 pCicIC->EscbCompComplete(imcLock); 198 199 pTLS->m_bNowOpening = TRUE; 200 HRESULT hr = SetCompartmentDWORD(m_cliendId, pThreadMgr, 201 GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, 202 imcLock.get().fOpen, FALSE); 203 pTLS->m_bNowOpening = FALSE; 204 return hr; 205 } 206 207 /// Selects the IME context. 208 /// @implemented 209 HRESULT 210 CicBridge::SelectEx( 211 _Inout_ TLS *pTLS, 212 _Inout_ ITfThreadMgr_P *pThreadMgr, 213 _In_ HIMC hIMC, 214 _In_ BOOL fSelect, 215 _In_ HKL hKL) 216 { 217 CicIMCLock imcLock(hIMC); 218 if (FAILED(imcLock.m_hr)) 219 return imcLock.m_hr; 220 221 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 222 if (FAILED(imeContext.m_hr)) 223 return imeContext.m_hr; 224 225 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 226 if (pCicIC) 227 pCicIC->m_bSelecting = TRUE; 228 229 if (fSelect) 230 { 231 if (pCicIC) 232 pCicIC->m_bCandidateOpen = FALSE; 233 if (imcLock.get().fOpen) 234 OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC); 235 } 236 else 237 { 238 ITfContext *pContext = GetInputContext(imeContext); 239 pThreadMgr->RequestPostponedLock(pContext); 240 if (pCicIC) 241 pCicIC->m_bSelecting = FALSE; 242 if (pContext) 243 pContext->Release(); 244 } 245 246 return imeContext.m_hr; 247 } 248 249 /// Used in CicBridge::EnumCreateInputContextCallback and 250 /// CicBridge::EnumDestroyInputContextCallback. 251 typedef struct ENUM_CREATE_DESTROY_IC 252 { 253 TLS *m_pTLS; 254 CicBridge *m_pBridge; 255 } ENUM_CREATE_DESTROY_IC, *PENUM_CREATE_DESTROY_IC; 256 257 /// Creates input context for the current thread. 258 /// @implemented 259 BOOL CALLBACK CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam) 260 { 261 PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam; 262 pData->m_pBridge->CreateInputContext(pData->m_pTLS, hIMC); 263 return TRUE; 264 } 265 266 /// Destroys input context for the current thread. 267 /// @implemented 268 BOOL CALLBACK CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam) 269 { 270 PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam; 271 pData->m_pBridge->DestroyInputContext(pData->m_pTLS, hIMC); 272 return TRUE; 273 } 274 275 /// @implemented 276 HRESULT 277 CicBridge::ActivateIMMX( 278 _Inout_ TLS *pTLS, 279 _Inout_ ITfThreadMgr_P *pThreadMgr) 280 { 281 HRESULT hr = pThreadMgr->ActivateEx(&m_cliendId, 1); 282 if (hr != S_OK) 283 { 284 m_cliendId = 0; 285 return E_FAIL; 286 } 287 288 if (m_cActivateLocks++ != 0) 289 return S_OK; 290 291 ITfSourceSingle *pSource = NULL; 292 hr = pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void**)&pSource); 293 if (FAILED(hr)) 294 { 295 DeactivateIMMX(pTLS, pThreadMgr); 296 return hr; 297 } 298 299 CFunctionProvider *pProvider = new(cicNoThrow) CFunctionProvider(m_cliendId); 300 if (!pProvider) 301 { 302 hr = E_FAIL; 303 goto Finish; 304 } 305 306 pSource->AdviseSingleSink(m_cliendId, IID_ITfFunctionProvider, pProvider); 307 pProvider->Release(); 308 309 if (!m_pDocMgr) 310 { 311 hr = pThreadMgr->CreateDocumentMgr(&m_pDocMgr); 312 if (FAILED(hr)) 313 { 314 hr = E_FAIL; 315 goto Finish; 316 } 317 318 SetCompartmentDWORD(m_cliendId, m_pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS, TRUE, FALSE); 319 } 320 321 pThreadMgr->SetSysHookSink(this); 322 323 hr = S_OK; 324 if (pTLS->m_bDestroyed) 325 { 326 ENUM_CREATE_DESTROY_IC Data = { pTLS, this }; 327 ImmEnumInputContext(0, CicBridge::EnumCreateInputContextCallback, (LPARAM)&Data); 328 } 329 330 Finish: 331 if (FAILED(hr)) 332 DeactivateIMMX(pTLS, pThreadMgr); 333 if (pSource) 334 pSource->Release(); 335 return hr; 336 } 337 338 /// @implemented 339 HRESULT 340 CicBridge::DeactivateIMMX( 341 _Inout_ TLS *pTLS, 342 _Inout_ ITfThreadMgr_P *pThreadMgr) 343 { 344 if (m_bDeactivating) 345 return TRUE; 346 347 m_bDeactivating = TRUE; 348 349 if (m_cliendId) 350 { 351 ENUM_CREATE_DESTROY_IC Data = { pTLS, this }; 352 ImmEnumInputContext(0, CicBridge::EnumDestroyInputContextCallback, (LPARAM)&Data); 353 pTLS->m_bDestroyed = TRUE; 354 355 ITfSourceSingle *pSource = NULL; 356 if (pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void **)&pSource) == S_OK) 357 pSource->UnadviseSingleSink(m_cliendId, IID_ITfFunctionProvider); 358 359 m_cliendId = 0; 360 361 while (m_cActivateLocks > 0) 362 { 363 --m_cActivateLocks; 364 pThreadMgr->Deactivate(); 365 } 366 367 if (pSource) 368 pSource->Release(); 369 } 370 371 if (m_pDocMgr) 372 { 373 m_pDocMgr->Release(); 374 m_pDocMgr = NULL; 375 } 376 377 pThreadMgr->SetSysHookSink(NULL); 378 379 m_bDeactivating = FALSE; 380 381 return S_OK; 382 } 383 384 /// @implemented 385 HRESULT 386 CicBridge::InitIMMX(_Inout_ TLS *pTLS) 387 { 388 if (m_bImmxInited) 389 return S_OK; 390 391 HRESULT hr = S_OK; 392 if (!pTLS->m_pThreadMgr) 393 { 394 ITfThreadMgr *pThreadMgr = NULL; 395 hr = TF_CreateThreadMgr(&pThreadMgr); 396 if (FAILED(hr)) 397 return E_FAIL; 398 399 hr = pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void **)&pTLS->m_pThreadMgr); 400 if (pThreadMgr) 401 pThreadMgr->Release(); 402 if (FAILED(hr)) 403 return E_FAIL; 404 } 405 406 if (!m_pThreadMgrEventSink) 407 { 408 m_pThreadMgrEventSink = 409 new(cicNoThrow) CThreadMgrEventSink(CThreadMgrEventSink::DIMCallback, NULL, NULL); 410 if (!m_pThreadMgrEventSink) 411 { 412 UnInitIMMX(pTLS); 413 return E_FAIL; 414 } 415 } 416 417 m_pThreadMgrEventSink->SetCallbackPV(m_pThreadMgrEventSink); 418 m_pThreadMgrEventSink->_Advise(pTLS->m_pThreadMgr); 419 420 if (!pTLS->m_pProfile) 421 { 422 pTLS->m_pProfile = new(cicNoThrow) CicProfile(); 423 if (!pTLS->m_pProfile) 424 return E_OUTOFMEMORY; 425 426 hr = pTLS->m_pProfile->InitProfileInstance(pTLS); 427 if (FAILED(hr)) 428 { 429 UnInitIMMX(pTLS); 430 return E_FAIL; 431 } 432 } 433 434 hr = pTLS->m_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr_P, (void **)&m_pKeystrokeMgr); 435 if (FAILED(hr)) 436 { 437 UnInitIMMX(pTLS); 438 return E_FAIL; 439 } 440 441 hr = InitDisplayAttrbuteLib(&m_LibThread); 442 if (FAILED(hr)) 443 { 444 UnInitIMMX(pTLS); 445 return E_FAIL; 446 } 447 448 m_bImmxInited = TRUE; 449 return S_OK; 450 } 451 452 /// @implemented 453 BOOL CicBridge::UnInitIMMX(_Inout_ TLS *pTLS) 454 { 455 UninitDisplayAttrbuteLib(&m_LibThread); 456 TFUninitLib_Thread(&m_LibThread); 457 458 if (m_pKeystrokeMgr) 459 { 460 m_pKeystrokeMgr->Release(); 461 m_pKeystrokeMgr = NULL; 462 } 463 464 if (pTLS->m_pProfile) 465 { 466 pTLS->m_pProfile->Release(); 467 pTLS->m_pProfile = NULL; 468 } 469 470 if (m_pThreadMgrEventSink) 471 { 472 m_pThreadMgrEventSink->_Unadvise(); 473 m_pThreadMgrEventSink->Release(); 474 m_pThreadMgrEventSink = NULL; 475 } 476 477 if (pTLS->m_pThreadMgr) 478 { 479 pTLS->m_pThreadMgr->Release(); 480 pTLS->m_pThreadMgr = NULL; 481 } 482 483 m_bImmxInited = FALSE; 484 return TRUE; 485 } 486 487 /// @implemented 488 STDMETHODIMP CicBridge::OnPreFocusDIM(HWND hwnd) 489 { 490 return S_OK; 491 } 492 493 /// @unimplemented 494 STDMETHODIMP CicBridge::OnSysKeyboardProc(UINT, LONG) 495 { 496 return E_NOTIMPL; 497 } 498 499 /// @implemented 500 STDMETHODIMP CicBridge::OnSysShellProc(INT, UINT, LONG) 501 { 502 return S_OK; 503 } 504 505 /// @implemented 506 void 507 CicBridge::PostTransMsg( 508 _In_ HWND hWnd, 509 _In_ INT cTransMsgs, 510 _In_ const TRANSMSG *pTransMsgs) 511 { 512 for (INT i = 0; i < cTransMsgs; ++i, ++pTransMsgs) 513 { 514 ::PostMessageW(hWnd, pTransMsgs->message, pTransMsgs->wParam, pTransMsgs->lParam); 515 } 516 } 517 518 /// @implemented 519 HRESULT 520 CicBridge::ConfigureGeneral( 521 _Inout_ TLS* pTLS, 522 _In_ ITfThreadMgr *pThreadMgr, 523 _In_ HKL hKL, 524 _In_ HWND hWnd) 525 { 526 CicProfile *pProfile = pTLS->m_pProfile; 527 if (!pProfile) 528 return E_OUTOFMEMORY; 529 530 TF_LANGUAGEPROFILE profile; 531 HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD, &profile); 532 if (FAILED(hr)) 533 return hr; 534 535 ITfFunctionProvider *pProvider = NULL; 536 hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider); 537 if (FAILED(hr)) 538 return hr; 539 540 ITfFnConfigure *pFnConfigure = NULL; 541 hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigure, (IUnknown**)&pFnConfigure); 542 if (FAILED(hr)) 543 { 544 pProvider->Release(); 545 return hr; 546 } 547 548 hr = pFnConfigure->Show(hWnd, profile.langid, profile.guidProfile); 549 550 pFnConfigure->Release(); 551 pProvider->Release(); 552 return hr; 553 } 554 555 /// @implemented 556 HRESULT 557 CicBridge::ConfigureRegisterWord( 558 _Inout_ TLS* pTLS, 559 _In_ ITfThreadMgr *pThreadMgr, 560 _In_ HKL hKL, 561 _In_ HWND hWnd, 562 _Inout_opt_ LPVOID lpData) 563 { 564 CicProfile *pProfile = pTLS->m_pProfile; 565 if (!pProfile) 566 return E_OUTOFMEMORY; 567 568 TF_LANGUAGEPROFILE profile; 569 HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD, &profile); 570 if (FAILED(hr)) 571 return hr; 572 573 ITfFunctionProvider *pProvider = NULL; 574 hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider); 575 if (FAILED(hr)) 576 return hr; 577 578 ITfFnConfigureRegisterWord *pFunction = NULL; 579 hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigureRegisterWord, (IUnknown**)&pFunction); 580 if (FAILED(hr)) 581 { 582 pProvider->Release(); 583 return hr; 584 } 585 586 REGISTERWORDW* pRegWord = (REGISTERWORDW*)lpData; 587 if (pRegWord) 588 { 589 if (pRegWord->lpWord) 590 { 591 hr = E_OUTOFMEMORY; 592 BSTR bstrWord = SysAllocString(pRegWord->lpWord); 593 if (bstrWord) 594 { 595 hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, bstrWord); 596 SysFreeString(bstrWord); 597 } 598 } 599 else 600 { 601 hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, NULL); 602 } 603 } 604 605 pProvider->Release(); 606 pFunction->Release(); 607 return hr; 608 } 609 610 /// @unimplemented 611 void CicBridge::SetAssociate( 612 TLS *pTLS, 613 HWND hWnd, 614 HIMC hIMC, 615 ITfThreadMgr_P *pThreadMgr, 616 ITfDocumentMgr *pDocMgr) 617 { 618 //FIXME 619 } 620 621 HRESULT 622 CicBridge::SetActiveContextAlways(TLS *pTLS, HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL) 623 { 624 auto pThreadMgr = pTLS->m_pThreadMgr; 625 if (!pThreadMgr) 626 return E_OUTOFMEMORY; 627 628 if (fActive) 629 { 630 if (!hIMC) 631 { 632 SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr); 633 return S_OK; 634 } 635 636 CicIMCLock imcLock(hIMC); 637 if (FAILED(imcLock.m_hr)) 638 return imcLock.m_hr; 639 640 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 641 if (FAILED(imeContext.m_hr)) 642 return imeContext.m_hr; 643 644 if (hIMC == ::ImmGetContext(hWnd)) 645 { 646 ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext); 647 if (pDocMgr) 648 { 649 SetAssociate(pTLS, imcLock.get().hWnd, hIMC, pThreadMgr, pDocMgr); 650 pDocMgr->Release(); 651 } 652 } 653 654 return S_OK; 655 } 656 657 if (hIMC && !IsEALang(LOWORD(hKL))) 658 { 659 CicIMCLock imcLock(hIMC); 660 if (FAILED(imcLock.m_hr)) 661 return imcLock.m_hr; 662 663 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 664 if (FAILED(imeContext.m_hr)) 665 return imeContext.m_hr; 666 667 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 668 if (!pCicIC->m_dwUnknown6_5[2] && !pCicIC->m_dwUnknown6_5[3]) 669 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 670 } 671 672 if (!hIMC || (::GetFocus() != hWnd) || (hIMC != ::ImmGetContext(hWnd))) 673 SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr); 674 675 return S_OK; 676 } 677 678 /// @unimplemented 679 BOOL 680 CicBridge::DoOpenCandidateHanja( 681 ITfThreadMgr_P *pThreadMgr, 682 CicIMCLock& imcLock, 683 CicInputContext *pCicIC) 684 { 685 return FALSE; 686 } 687 688 /// @unimplemented 689 HRESULT 690 CicBridge::OnSetConversionSentenceMode( 691 ITfThreadMgr_P *pThreadMgr, 692 CicIMCLock& imcLock, 693 CicInputContext *pCicIC, 694 DWORD dwValue, 695 LANGID LangID) 696 { 697 return E_NOTIMPL; 698 } 699 700 /// @implemented 701 HRESULT CicBridge::Notify( 702 TLS *pTLS, 703 ITfThreadMgr_P *pThreadMgr, 704 HIMC hIMC, 705 DWORD dwAction, 706 DWORD dwIndex, 707 DWORD_PTR dwValue) 708 { 709 CicIMCLock imcLock(hIMC); 710 if (FAILED(imcLock.m_hr)) 711 return imcLock.m_hr; 712 713 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 714 if (FAILED(imeContext.m_hr)) 715 return imeContext.m_hr; 716 717 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 718 if (!pCicIC) 719 return E_OUTOFMEMORY; 720 721 CicProfile *pProfile = pTLS->m_pProfile; 722 if (!pProfile) 723 return E_OUTOFMEMORY; 724 725 LANGID LangID; 726 pProfile->GetLangId(&LangID); 727 728 switch (dwAction) 729 { 730 case NI_OPENCANDIDATE: 731 if (PRIMARYLANGID(LangID) == LANG_KOREAN) 732 { 733 if (DoOpenCandidateHanja(pThreadMgr, imcLock, pCicIC)) 734 return S_OK; 735 return E_FAIL; 736 } 737 return E_NOTIMPL; 738 739 case NI_COMPOSITIONSTR: 740 switch (dwIndex) 741 { 742 case CPS_COMPLETE: 743 pCicIC->EscbCompComplete(imcLock); 744 break; 745 746 case CPS_CONVERT: 747 case CPS_REVERT: 748 return E_NOTIMPL; 749 750 case CPS_CANCEL: 751 pCicIC->EscbCompCancel(imcLock); 752 break; 753 754 default: 755 return E_FAIL; 756 } 757 return S_OK; 758 759 case NI_CONTEXTUPDATED: 760 switch (dwValue) 761 { 762 case IMC_SETCONVERSIONMODE: 763 case IMC_SETSENTENCEMODE: 764 return OnSetConversionSentenceMode(pThreadMgr, imcLock, pCicIC, dwValue, LangID); 765 766 case IMC_SETOPENSTATUS: 767 return OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC); 768 769 case IMC_SETCANDIDATEPOS: 770 return pCicIC->OnSetCandidatePos(pTLS, imcLock); 771 772 case IMC_SETCOMPOSITIONFONT: 773 case IMC_SETCOMPOSITIONWINDOW: 774 return E_NOTIMPL; 775 776 default: 777 return E_FAIL; 778 } 779 break; 780 781 default: 782 return E_NOTIMPL; 783 } 784 } 785 786 /// @unimplemented 787 BOOL CicBridge::ProcessKey( 788 TLS *pTLS, 789 ITfThreadMgr_P *pThreadMgr, 790 HIMC hIMC, 791 WPARAM wParam, 792 LPARAM lParam, 793 CONST LPBYTE lpbKeyState, 794 INT *pnUnknown60) 795 { 796 return FALSE; // FIXME 797 } 798 799 /// @unimplemented 800 HRESULT 801 CicBridge::ToAsciiEx( 802 TLS *pTLS, 803 ITfThreadMgr_P *pThreadMgr, 804 UINT uVirtKey, 805 UINT uScanCode, 806 CONST LPBYTE lpbKeyState, 807 LPTRANSMSGLIST lpTransBuf, 808 UINT fuState, 809 HIMC hIMC, 810 UINT *pResult) 811 { 812 return E_NOTIMPL; // FIXME 813 } 814 815 /// @implemented 816 BOOL 817 CicBridge::SetCompositionString( 818 TLS *pTLS, 819 ITfThreadMgr_P *pThreadMgr, 820 HIMC hIMC, 821 DWORD dwIndex, 822 LPCVOID lpComp, 823 DWORD dwCompLen, 824 LPCVOID lpRead, 825 DWORD dwReadLen) 826 { 827 CicIMCLock imcLock(hIMC); 828 if (FAILED(imcLock.m_hr)) 829 return FALSE; 830 831 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 832 if (FAILED(imeContext.m_hr)) 833 return FALSE; 834 835 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 836 auto pProfile = pTLS->m_pProfile; 837 if (!pCicIC || !pProfile) 838 return FALSE; 839 840 UINT uCodePage; 841 pProfile->GetCodePageA(&uCodePage); 842 843 LANGID LangID; 844 if (dwIndex != SCS_SETSTR || 845 !lpComp || *(WORD*)lpComp || 846 !dwCompLen || 847 FAILED(pProfile->GetLangId(&LangID)) || 848 PRIMARYLANGID(LangID) != LANG_KOREAN) 849 { 850 return pCicIC->SetCompositionString(imcLock, pThreadMgr, dwIndex, 851 lpComp, dwCompLen, lpRead, dwReadLen, 852 uCodePage); 853 } 854 855 if (imcLock.get().fdwConversion & IME_CMODE_NATIVE) 856 { 857 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 858 return TRUE; 859 } 860 861 return FALSE; 862 } 863 864 /// @unimplemented 865 LRESULT 866 CicBridge::EscHanjaMode(TLS *pTLS, HIMC hIMC, LPVOID lpData) 867 { 868 CicIMCLock imcLock(hIMC); 869 if (FAILED(imcLock.m_hr)) 870 return imcLock.m_hr; 871 872 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 873 if (FAILED(imeContext.m_hr)) 874 return imeContext.m_hr; 875 876 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 877 if (!pCicIC) 878 return TRUE; 879 880 if (pCicIC->m_bCandidateOpen) 881 return TRUE; 882 883 pCicIC->m_dwUnknown6_5[4] |= 0x1; 884 885 //FIXME 886 887 pCicIC->m_dwUnknown6_5[4] &= ~0x1; 888 889 return TRUE; 890 } 891 892 /// @implemented 893 LRESULT 894 CicBridge::EscapeKorean(TLS *pTLS, HIMC hIMC, UINT uSubFunc, LPVOID lpData) 895 { 896 if (uSubFunc == IME_ESC_QUERY_SUPPORT) 897 return *(DWORD*)lpData == IME_ESC_HANJA_MODE; 898 if (uSubFunc == IME_ESC_HANJA_MODE) 899 return EscHanjaMode(pTLS, hIMC, lpData); 900 return 0; 901 } 902 903 /// @implemented 904 BOOL CicBridge::IsOwnDim(ITfDocumentMgr *pDocMgr) 905 { 906 DWORD dwDimFlags = 0; 907 HRESULT hr = ::GetCompartmentDWORD(pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS, 908 &dwDimFlags, FALSE); 909 if (FAILED(hr)) 910 return FALSE; 911 return !!(dwDimFlags & 0x1); 912 } 913