Reactos
at master 669 lines 15 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: Miscellaneous 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/// East-Asian language? 13/// @implemented 14BOOL IsEALang(_In_opt_ LANGID LangID) 15{ 16 if (LangID == 0) 17 { 18 TLS *pTLS = TLS::GetTLS(); 19 if (!pTLS || !pTLS->m_pProfile) 20 return FALSE; 21 22 pTLS->m_pProfile->GetLangId(&LangID); 23 } 24 25 switch (PRIMARYLANGID(LangID)) 26 { 27 case LANG_CHINESE: 28 case LANG_JAPANESE: 29 case LANG_KOREAN: 30 return TRUE; 31 32 default: 33 return FALSE; 34 } 35} 36 37typedef BOOLEAN (WINAPI *FN_DllShutdownInProgress)(VOID); 38 39/// This function calls ntdll!RtlDllShutdownInProgress. 40/// It can detect the system is shutting down or not. 41/// @implemented 42BOOLEAN DllShutdownInProgress(VOID) 43{ 44 HMODULE hNTDLL; 45 static FN_DllShutdownInProgress s_fnDllShutdownInProgress = NULL; 46 47 if (s_fnDllShutdownInProgress) 48 return s_fnDllShutdownInProgress(); 49 50 hNTDLL = cicGetSystemModuleHandle(L"ntdll.dll", FALSE); 51 s_fnDllShutdownInProgress = 52 (FN_DllShutdownInProgress)GetProcAddress(hNTDLL, "RtlDllShutdownInProgress"); 53 if (!s_fnDllShutdownInProgress) 54 return FALSE; 55 56 return s_fnDllShutdownInProgress(); 57} 58 59/// This function checks if the current user logon session is interactive. 60/// @implemented 61BOOL IsInteractiveUserLogon(VOID) 62{ 63 BOOL bOK, IsMember = FALSE; 64 PSID pSid; 65 SID_IDENTIFIER_AUTHORITY IdentAuth = { SECURITY_NT_AUTHORITY }; 66 67 if (!AllocateAndInitializeSid(&IdentAuth, 1, SECURITY_INTERACTIVE_RID, 68 0, 0, 0, 0, 0, 0, 0, &pSid)) 69 { 70 ERR("Error: %ld\n", GetLastError()); 71 return FALSE; 72 } 73 74 bOK = CheckTokenMembership(NULL, pSid, &IsMember); 75 76 if (pSid) 77 FreeSid(pSid); 78 79 return bOK && IsMember; 80} 81 82/// Gets the charset from a language ID. 83/// @implemented 84BYTE GetCharsetFromLangId(_In_ DWORD dwValue) 85{ 86 CHARSETINFO info; 87 if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, TCI_SRCLOCALE)) 88 return 0; 89 return info.ciCharset; 90} 91 92/// Get the active input context. 93/// @implemented 94HIMC GetActiveContext(VOID) 95{ 96 HWND hwndFocus = ::GetFocus(); 97 if (!hwndFocus) 98 hwndFocus = ::GetActiveWindow(); 99 return ::ImmGetContext(hwndFocus); 100} 101 102// MSIMTF.dll!MsimtfIsGuidMapEnable 103typedef BOOL (WINAPI *FN_MsimtfIsGuidMapEnable)(HIMC hIMC, LPBOOL pbValue); 104HINSTANCE g_hMSIMTF = NULL; 105 106/// @implemented 107BOOL MsimtfIsGuidMapEnable(_In_ HIMC hIMC, _Out_opt_ LPBOOL pbValue) 108{ 109 static FN_MsimtfIsGuidMapEnable s_fn = NULL; 110 if (!cicGetFN(g_hMSIMTF, s_fn, L"msimtf.dll", "MsimtfIsGuidMapEnable")) 111 return FALSE; 112 return s_fn(hIMC, pbValue); 113} 114 115/// @implemented 116BOOL IsVKDBEKey(_In_ UINT uVirtKey) 117{ 118 switch (uVirtKey) 119 { 120 case VK_KANJI: 121 case VK_CONVERT: 122 return TRUE; 123 default: 124 return (VK_OEM_ATTN <= uVirtKey && uVirtKey <= VK_PA1); 125 } 126} 127 128/// @implemented 129ITfCategoryMgr *GetUIMCat(PCIC_LIBTHREAD pLibThread) 130{ 131 if (!pLibThread) 132 return NULL; 133 134 if (pLibThread->m_pCategoryMgr) 135 return pLibThread->m_pCategoryMgr; 136 137 if (FAILED(cicCoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, 138 IID_ITfCategoryMgr, (void **)&pLibThread->m_pCategoryMgr))) 139 { 140 return NULL; 141 } 142 return pLibThread->m_pCategoryMgr; 143} 144 145/// @implemented 146static HRESULT 147LibEnumItemsInCategory(PCIC_LIBTHREAD pLibThread, REFGUID rguid, IEnumGUID **ppEnum) 148{ 149 ITfCategoryMgr *pCat = GetUIMCat(pLibThread); 150 if (!pCat) 151 return E_FAIL; 152 return pCat->EnumItemsInCategory(rguid, ppEnum); 153} 154 155/// @implemented 156HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread) 157{ 158 if (!pLibThread) 159 return E_FAIL; 160 161 if (pLibThread->m_pDisplayAttrMgr) 162 { 163 pLibThread->m_pDisplayAttrMgr->Release(); 164 pLibThread->m_pDisplayAttrMgr = NULL; 165 } 166 167 if (FAILED(cicCoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, CLSCTX_INPROC_SERVER, 168 IID_ITfDisplayAttributeMgr, 169 (void **)&pLibThread->m_pDisplayAttrMgr))) 170 { 171 return E_FAIL; 172 } 173 174 IEnumGUID *pEnumGuid; 175 LibEnumItemsInCategory(pLibThread, GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY, &pEnumGuid); 176 177 HRESULT hr = E_OUTOFMEMORY; 178 179 ::EnterCriticalSection(&g_csLock); 180 if (pEnumGuid && !g_pPropCache) 181 { 182 g_pPropCache = new(cicNoThrow) CDispAttrPropCache(); 183 if (g_pPropCache) 184 { 185 g_pPropCache->Add(GUID_PROP_ATTRIBUTE); 186 GUID guid; 187 while (pEnumGuid->Next(1, &guid, NULL) == S_OK) 188 { 189 if (!IsEqualGUID(guid, GUID_PROP_ATTRIBUTE)) 190 g_pPropCache->Add(guid); 191 } 192 hr = S_OK; 193 } 194 } 195 ::LeaveCriticalSection(&g_csLock); 196 197 return hr; 198} 199 200/// @implemented 201HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread) 202{ 203 if (!pLibThread) 204 return E_FAIL; 205 206 if (pLibThread->m_pDisplayAttrMgr) 207 { 208 pLibThread->m_pDisplayAttrMgr->Release(); 209 pLibThread->m_pDisplayAttrMgr = NULL; 210 } 211 212 return S_OK; 213} 214 215/***********************************************************************/ 216 217/// @implemented 218HRESULT 219GetCompartment( 220 IUnknown *pUnknown, 221 REFGUID rguid, 222 ITfCompartment **ppComp, 223 BOOL bThread) 224{ 225 *ppComp = NULL; 226 227 ITfThreadMgr *pThreadMgr = NULL; 228 ITfCompartmentMgr *pCompMgr = NULL; 229 230 HRESULT hr; 231 if (bThread) 232 { 233 hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr); 234 if (FAILED(hr)) 235 return hr; 236 237 hr = pThreadMgr->GetGlobalCompartment(&pCompMgr); 238 } 239 else 240 { 241 hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr); 242 } 243 244 if (SUCCEEDED(hr)) 245 { 246 hr = E_FAIL; 247 if (pCompMgr) 248 { 249 hr = pCompMgr->GetCompartment(rguid, ppComp); 250 pCompMgr->Release(); 251 } 252 } 253 254 if (pThreadMgr) 255 pThreadMgr->Release(); 256 257 return hr; 258} 259 260/// @implemented 261HRESULT 262SetCompartmentDWORD( 263 TfEditCookie cookie, 264 IUnknown *pUnknown, 265 REFGUID rguid, 266 DWORD dwValue, 267 BOOL bThread) 268{ 269 ITfCompartment *pComp = NULL; 270 HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread); 271 if (FAILED(hr)) 272 return hr; 273 274 VARIANT vari; 275 V_I4(&vari) = dwValue; 276 V_VT(&vari) = VT_I4; 277 hr = pComp->SetValue(cookie, &vari); 278 279 pComp->Release(); 280 return hr; 281} 282 283/// @implemented 284HRESULT 285GetCompartmentDWORD( 286 IUnknown *pUnknown, 287 REFGUID rguid, 288 LPDWORD pdwValue, 289 BOOL bThread) 290{ 291 *pdwValue = 0; 292 293 ITfCompartment *pComp = NULL; 294 HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread); 295 if (FAILED(hr)) 296 return hr; 297 298 VARIANT vari; 299 hr = pComp->GetValue(&vari); 300 if (hr == S_OK) 301 *pdwValue = V_I4(&vari); 302 303 pComp->Release(); 304 return hr; 305} 306 307/// @implemented 308HRESULT 309SetCompartmentUnknown( 310 TfEditCookie cookie, 311 IUnknown *pUnknown, 312 REFGUID rguid, 313 IUnknown *punkValue) 314{ 315 ITfCompartment *pComp = NULL; 316 HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, FALSE); 317 if (FAILED(hr)) 318 return hr; 319 320 VARIANT vari; 321 V_UNKNOWN(&vari) = punkValue; 322 V_VT(&vari) = VT_UNKNOWN; 323 hr = pComp->SetValue(cookie, &vari); 324 325 pComp->Release(); 326 return hr; 327} 328 329/// @implemented 330HRESULT 331ClearCompartment( 332 TfClientId tid, 333 IUnknown *pUnknown, 334 REFGUID rguid, 335 BOOL bThread) 336{ 337 ITfCompartmentMgr *pCompMgr = NULL; 338 ITfThreadMgr *pThreadMgr = NULL; 339 340 HRESULT hr; 341 if (bThread) 342 { 343 hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr); 344 if (FAILED(hr)) 345 return hr; 346 347 hr = pThreadMgr->GetGlobalCompartment(&pCompMgr); 348 } 349 else 350 { 351 hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr); 352 } 353 354 if (SUCCEEDED(hr)) 355 { 356 hr = E_FAIL; 357 if (pCompMgr) 358 { 359 hr = pCompMgr->ClearCompartment(tid, rguid); 360 pCompMgr->Release(); 361 } 362 } 363 364 if (pThreadMgr) 365 pThreadMgr->Release(); 366 367 return hr; 368} 369 370/***********************************************************************/ 371 372struct MODEBIAS 373{ 374 REFGUID m_guid; 375 LONG m_bias; 376}; 377 378static const MODEBIAS g_ModeBiasMap[] = 379{ 380 { GUID_MODEBIAS_FILENAME, 0x00000001 }, 381 { GUID_MODEBIAS_NUMERIC, 0x00000004 }, 382 { GUID_MODEBIAS_URLHISTORY, 0x00010000 }, 383 { GUID_MODEBIAS_DEFAULT, 0x00000000 }, 384 { GUID_MODEBIAS_NONE, 0x00000000 }, 385}; 386 387/// @implemented 388void CModeBias::SetModeBias(REFGUID rguid) 389{ 390 m_guid = rguid; 391} 392 393/// @implemented 394GUID CModeBias::ConvertModeBias(LONG bias) 395{ 396 const GUID *pguid = &GUID_NULL; 397 for (auto& item : g_ModeBiasMap) 398 { 399 if (item.m_bias == bias) 400 { 401 pguid = &item.m_guid; 402 break; 403 } 404 } 405 406 return *pguid; 407} 408 409/// @implemented 410LONG CModeBias::ConvertModeBias(REFGUID guid) 411{ 412 for (auto& item : g_ModeBiasMap) 413 { 414 if (IsEqualGUID(guid, item.m_guid)) 415 return item.m_bias; 416 } 417 return 0; 418} 419 420/***********************************************************************/ 421 422/// @implemented 423CFunctionProviderBase::CFunctionProviderBase(_In_ TfClientId clientId) 424{ 425 m_clientId = clientId; 426 m_guid = GUID_NULL; 427 m_bstr = NULL; 428 m_cRefs = 1; 429} 430 431/// @implemented 432CFunctionProviderBase::~CFunctionProviderBase() 433{ 434 if (!DllShutdownInProgress()) 435 ::SysFreeString(m_bstr); 436} 437 438/// @implemented 439BOOL 440CFunctionProviderBase::Init( 441 _In_ REFGUID rguid, 442 _In_ LPCWSTR psz) 443{ 444 m_bstr = ::SysAllocString(psz); 445 m_guid = rguid; 446 return (m_bstr != NULL); 447} 448 449/// @implemented 450STDMETHODIMP 451CFunctionProviderBase::QueryInterface( 452 _In_ REFIID riid, 453 _Out_ LPVOID* ppvObj) 454{ 455 static const QITAB c_tab[] = 456 { 457 QITABENT(CFunctionProviderBase, ITfFunctionProvider), 458 { NULL } 459 }; 460 return ::QISearch(this, c_tab, riid, ppvObj); 461} 462 463/// @implemented 464STDMETHODIMP_(ULONG) CFunctionProviderBase::AddRef() 465{ 466 return ::InterlockedIncrement(&m_cRefs); 467} 468 469/// @implemented 470STDMETHODIMP_(ULONG) CFunctionProviderBase::Release() 471{ 472 if (::InterlockedDecrement(&m_cRefs) == 0) 473 { 474 delete this; 475 return 0; 476 } 477 return m_cRefs; 478} 479 480/// @implemented 481STDMETHODIMP CFunctionProviderBase::GetType(_Out_ GUID *guid) 482{ 483 *guid = m_guid; 484 return S_OK; 485} 486 487/// @implemented 488STDMETHODIMP CFunctionProviderBase::GetDescription(_Out_ BSTR *desc) 489{ 490 *desc = ::SysAllocString(m_bstr); 491 return (*desc ? S_OK : E_OUTOFMEMORY); 492} 493 494/***********************************************************************/ 495 496/// @implemented 497CFunctionProvider::CFunctionProvider(_In_ TfClientId clientId) : CFunctionProviderBase(clientId) 498{ 499 Init(CLSID_CAImmLayer, L"MSCTFIME::Function Provider"); 500} 501 502/// @implemented 503STDMETHODIMP 504CFunctionProvider::GetFunction( 505 _In_ REFGUID guid, 506 _In_ REFIID riid, 507 _Out_ IUnknown **func) 508{ 509 *func = NULL; 510 511 if (IsEqualGUID(guid, GUID_NULL) && 512 IsEqualIID(riid, IID_IAImmFnDocFeed)) 513 { 514 *func = new(cicNoThrow) CFnDocFeed(); 515 if (*func) 516 return S_OK; 517 } 518 519 return E_NOINTERFACE; 520} 521 522/***********************************************************************/ 523 524CFnDocFeed::CFnDocFeed() 525{ 526 m_cRefs = 1; 527} 528 529CFnDocFeed::~CFnDocFeed() 530{ 531} 532 533/// @implemented 534STDMETHODIMP CFnDocFeed::QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) 535{ 536 static const QITAB c_tab[] = 537 { 538 QITABENT(CFnDocFeed, IAImmFnDocFeed), 539 { NULL } 540 }; 541 return ::QISearch(this, c_tab, riid, ppvObj); 542} 543 544/// @implemented 545STDMETHODIMP_(ULONG) CFnDocFeed::AddRef() 546{ 547 return ::InterlockedIncrement(&m_cRefs); 548} 549 550/// @implemented 551STDMETHODIMP_(ULONG) CFnDocFeed::Release() 552{ 553 if (::InterlockedDecrement(&m_cRefs) == 0) 554 { 555 delete this; 556 return 0; 557 } 558 return m_cRefs; 559} 560 561/// @implemented 562STDMETHODIMP CFnDocFeed::DocFeed() 563{ 564 TLS *pTLS = TLS::GetTLS(); 565 if (!pTLS) 566 return E_OUTOFMEMORY; 567 568 HIMC hIMC = GetActiveContext(); 569 CicIMCLock imcLock(hIMC); 570 if (FAILED(imcLock.m_hr)) 571 return imcLock.m_hr; 572 573 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 574 if (FAILED(imeContext.m_hr)) 575 return imeContext.m_hr; 576 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 577 if (!pCicIC) 578 return E_FAIL; 579 580 UINT uCodePage = CP_ACP; 581 pTLS->m_pProfile->GetCodePageA(&uCodePage); 582 pCicIC->SetupDocFeedString(imcLock, uCodePage); 583 return S_OK; 584} 585 586/// @implemented 587STDMETHODIMP CFnDocFeed::ClearDocFeedBuffer() 588{ 589 if (!TLS::GetTLS()) 590 return E_OUTOFMEMORY; 591 592 HIMC hIMC = GetActiveContext(); 593 CicIMCLock imcLock(hIMC); 594 if (FAILED(imcLock.m_hr)) 595 return imcLock.m_hr; 596 597 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 598 if (FAILED(imeContext.m_hr)) 599 return imeContext.m_hr; 600 601 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 602 if (!pCicIC) 603 return E_FAIL; 604 605 pCicIC->EscbClearDocFeedBuffer(imcLock, TRUE); 606 return S_OK; 607} 608 609/// @unimplemented 610STDMETHODIMP CFnDocFeed::StartReconvert() 611{ 612 TLS *pTLS = TLS::GetTLS(); 613 if (!pTLS) 614 return E_OUTOFMEMORY; 615 auto *pThreadMgr = pTLS->m_pThreadMgr; 616 if (!pThreadMgr) 617 return E_OUTOFMEMORY; 618 619 HIMC hIMC = GetActiveContext(); 620 CicIMCLock imcLock(hIMC); 621 if (FAILED(imcLock.m_hr)) 622 return imcLock.m_hr; 623 624 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 625 if (FAILED(imeContext.m_hr)) 626 return imeContext.m_hr; 627 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 628 if (!pCicIC) 629 return E_FAIL; 630 631 UINT uCodePage = CP_ACP; 632 pTLS->m_pProfile->GetCodePageA(&uCodePage); 633 634 pCicIC->m_bReconverting = TRUE; 635 pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, 0); 636 pCicIC->EndReconvertString(imcLock); 637 pCicIC->m_bReconverting = FALSE; 638 return S_OK; 639} 640 641/// @implemented 642STDMETHODIMP CFnDocFeed::StartUndoCompositionString() 643{ 644 TLS *pTLS = TLS::GetTLS(); 645 if (!pTLS) 646 return E_OUTOFMEMORY; 647 auto *pThreadMgr = pTLS->m_pThreadMgr; 648 if (!pThreadMgr) 649 return E_OUTOFMEMORY; 650 651 HIMC hIMC = GetActiveContext(); 652 CicIMCLock imcLock(hIMC); 653 if (FAILED(imcLock.m_hr)) 654 return imcLock.m_hr; 655 656 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext); 657 if (FAILED(imeContext.m_hr)) 658 return imeContext.m_hr; 659 CicInputContext *pCicIC = imeContext.get().m_pCicIC; 660 if (!pCicIC) 661 return E_FAIL; 662 663 UINT uCodePage = CP_ACP; 664 pTLS->m_pProfile->GetCodePageA(&uCodePage); 665 666 pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, TRUE); 667 pCicIC->EndReconvertString(imcLock); 668 return S_OK; 669}