From ffa1c541aaef6b0bf2c1ddf606526701512e03df Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 20 Apr 2026 21:51:45 +0900 Subject: [PATCH] [MSCTFIME][CICERO] Implement CicProfile::GetActiveLanguageProfile (#8869) Supporting CTF IMEs. JIRA issue: CORE-19360 - Add base/ctf/cicero/ciciface.h to add CicInterface_RefCnt template class. - Add CicProfile:: LanguageProfilesCallback callback function. - Implement CicProfile:: GetActiveLanguageProfile and CicProfile::IsIME functions. --- base/ctf/cicero/cicbase.h | 5 +- base/ctf/cicero/ciciface.h | 59 ++++++++++++++++++++++ base/ctf/msctfime/msctfime.h | 1 + base/ctf/msctfime/profile.cpp | 93 +++++++++++++++++++++++++++++++---- base/ctf/msctfime/profile.h | 18 +++++-- 5 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 base/ctf/cicero/ciciface.h diff --git a/base/ctf/cicero/cicbase.h b/base/ctf/cicero/cicbase.h index 0ddf7c98e7d..e8ca93ff74c 100644 --- a/base/ctf/cicero/cicbase.h +++ b/base/ctf/cicero/cicbase.h @@ -2,11 +2,14 @@ * PROJECT: ReactOS Cicero * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Cicero base - * COPYRIGHT: Copyright 2023-2024 Katayama Hirofumi MZ + * COPYRIGHT: Copyright 2023-2026 Katayama Hirofumi MZ */ #pragma once +#include +#define cicAssert assert + static inline LPVOID cicMemAlloc(SIZE_T size) { return LocalAlloc(0, size); diff --git a/base/ctf/cicero/ciciface.h b/base/ctf/cicero/ciciface.h new file mode 100644 index 00000000000..57e9d854ea2 --- /dev/null +++ b/base/ctf/cicero/ciciface.h @@ -0,0 +1,59 @@ +/* + * PROJECT: ReactOS Cicero + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Cicero COM interface + * COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ + */ + +#pragma once + +#include "cicbase.h" + +template +class CicInterface_RefCnt +{ +protected: + T_IFACE* m_ptr; + +public: + CicInterface_RefCnt() : m_ptr(NULL) { } + + CicInterface_RefCnt(T_IFACE* ptr) : m_ptr(ptr) + { + if (m_ptr) + m_ptr->AddRef(); + } + + ~CicInterface_RefCnt() + { + if (m_ptr) + m_ptr->Release(); + } + + void Attach(T_IFACE* ptr) + { + if (m_ptr) + m_ptr->Release(); + m_ptr = ptr; + } + + T_IFACE* Detach() + { + T_IFACE* old_ptr = m_ptr; + m_ptr = NULL; + return old_ptr; + } + + operator T_IFACE*() { return m_ptr; } + T_IFACE* operator->() { return m_ptr; } + + T_IFACE** operator&() + { + cicAssert(!m_ptr); + return &m_ptr; + } + +private: + CicInterface_RefCnt(const CicInterface_RefCnt&) = delete; + CicInterface_RefCnt& operator=(const CicInterface_RefCnt&) = delete; +}; diff --git a/base/ctf/msctfime/msctfime.h b/base/ctf/msctfime/msctfime.h index 07ac3ca121e..c2d7bc7d2e0 100644 --- a/base/ctf/msctfime/msctfime.h +++ b/base/ctf/msctfime/msctfime.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/base/ctf/msctfime/profile.cpp b/base/ctf/msctfime/profile.cpp index fd43f67942d..70f783ce109 100644 --- a/base/ctf/msctfime/profile.cpp +++ b/base/ctf/msctfime/profile.cpp @@ -2,13 +2,67 @@ * PROJECT: ReactOS msctfime.ime * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Profile of msctfime.ime - * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ + * COPYRIGHT: Copyright 2024-2026 Katayama Hirofumi MZ */ #include "msctfime.h" WINE_DEFAULT_DEBUG_CHANNEL(msctfime); +// The callback function type +typedef HRESULT (CALLBACK *FN_LanguageProfilesCallback)(TF_LANGUAGEPROFILE profile, LPARAM lParam); + +/// @implemented +HRESULT +CicProfile::LanguageProfilesCallback( + _In_ TF_LANGUAGEPROFILE profile, + _Inout_opt_ LPARAM lParam) +{ + if (!profile.fActive || !memcmp(&profile.clsid, &GUID_NULL, sizeof(GUID_NULL))) + return S_FALSE; + PLANG_PROF_ENUM_ARG pArg = (PLANG_PROF_ENUM_ARG)lParam; + if (!pArg) + return S_OK; + if (memcmp(&profile.catid, &pArg->catid, sizeof(profile.catid)) != 0) + return S_FALSE; + pArg->profile = profile; + return S_OK; +} + +template +class CicEnumValue +{ + T_IFACE* m_iface; + FN_LanguageProfilesCallback m_callback; + LPARAM m_lParam; + +public: + CicEnumValue(T_IFACE* iface, FN_LanguageProfilesCallback callback, LPARAM lParam = 0) + : m_iface(iface) + , m_callback(callback) + , m_lParam(lParam) + { } + + DWORD DoEnum() + { + HRESULT hr; + T_DATA data; + + for (;;) + { + hr = m_iface->Next(1, &data, NULL); + if (hr != S_OK) + break; + + hr = m_callback(data, m_lParam); + if (hr == S_OK) + return ERROR_SUCCESS; + } + + return ERROR_FILE_NOT_FOUND; + } +}; + /// @implemented CicProfile::CicProfile() { @@ -162,19 +216,40 @@ CicProfile::InitProfileInstance(_Inout_ TLS *pTLS) return hr; } -/// @unimplemented +/// @implemented HRESULT CicProfile::GetActiveLanguageProfile( _In_ HKL hKL, - _In_ REFGUID rguid, - _Out_ TF_LANGUAGEPROFILE *pProfile) + _In_ REFGUID catid, + _Out_ TF_LANGUAGEPROFILE* pProfile) { - return E_NOTIMPL; + CicInterface_RefCnt pEnum; + HRESULT hr = m_pIPProfiles->EnumLanguageProfiles(LOWORD(hKL), &pEnum); + if (FAILED(hr)) + return S_FALSE; + + LANG_PROF_ENUM_ARG arg; + arg.catid = catid; + + CicEnumValue + enumValue(pEnum, LanguageProfilesCallback, (LPARAM)&arg); + DWORD ret = enumValue.DoEnum(); + if (ret != ERROR_SUCCESS || !pProfile) + return S_FALSE; + *pProfile = arg.profile; + return S_OK; } -/// The return value of CicProfile::IsIME is brain-damaged. -/// @unimplemented -BOOL CicProfile::IsIME(HKL hKL) +/// @implemented +HRESULT CicProfile::IsIME(HKL hKL) { - return TRUE; + CicInterface_RefCnt pEnum; + HRESULT hr = m_pIPProfiles->EnumLanguageProfiles(LOWORD(hKL), &pEnum); + if (FAILED(hr)) + return S_FALSE; + + CicEnumValue + enumValue(pEnum, LanguageProfilesCallback); + DWORD ret = enumValue.DoEnum(); + return (ret == ERROR_SUCCESS) ? S_OK : S_FALSE; } diff --git a/base/ctf/msctfime/profile.h b/base/ctf/msctfime/profile.h index 88c277c4b4d..fd88aff1398 100644 --- a/base/ctf/msctfime/profile.h +++ b/base/ctf/msctfime/profile.h @@ -2,7 +2,7 @@ * PROJECT: ReactOS msctfime.ime * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Profile of msctfime.ime - * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ + * COPYRIGHT: Copyright 2024-2026 Katayama Hirofumi MZ */ #pragma once @@ -12,6 +12,12 @@ class CicProfile : public IUnknown { protected: + typedef struct tagLANG_PROF_ENUM_ARG + { + GUID catid; + TF_LANGUAGEPROFILE profile; + } LANG_PROF_ENUM_ARG, *PLANG_PROF_ENUM_ARG; + ITfInputProcessorProfiles *m_pIPProfiles; CActiveLanguageProfileNotifySink *m_pActiveLanguageProfileNotifySink; LANGID m_LangID1; @@ -42,12 +48,16 @@ public: HRESULT GetActiveLanguageProfile( _In_ HKL hKL, - _In_ REFGUID rguid, - _Out_ TF_LANGUAGEPROFILE *pProfile); + _In_ REFGUID catid, + _Out_ TF_LANGUAGEPROFILE* pProfile); HRESULT GetLangId(_Out_ LANGID *pLangID); HRESULT GetCodePageA(_Out_ UINT *puCodePage); HRESULT InitProfileInstance(_Inout_ TLS *pTLS); + HRESULT IsIME(HKL hKL); - BOOL IsIME(HKL hKL); + static HRESULT CALLBACK + LanguageProfilesCallback( + _In_ TF_LANGUAGEPROFILE profile, + _Inout_opt_ LPARAM lParam); };