Reactos
at master 501 lines 10 kB view raw
1/* 2 * PROJECT: ReactOS msctfime.ime 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Input Context of msctfime.ime 5 * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8#include "msctfime.h" 9 10WINE_DEFAULT_DEBUG_CHANNEL(msctfime); 11 12/*********************************************************************** 13 * CInputContextOwner 14 */ 15 16/// @unimplemented 17CInputContextOwner::CInputContextOwner(FN_IC_OWNER_CALLBACK fnCallback, LPVOID pCallbackPV) 18{ 19 m_dwCookie = -1; 20 m_fnCallback = fnCallback; 21 m_cRefs = 1; 22 m_pCallbackPV = pCallbackPV; 23} 24 25/// @implemented 26CInputContextOwner::~CInputContextOwner() 27{ 28} 29 30/// @implemented 31HRESULT CInputContextOwner::_Advise(IUnknown *pContext) 32{ 33 ITfSource *pSource = NULL; 34 35 m_pContext = NULL; 36 37 HRESULT hr = E_FAIL; 38 if (SUCCEEDED(m_pContext->QueryInterface(IID_ITfSource, (LPVOID*)&pSource)) && 39 SUCCEEDED(pSource->AdviseSink(IID_ITfContextOwner, 40 static_cast<ITfContextOwner*>(this), &m_dwCookie))) 41 { 42 m_pContext = pContext; 43 m_pContext->AddRef(); 44 hr = S_OK; 45 } 46 47 if (pSource) 48 pSource->Release(); 49 50 return hr; 51} 52 53/// @implemented 54HRESULT CInputContextOwner::_Unadvise() 55{ 56 ITfSource *pSource = NULL; 57 58 HRESULT hr = E_FAIL; 59 if (m_pContext) 60 { 61 if (SUCCEEDED(m_pContext->QueryInterface(IID_ITfSource, (LPVOID*)&pSource)) && 62 SUCCEEDED(pSource->UnadviseSink(m_dwCookie))) 63 { 64 hr = S_OK; 65 } 66 } 67 68 if (m_pContext) 69 { 70 m_pContext->Release(); 71 m_pContext = NULL; 72 } 73 74 if (pSource) 75 pSource->Release(); 76 77 return hr; 78} 79 80/// @implemented 81STDMETHODIMP CInputContextOwner::QueryInterface(REFIID riid, LPVOID* ppvObj) 82{ 83 static const QITAB c_tab[] = 84 { 85 QITABENT(CInputContextOwner, ITfContextOwner), 86 QITABENT(CInputContextOwner, ITfMouseTrackerACP), 87 { NULL } 88 }; 89 return ::QISearch(this, c_tab, riid, ppvObj); 90} 91 92/// @implemented 93STDMETHODIMP_(ULONG) CInputContextOwner::AddRef() 94{ 95 return ++m_cRefs; 96} 97 98/// @implemented 99STDMETHODIMP_(ULONG) CInputContextOwner::Release() 100{ 101 if (--m_cRefs == 0) 102 { 103 delete this; 104 return 0; 105 } 106 return m_cRefs; 107} 108 109/// @unimplemented 110STDMETHODIMP 111CInputContextOwner::GetACPFromPoint( 112 const POINT *ptScreen, 113 DWORD dwFlags, 114 LONG *pacp) 115{ 116 return E_NOTIMPL; 117} 118 119/// @unimplemented 120STDMETHODIMP 121CInputContextOwner::GetTextExt( 122 LONG acpStart, 123 LONG acpEnd, 124 RECT *prc, 125 BOOL *pfClipped) 126{ 127 return E_NOTIMPL; 128} 129 130/// @implemented 131STDMETHODIMP CInputContextOwner::GetScreenExt(RECT *prc) 132{ 133 return m_fnCallback(2, &prc, m_pCallbackPV); 134} 135 136/// @implemented 137STDMETHODIMP CInputContextOwner::GetStatus(TF_STATUS *pdcs) 138{ 139 return m_fnCallback(6, &pdcs, m_pCallbackPV); 140} 141 142/// @unimplemented 143STDMETHODIMP CInputContextOwner::GetWnd(HWND *phwnd) 144{ 145 return m_fnCallback(7, &phwnd, m_pCallbackPV); 146} 147 148/// @unimplemented 149STDMETHODIMP CInputContextOwner::GetAttribute(REFGUID rguidAttribute, VARIANT *pvarValue) 150{ 151 return E_NOTIMPL; 152} 153 154struct MOUSE_SINK_ARGS 155{ 156 ITfRangeACP *range; 157 ITfMouseSink *pSink; 158 DWORD *pdwCookie; 159}; 160 161/// @implemented 162STDMETHODIMP CInputContextOwner::AdviseMouseSink( 163 ITfRangeACP *range, 164 ITfMouseSink *pSink, 165 DWORD *pdwCookie) 166{ 167 MOUSE_SINK_ARGS args = { range, pSink, pdwCookie }; 168 return m_fnCallback(9, &args, m_pCallbackPV); 169} 170 171/// @implemented 172STDMETHODIMP CInputContextOwner::UnadviseMouseSink(DWORD dwCookie) 173{ 174 return m_fnCallback(10, &dwCookie, m_pCallbackPV); 175} 176 177/*********************************************************************** 178 * CicInputContext 179 */ 180 181/// @unimplemented 182CicInputContext::CicInputContext( 183 _In_ TfClientId cliendId, 184 _Inout_ PCIC_LIBTHREAD pLibThread, 185 _In_ HIMC hIMC) 186{ 187 m_hIMC = hIMC; 188 m_dwQueryPos = 0; 189 m_cRefs = 1; 190} 191 192/// @implemented 193STDMETHODIMP CicInputContext::QueryInterface(REFIID riid, LPVOID* ppvObj) 194{ 195 static const QITAB c_tab[] = 196 { 197 QITABENT(CicInputContext, ITfCleanupContextSink), 198 QITABENT(CicInputContext, ITfContextOwnerCompositionSink), 199 { NULL } 200 }; 201 return ::QISearch(this, c_tab, riid, ppvObj); 202} 203 204/// @implemented 205STDMETHODIMP_(ULONG) CicInputContext::AddRef() 206{ 207 return ::InterlockedIncrement(&m_cRefs); 208} 209 210/// @implemented 211STDMETHODIMP_(ULONG) CicInputContext::Release() 212{ 213 if (::InterlockedDecrement(&m_cRefs) == 0) 214 { 215 delete this; 216 return 0; 217 } 218 return m_cRefs; 219} 220 221/// @implemented 222STDMETHODIMP 223CicInputContext::OnStartComposition( 224 ITfCompositionView *pComposition, 225 BOOL *pfOk) 226{ 227 if ((m_cCompLocks <= 0) || m_bReconverting) 228 { 229 *pfOk = TRUE; 230 ++m_cCompLocks; 231 } 232 else 233 { 234 *pfOk = FALSE; 235 } 236 return S_OK; 237} 238 239/// @implemented 240STDMETHODIMP 241CicInputContext::OnUpdateComposition( 242 ITfCompositionView *pComposition, 243 ITfRange *pRangeNew) 244{ 245 return S_OK; 246} 247 248/// @implemented 249STDMETHODIMP 250CicInputContext::OnEndComposition( 251 ITfCompositionView *pComposition) 252{ 253 --m_cCompLocks; 254 return S_OK; 255} 256 257/// @implemented 258HRESULT 259CicInputContext::GetGuidAtom( 260 _Inout_ CicIMCLock& imcLock, 261 _In_ BYTE iAtom, 262 _Out_opt_ LPDWORD pdwGuidAtom) 263{ 264 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCompStr); 265 if (FAILED(imeContext.m_hr)) 266 return imeContext.m_hr; 267 268 HRESULT hr = E_FAIL; 269 if (iAtom < m_cGuidAtoms) 270 { 271 *pdwGuidAtom = m_adwGuidAtoms[iAtom]; 272 hr = S_OK; 273 } 274 275 return hr; 276} 277 278/// @unimplemented 279HRESULT 280CicInputContext::CreateInputContext( 281 _Inout_ ITfThreadMgr *pThreadMgr, 282 _Inout_ CicIMCLock& imcLock) 283{ 284 //FIXME 285 return E_NOTIMPL; 286} 287 288/// @unimplemented 289HRESULT 290CicInputContext::DestroyInputContext() 291{ 292 ITfSourceSingle *pSource = NULL; 293 294 if (m_pContext && m_pContext->QueryInterface(IID_ITfSourceSingle, (void **)&pSource) == S_OK) 295 pSource->UnadviseSingleSink(m_clientId, IID_ITfCleanupContextSink); 296 297 //FIXME: m_dwUnknown5 298 299 if (m_pTextEventSink) 300 { 301 m_pTextEventSink->_Unadvise(); 302 m_pTextEventSink->Release(); 303 m_pTextEventSink = NULL; 304 } 305 306 if (m_pCompEventSink2) 307 { 308 m_pCompEventSink2->_Unadvise(); 309 m_pCompEventSink2->Release(); 310 m_pCompEventSink2 = NULL; 311 } 312 313 if (m_pCompEventSink1) 314 { 315 m_pCompEventSink1->_Unadvise(); 316 m_pCompEventSink1->Release(); 317 m_pCompEventSink1 = NULL; 318 } 319 320 if (m_pInputContextOwner) 321 { 322 m_pInputContextOwner->_Unadvise(); 323 m_pInputContextOwner->Release(); 324 m_pInputContextOwner = NULL; 325 } 326 327 if (m_pDocumentMgr) 328 m_pDocumentMgr->Pop(1); 329 330 if (m_pContext) 331 { 332 ClearCompartment(m_clientId, m_pContext, GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT, 0); 333 m_pContext->Release(); 334 m_pContext = NULL; 335 } 336 337 if (m_pContextOwnerServices) 338 { 339 m_pContextOwnerServices->Release(); 340 m_pContextOwnerServices = NULL; 341 } 342 343 // FIXME: m_pICOwnerCallback 344 345 if (m_pDocumentMgr) 346 { 347 m_pDocumentMgr->Release(); 348 m_pDocumentMgr = NULL; 349 } 350 351 if (pSource) 352 pSource->Release(); 353 354 return S_OK; 355} 356 357/// @implemented 358STDMETHODIMP 359CicInputContext::OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition *pComposition) 360{ 361 return S_OK; 362} 363 364/// @implemented 365STDMETHODIMP 366CicInputContext::OnCleanupContext( 367 _In_ TfEditCookie ecWrite, 368 _Inout_ ITfContext *pic) 369{ 370 TLS *pTLS = TLS::PeekTLS(); 371 if (!pTLS || !pTLS->m_pProfile) 372 return E_OUTOFMEMORY; 373 374 LANGID LangID; 375 pTLS->m_pProfile->GetLangId(&LangID); 376 377 IMEINFO IMEInfo; 378 WCHAR szPath[MAX_PATH]; 379 if (Inquire(&IMEInfo, szPath, 0, (HKL)UlongToHandle(LangID)) != S_OK) 380 return E_FAIL; 381 382 ITfProperty *pProp = NULL; 383 if (!(IMEInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT)) 384 return S_OK; 385 386 HRESULT hr = pic->GetProperty(GUID_PROP_COMPOSING, &pProp); 387 if (FAILED(hr)) 388 return S_OK; 389 390 IEnumTfRanges *pRanges = NULL; 391 hr = pProp->EnumRanges(ecWrite, &pRanges, NULL); 392 if (SUCCEEDED(hr)) 393 { 394 ITfRange *pRange = NULL; 395 while (pRanges->Next(1, &pRange, 0) == S_OK) 396 { 397 VARIANT vari; 398 V_VT(&vari) = VT_EMPTY; 399 pProp->GetValue(ecWrite, pRange, &vari); 400 if (V_VT(&vari) == VT_I4) 401 { 402 if (V_I4(&vari)) 403 pProp->Clear(ecWrite, pRange); 404 } 405 pRange->Release(); 406 pRange = NULL; 407 } 408 pRanges->Release(); 409 } 410 pProp->Release(); 411 412 return S_OK; 413} 414 415/// @unimplemented 416HRESULT CicInputContext::SetupDocFeedString(CicIMCLock& imcLock, UINT uCodePage) 417{ 418 return E_NOTIMPL; 419} 420 421/// @unimplemented 422HRESULT CicInputContext::EscbClearDocFeedBuffer(CicIMCLock& imcLock, BOOL bFlag) 423{ 424 return E_NOTIMPL; 425} 426 427/// @unimplemented 428HRESULT CicInputContext::EscbCompComplete(CicIMCLock& imcLock) 429{ 430 return E_NOTIMPL; 431} 432 433/// @unimplemented 434HRESULT CicInputContext::EscbCompCancel(CicIMCLock& imcLock) 435{ 436 return E_NOTIMPL; 437} 438 439/// @unimplemented 440HRESULT CicInputContext::OnSetCandidatePos(TLS *pTLS, CicIMCLock& imcLock) 441{ 442 return E_NOTIMPL; 443} 444 445/// @unimplemented 446HRESULT CicInputContext::DelayedReconvertFuncCall(CicIMCLock& imcLock) 447{ 448 return E_NOTIMPL; 449} 450 451/// @unimplemented 452HRESULT 453CicInputContext::MsImeMouseHandler( 454 DWORD dwUnknown58, 455 DWORD dwUnknown59, 456 UINT keys, 457 CicIMCLock& imcLock) 458{ 459 return E_NOTIMPL; 460} 461 462/// @unimplemented 463HRESULT 464CicInputContext::SetupReconvertString( 465 CicIMCLock& imcLock, 466 ITfThreadMgr_P *pThreadMgr, 467 UINT uCodePage, 468 UINT uMsg, 469 BOOL bUndo) 470{ 471 return E_NOTIMPL; 472} 473 474void CicInputContext::ClearPrevCandidatePos() 475{ 476 m_dwUnknown8 = 0; 477 ZeroMemory(&m_rcCandidate1, sizeof(m_rcCandidate1)); 478 ZeroMemory(&m_CandForm, sizeof(m_CandForm)); 479 ZeroMemory(&m_rcCandidate2, sizeof(m_rcCandidate2)); 480 m_dwQueryPos = 0; 481} 482 483/// @unimplemented 484HRESULT CicInputContext::EndReconvertString(CicIMCLock& imcLock) 485{ 486 return E_NOTIMPL; 487} 488 489/// @unimplemented 490BOOL CicInputContext::SetCompositionString( 491 CicIMCLock& imcLock, 492 ITfThreadMgr_P *pThreadMgr, 493 DWORD dwIndex, 494 LPCVOID lpComp, 495 DWORD dwCompLen, 496 LPCVOID lpRead, 497 DWORD dwReadLen, 498 UINT uCodePage) 499{ 500 return FALSE; 501}