https://git.reactos.org/?p=reactos.git;a=commitdiff;h=b2ec78673d2f2fd8f4156…
commit b2ec78673d2f2fd8f41565fef070f40297e911da
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Feb 20 21:11:08 2024 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Feb 20 21:11:08 2024 +0900
[MSCTFIME] Restructuring (#6505)
Improve code flexibility. 3700+
lines of msctfime.cpp was too long.
JIRA issue: CORE-19360
- Split msctfime.cpp code to some
source files and header files.
---
dll/ime/msctfime/CMakeLists.txt | 10 +-
dll/ime/msctfime/bridge.cpp | 608 ++++++++
dll/ime/msctfime/bridge.h | 80 +
dll/ime/msctfime/compartment.cpp | 163 ++
dll/ime/msctfime/compartment.h | 44 +
dll/ime/msctfime/functions.cpp | 175 +++
dll/ime/msctfime/functions.h | 63 +
dll/ime/msctfime/inputcontext.cpp | 323 ++++
dll/ime/msctfime/inputcontext.h | 91 ++
dll/ime/msctfime/msctfime.cpp | 3003 ++-----------------------------------
dll/ime/msctfime/msctfime.h | 17 +
dll/ime/msctfime/profile.cpp | 173 +++
dll/ime/msctfime/profile.h | 51 +
dll/ime/msctfime/sinks.cpp | 539 +++++++
dll/ime/msctfime/sinks.h | 166 ++
dll/ime/msctfime/tls.cpp | 56 +
dll/ime/msctfime/tls.h | 74 +
dll/ime/msctfime/ui.cpp | 393 +++++
dll/ime/msctfime/ui.h | 68 +
19 files changed, 3177 insertions(+), 2920 deletions(-)
diff --git a/dll/ime/msctfime/CMakeLists.txt b/dll/ime/msctfime/CMakeLists.txt
index 5a034398964..288c14afc7f 100644
--- a/dll/ime/msctfime/CMakeLists.txt
+++ b/dll/ime/msctfime/CMakeLists.txt
@@ -5,7 +5,15 @@ include_directories(
spec2def(msctfime.ime msctfime.spec)
list(APPEND SOURCE
- msctfime.cpp)
+ bridge.cpp
+ compartment.cpp
+ functions.cpp
+ inputcontext.cpp
+ msctfime.cpp
+ profile.cpp
+ sinks.cpp
+ tls.cpp
+ ui.cpp)
file(GLOB msctfime_rc_deps res/*.*)
add_rc_deps(msctfime.rc ${msctfime_rc_deps})
diff --git a/dll/ime/msctfime/bridge.cpp b/dll/ime/msctfime/bridge.cpp
new file mode 100644
index 00000000000..de9e6ba10ef
--- /dev/null
+++ b/dll/ime/msctfime/bridge.cpp
@@ -0,0 +1,608 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Bridge
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "msctfime.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
+
+/// @implemented
+CicBridge::CicBridge()
+{
+ m_bImmxInited = FALSE;
+ m_bUnknown1 = FALSE;
+ m_bDeactivating = FALSE;
+ m_bUnknown2 = FALSE;
+ m_pKeystrokeMgr = NULL;
+ m_pDocMgr = NULL;
+ m_pThreadMgrEventSink = NULL;
+ m_cliendId = 0;
+ m_cRefs = 1;
+}
+
+/// @implemented
+STDMETHODIMP CicBridge::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ if (!IsEqualIID(riid, IID_ITfSysHookSink))
+ return E_NOINTERFACE;
+
+ *ppvObj = this;
+ AddRef();
+
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicBridge::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicBridge::Release()
+{
+ if (::InterlockedDecrement(&m_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRefs;
+}
+
+/// @implemented
+CicBridge::~CicBridge()
+{
+ TLS *pTLS = TLS::PeekTLS();
+ if (!pTLS || !pTLS->m_pThreadMgr)
+ return;
+
+ if (SUCCEEDED(DeactivateIMMX(pTLS, pTLS->m_pThreadMgr)))
+ UnInitIMMX(pTLS);
+}
+
+void CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>&
imeContext)
+{
+ CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+ if (pCicIC)
+ {
+ m_pDocMgr = pCicIC->m_pDocumentMgr;
+ m_pDocMgr->AddRef();
+ }
+ else
+ {
+ m_pDocMgr->Release();
+ m_pDocMgr = NULL;
+ }
+}
+
+/// @unimplemented
+HRESULT
+CicBridge::CreateInputContext(
+ _Inout_ TLS *pTLS,
+ _In_ HIMC hIMC)
+{
+ CicIMCLock imcLock(hIMC);
+ HRESULT hr = imcLock.m_hr;
+ if (!imcLock)
+ hr = E_FAIL;
+ if (FAILED(hr))
+ return hr;
+
+ if (!imcLock.get().hCtfImeContext)
+ {
+ HIMCC hCtfImeContext = ImmCreateIMCC(sizeof(CTFIMECONTEXT));
+ if (!hCtfImeContext)
+ return E_OUTOFMEMORY;
+ imcLock.get().hCtfImeContext = hCtfImeContext;
+ }
+
+ CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+ CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+ if (!pCicIC)
+ {
+ pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, hIMC);
+ if (!pCicIC)
+ {
+ imeContext.unlock();
+ imcLock.unlock();
+ DestroyInputContext(pTLS, hIMC);
+ return E_OUTOFMEMORY;
+ }
+
+ if (!pTLS->m_pThreadMgr)
+ {
+ pCicIC->Release();
+ imeContext.unlock();
+ imcLock.unlock();
+ DestroyInputContext(pTLS, hIMC);
+ return E_NOINTERFACE;
+ }
+
+ imeContext.get().m_pCicIC = pCicIC;
+ }
+
+ hr = pCicIC->CreateInputContext(pTLS->m_pThreadMgr, imcLock);
+ if (FAILED(hr))
+ {
+ pCicIC->Release();
+ imeContext.get().m_pCicIC = NULL;
+ }
+ else
+ {
+ if (imcLock.get().hWnd && imcLock.get().hWnd == ::GetFocus())
+ {
+ GetDocumentManager(imeContext);
+ //FIXME
+ }
+ }
+
+ return E_NOTIMPL;
+}
+
+/// @implemented
+HRESULT CicBridge::DestroyInputContext(TLS *pTLS, HIMC hIMC)
+{
+ CicIMCLock imcLock(hIMC);
+ HRESULT hr = imcLock.m_hr;
+ if (!imcLock)
+ hr = E_FAIL;
+ if (FAILED(hr))
+ return hr;
+
+ hr = E_FAIL;
+ CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+ if (imeContext)
+ hr = imeContext.m_hr;
+
+ if (SUCCEEDED(hr) && !(imeContext.get().m_dwCicFlags & 1))
+ {
+ imeContext.get().m_dwCicFlags |= 1;
+
+ CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+ if (pCicIC)
+ {
+ imeContext.get().m_pCicIC = NULL;
+ hr = pCicIC->DestroyInputContext();
+ pCicIC->Release();
+ imeContext.get().m_pCicIC = NULL;
+ }
+ }
+
+ if (imcLock.get().hCtfImeContext)
+ {
+ ImmDestroyIMCC(imcLock.get().hCtfImeContext);
+ imcLock.get().hCtfImeContext = NULL;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+ITfContext *
+CicBridge::GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext)
+{
+ CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+ if (!pCicIC)
+ return NULL;
+ return pCicIC->m_pContext;
+}
+
+/// @unimplemented
+HRESULT CicBridge::OnSetOpenStatus(
+ TLS *pTLS,
+ ITfThreadMgr_P *pThreadMgr,
+ CicIMCLock& imcLock,
+ CicInputContext *pCicIC)
+{
+ return E_NOTIMPL;
+}
+
+/// Selects the IME context.
+/// @implemented
+HRESULT
+CicBridge::SelectEx(
+ _Inout_ TLS *pTLS,
+ _Inout_ ITfThreadMgr_P *pThreadMgr,
+ _In_ HIMC hIMC,
+ _In_ BOOL fSelect,
+ _In_ HKL hKL)
+{
+ CicIMCLock imcLock(hIMC);
+ if (FAILED(imcLock.m_hr))
+ return imcLock.m_hr;
+
+ CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+ if (!imeContext)
+ imeContext.m_hr = E_FAIL;
+ if (FAILED(imeContext.m_hr))
+ return imeContext.m_hr;
+
+ CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+ if (pCicIC)
+ pCicIC->m_bSelecting = TRUE;
+
+ if (fSelect)
+ {
+ if (pCicIC)
+ pCicIC->m_dwUnknown6[1] &= ~1;
+ if (imcLock.get().fOpen)
+ OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC);
+ }
+ else
+ {
+ ITfContext *pContext = GetInputContext(imeContext);
+ pThreadMgr->RequestPostponedLock(pContext);
+ if (pCicIC)
+ pCicIC->m_bSelecting = FALSE;
+ if (pContext)
+ pContext->Release();
+ }
+
+ return imeContext.m_hr;
+}
+
+/// Used in CicBridge::EnumCreateInputContextCallback and
+/// CicBridge::EnumDestroyInputContextCallback.
+typedef struct ENUM_CREATE_DESTROY_IC
+{
+ TLS *m_pTLS;
+ CicBridge *m_pBridge;
+} ENUM_CREATE_DESTROY_IC, *PENUM_CREATE_DESTROY_IC;
+
+/// Creates input context for the current thread.
+/// @implemented
+BOOL CALLBACK CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam)
+{
+ PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
+ pData->m_pBridge->CreateInputContext(pData->m_pTLS, hIMC);
+ return TRUE;
+}
+
+/// Destroys input context for the current thread.
+/// @implemented
+BOOL CALLBACK CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam)
+{
+ PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
+ pData->m_pBridge->DestroyInputContext(pData->m_pTLS, hIMC);
+ return TRUE;
+}
+
+/// @implemented
+HRESULT
+CicBridge::ActivateIMMX(
+ _Inout_ TLS *pTLS,
+ _Inout_ ITfThreadMgr_P *pThreadMgr)
+{
+ HRESULT hr = pThreadMgr->ActivateEx(&m_cliendId, 1);
+ if (hr != S_OK)
+ {
+ m_cliendId = 0;
+ return E_FAIL;
+ }
+
+ if (m_cActivateLocks++ != 0)
+ return S_OK;
+
+ ITfSourceSingle *pSource = NULL;
+ hr = pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void**)&pSource);
+ if (FAILED(hr))
+ {
+ DeactivateIMMX(pTLS, pThreadMgr);
+ return hr;
+ }
+
+ CFunctionProvider *pProvider = new(cicNoThrow) CFunctionProvider(m_cliendId);
+ if (!pProvider)
+ {
+ hr = E_FAIL;
+ goto Finish;
+ }
+
+ pSource->AdviseSingleSink(m_cliendId, IID_ITfFunctionProvider, pProvider);
+ pProvider->Release();
+
+ if (!m_pDocMgr)
+ {
+ hr = pThreadMgr->CreateDocumentMgr(&m_pDocMgr);
+ if (FAILED(hr))
+ {
+ hr = E_FAIL;
+ goto Finish;
+ }
+
+ SetCompartmentDWORD(m_cliendId, m_pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS,
TRUE, FALSE);
+ }
+
+ pThreadMgr->SetSysHookSink(this);
+
+ hr = S_OK;
+ if (pTLS->m_bDestroyed)
+ {
+ ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
+ ImmEnumInputContext(0, CicBridge::EnumCreateInputContextCallback,
(LPARAM)&Data);
+ }
+
+Finish:
+ if (FAILED(hr))
+ DeactivateIMMX(pTLS, pThreadMgr);
+ if (pSource)
+ pSource->Release();
+ return hr;
+}
+
+/// @implemented
+HRESULT
+CicBridge::DeactivateIMMX(
+ _Inout_ TLS *pTLS,
+ _Inout_ ITfThreadMgr_P *pThreadMgr)
+{
+ if (m_bDeactivating)
+ return TRUE;
+
+ m_bDeactivating = TRUE;
+
+ if (m_cliendId)
+ {
+ ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
+ ImmEnumInputContext(0, CicBridge::EnumDestroyInputContextCallback,
(LPARAM)&Data);
+ pTLS->m_bDestroyed = TRUE;
+
+ ITfSourceSingle *pSource = NULL;
+ if (pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void **)&pSource) ==
S_OK)
+ pSource->UnadviseSingleSink(m_cliendId, IID_ITfFunctionProvider);
+
+ m_cliendId = 0;
+
+ while (m_cActivateLocks > 0)
+ {
+ --m_cActivateLocks;
+ pThreadMgr->Deactivate();
+ }
+
+ if (pSource)
+ pSource->Release();
+ }
+
+ if (m_pDocMgr)
+ {
+ m_pDocMgr->Release();
+ m_pDocMgr = NULL;
+ }
+
+ pThreadMgr->SetSysHookSink(NULL);
+
+ m_bDeactivating = FALSE;
+
+ return S_OK;
+}
+
+/// @implemented
+HRESULT
+CicBridge::InitIMMX(_Inout_ TLS *pTLS)
+{
+ if (m_bImmxInited)
+ return S_OK;
+
+ HRESULT hr = S_OK;
+ if (!pTLS->m_pThreadMgr)
+ {
+ ITfThreadMgr *pThreadMgr = NULL;
+ hr = TF_CreateThreadMgr(&pThreadMgr);
+ if (FAILED(hr))
+ return E_FAIL;
+
+ hr = pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void
**)&pTLS->m_pThreadMgr);
+ if (pThreadMgr)
+ pThreadMgr->Release();
+ if (FAILED(hr))
+ return E_FAIL;
+ }
+
+ if (!m_pThreadMgrEventSink)
+ {
+ m_pThreadMgrEventSink =
+ new(cicNoThrow) CThreadMgrEventSink(CThreadMgrEventSink::DIMCallback, NULL,
NULL);
+ if (!m_pThreadMgrEventSink)
+ {
+ UnInitIMMX(pTLS);
+ return E_FAIL;
+ }
+ }
+
+ m_pThreadMgrEventSink->SetCallbackPV(m_pThreadMgrEventSink);
+ m_pThreadMgrEventSink->_Advise(pTLS->m_pThreadMgr);
+
+ if (!pTLS->m_pProfile)
+ {
+ pTLS->m_pProfile = new(cicNoThrow) CicProfile();
+ if (!pTLS->m_pProfile)
+ return E_OUTOFMEMORY;
+
+ hr = pTLS->m_pProfile->InitProfileInstance(pTLS);
+ if (FAILED(hr))
+ {
+ UnInitIMMX(pTLS);
+ return E_FAIL;
+ }
+ }
+
+ hr = pTLS->m_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr_P, (void
**)&m_pKeystrokeMgr);
+ if (FAILED(hr))
+ {
+ UnInitIMMX(pTLS);
+ return E_FAIL;
+ }
+
+ hr = InitDisplayAttrbuteLib(&m_LibThread);
+ if (FAILED(hr))
+ {
+ UnInitIMMX(pTLS);
+ return E_FAIL;
+ }
+
+ m_bImmxInited = TRUE;
+ return S_OK;
+}
+
+/// @implemented
+BOOL CicBridge::UnInitIMMX(_Inout_ TLS *pTLS)
+{
+ UninitDisplayAttrbuteLib(&m_LibThread);
+ TFUninitLib_Thread(&m_LibThread);
+
+ if (m_pKeystrokeMgr)
+ {
+ m_pKeystrokeMgr->Release();
+ m_pKeystrokeMgr = NULL;
+ }
+
+ if (pTLS->m_pProfile)
+ {
+ pTLS->m_pProfile->Release();
+ pTLS->m_pProfile = NULL;
+ }
+
+ if (m_pThreadMgrEventSink)
+ {
+ m_pThreadMgrEventSink->_Unadvise();
+ m_pThreadMgrEventSink->Release();
+ m_pThreadMgrEventSink = NULL;
+ }
+
+ if (pTLS->m_pThreadMgr)
+ {
+ pTLS->m_pThreadMgr->Release();
+ pTLS->m_pThreadMgr = NULL;
+ }
+
+ m_bImmxInited = FALSE;
+ return TRUE;
+}
+
+/// @implemented
+STDMETHODIMP CicBridge::OnPreFocusDIM(HWND hwnd)
+{
+ return S_OK;
+}
+
+/// @unimplemented
+STDMETHODIMP CicBridge::OnSysKeyboardProc(UINT, LONG)
+{
+ return E_NOTIMPL;
+}
+
+/// @implemented
+STDMETHODIMP CicBridge::OnSysShellProc(INT, UINT, LONG)
+{
+ return S_OK;
+}
+
+/// @implemented
+void
+CicBridge::PostTransMsg(
+ _In_ HWND hWnd,
+ _In_ INT cTransMsgs,
+ _In_ const TRANSMSG *pTransMsgs)
+{
+ for (INT i = 0; i < cTransMsgs; ++i, ++pTransMsgs)
+ {
+ ::PostMessageW(hWnd, pTransMsgs->message, pTransMsgs->wParam,
pTransMsgs->lParam);
+ }
+}
+
+/// @implemented
+HRESULT
+CicBridge::ConfigureGeneral(
+ _Inout_ TLS* pTLS,
+ _In_ ITfThreadMgr *pThreadMgr,
+ _In_ HKL hKL,
+ _In_ HWND hWnd)
+{
+ CicProfile *pProfile = pTLS->m_pProfile;
+ if (!pProfile)
+ return E_OUTOFMEMORY;
+
+ TF_LANGUAGEPROFILE profile;
+ HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD,
&profile);
+ if (FAILED(hr))
+ return hr;
+
+ ITfFunctionProvider *pProvider = NULL;
+ hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
+ if (FAILED(hr))
+ return hr;
+
+ ITfFnConfigure *pFnConfigure = NULL;
+ hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigure,
(IUnknown**)&pFnConfigure);
+ if (FAILED(hr))
+ {
+ pProvider->Release();
+ return hr;
+ }
+
+ hr = pFnConfigure->Show(hWnd, profile.langid, profile.guidProfile);
+
+ pFnConfigure->Release();
+ pProvider->Release();
+ return hr;
+}
+
+/// @implemented
+HRESULT
+CicBridge::ConfigureRegisterWord(
+ _Inout_ TLS* pTLS,
+ _In_ ITfThreadMgr *pThreadMgr,
+ _In_ HKL hKL,
+ _In_ HWND hWnd,
+ _Inout_opt_ LPVOID lpData)
+{
+ CicProfile *pProfile = pTLS->m_pProfile;
+ if (!pProfile)
+ return E_OUTOFMEMORY;
+
+ TF_LANGUAGEPROFILE profile;
+ HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD,
&profile);
+ if (FAILED(hr))
+ return hr;
+
+ ITfFunctionProvider *pProvider = NULL;
+ hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
+ if (FAILED(hr))
+ return hr;
+
+ ITfFnConfigureRegisterWord *pFunction = NULL;
+ hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigureRegisterWord,
(IUnknown**)&pFunction);
+ if (FAILED(hr))
+ {
+ pProvider->Release();
+ return hr;
+ }
+
+ REGISTERWORDW* pRegWord = (REGISTERWORDW*)lpData;
+ if (pRegWord)
+ {
+ if (pRegWord->lpWord)
+ {
+ hr = E_OUTOFMEMORY;
+ BSTR bstrWord = SysAllocString(pRegWord->lpWord);
+ if (bstrWord)
+ {
+ hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile,
bstrWord);
+ SysFreeString(bstrWord);
+ }
+ }
+ else
+ {
+ hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, NULL);
+ }
+ }
+
+ pProvider->Release();
+ pFunction->Release();
+ return hr;
+}
diff --git a/dll/ime/msctfime/bridge.h b/dll/ime/msctfime/bridge.h
new file mode 100644
index 00000000000..c8b8441203d
--- /dev/null
+++ b/dll/ime/msctfime/bridge.h
@@ -0,0 +1,80 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Bridge
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#pragma once
+
+#include "sinks.h"
+#include "tls.h"
+
+class CicBridge : public ITfSysHookSink
+{
+protected:
+ LONG m_cRefs;
+ BOOL m_bImmxInited;
+ BOOL m_bUnknown1;
+ BOOL m_bDeactivating;
+ DWORD m_cActivateLocks;
+ ITfKeystrokeMgr *m_pKeystrokeMgr;
+ ITfDocumentMgr *m_pDocMgr;
+ CThreadMgrEventSink *m_pThreadMgrEventSink;
+ TfClientId m_cliendId;
+ CIC_LIBTHREAD m_LibThread;
+ BOOL m_bUnknown2;
+
+ static BOOL CALLBACK EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam);
+ static BOOL CALLBACK EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam);
+
+public:
+ CicBridge();
+ virtual ~CicBridge();
+
+ // IUnknown interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // ITfSysHookSink interface
+ STDMETHODIMP OnPreFocusDIM(HWND hwnd) override;
+ STDMETHODIMP OnSysKeyboardProc(UINT, LONG) override;
+ STDMETHODIMP OnSysShellProc(INT, UINT, LONG) override;
+
+ HRESULT InitIMMX(_Inout_ TLS *pTLS);
+ BOOL UnInitIMMX(_Inout_ TLS *pTLS);
+ HRESULT ActivateIMMX(_Inout_ TLS *pTLS, _Inout_ ITfThreadMgr_P *pThreadMgr);
+ HRESULT DeactivateIMMX(_Inout_ TLS *pTLS, _Inout_ ITfThreadMgr_P *pThreadMgr);
+
+ HRESULT CreateInputContext(TLS *pTLS, HIMC hIMC);
+ HRESULT DestroyInputContext(TLS *pTLS, HIMC hIMC);
+ ITfContext *GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext);
+
+ HRESULT SelectEx(
+ _Inout_ TLS *pTLS,
+ _Inout_ ITfThreadMgr_P *pThreadMgr,
+ _In_ HIMC hIMC,
+ _In_ BOOL fSelect,
+ _In_ HKL hKL);
+ HRESULT OnSetOpenStatus(
+ TLS *pTLS,
+ ITfThreadMgr_P *pThreadMgr,
+ CicIMCLock& imcLock,
+ CicInputContext *pCicIC);
+
+ void PostTransMsg(_In_ HWND hWnd, _In_ INT cTransMsgs, _In_ const TRANSMSG
*pTransMsgs);
+ void GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext);
+
+ HRESULT
+ ConfigureGeneral(_Inout_ TLS* pTLS,
+ _In_ ITfThreadMgr *pThreadMgr,
+ _In_ HKL hKL,
+ _In_ HWND hWnd);
+ HRESULT ConfigureRegisterWord(
+ _Inout_ TLS* pTLS,
+ _In_ ITfThreadMgr *pThreadMgr,
+ _In_ HKL hKL,
+ _In_ HWND hWnd,
+ _Inout_opt_ LPVOID lpData);
+};
diff --git a/dll/ime/msctfime/compartment.cpp b/dll/ime/msctfime/compartment.cpp
new file mode 100644
index 00000000000..d92b1b526f4
--- /dev/null
+++ b/dll/ime/msctfime/compartment.cpp
@@ -0,0 +1,163 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Supporting compartments
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "msctfime.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
+
+/// @implemented
+HRESULT
+GetCompartment(
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ ITfCompartment **ppComp,
+ BOOL bThread)
+{
+ *ppComp = NULL;
+
+ ITfThreadMgr *pThreadMgr = NULL;
+ ITfCompartmentMgr *pCompMgr = NULL;
+
+ HRESULT hr;
+ if (bThread)
+ {
+ hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr);
+ if (FAILED(hr))
+ return hr;
+
+ hr = pThreadMgr->GetGlobalCompartment(&pCompMgr);
+ }
+ else
+ {
+ hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = E_FAIL;
+ if (pCompMgr)
+ {
+ hr = pCompMgr->GetCompartment(rguid, ppComp);
+ pCompMgr->Release();
+ }
+ }
+
+ if (pThreadMgr)
+ pThreadMgr->Release();
+
+ return hr;
+}
+
+/// @implemented
+HRESULT
+SetCompartmentDWORD(
+ TfEditCookie cookie,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ DWORD dwValue,
+ BOOL bThread)
+{
+ ITfCompartment *pComp = NULL;
+ HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread);
+ if (FAILED(hr))
+ return hr;
+
+ VARIANT vari;
+ V_I4(&vari) = dwValue;
+ V_VT(&vari) = VT_I4;
+ hr = pComp->SetValue(cookie, &vari);
+
+ pComp->Release();
+ return hr;
+}
+
+/// @implemented
+HRESULT
+GetCompartmentDWORD(
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ LPDWORD pdwValue,
+ BOOL bThread)
+{
+ *pdwValue = 0;
+
+ ITfCompartment *pComp = NULL;
+ HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread);
+ if (FAILED(hr))
+ return hr;
+
+ VARIANT vari;
+ hr = pComp->GetValue(&vari);
+ if (hr == S_OK)
+ *pdwValue = V_I4(&vari);
+
+ pComp->Release();
+ return hr;
+}
+
+/// @implemented
+HRESULT
+SetCompartmentUnknown(
+ TfEditCookie cookie,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ IUnknown *punkValue)
+{
+ ITfCompartment *pComp = NULL;
+ HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, FALSE);
+ if (FAILED(hr))
+ return hr;
+
+ VARIANT vari;
+ V_UNKNOWN(&vari) = punkValue;
+ V_VT(&vari) = VT_UNKNOWN;
+ hr = pComp->SetValue(cookie, &vari);
+
+ pComp->Release();
+ return hr;
+}
+
+/// @implemented
+HRESULT
+ClearCompartment(
+ TfClientId tid,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ BOOL bThread)
+{
+ ITfCompartmentMgr *pCompMgr = NULL;
+ ITfThreadMgr *pThreadMgr = NULL;
+
+ HRESULT hr;
+ if (bThread)
+ {
+ hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr);
+ if (FAILED(hr))
+ return hr;
+
+ hr = pThreadMgr->GetGlobalCompartment(&pCompMgr);
+ }
+ else
+ {
+ hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = E_FAIL;
+ if (pCompMgr)
+ {
+ hr = pCompMgr->ClearCompartment(tid, rguid);
+ pCompMgr->Release();
+ }
+ }
+
+ if (pThreadMgr)
+ pThreadMgr->Release();
+
+ return hr;
+}
diff --git a/dll/ime/msctfime/compartment.h b/dll/ime/msctfime/compartment.h
new file mode 100644
index 00000000000..88805566832
--- /dev/null
+++ b/dll/ime/msctfime/compartment.h
@@ -0,0 +1,44 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Supporting compartments
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#pragma once
+
+HRESULT
+GetCompartment(
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ ITfCompartment **ppComp,
+ BOOL bThread);
+
+HRESULT
+SetCompartmentDWORD(
+ TfEditCookie cookie,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ DWORD dwValue,
+ BOOL bThread);
+
+HRESULT
+GetCompartmentDWORD(
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ LPDWORD pdwValue,
+ BOOL bThread);
+
+HRESULT
+SetCompartmentUnknown(
+ TfEditCookie cookie,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ IUnknown *punkValue);
+
+HRESULT
+ClearCompartment(
+ TfClientId tid,
+ IUnknown *pUnknown,
+ REFGUID rguid,
+ BOOL bThread);
diff --git a/dll/ime/msctfime/functions.cpp b/dll/ime/msctfime/functions.cpp
new file mode 100644
index 00000000000..c9832f90cff
--- /dev/null
+++ b/dll/ime/msctfime/functions.cpp
@@ -0,0 +1,175 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: The functions of msctfime.ime
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "msctfime.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
+
+/// @implemented
+CFunctionProviderBase::CFunctionProviderBase(_In_ TfClientId clientId)
+{
+ m_clientId = clientId;
+ m_guid = GUID_NULL;
+ m_bstr = NULL;
+ m_cRefs = 1;
+}
+
+/// @implemented
+CFunctionProviderBase::~CFunctionProviderBase()
+{
+ if (!DllShutdownInProgress())
+ ::SysFreeString(m_bstr);
+}
+
+/// @implemented
+BOOL
+CFunctionProviderBase::Init(
+ _In_ REFGUID rguid,
+ _In_ LPCWSTR psz)
+{
+ m_bstr = ::SysAllocString(psz);
+ m_guid = rguid;
+ return (m_bstr != NULL);
+}
+
+/// @implemented
+STDMETHODIMP
+CFunctionProviderBase::QueryInterface(
+ _In_ REFIID riid,
+ _Out_ LPVOID* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfFunctionProvider))
+ {
+ *ppvObj = this;
+ AddRef();
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFunctionProviderBase::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFunctionProviderBase::Release()
+{
+ if (::InterlockedDecrement(&m_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRefs;
+}
+
+/// @implemented
+STDMETHODIMP CFunctionProviderBase::GetType(_Out_ GUID *guid)
+{
+ *guid = m_guid;
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP CFunctionProviderBase::GetDescription(_Out_ BSTR *desc)
+{
+ *desc = ::SysAllocString(m_bstr);
+ return (*desc ? S_OK : E_OUTOFMEMORY);
+}
+
+/***********************************************************************/
+
+/// @implemented
+CFunctionProvider::CFunctionProvider(_In_ TfClientId clientId) :
CFunctionProviderBase(clientId)
+{
+ Init(CLSID_CAImmLayer, L"MSCTFIME::Function Provider");
+}
+
+/// @implemented
+STDMETHODIMP
+CFunctionProvider::GetFunction(
+ _In_ REFGUID guid,
+ _In_ REFIID riid,
+ _Out_ IUnknown **func)
+{
+ *func = NULL;
+
+ if (IsEqualGUID(guid, GUID_NULL) &&
+ IsEqualIID(riid, IID_IAImmFnDocFeed))
+ {
+ *func = new(cicNoThrow) CFnDocFeed();
+ if (*func)
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+/***********************************************************************/
+
+CFnDocFeed::CFnDocFeed()
+{
+ m_cRefs = 1;
+}
+
+CFnDocFeed::~CFnDocFeed()
+{
+}
+
+/// @implemented
+STDMETHODIMP CFnDocFeed::QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAImmFnDocFeed))
+ {
+ *ppvObj = this;
+ AddRef();
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFnDocFeed::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFnDocFeed::Release()
+{
+ if (::InterlockedDecrement(&m_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRefs;
+}
+
+/// @unimplemented
+STDMETHODIMP CFnDocFeed::DocFeed()
+{
+ return E_NOTIMPL;
+}
+
+/// @unimplemented
+STDMETHODIMP CFnDocFeed::ClearDocFeedBuffer()
+{
+ return E_NOTIMPL;
+}
+
+/// @unimplemented
+STDMETHODIMP CFnDocFeed::StartReconvert()
+{
+ return E_NOTIMPL;
+}
+
+/// @unimplemented
+STDMETHODIMP CFnDocFeed::StartUndoCompositionString()
+{
+ return E_NOTIMPL;
+}
diff --git a/dll/ime/msctfime/functions.h b/dll/ime/msctfime/functions.h
new file mode 100644
index 00000000000..6938162a6e5
--- /dev/null
+++ b/dll/ime/msctfime/functions.h
@@ -0,0 +1,63 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: The functions of msctfime.ime
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+class CFunctionProviderBase : public ITfFunctionProvider
+{
+protected:
+ TfClientId m_clientId;
+ GUID m_guid;
+ BSTR m_bstr;
+ LONG m_cRefs;
+
+public:
+ CFunctionProviderBase(_In_ TfClientId clientId);
+ virtual ~CFunctionProviderBase();
+
+ // IUnknown interface
+ STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // ITfFunctionProvider interface
+ STDMETHODIMP GetType(_Out_ GUID *guid) override;
+ STDMETHODIMP GetDescription(_Out_ BSTR *desc) override;
+ //STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ IUnknown
**func) = 0;
+
+ BOOL Init(_In_ REFGUID rguid, _In_ LPCWSTR psz);
+};
+
+/***********************************************************************/
+
+class CFunctionProvider : public CFunctionProviderBase
+{
+public:
+ CFunctionProvider(_In_ TfClientId clientId);
+
+ STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ IUnknown **func)
override;
+};
+
+/***********************************************************************/
+
+class CFnDocFeed : public IAImmFnDocFeed
+{
+ LONG m_cRefs;
+
+public:
+ CFnDocFeed();
+ virtual ~CFnDocFeed();
+
+ // IUnknown interface
+ STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // IAImmFnDocFeed interface
+ STDMETHODIMP DocFeed() override;
+ STDMETHODIMP ClearDocFeedBuffer() override;
+ STDMETHODIMP StartReconvert() override;
+ STDMETHODIMP StartUndoCompositionString() override;
+};
diff --git a/dll/ime/msctfime/inputcontext.cpp b/dll/ime/msctfime/inputcontext.cpp
new file mode 100644
index 00000000000..1bdf64cb62e
--- /dev/null
+++ b/dll/ime/msctfime/inputcontext.cpp
@@ -0,0 +1,323 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Input Context of msctfime.ime
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "msctfime.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
+
+/// @unimplemented
+CicInputContext::CicInputContext(
+ _In_ TfClientId cliendId,
+ _Inout_ PCIC_LIBTHREAD pLibThread,
+ _In_ HIMC hIMC)
+{
+ m_hIMC = hIMC;
+ m_guid = GUID_NULL;
+ m_dwQueryPos = 0;
+ m_cRefs = 1;
+}
+
+/// @implemented
+STDMETHODIMP CicInputContext::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ if (IsEqualIID(riid, IID_ITfContextOwnerCompositionSink))
+ {
+ *ppvObj = static_cast<ITfContextOwnerCompositionSink*>(this);
+ AddRef();
+ return S_OK;
+ }
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCleanupContextSink))
+ {
+ *ppvObj = this;
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicInputContext::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicInputContext::Release()
+{
+ if (::InterlockedDecrement(&m_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRefs;
+}
+
+/// @implemented
+STDMETHODIMP
+CicInputContext::OnStartComposition(
+ ITfCompositionView *pComposition,
+ BOOL *pfOk)
+{
+ if ((m_cCompLocks <= 0) || m_dwUnknown6_5)
+ {
+ *pfOk = TRUE;
+ ++m_cCompLocks;
+ }
+ else
+ {
+ *pfOk = FALSE;
+ }
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP
+CicInputContext::OnUpdateComposition(
+ ITfCompositionView *pComposition,
+ ITfRange *pRangeNew)
+{
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP
+CicInputContext::OnEndComposition(
+ ITfCompositionView *pComposition)
+{
+ --m_cCompLocks;
+ return S_OK;
+}
+
+/// @implemented
+HRESULT
+CicInputContext::GetGuidAtom(
+ _Inout_ CicIMCLock& imcLock,
+ _In_ BYTE iAtom,
+ _Out_opt_ LPDWORD pdwGuidAtom)
+{
+ CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCompStr);
+ HRESULT hr = imeContext.m_hr;
+ if (!imeContext)
+ hr = E_FAIL;
+ if (FAILED(hr))
+ return hr;
+
+ hr = E_FAIL;
+ if (iAtom < m_cGuidAtoms)
+ {
+ *pdwGuidAtom = m_adwGuidAtoms[iAtom];
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+/// @unimplemented
+HRESULT
+CicInputContext::CreateInputContext(
+ _Inout_ ITfThreadMgr *pThreadMgr,
+ _Inout_ CicIMCLock& imcLock)
+{
+ //FIXME
+ return E_NOTIMPL;
+}
+
+/// @unimplemented
+HRESULT
+CicInputContext::DestroyInputContext()
+{
+ ITfSourceSingle *pSource = NULL;
+
+ if (m_pContext && m_pContext->QueryInterface(IID_ITfSourceSingle, (void
**)&pSource) == S_OK)
+ pSource->UnadviseSingleSink(m_clientId, IID_ITfCleanupContextSink);
+
+ //FIXME: m_dwUnknown5
+
+ if (m_pTextEventSink)
+ {
+ m_pTextEventSink->_Unadvise();
+ m_pTextEventSink->Release();
+ m_pTextEventSink = NULL;
+ }
+
+ if (m_pCompEventSink2)
+ {
+ m_pCompEventSink2->_Unadvise();
+ m_pCompEventSink2->Release();
+ m_pCompEventSink2 = NULL;
+ }
+
+ if (m_pCompEventSink1)
+ {
+ m_pCompEventSink1->_Unadvise();
+ m_pCompEventSink1->Release();
+ m_pCompEventSink1 = NULL;
+ }
+
+ //FIXME: m_pInputContextOwner
+
+ if (m_pDocumentMgr)
+ m_pDocumentMgr->Pop(1);
+
+ if (m_pContext)
+ {
+ ClearCompartment(m_clientId, m_pContext, GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT,
0);
+ m_pContext->Release();
+ m_pContext = NULL;
+ }
+
+ if (m_pContextOwnerServices)
+ {
+ m_pContextOwnerServices->Release();
+ m_pContextOwnerServices = NULL;
+ }
+
+ // FIXME: m_pICOwnerCallback
+
+ if (m_pDocumentMgr)
+ {
+ m_pDocumentMgr->Release();
+ m_pDocumentMgr = NULL;
+ }
+
+ if (pSource)
+ pSource->Release();
+
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP
+CicInputContext::OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition
*pComposition)
+{
+ return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP
+CicInputContext::OnCleanupContext(
+ _In_ TfEditCookie ecWrite,
+ _Inout_ ITfContext *pic)
+{
+ TLS *pTLS = TLS::PeekTLS();
+ if (!pTLS || !pTLS->m_pProfile)
+ return E_OUTOFMEMORY;
+
+ LANGID LangID;
+ pTLS->m_pProfile->GetLangId(&LangID);
+
+ IMEINFO IMEInfo;
+ WCHAR szPath[MAX_PATH];
+ if (Inquire(&IMEInfo, szPath, 0, (HKL)UlongToHandle(LangID)) != S_OK)
+ return E_FAIL;
+
+ ITfProperty *pProp = NULL;
+ if (!(IMEInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT))
+ return S_OK;
+
+ HRESULT hr = pic->GetProperty(GUID_PROP_COMPOSING, &pProp);
+ if (FAILED(hr))
+ return S_OK;
+
+ IEnumTfRanges *pRanges = NULL;
+ hr = pProp->EnumRanges(ecWrite, &pRanges, NULL);
+ if (SUCCEEDED(hr))
+ {
+ ITfRange *pRange = NULL;
+ while (pRanges->Next(1, &pRange, 0) == S_OK)
+ {
+ VARIANT vari;
+ V_VT(&vari) = VT_EMPTY;
+ pProp->GetValue(ecWrite, pRange, &vari);
+ if (V_VT(&vari) == VT_I4)
+ {
+ if (V_I4(&vari))
+ pProp->Clear(ecWrite, pRange);
+ }
+ pRange->Release();
+ pRange = NULL;
+ }
+ pRanges->Release();
+ }
+ pProp->Release();
+
+ return S_OK;
+}
+
+/// Retrieves the IME information.
+/// @implemented
+HRESULT
+Inquire(
+ _Out_ LPIMEINFO lpIMEInfo,
+ _Out_ LPWSTR lpszWndClass,
+ _In_ DWORD dwSystemInfoFlags,
+ _In_ HKL hKL)
+{
+ if (!lpIMEInfo)
+ return E_OUTOFMEMORY;
+
+ StringCchCopyW(lpszWndClass, 64, L"MSCTFIME UI");
+ lpIMEInfo->dwPrivateDataSize = 0;
+
+ switch (LOWORD(hKL)) // Language ID
+ {
+ case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): // Japanese
+ {
+ lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT |
IME_PROP_SPECIAL_UI |
+ IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
+ IME_PROP_KBD_CHAR_FIRST;
+ lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA |
+ IME_CMODE_NATIVE;
+ lpIMEInfo->fdwSentenceCaps = IME_SMODE_CONVERSATION |
IME_SMODE_PLAURALCLAUSE;
+ lpIMEInfo->fdwSelectCaps = SELECT_CAP_SENTENCE | SELECT_CAP_CONVERSION;
+ lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
+ SCS_CAP_COMPSTR;
+ lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
+ break;
+ }
+ case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT): // Korean
+ {
+ lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT |
IME_PROP_SPECIAL_UI |
+ IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
+ IME_PROP_KBD_CHAR_FIRST;
+ lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
+ lpIMEInfo->fdwSentenceCaps = 0;
+ lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_COMPSTR;
+ lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
+ lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
+ break;
+ }
+ case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): // Simplified Chinese
+ case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): // Traditional
Chinese
+ {
+ lpIMEInfo->fdwProperty = IME_PROP_SPECIAL_UI | IME_PROP_AT_CARET |
+ IME_PROP_NEED_ALTKEY | IME_PROP_KBD_CHAR_FIRST;
+ lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
+ lpIMEInfo->fdwSentenceCaps = SELECT_CAP_CONVERSION;
+ lpIMEInfo->fdwSelectCaps = 0;
+ lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
+ SCS_CAP_COMPSTR;
+ lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
+ break;
+ }
+ default: // Otherwise
+ {
+ lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
+ lpIMEInfo->fdwConversionCaps = 0;
+ lpIMEInfo->fdwSentenceCaps = 0;
+ lpIMEInfo->fdwSCSCaps = 0;
+ lpIMEInfo->fdwUICaps = 0;
+ lpIMEInfo->fdwSelectCaps = 0;
+ break;
+ }
+ }
+
+ return S_OK;
+}
diff --git a/dll/ime/msctfime/inputcontext.h b/dll/ime/msctfime/inputcontext.h
new file mode 100644
index 00000000000..2273161926e
--- /dev/null
+++ b/dll/ime/msctfime/inputcontext.h
@@ -0,0 +1,91 @@
+/*
+ * PROJECT: ReactOS msctfime.ime
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Input Context of msctfime.ime
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#pragma once
+
+#include "sinks.h"
+
+class CInputContextOwnerCallBack;
+class CInputContextOwner;
+
+HRESULT
+Inquire(
+ _Out_ LPIMEINFO lpIMEInfo,
+ _Out_ LPWSTR lpszWndClass,
+ _In_ DWORD dwSystemInfoFlags,
+ _In_ HKL hKL);
+
+/***********************************************************************
+ * CicInputContext
+ *
+ * The msctfime.ime's input context.
+ */
+class CicInputContext
+ : public ITfCleanupContextSink
+ , public ITfContextOwnerCompositionSink
+ , public ITfCompositionSink
+{
+public:
+ LONG m_cRefs;
+ HIMC m_hIMC;
+ ITfDocumentMgr *m_pDocumentMgr;
+ ITfContext *m_pContext;
+ ITfContextOwnerServices *m_pContextOwnerServices;
+ CInputContextOwnerCallBack *m_pICOwnerCallback;
+ CTextEventSink *m_pTextEventSink;
+ CCompartmentEventSink *m_pCompEventSink1;
+ CCompartmentEventSink *m_pCompEventSink2;
+ CInputContextOwner *m_pInputContextOwner;
+ DWORD m_dwUnknown3[3];
+ DWORD m_dwUnknown4[2];
+ DWORD m_dwQueryPos;
+ DWORD m_dwUnknown5;
+ GUID m_guid;
+ DWORD m_dwUnknown6[11];
+ BOOL m_bSelecting;
+ DWORD m_dwUnknown6_5;
+ LONG m_cCompLocks;
+ DWORD m_dwUnknown7[5];
+ WORD m_cGuidAtoms;
+ WORD m_padding;
+ DWORD m_adwGuidAtoms[256];
+ DWORD m_dwUnknown8[17];
+ TfClientId m_clientId;
+ DWORD m_dwUnknown9;
+
+public:
+ CicInputContext(
+ _In_ TfClientId cliendId,
+ _Inout_ PCIC_LIBTHREAD pLibThread,
+ _In_ HIMC hIMC);
+ virtual ~CicInputContext() { }
+
+ // IUnknown interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // ITfCleanupContextSink interface
+ STDMETHODIMP OnCleanupContext(_In_ TfEditCookie ecWrite, _Inout_ ITfContext *pic)
override;
+
+ // ITfContextOwnerCompositionSink interface
+ STDMETHODIMP OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk)
override;
+ STDMETHODIMP OnUpdateComposition(ITfCompositionView *pComposition, ITfRange
*pRangeNew) override;
+ STDMETHODIMP OnEndComposition(ITfCompositionView *pComposition) override;
+
+ // ITfCompositionSink interface
+ STDMETHODIMP OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition
*pComposition) override;
+
+ HRESULT
+ GetGuidAtom(
+ _Inout_ CicIMCLock& imcLock,
+ _In_ BYTE iAtom,
+ _Out_opt_ LPDWORD pdwGuidAtom);
+
+ HRESULT CreateInputContext(_Inout_ ITfThreadMgr *pThreadMgr, _Inout_ CicIMCLock&
imcLock);
+ HRESULT DestroyInputContext();
+};
diff --git a/dll/ime/msctfime/msctfime.cpp b/dll/ime/msctfime/msctfime.cpp
index ccd442083ab..445998d6a9c 100644
--- a/dll/ime/msctfime/msctfime.cpp
+++ b/dll/ime/msctfime/msctfime.cpp
@@ -20,87 +20,31 @@ BOOL gfTFInitLib = FALSE;
CRITICAL_SECTION g_csLock;
CDispAttrPropCache *g_pPropCache = NULL;
-DEFINE_GUID(GUID_COMPARTMENT_CTFIME_DIMFLAGS, 0xA94C5FD2, 0xC471, 0x4031, 0x95,
0x46, 0x70, 0x9C, 0x17, 0x30, 0x0C, 0xB9);
-DEFINE_GUID(GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT, 0x85A688F7, 0x6DC8, 0x4F17, 0xA8,
0x3A, 0xB1, 0x1C, 0x09, 0xCD, 0xD7, 0xBF);
-
EXTERN_C void __cxa_pure_virtual(void)
{
ERR("__cxa_pure_virtual\n");
}
-UINT WM_MSIME_SERVICE = 0;
-UINT WM_MSIME_UIREADY = 0;
-UINT WM_MSIME_RECONVERTREQUEST = 0;
-UINT WM_MSIME_RECONVERT = 0;
-UINT WM_MSIME_DOCUMENTFEED = 0;
-UINT WM_MSIME_QUERYPOSITION = 0;
-UINT WM_MSIME_MODEBIAS = 0;
-UINT WM_MSIME_SHOWIMEPAD = 0;
-UINT WM_MSIME_MOUSE = 0;
-UINT WM_MSIME_KEYMAP = 0;
-
-/// @implemented
-BOOL IsMsImeMessage(_In_ UINT uMsg)
-{
- return (uMsg == WM_MSIME_SERVICE ||
- uMsg == WM_MSIME_UIREADY ||
- uMsg == WM_MSIME_RECONVERTREQUEST ||
- uMsg == WM_MSIME_RECONVERT ||
- uMsg == WM_MSIME_DOCUMENTFEED ||
- uMsg == WM_MSIME_QUERYPOSITION ||
- uMsg == WM_MSIME_MODEBIAS ||
- uMsg == WM_MSIME_SHOWIMEPAD ||
- uMsg == WM_MSIME_MOUSE ||
- uMsg == WM_MSIME_KEYMAP);
-}
-
-/// @implemented
-BOOL RegisterMSIMEMessage(VOID)
-{
- // Using ANSI (A) version here can reduce binary size.
- WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
- WM_MSIME_UIREADY = RegisterWindowMessageA("MSIMEUIReady");
- WM_MSIME_RECONVERTREQUEST =
RegisterWindowMessageA("MSIMEReconvertRequest");
- WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
- WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
- WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
- WM_MSIME_MODEBIAS = RegisterWindowMessageA("MSIMEModeBias");
- WM_MSIME_SHOWIMEPAD = RegisterWindowMessageA("MSIMEShowImePad");
- WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
- WM_MSIME_KEYMAP = RegisterWindowMessageA("MSIMEKeyMap");
- return (WM_MSIME_SERVICE &&
- WM_MSIME_UIREADY &&
- WM_MSIME_RECONVERTREQUEST &&
- WM_MSIME_RECONVERT &&
- WM_MSIME_DOCUMENTFEED &&
- WM_MSIME_QUERYPOSITION &&
- WM_MSIME_MODEBIAS &&
- WM_MSIME_SHOWIMEPAD &&
- WM_MSIME_MOUSE &&
- WM_MSIME_KEYMAP);
-}
-
-typedef BOOLEAN (WINAPI *FN_DllShutDownInProgress)(VOID);
+typedef BOOLEAN (WINAPI *FN_DllShutdownInProgress)(VOID);
/// This function calls ntdll!RtlDllShutdownInProgress.
/// It can detect the system is shutting down or not.
/// @implemented
-EXTERN_C BOOLEAN WINAPI
-DllShutDownInProgress(VOID)
+EXTERN_C BOOLEAN WINAPI DllShutdownInProgress(VOID)
{
HMODULE hNTDLL;
- static FN_DllShutDownInProgress s_fnDllShutDownInProgress = NULL;
+ static FN_DllShutdownInProgress s_fnDllShutdownInProgress = NULL;
- if (s_fnDllShutDownInProgress)
- return s_fnDllShutDownInProgress();
+ if (s_fnDllShutdownInProgress)
+ return s_fnDllShutdownInProgress();
hNTDLL = cicGetSystemModuleHandle(L"ntdll.dll", FALSE);
- s_fnDllShutDownInProgress =
- (FN_DllShutDownInProgress)GetProcAddress(hNTDLL,
"RtlDllShutdownInProgress");
- if (!s_fnDllShutDownInProgress)
+ s_fnDllShutdownInProgress =
+ (FN_DllShutdownInProgress)GetProcAddress(hNTDLL,
"RtlDllShutdownInProgress");
+ if (!s_fnDllShutdownInProgress)
return FALSE;
- return s_fnDllShutDownInProgress();
+ return s_fnDllShutdownInProgress();
}
/// This function checks if the current user logon session is interactive.
@@ -195,2533 +139,115 @@ HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
}
::LeaveCriticalSection(&g_csLock);
- return hr;
-}
-
-HIMC GetActiveContext(VOID)
-{
- HWND hwndFocus = ::GetFocus();
- if (!hwndFocus)
- hwndFocus = ::GetActiveWindow();
- return ::ImmGetContext(hwndFocus);
-}
-
-/// @implemented
-HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
-{
- if (!pLibThread)
- return E_FAIL;
-
- if (pLibThread->m_pDisplayAttrMgr)
- {
- pLibThread->m_pDisplayAttrMgr->Release();
- pLibThread->m_pDisplayAttrMgr = NULL;
- }
-
- return S_OK;
-}
-
-/// Gets the charset from a language ID.
-/// @implemented
-BYTE GetCharsetFromLangId(_In_ DWORD dwValue)
-{
- CHARSETINFO info;
- if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, TCI_SRCLOCALE))
- return 0;
- return info.ciCharset;
-}
-
-/// Selects or unselects the input context.
-/// @implemented
-HRESULT
-InternalSelectEx(
- _In_ HIMC hIMC,
- _In_ BOOL fSelect,
- _In_ LANGID LangID)
-{
- CicIMCLock imcLock(hIMC);
- if (!imcLock)
- imcLock.m_hr = E_FAIL;
- if (FAILED(imcLock.m_hr))
- return imcLock.m_hr;
-
- if (PRIMARYLANGID(LangID) == LANG_CHINESE)
- {
- imcLock.get().cfCandForm[0].dwStyle = 0;
- imcLock.get().cfCandForm[0].dwIndex = (DWORD)-1;
- }
-
- if (!fSelect)
- {
- imcLock.get().fdwInit &= ~INIT_GUIDMAP;
- return imcLock.m_hr;
- }
-
- if (!imcLock.ClearCand())
- return imcLock.m_hr;
-
- // Populate conversion mode
- if (!(imcLock.get().fdwInit & INIT_CONVERSION))
- {
- DWORD dwConv = (imcLock.get().fdwConversion & IME_CMODE_SOFTKBD);
- if (LangID)
- {
- if (PRIMARYLANGID(LangID) == LANG_JAPANESE)
- {
- dwConv |= IME_CMODE_ROMAN | IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
- }
- else if (PRIMARYLANGID(LangID) != LANG_KOREAN)
- {
- dwConv |= IME_CMODE_NATIVE;
- }
- }
- imcLock.get().fdwConversion |= dwConv;
- imcLock.get().fdwInit |= INIT_CONVERSION;
- }
-
- // Populate sentence mode
- imcLock.get().fdwSentence |= IME_SMODE_PHRASEPREDICT;
-
- // Populate LOGFONT
- if (!(imcLock.get().fdwInit & INIT_LOGFONT))
- {
- // Get logical font
- LOGFONTW lf;
- HDC hDC = ::GetDC(imcLock.get().hWnd);
- HGDIOBJ hFont = GetCurrentObject(hDC, OBJ_FONT);
- ::GetObjectW(hFont, sizeof(LOGFONTW), &lf);
- ::ReleaseDC(imcLock.get().hWnd, hDC);
-
- imcLock.get().lfFont.W = lf;
- imcLock.get().fdwInit |= INIT_LOGFONT;
- }
- imcLock.get().lfFont.W.lfCharSet = GetCharsetFromLangId(LangID);
-
- imcLock.InitContext();
-
- return imcLock.m_hr;
-}
-
-/***********************************************************************
- * Compartment
- */
-
-/// @implemented
-HRESULT
-GetCompartment(
- IUnknown *pUnknown,
- REFGUID rguid,
- ITfCompartment **ppComp,
- BOOL bThread)
-{
- *ppComp = NULL;
-
- ITfThreadMgr *pThreadMgr = NULL;
- ITfCompartmentMgr *pCompMgr = NULL;
-
- HRESULT hr;
- if (bThread)
- {
- hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr);
- if (FAILED(hr))
- return hr;
-
- hr = pThreadMgr->GetGlobalCompartment(&pCompMgr);
- }
- else
- {
- hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = E_FAIL;
- if (pCompMgr)
- {
- hr = pCompMgr->GetCompartment(rguid, ppComp);
- pCompMgr->Release();
- }
- }
-
- if (pThreadMgr)
- pThreadMgr->Release();
-
- return hr;
-}
-
-/// @implemented
-HRESULT
-SetCompartmentDWORD(
- TfEditCookie cookie,
- IUnknown *pUnknown,
- REFGUID rguid,
- DWORD dwValue,
- BOOL bThread)
-{
- ITfCompartment *pComp = NULL;
- HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread);
- if (FAILED(hr))
- return hr;
-
- VARIANT vari;
- V_I4(&vari) = dwValue;
- V_VT(&vari) = VT_I4;
- hr = pComp->SetValue(cookie, &vari);
-
- pComp->Release();
- return hr;
-}
-
-/// @implemented
-HRESULT
-GetCompartmentDWORD(
- IUnknown *pUnknown,
- REFGUID rguid,
- LPDWORD pdwValue,
- BOOL bThread)
-{
- *pdwValue = 0;
-
- ITfCompartment *pComp = NULL;
- HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, bThread);
- if (FAILED(hr))
- return hr;
-
- VARIANT vari;
- hr = pComp->GetValue(&vari);
- if (hr == S_OK)
- *pdwValue = V_I4(&vari);
-
- pComp->Release();
- return hr;
-}
-
-/// @implemented
-HRESULT
-SetCompartmentUnknown(
- TfEditCookie cookie,
- IUnknown *pUnknown,
- REFGUID rguid,
- IUnknown *punkValue)
-{
- ITfCompartment *pComp = NULL;
- HRESULT hr = GetCompartment(pUnknown, rguid, &pComp, FALSE);
- if (FAILED(hr))
- return hr;
-
- VARIANT vari;
- V_UNKNOWN(&vari) = punkValue;
- V_VT(&vari) = VT_UNKNOWN;
- hr = pComp->SetValue(cookie, &vari);
-
- pComp->Release();
- return hr;
-}
-
-/// @implemented
-HRESULT
-ClearCompartment(
- TfClientId tid,
- IUnknown *pUnknown,
- REFGUID rguid,
- BOOL bThread)
-{
- ITfCompartmentMgr *pCompMgr = NULL;
- ITfThreadMgr *pThreadMgr = NULL;
-
- HRESULT hr;
- if (bThread)
- {
- hr = pUnknown->QueryInterface(IID_ITfThreadMgr, (void **)&pThreadMgr);
- if (FAILED(hr))
- return hr;
-
- hr = pThreadMgr->GetGlobalCompartment(&pCompMgr);
- }
- else
- {
- hr = pUnknown->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = E_FAIL;
- if (pCompMgr)
- {
- hr = pCompMgr->ClearCompartment(tid, rguid);
- pCompMgr->Release();
- }
- }
-
- if (pThreadMgr)
- pThreadMgr->Release();
-
- return hr;
-}
-
-typedef struct CESMAP
-{
- ITfCompartment *m_pComp;
- DWORD m_dwCookie;
-} CESMAP, *PCESMAP;
-
-typedef INT (CALLBACK *FN_EVENTSINK)(LPVOID, REFGUID);
-
-class CCompartmentEventSink : public ITfCompartmentEventSink
-{
- CicArray<CESMAP> m_array;
- LONG m_cRefs;
- FN_EVENTSINK m_fnEventSink;
- LPVOID m_pUserData;
-
-public:
- CCompartmentEventSink(FN_EVENTSINK fnEventSink, LPVOID pUserData);
- virtual ~CCompartmentEventSink();
-
- HRESULT _Advise(IUnknown *pUnknown, REFGUID rguid, BOOL bThread);
- HRESULT _Unadvise();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfCompartmentEventSink interface
- STDMETHODIMP OnChange(REFGUID rguid) override;
-};
-
-/// @implemented
-CCompartmentEventSink::CCompartmentEventSink(FN_EVENTSINK fnEventSink, LPVOID pUserData)
- : m_array()
- , m_cRefs(1)
- , m_fnEventSink(fnEventSink)
- , m_pUserData(pUserData)
-{
-}
-
-/// @implemented
-CCompartmentEventSink::~CCompartmentEventSink()
-{
-}
-
-/// @implemented
-STDMETHODIMP CCompartmentEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCompartmentEventSink))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
-
- *ppvObj = NULL;
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CCompartmentEventSink::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CCompartmentEventSink::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP CCompartmentEventSink::OnChange(REFGUID rguid)
-{
- return m_fnEventSink(m_pUserData, rguid);
-}
-
-/// @implemented
-HRESULT
-CCompartmentEventSink::_Advise(IUnknown *pUnknown, REFGUID rguid, BOOL bThread)
-{
- CESMAP *pCesMap = m_array.Append(1);
- if (!pCesMap)
- return E_OUTOFMEMORY;
-
- ITfSource *pSource = NULL;
-
- HRESULT hr = GetCompartment(pUnknown, rguid, &pCesMap->m_pComp, bThread);
- if (FAILED(hr))
- {
- hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void
**)&pSource);
- if (FAILED(hr))
- {
- hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this,
&pCesMap->m_dwCookie);
- if (FAILED(hr))
- {
- if (pCesMap->m_pComp)
- {
- pCesMap->m_pComp->Release();
- pCesMap->m_pComp = NULL;
- }
- m_array.Remove(m_array.size() - 1, 1);
- }
- else
- {
- hr = S_OK;
- }
- }
- }
-
- if (pSource)
- pSource->Release();
-
- return hr;
-}
-
-/// @implemented
-HRESULT CCompartmentEventSink::_Unadvise()
-{
- CESMAP *pCesMap = m_array.data();
- size_t cItems = m_array.size();
- if (!cItems)
- return S_OK;
-
- do
- {
- ITfSource *pSource = NULL;
- HRESULT hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void
**)&pSource);
- if (SUCCEEDED(hr))
- pSource->UnadviseSink(pCesMap->m_dwCookie);
-
- if (pCesMap->m_pComp)
- {
- pCesMap->m_pComp->Release();
- pCesMap->m_pComp = NULL;
- }
-
- if (pSource)
- pSource->Release();
-
- ++pCesMap;
- --cItems;
- } while (cItems);
-
- return S_OK;
-}
-
-class CInputContextOwnerCallBack;
-class CInputContextOwner;
-
-typedef INT (CALLBACK *FN_ENDEDIT)(INT, LPVOID, LPVOID);
-typedef INT (CALLBACK *FN_LAYOUTCHANGE)(UINT nType, FN_ENDEDIT fnEndEdit, ITfContextView
*pView);
-
-class CTextEventSink : public ITfTextEditSink, ITfTextLayoutSink
-{
-protected:
- LONG m_cRefs;
- IUnknown *m_pUnknown;
- DWORD m_dwEditSinkCookie;
- DWORD m_dwLayoutSinkCookie;
- union
- {
- UINT m_uFlags;
- FN_LAYOUTCHANGE m_fnLayoutChange;
- };
- FN_ENDEDIT m_fnEndEdit;
- LPVOID m_pCallbackPV;
-
-public:
- CTextEventSink(FN_ENDEDIT fnEndEdit, LPVOID pCallbackPV);
- virtual ~CTextEventSink();
-
- HRESULT _Advise(IUnknown *pUnknown, UINT uFlags);
- HRESULT _Unadvise();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfTextEditSink interface
- STDMETHODIMP OnEndEdit(
- ITfContext *pic,
- TfEditCookie ecReadOnly,
- ITfEditRecord *pEditRecord) override;
-
- // ITfTextLayoutSink interface
- STDMETHODIMP
- OnLayoutChange(
- ITfContext *pContext,
- TfLayoutCode lcode,
- ITfContextView *pContextView) override;
-};
-
-/// @implemented
-CTextEventSink::CTextEventSink(FN_ENDEDIT fnEndEdit, LPVOID pCallbackPV)
-{
- m_cRefs = 1;
- m_pUnknown = NULL;
- m_dwEditSinkCookie = (DWORD)-1;
- m_dwLayoutSinkCookie = (DWORD)-1;
- m_fnLayoutChange = NULL;
- m_fnEndEdit = fnEndEdit;
- m_pCallbackPV = pCallbackPV;
-}
-
-/// @implemented
-CTextEventSink::~CTextEventSink()
-{
-}
-
-/// @implemented
-STDMETHODIMP CTextEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfTextEditSink))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- if (IsEqualIID(riid, IID_ITfTextLayoutSink))
- {
- *ppvObj = static_cast<ITfTextLayoutSink*>(this);
- AddRef();
- return S_OK;
- }
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CTextEventSink::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CTextEventSink::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-struct TEXT_EVENT_SINK_END_EDIT
-{
- TfEditCookie m_ecReadOnly;
- ITfEditRecord *m_pEditRecord;
- ITfContext *m_pContext;
-};
-
-/// @implemented
-STDMETHODIMP CTextEventSink::OnEndEdit(
- ITfContext *pic,
- TfEditCookie ecReadOnly,
- ITfEditRecord *pEditRecord)
-{
- TEXT_EVENT_SINK_END_EDIT Data = { ecReadOnly, pEditRecord, pic };
- return m_fnEndEdit(1, m_pCallbackPV, (LPVOID)&Data);
-}
-
-/// @implemented
-STDMETHODIMP CTextEventSink::OnLayoutChange(
- ITfContext *pContext,
- TfLayoutCode lcode,
- ITfContextView *pContextView)
-{
- switch (lcode)
- {
- case TF_LC_CREATE:
- return m_fnLayoutChange(3, m_fnEndEdit, pContextView);
- case TF_LC_CHANGE:
- return m_fnLayoutChange(2, m_fnEndEdit, pContextView);
- case TF_LC_DESTROY:
- return m_fnLayoutChange(4, m_fnEndEdit, pContextView);
- default:
- return E_INVALIDARG;
- }
-}
-
-/// @implemented
-HRESULT CTextEventSink::_Advise(IUnknown *pUnknown, UINT uFlags)
-{
- m_pUnknown = NULL;
- m_uFlags = uFlags;
-
- ITfSource *pSource = NULL;
- HRESULT hr = pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
- if (SUCCEEDED(hr))
- {
- ITfTextEditSink *pSink = static_cast<ITfTextEditSink*>(this);
- if (uFlags & 1)
- hr = pSource->AdviseSink(IID_ITfTextEditSink, pSink,
&m_dwEditSinkCookie);
- if (SUCCEEDED(hr) && (uFlags & 2))
- hr = pSource->AdviseSink(IID_ITfTextLayoutSink, pSink,
&m_dwLayoutSinkCookie);
-
- if (SUCCEEDED(hr))
- {
- m_pUnknown = pUnknown;
- pUnknown->AddRef();
- }
- else
- {
- pSource->UnadviseSink(m_dwEditSinkCookie);
- }
- }
-
- if (pSource)
- pSource->Release();
-
- return hr;
-}
-
-/// @implemented
-HRESULT CTextEventSink::_Unadvise()
-{
- if (!m_pUnknown)
- return E_FAIL;
-
- ITfSource *pSource = NULL;
- HRESULT hr = m_pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
- if (SUCCEEDED(hr))
- {
- if (m_uFlags & 1)
- hr = pSource->UnadviseSink(m_dwEditSinkCookie);
- if (m_uFlags & 2)
- hr = pSource->UnadviseSink(m_dwLayoutSinkCookie);
-
- pSource->Release();
- }
-
- m_pUnknown->Release();
- m_pUnknown = NULL;
-
- return E_NOTIMPL;
-}
-
-/***********************************************************************
- * CicInputContext
- *
- * The msctfime.ime's input context.
- */
-class CicInputContext
- : public ITfCleanupContextSink
- , public ITfContextOwnerCompositionSink
- , public ITfCompositionSink
-{
-public:
- LONG m_cRefs;
- HIMC m_hIMC;
- ITfDocumentMgr *m_pDocumentMgr;
- ITfContext *m_pContext;
- ITfContextOwnerServices *m_pContextOwnerServices;
- CInputContextOwnerCallBack *m_pICOwnerCallback;
- CTextEventSink *m_pTextEventSink;
- CCompartmentEventSink *m_pCompEventSink1;
- CCompartmentEventSink *m_pCompEventSink2;
- CInputContextOwner *m_pInputContextOwner;
- DWORD m_dwUnknown3[3];
- DWORD m_dwUnknown4[2];
- DWORD m_dwQueryPos;
- DWORD m_dwUnknown5;
- GUID m_guid;
- DWORD m_dwUnknown6[11];
- BOOL m_bSelecting;
- DWORD m_dwUnknown6_5;
- LONG m_cCompLocks;
- DWORD m_dwUnknown7[5];
- WORD m_cGuidAtoms;
- WORD m_padding;
- DWORD m_adwGuidAtoms[256];
- DWORD m_dwUnknown8[17];
- TfClientId m_clientId;
- DWORD m_dwUnknown9;
-
-public:
- CicInputContext(
- _In_ TfClientId cliendId,
- _Inout_ PCIC_LIBTHREAD pLibThread,
- _In_ HIMC hIMC);
- virtual ~CicInputContext() { }
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfCleanupContextSink interface
- STDMETHODIMP OnCleanupContext(_In_ TfEditCookie ecWrite, _Inout_ ITfContext *pic)
override;
-
- // ITfContextOwnerCompositionSink interface
- STDMETHODIMP OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk)
override;
- STDMETHODIMP OnUpdateComposition(ITfCompositionView *pComposition, ITfRange
*pRangeNew) override;
- STDMETHODIMP OnEndComposition(ITfCompositionView *pComposition) override;
-
- // ITfCompositionSink interface
- STDMETHODIMP OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition
*pComposition) override;
-
- HRESULT
- GetGuidAtom(
- _Inout_ CicIMCLock& imcLock,
- _In_ BYTE iAtom,
- _Out_opt_ LPDWORD pdwGuidAtom);
-
- HRESULT CreateInputContext(_Inout_ ITfThreadMgr *pThreadMgr, _Inout_ CicIMCLock&
imcLock);
- HRESULT DestroyInputContext();
-};
-
-/// @unimplemented
-CicInputContext::CicInputContext(
- _In_ TfClientId cliendId,
- _Inout_ PCIC_LIBTHREAD pLibThread,
- _In_ HIMC hIMC)
-{
- m_hIMC = hIMC;
- m_guid = GUID_NULL;
- m_dwQueryPos = 0;
- m_cRefs = 1;
-}
-
-/// @implemented
-STDMETHODIMP CicInputContext::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- *ppvObj = NULL;
-
- if (IsEqualIID(riid, IID_ITfContextOwnerCompositionSink))
- {
- *ppvObj = static_cast<ITfContextOwnerCompositionSink*>(this);
- AddRef();
- return S_OK;
- }
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCleanupContextSink))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
-
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicInputContext::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicInputContext::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP
-CicInputContext::OnStartComposition(
- ITfCompositionView *pComposition,
- BOOL *pfOk)
-{
- if ((m_cCompLocks <= 0) || m_dwUnknown6_5)
- {
- *pfOk = TRUE;
- ++m_cCompLocks;
- }
- else
- {
- *pfOk = FALSE;
- }
- return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP
-CicInputContext::OnUpdateComposition(
- ITfCompositionView *pComposition,
- ITfRange *pRangeNew)
-{
- return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP
-CicInputContext::OnEndComposition(
- ITfCompositionView *pComposition)
-{
- --m_cCompLocks;
- return S_OK;
-}
-
-/// @implemented
-HRESULT
-CicInputContext::GetGuidAtom(
- _Inout_ CicIMCLock& imcLock,
- _In_ BYTE iAtom,
- _Out_opt_ LPDWORD pdwGuidAtom)
-{
- CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCompStr);
- HRESULT hr = imeContext.m_hr;
- if (!imeContext)
- hr = E_FAIL;
- if (FAILED(hr))
- return hr;
-
- hr = E_FAIL;
- if (iAtom < m_cGuidAtoms)
- {
- *pdwGuidAtom = m_adwGuidAtoms[iAtom];
- hr = S_OK;
- }
-
- return hr;
-}
-
-/// @unimplemented
-HRESULT
-CicInputContext::CreateInputContext(
- _Inout_ ITfThreadMgr *pThreadMgr,
- _Inout_ CicIMCLock& imcLock)
-{
- //FIXME
- return E_NOTIMPL;
-}
-
-/// @unimplemented
-HRESULT
-CicInputContext::DestroyInputContext()
-{
- ITfSourceSingle *pSource = NULL;
-
- if (m_pContext && m_pContext->QueryInterface(IID_ITfSourceSingle, (void
**)&pSource) == S_OK)
- pSource->UnadviseSingleSink(m_clientId, IID_ITfCleanupContextSink);
-
- //FIXME: m_dwUnknown5
-
- if (m_pTextEventSink)
- {
- m_pTextEventSink->_Unadvise();
- m_pTextEventSink->Release();
- m_pTextEventSink = NULL;
- }
-
- if (m_pCompEventSink2)
- {
- m_pCompEventSink2->_Unadvise();
- m_pCompEventSink2->Release();
- m_pCompEventSink2 = NULL;
- }
-
- if (m_pCompEventSink1)
- {
- m_pCompEventSink1->_Unadvise();
- m_pCompEventSink1->Release();
- m_pCompEventSink1 = NULL;
- }
-
- //FIXME: m_pInputContextOwner
-
- if (m_pDocumentMgr)
- m_pDocumentMgr->Pop(1);
-
- if (m_pContext)
- {
- ClearCompartment(m_clientId, m_pContext, GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT,
0);
- m_pContext->Release();
- m_pContext = NULL;
- }
-
- if (m_pContextOwnerServices)
- {
- m_pContextOwnerServices->Release();
- m_pContextOwnerServices = NULL;
- }
-
- // FIXME: m_pICOwnerCallback
-
- if (m_pDocumentMgr)
- {
- m_pDocumentMgr->Release();
- m_pDocumentMgr = NULL;
- }
-
- if (pSource)
- pSource->Release();
-
- return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP
-CicInputContext::OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition
*pComposition)
-{
- return S_OK;
-}
-
-/// Retrieves the IME information.
-/// @implemented
-HRESULT
-Inquire(
- _Out_ LPIMEINFO lpIMEInfo,
- _Out_ LPWSTR lpszWndClass,
- _In_ DWORD dwSystemInfoFlags,
- _In_ HKL hKL)
-{
- if (!lpIMEInfo)
- return E_OUTOFMEMORY;
-
- StringCchCopyW(lpszWndClass, 64, L"MSCTFIME UI");
- lpIMEInfo->dwPrivateDataSize = 0;
-
- switch (LOWORD(hKL)) // Language ID
- {
- case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): // Japanese
- {
- lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT |
IME_PROP_SPECIAL_UI |
- IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
- IME_PROP_KBD_CHAR_FIRST;
- lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA |
- IME_CMODE_NATIVE;
- lpIMEInfo->fdwSentenceCaps = IME_SMODE_CONVERSATION |
IME_SMODE_PLAURALCLAUSE;
- lpIMEInfo->fdwSelectCaps = SELECT_CAP_SENTENCE | SELECT_CAP_CONVERSION;
- lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
- SCS_CAP_COMPSTR;
- lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
- break;
- }
- case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT): // Korean
- {
- lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT |
IME_PROP_SPECIAL_UI |
- IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
- IME_PROP_KBD_CHAR_FIRST;
- lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
- lpIMEInfo->fdwSentenceCaps = 0;
- lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_COMPSTR;
- lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
- lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
- break;
- }
- case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): // Simplified Chinese
- case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): // Traditional
Chinese
- {
- lpIMEInfo->fdwProperty = IME_PROP_SPECIAL_UI | IME_PROP_AT_CARET |
- IME_PROP_NEED_ALTKEY | IME_PROP_KBD_CHAR_FIRST;
- lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
- lpIMEInfo->fdwSentenceCaps = SELECT_CAP_CONVERSION;
- lpIMEInfo->fdwSelectCaps = 0;
- lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
- SCS_CAP_COMPSTR;
- lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
- break;
- }
- default: // Otherwise
- {
- lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
- lpIMEInfo->fdwConversionCaps = 0;
- lpIMEInfo->fdwSentenceCaps = 0;
- lpIMEInfo->fdwSCSCaps = 0;
- lpIMEInfo->fdwUICaps = 0;
- lpIMEInfo->fdwSelectCaps = 0;
- break;
- }
- }
-
- return S_OK;
-}
-
-class TLS;
-
-typedef INT (CALLBACK *FN_INITDOCMGR)(UINT, ITfDocumentMgr *, ITfDocumentMgr *, LPVOID);
-typedef INT (CALLBACK *FN_PUSHPOP)(UINT, ITfContext *, LPVOID);
-
-class CThreadMgrEventSink : public ITfThreadMgrEventSink
-{
-protected:
- ITfThreadMgr *m_pThreadMgr;
- DWORD m_dwCookie;
- FN_INITDOCMGR m_fnInit;
- FN_PUSHPOP m_fnPushPop;
- DWORD m_dw;
- LPVOID m_pCallbackPV;
- LONG m_cRefs;
-
-public:
- CThreadMgrEventSink(
- _In_ FN_INITDOCMGR fnInit,
- _In_ FN_PUSHPOP fnPushPop = NULL,
- _Inout_ LPVOID pvCallbackPV = NULL);
- virtual ~CThreadMgrEventSink() { }
-
- void SetCallbackPV(_Inout_ LPVOID pv);
- HRESULT _Advise(ITfThreadMgr *pThreadMgr);
- HRESULT _Unadvise();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfThreadMgrEventSink interface
- STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr *pdim) override;
- STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr *pdim) override;
- STDMETHODIMP OnSetFocus(ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus)
override;
- STDMETHODIMP OnPushContext(ITfContext *pic) override;
- STDMETHODIMP OnPopContext(ITfContext *pic) override;
-
- static INT CALLBACK DIMCallback(
- UINT nCode,
- ITfDocumentMgr *pDocMgr1,
- ITfDocumentMgr *pDocMgr2,
- LPVOID pUserData);
-};
-
-/// @implemented
-CThreadMgrEventSink::CThreadMgrEventSink(
- _In_ FN_INITDOCMGR fnInit,
- _In_ FN_PUSHPOP fnPushPop,
- _Inout_ LPVOID pvCallbackPV)
-{
- m_fnInit = fnInit;
- m_fnPushPop = fnPushPop;
- m_pCallbackPV = pvCallbackPV;
- m_cRefs = 1;
-}
-
-/// @implemented
-STDMETHODIMP CThreadMgrEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfThreadMgrEventSink))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- *ppvObj = NULL;
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CThreadMgrEventSink::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CThreadMgrEventSink::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-INT CALLBACK
-CThreadMgrEventSink::DIMCallback(
- UINT nCode,
- ITfDocumentMgr *pDocMgr1,
- ITfDocumentMgr *pDocMgr2,
- LPVOID pUserData)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CThreadMgrEventSink::OnInitDocumentMgr(ITfDocumentMgr *pdim)
-{
- if (!m_fnInit)
- return S_OK;
- return m_fnInit(0, pdim, NULL, m_pCallbackPV);
-}
-
-STDMETHODIMP CThreadMgrEventSink::OnUninitDocumentMgr(ITfDocumentMgr *pdim)
-{
- if (!m_fnInit)
- return S_OK;
- return m_fnInit(1, pdim, NULL, m_pCallbackPV);
-}
-
-STDMETHODIMP
-CThreadMgrEventSink::OnSetFocus(ITfDocumentMgr *pdimFocus, ITfDocumentMgr
*pdimPrevFocus)
-{
- if (!m_fnInit)
- return S_OK;
- return m_fnInit(2, pdimFocus, pdimPrevFocus, m_pCallbackPV);
-}
-
-STDMETHODIMP CThreadMgrEventSink::OnPushContext(ITfContext *pic)
-{
- if (!m_fnPushPop)
- return S_OK;
- return m_fnPushPop(3, pic, m_pCallbackPV);
-}
-
-STDMETHODIMP CThreadMgrEventSink::OnPopContext(ITfContext *pic)
-{
- if (!m_fnPushPop)
- return S_OK;
- return m_fnPushPop(4, pic, m_pCallbackPV);
-}
-
-void CThreadMgrEventSink::SetCallbackPV(_Inout_ LPVOID pv)
-{
- if (!m_pCallbackPV)
- m_pCallbackPV = pv;
-}
-
-HRESULT CThreadMgrEventSink::_Advise(ITfThreadMgr *pThreadMgr)
-{
- m_pThreadMgr = NULL;
-
- HRESULT hr = E_FAIL;
- ITfSource *pSource = NULL;
- if (pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK
&&
- pSource->AdviseSink(IID_ITfThreadMgrEventSink, this, &m_dwCookie) ==
S_OK)
- {
- m_pThreadMgr = pThreadMgr;
- pThreadMgr->AddRef();
- hr = S_OK;
- }
-
- if (pSource)
- pSource->Release();
-
- return hr;
-}
-
-HRESULT CThreadMgrEventSink::_Unadvise()
-{
- HRESULT hr = E_FAIL;
- ITfSource *pSource = NULL;
-
- if (m_pThreadMgr)
- {
- if (m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK
&&
- pSource->UnadviseSink(m_dwCookie) == S_OK)
- {
- hr = S_OK;
- }
-
- if (pSource)
- pSource->Release();
- }
-
- if (m_pThreadMgr)
- {
- m_pThreadMgr->Release();
- m_pThreadMgr = NULL;
- }
-
- return hr;
-}
-
-class CFunctionProviderBase : public ITfFunctionProvider
-{
-protected:
- TfClientId m_clientId;
- GUID m_guid;
- BSTR m_bstr;
- LONG m_cRefs;
-
-public:
- CFunctionProviderBase(_In_ TfClientId clientId);
- virtual ~CFunctionProviderBase();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfFunctionProvider interface
- STDMETHODIMP GetType(_Out_ GUID *guid) override;
- STDMETHODIMP GetDescription(_Out_ BSTR *desc) override;
- //STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ IUnknown
**func) = 0;
-
- BOOL Init(_In_ REFGUID rguid, _In_ LPCWSTR psz);
-};
-
-/// @implemented
-CFunctionProviderBase::CFunctionProviderBase(_In_ TfClientId clientId)
-{
- m_clientId = clientId;
- m_guid = GUID_NULL;
- m_bstr = NULL;
- m_cRefs = 1;
-}
-
-/// @implemented
-CFunctionProviderBase::~CFunctionProviderBase()
-{
- if (!RtlDllShutdownInProgress())
- ::SysFreeString(m_bstr);
-}
-
-/// @implemented
-BOOL
-CFunctionProviderBase::Init(
- _In_ REFGUID rguid,
- _In_ LPCWSTR psz)
-{
- m_bstr = ::SysAllocString(psz);
- m_guid = rguid;
- return (m_bstr != NULL);
-}
-
-class CFnDocFeed : public IAImmFnDocFeed
-{
- LONG m_cRefs;
-
-public:
- CFnDocFeed();
- virtual ~CFnDocFeed();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // IAImmFnDocFeed interface
- STDMETHODIMP DocFeed() override;
- STDMETHODIMP ClearDocFeedBuffer() override;
- STDMETHODIMP StartReconvert() override;
- STDMETHODIMP StartUndoCompositionString() override;
-};
-
-CFnDocFeed::CFnDocFeed()
-{
- m_cRefs = 1;
-}
-
-CFnDocFeed::~CFnDocFeed()
-{
-}
-
-/// @implemented
-STDMETHODIMP CFnDocFeed::QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAImmFnDocFeed))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFnDocFeed::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFnDocFeed::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @unimplemented
-STDMETHODIMP CFnDocFeed::DocFeed()
-{
- return E_NOTIMPL;
-}
-
-/// @unimplemented
-STDMETHODIMP CFnDocFeed::ClearDocFeedBuffer()
-{
- return E_NOTIMPL;
-}
-
-/// @unimplemented
-STDMETHODIMP CFnDocFeed::StartReconvert()
-{
- return E_NOTIMPL;
-}
-
-/// @unimplemented
-STDMETHODIMP CFnDocFeed::StartUndoCompositionString()
-{
- return E_NOTIMPL;
-}
-
-/// @implemented
-STDMETHODIMP
-CFunctionProviderBase::QueryInterface(
- _In_ REFIID riid,
- _Out_ LPVOID* ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfFunctionProvider))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFunctionProviderBase::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFunctionProviderBase::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP CFunctionProviderBase::GetType(_Out_ GUID *guid)
-{
- *guid = m_guid;
- return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP CFunctionProviderBase::GetDescription(_Out_ BSTR *desc)
-{
- *desc = ::SysAllocString(m_bstr);
- return (*desc ? S_OK : E_OUTOFMEMORY);
-}
-
-class CFunctionProvider : public CFunctionProviderBase
-{
-public:
- CFunctionProvider(_In_ TfClientId clientId);
-
- STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ IUnknown **func)
override;
-};
-
-/// @implemented
-CFunctionProvider::CFunctionProvider(_In_ TfClientId clientId) :
CFunctionProviderBase(clientId)
-{
- Init(CLSID_CAImmLayer, L"MSCTFIME::Function Provider");
-}
-
-/// @implemented
-STDMETHODIMP
-CFunctionProvider::GetFunction(
- _In_ REFGUID guid,
- _In_ REFIID riid,
- _Out_ IUnknown **func)
-{
- *func = NULL;
-
- if (IsEqualGUID(guid, GUID_NULL) &&
- IsEqualIID(riid, IID_IAImmFnDocFeed))
- {
- *func = new(cicNoThrow) CFnDocFeed();
- if (*func)
- return S_OK;
- }
-
- return E_NOINTERFACE;
-}
-
-/* FIXME */
-class CicBridge : public ITfSysHookSink
-{
-protected:
- LONG m_cRefs;
- BOOL m_bImmxInited;
- BOOL m_bUnknown1;
- BOOL m_bDeactivating;
- DWORD m_cActivateLocks;
- ITfKeystrokeMgr *m_pKeystrokeMgr;
- ITfDocumentMgr *m_pDocMgr;
- CThreadMgrEventSink *m_pThreadMgrEventSink;
- TfClientId m_cliendId;
- CIC_LIBTHREAD m_LibThread;
- BOOL m_bUnknown2;
-
- static BOOL CALLBACK EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam);
- static BOOL CALLBACK EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam);
-
-public:
- CicBridge();
- virtual ~CicBridge();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfSysHookSink interface
- STDMETHODIMP OnPreFocusDIM(HWND hwnd) override;
- STDMETHODIMP OnSysKeyboardProc(UINT, LONG) override;
- STDMETHODIMP OnSysShellProc(INT, UINT, LONG) override;
-
- HRESULT InitIMMX(_Inout_ TLS *pTLS);
- BOOL UnInitIMMX(_Inout_ TLS *pTLS);
- HRESULT ActivateIMMX(_Inout_ TLS *pTLS, _Inout_ ITfThreadMgr_P *pThreadMgr);
- HRESULT DeactivateIMMX(_Inout_ TLS *pTLS, _Inout_ ITfThreadMgr_P *pThreadMgr);
-
- HRESULT CreateInputContext(TLS *pTLS, HIMC hIMC);
- HRESULT DestroyInputContext(TLS *pTLS, HIMC hIMC);
- ITfContext *GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext);
-
- HRESULT SelectEx(
- _Inout_ TLS *pTLS,
- _Inout_ ITfThreadMgr_P *pThreadMgr,
- _In_ HIMC hIMC,
- _In_ BOOL fSelect,
- _In_ HKL hKL);
- HRESULT OnSetOpenStatus(
- TLS *pTLS,
- ITfThreadMgr_P *pThreadMgr,
- CicIMCLock& imcLock,
- CicInputContext *pCicIC);
-
- void PostTransMsg(_In_ HWND hWnd, _In_ INT cTransMsgs, _In_ const TRANSMSG
*pTransMsgs);
- void GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext);
-
- HRESULT
- ConfigureGeneral(_Inout_ TLS* pTLS,
- _In_ ITfThreadMgr *pThreadMgr,
- _In_ HKL hKL,
- _In_ HWND hWnd);
- HRESULT ConfigureRegisterWord(
- _Inout_ TLS* pTLS,
- _In_ ITfThreadMgr *pThreadMgr,
- _In_ HKL hKL,
- _In_ HWND hWnd,
- _Inout_opt_ LPVOID lpData);
-};
-
-class CActiveLanguageProfileNotifySink : public ITfActiveLanguageProfileNotifySink
-{
-protected:
- typedef INT (CALLBACK *FN_COMPARE)(REFGUID rguid1, REFGUID rguid2, BOOL fActivated,
LPVOID pUserData);
- LONG m_cRefs;
- ITfThreadMgr *m_pThreadMgr;
- DWORD m_dwConnection;
- FN_COMPARE m_fnCompare;
- LPVOID m_pUserData;
-
-public:
- CActiveLanguageProfileNotifySink(_In_ FN_COMPARE fnCompare, _Inout_opt_ void
*pUserData);
- virtual ~CActiveLanguageProfileNotifySink();
-
- HRESULT _Advise(ITfThreadMgr *pThreadMgr);
- HRESULT _Unadvise();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // ITfActiveLanguageProfileNotifySink interface
- STDMETHODIMP
- OnActivated(
- REFCLSID clsid,
- REFGUID guidProfile,
- BOOL fActivated) override;
-};
-
-/// @implemented
-CActiveLanguageProfileNotifySink::CActiveLanguageProfileNotifySink(
- _In_ FN_COMPARE fnCompare,
- _Inout_opt_ void *pUserData)
-{
- m_dwConnection = (DWORD)-1;
- m_fnCompare = fnCompare;
- m_cRefs = 1;
- m_pUserData = pUserData;
-}
-
-/// @implemented
-CActiveLanguageProfileNotifySink::~CActiveLanguageProfileNotifySink()
-{
-}
-
-/// @implemented
-STDMETHODIMP CActiveLanguageProfileNotifySink::QueryInterface(REFIID riid, LPVOID*
ppvObj)
-{
- if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid,
IID_ITfActiveLanguageProfileNotifySink))
- {
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- *ppvObj = NULL;
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP
-CActiveLanguageProfileNotifySink::OnActivated(
- REFCLSID clsid,
- REFGUID guidProfile,
- BOOL fActivated)
-{
- if (!m_fnCompare)
- return 0;
-
- return m_fnCompare(clsid, guidProfile, fActivated, m_pUserData);
-}
-
-/// @implemented
-HRESULT
-CActiveLanguageProfileNotifySink::_Advise(
- ITfThreadMgr *pThreadMgr)
-{
- m_pThreadMgr = NULL;
-
- ITfSource *pSource = NULL;
- HRESULT hr = pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
- if (FAILED(hr))
- return E_FAIL;
-
- hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, this,
&m_dwConnection);
- if (SUCCEEDED(hr))
- {
- m_pThreadMgr = pThreadMgr;
- pThreadMgr->AddRef();
- hr = S_OK;
- }
- else
- {
- hr = E_FAIL;
- }
-
- if (pSource)
- pSource->Release();
-
- return hr;
-}
-
-/// @implemented
-HRESULT
-CActiveLanguageProfileNotifySink::_Unadvise()
-{
- if (!m_pThreadMgr)
- return E_FAIL;
-
- ITfSource *pSource = NULL;
- HRESULT hr = m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
- if (SUCCEEDED(hr))
- {
- hr = pSource->UnadviseSink(m_dwConnection);
- if (SUCCEEDED(hr))
- hr = S_OK;
- }
-
- if (pSource)
- pSource->Release();
-
- if (m_pThreadMgr)
- {
- m_pThreadMgr->Release();
- m_pThreadMgr = NULL;
- }
-
- return hr;
-}
-
-/* FIXME */
-class CicProfile : public IUnknown
-{
-protected:
- ITfInputProcessorProfiles *m_pIPProfiles;
- CActiveLanguageProfileNotifySink *m_pActiveLanguageProfileNotifySink;
- LANGID m_LangID1;
- WORD m_padding1;
- DWORD m_dwFlags;
- UINT m_nCodePage;
- LANGID m_LangID2;
- WORD m_padding2;
- DWORD m_dwUnknown1;
- LONG m_cRefs;
-
- static INT CALLBACK
- ActiveLanguageProfileNotifySinkCallback(
- REFGUID rguid1,
- REFGUID rguid2,
- BOOL fActivated,
- LPVOID pUserData);
-
-public:
- CicProfile();
- virtual ~CicProfile();
-
- // IUnknown interface
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- HRESULT
- GetActiveLanguageProfile(
- _In_ HKL hKL,
- _In_ REFGUID rguid,
- _Out_ TF_LANGUAGEPROFILE *pProfile);
- HRESULT GetLangId(_Out_ LANGID *pLangID);
- HRESULT GetCodePageA(_Out_ UINT *puCodePage);
-
- HRESULT InitProfileInstance(_Inout_ TLS *pTLS);
-};
-
-/// @implemented
-CicProfile::CicProfile()
-{
- m_dwFlags &= 0xFFFFFFF0;
- m_cRefs = 1;
- m_pIPProfiles = NULL;
- m_pActiveLanguageProfileNotifySink = NULL;
- m_LangID1 = 0;
- m_nCodePage = CP_ACP;
- m_LangID2 = 0;
- m_dwUnknown1 = 0;
-}
-
-/// @implemented
-CicProfile::~CicProfile()
-{
- if (m_pIPProfiles)
- {
- if (m_LangID1)
- m_pIPProfiles->ChangeCurrentLanguage(m_LangID1);
-
- m_pIPProfiles->Release();
- m_pIPProfiles = NULL;
- }
-
- if (m_pActiveLanguageProfileNotifySink)
- {
- m_pActiveLanguageProfileNotifySink->_Unadvise();
- m_pActiveLanguageProfileNotifySink->Release();
- m_pActiveLanguageProfileNotifySink = NULL;
- }
-}
-
-/// @implemented
-STDMETHODIMP CicProfile::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- *ppvObj = NULL;
- return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicProfile::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicProfile::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-INT CALLBACK
-CicProfile::ActiveLanguageProfileNotifySinkCallback(
- REFGUID rguid1,
- REFGUID rguid2,
- BOOL fActivated,
- LPVOID pUserData)
-{
- CicProfile *pThis = (CicProfile *)pUserData;
- pThis->m_dwFlags &= ~0xE;
- return 0;
-}
-
-/// @implemented
-HRESULT CicProfile::GetCodePageA(_Out_ UINT *puCodePage)
-{
- if (!puCodePage)
- return E_INVALIDARG;
-
- if (m_dwFlags & 2)
- {
- *puCodePage = m_nCodePage;
- return S_OK;
- }
-
- *puCodePage = 0;
-
- LANGID LangID;
- HRESULT hr = GetLangId(&LangID);
- if (FAILED(hr))
- return E_FAIL;
-
- WCHAR szBuff[12];
- INT cch = ::GetLocaleInfoW(LangID, LOCALE_IDEFAULTANSICODEPAGE, szBuff,
_countof(szBuff));
- if (cch)
- {
- szBuff[cch] = 0;
- m_nCodePage = *puCodePage = wcstoul(szBuff, NULL, 10);
- m_dwFlags |= 2;
- }
-
- return S_OK;
-}
-
-/// @implemented
-HRESULT CicProfile::GetLangId(_Out_ LANGID *pLangID)
-{
- *pLangID = 0;
-
- if (!m_pIPProfiles)
- return E_FAIL;
-
- if (m_dwFlags & 4)
- {
- *pLangID = m_LangID2;
- return S_OK;
- }
-
- HRESULT hr = m_pIPProfiles->GetCurrentLanguage(pLangID);
- if (SUCCEEDED(hr))
- {
- m_dwFlags |= 4;
- m_LangID2 = *pLangID;
- }
-
- return hr;
-}
-
-class TLS
-{
-public:
- static DWORD s_dwTlsIndex;
-
- DWORD m_dwSystemInfoFlags;
- CicBridge *m_pBridge;
- CicProfile *m_pProfile;
- ITfThreadMgr_P *m_pThreadMgr;
- DWORD m_dwFlags1;
- DWORD m_dwFlags2;
- DWORD m_dwUnknown2;
- BOOL m_bDestroyed;
- DWORD m_dwNowOpening;
- DWORD m_NonEAComposition;
- DWORD m_cWnds;
-
- /**
- * @implemented
- */
- static BOOL Initialize()
- {
- s_dwTlsIndex = ::TlsAlloc();
- return s_dwTlsIndex != (DWORD)-1;
- }
-
- /**
- * @implemented
- */
- static VOID Uninitialize()
- {
- if (s_dwTlsIndex != (DWORD)-1)
- {
- ::TlsFree(s_dwTlsIndex);
- s_dwTlsIndex = (DWORD)-1;
- }
- }
-
- /**
- * @implemented
- */
- static TLS* GetTLS()
- {
- if (s_dwTlsIndex == (DWORD)-1)
- return NULL;
-
- return InternalAllocateTLS();
- }
-
- /**
- * @implemented
- */
- static TLS* PeekTLS()
- {
- return (TLS*)::TlsGetValue(TLS::s_dwTlsIndex);
- }
-
- static TLS* InternalAllocateTLS();
- static BOOL InternalDestroyTLS();
-
-};
-
-DWORD TLS::s_dwTlsIndex = (DWORD)-1;
-
-/// @implemented
-TLS* TLS::InternalAllocateTLS()
-{
- TLS *pTLS = TLS::PeekTLS();
- if (pTLS)
- return pTLS;
-
- if (DllShutDownInProgress())
- return NULL;
-
- pTLS = (TLS *)cicMemAllocClear(sizeof(TLS));
- if (!pTLS)
- return NULL;
-
- if (!::TlsSetValue(s_dwTlsIndex, pTLS))
- {
- cicMemFree(pTLS);
- return NULL;
- }
-
- pTLS->m_dwFlags1 |= 1;
- pTLS->m_dwUnknown2 |= 1;
- return pTLS;
-}
-
-/// @implemented
-BOOL TLS::InternalDestroyTLS()
-{
- TLS *pTLS = TLS::PeekTLS();
- if (!pTLS)
- return FALSE;
-
- if (pTLS->m_pBridge)
- pTLS->m_pBridge->Release();
- if (pTLS->m_pProfile)
- pTLS->m_pProfile->Release();
- if (pTLS->m_pThreadMgr)
- pTLS->m_pThreadMgr->Release();
-
- cicMemFree(pTLS);
- ::TlsSetValue(s_dwTlsIndex, NULL);
- return TRUE;
-}
-
-/// @implemented
-HRESULT
-CicProfile::InitProfileInstance(_Inout_ TLS *pTLS)
-{
- HRESULT hr = TF_CreateInputProcessorProfiles(&m_pIPProfiles);
- if (FAILED(hr))
- return hr;
-
- if (!m_pActiveLanguageProfileNotifySink)
- {
- CActiveLanguageProfileNotifySink *pSink =
- new(cicNoThrow) CActiveLanguageProfileNotifySink(
- CicProfile::ActiveLanguageProfileNotifySinkCallback, this);
- if (!pSink)
- {
- m_pIPProfiles->Release();
- m_pIPProfiles = NULL;
- return E_FAIL;
- }
- m_pActiveLanguageProfileNotifySink = pSink;
- }
-
- if (pTLS->m_pThreadMgr)
- m_pActiveLanguageProfileNotifySink->_Advise(pTLS->m_pThreadMgr);
-
- return hr;
-}
-
-/// @implemented
-STDMETHODIMP
-CicInputContext::OnCleanupContext(
- _In_ TfEditCookie ecWrite,
- _Inout_ ITfContext *pic)
-{
- TLS *pTLS = TLS::PeekTLS();
- if (!pTLS || !pTLS->m_pProfile)
- return E_OUTOFMEMORY;
-
- LANGID LangID;
- pTLS->m_pProfile->GetLangId(&LangID);
-
- IMEINFO IMEInfo;
- WCHAR szPath[MAX_PATH];
- if (Inquire(&IMEInfo, szPath, 0, (HKL)UlongToHandle(LangID)) != S_OK)
- return E_FAIL;
-
- ITfProperty *pProp = NULL;
- if (!(IMEInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT))
- return S_OK;
-
- HRESULT hr = pic->GetProperty(GUID_PROP_COMPOSING, &pProp);
- if (FAILED(hr))
- return S_OK;
-
- IEnumTfRanges *pRanges = NULL;
- hr = pProp->EnumRanges(ecWrite, &pRanges, NULL);
- if (SUCCEEDED(hr))
- {
- ITfRange *pRange = NULL;
- while (pRanges->Next(1, &pRange, 0) == S_OK)
- {
- VARIANT vari;
- V_VT(&vari) = VT_EMPTY;
- pProp->GetValue(ecWrite, pRange, &vari);
- if (V_VT(&vari) == VT_I4)
- {
- if (V_I4(&vari))
- pProp->Clear(ecWrite, pRange);
- }
- pRange->Release();
- pRange = NULL;
- }
- pRanges->Release();
- }
- pProp->Release();
-
- return S_OK;
-}
-
-/***********************************************************************
- * CicBridge
- */
-
-CicBridge::CicBridge()
-{
- m_bImmxInited = FALSE;
- m_bUnknown1 = FALSE;
- m_bDeactivating = FALSE;
- m_bUnknown2 = FALSE;
- m_pKeystrokeMgr = NULL;
- m_pDocMgr = NULL;
- m_pThreadMgrEventSink = NULL;
- m_cliendId = 0;
- m_cRefs = 1;
-}
-
-/// @implemented
-STDMETHODIMP CicBridge::QueryInterface(REFIID riid, LPVOID* ppvObj)
-{
- *ppvObj = NULL;
-
- if (!IsEqualIID(riid, IID_ITfSysHookSink))
- return E_NOINTERFACE;
-
- *ppvObj = this;
- AddRef();
-
- return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicBridge::AddRef()
-{
- return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CicBridge::Release()
-{
- if (::InterlockedDecrement(&m_cRefs) == 0)
- {
- delete this;
- return 0;
- }
- return m_cRefs;
-}
-
-/// @implemented
-CicBridge::~CicBridge()
-{
- TLS *pTLS = TLS::PeekTLS();
- if (!pTLS || !pTLS->m_pThreadMgr)
- return;
-
- if (SUCCEEDED(DeactivateIMMX(pTLS, pTLS->m_pThreadMgr)))
- UnInitIMMX(pTLS);
-}
-
-void CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>&
imeContext)
-{
- CicInputContext *pCicIC = imeContext.get().m_pCicIC;
- if (pCicIC)
- {
- m_pDocMgr = pCicIC->m_pDocumentMgr;
- m_pDocMgr->AddRef();
- }
- else
- {
- m_pDocMgr->Release();
- m_pDocMgr = NULL;
- }
-}
-
-/// @unimplemented
-HRESULT
-CicBridge::CreateInputContext(
- _Inout_ TLS *pTLS,
- _In_ HIMC hIMC)
-{
- CicIMCLock imcLock(hIMC);
- HRESULT hr = imcLock.m_hr;
- if (!imcLock)
- hr = E_FAIL;
- if (FAILED(hr))
- return hr;
-
- if (!imcLock.get().hCtfImeContext)
- {
- HIMCC hCtfImeContext = ImmCreateIMCC(sizeof(CTFIMECONTEXT));
- if (!hCtfImeContext)
- return E_OUTOFMEMORY;
- imcLock.get().hCtfImeContext = hCtfImeContext;
- }
-
- CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
- CicInputContext *pCicIC = imeContext.get().m_pCicIC;
- if (!pCicIC)
- {
- pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, hIMC);
- if (!pCicIC)
- {
- imeContext.unlock();
- imcLock.unlock();
- DestroyInputContext(pTLS, hIMC);
- return E_OUTOFMEMORY;
- }
-
- if (!pTLS->m_pThreadMgr)
- {
- pCicIC->Release();
- imeContext.unlock();
- imcLock.unlock();
- DestroyInputContext(pTLS, hIMC);
- return E_NOINTERFACE;
- }
-
- imeContext.get().m_pCicIC = pCicIC;
- }
-
- hr = pCicIC->CreateInputContext(pTLS->m_pThreadMgr, imcLock);
- if (FAILED(hr))
- {
- pCicIC->Release();
- imeContext.get().m_pCicIC = NULL;
- }
- else
- {
- if (imcLock.get().hWnd && imcLock.get().hWnd == ::GetFocus())
- {
- GetDocumentManager(imeContext);
- //FIXME
- }
- }
-
- return E_NOTIMPL;
-}
-
-/// @implemented
-HRESULT CicBridge::DestroyInputContext(TLS *pTLS, HIMC hIMC)
-{
- CicIMCLock imcLock(hIMC);
- HRESULT hr = imcLock.m_hr;
- if (!imcLock)
- hr = E_FAIL;
- if (FAILED(hr))
- return hr;
-
- hr = E_FAIL;
- CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
- if (imeContext)
- hr = imeContext.m_hr;
-
- if (SUCCEEDED(hr) && !(imeContext.get().m_dwCicFlags & 1))
- {
- imeContext.get().m_dwCicFlags |= 1;
-
- CicInputContext *pCicIC = imeContext.get().m_pCicIC;
- if (pCicIC)
- {
- imeContext.get().m_pCicIC = NULL;
- hr = pCicIC->DestroyInputContext();
- pCicIC->Release();
- imeContext.get().m_pCicIC = NULL;
- }
- }
-
- if (imcLock.get().hCtfImeContext)
- {
- ImmDestroyIMCC(imcLock.get().hCtfImeContext);
- imcLock.get().hCtfImeContext = NULL;
- hr = S_OK;
- }
-
- return hr;
-}
-
-ITfContext *
-CicBridge::GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext)
-{
- CicInputContext *pCicIC = imeContext.get().m_pCicIC;
- if (!pCicIC)
- return NULL;
- return pCicIC->m_pContext;
-}
-
-/// @unimplemented
-HRESULT CicBridge::OnSetOpenStatus(
- TLS *pTLS,
- ITfThreadMgr_P *pThreadMgr,
- CicIMCLock& imcLock,
- CicInputContext *pCicIC)
-{
- return E_NOTIMPL;
-}
-
-/// Selects the IME context.
-/// @implemented
-HRESULT
-CicBridge::SelectEx(
- _Inout_ TLS *pTLS,
- _Inout_ ITfThreadMgr_P *pThreadMgr,
- _In_ HIMC hIMC,
- _In_ BOOL fSelect,
- _In_ HKL hKL)
-{
- CicIMCLock imcLock(hIMC);
- if (FAILED(imcLock.m_hr))
- return imcLock.m_hr;
-
- CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
- if (!imeContext)
- imeContext.m_hr = E_FAIL;
- if (FAILED(imeContext.m_hr))
- return imeContext.m_hr;
-
- CicInputContext *pCicIC = imeContext.get().m_pCicIC;
- if (pCicIC)
- pCicIC->m_bSelecting = TRUE;
-
- if (fSelect)
- {
- if (pCicIC)
- pCicIC->m_dwUnknown6[1] &= ~1;
- if (imcLock.get().fOpen)
- OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC);
- }
- else
- {
- ITfContext *pContext = GetInputContext(imeContext);
- pThreadMgr->RequestPostponedLock(pContext);
- if (pCicIC)
- pCicIC->m_bSelecting = FALSE;
- if (pContext)
- pContext->Release();
- }
-
- return imeContext.m_hr;
-}
-
-/// Used in CicBridge::EnumCreateInputContextCallback and
-/// CicBridge::EnumDestroyInputContextCallback.
-typedef struct ENUM_CREATE_DESTROY_IC
-{
- TLS *m_pTLS;
- CicBridge *m_pBridge;
-} ENUM_CREATE_DESTROY_IC, *PENUM_CREATE_DESTROY_IC;
-
-/// Creates input context for the current thread.
-/// @implemented
-BOOL CALLBACK CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam)
-{
- PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
- pData->m_pBridge->CreateInputContext(pData->m_pTLS, hIMC);
- return TRUE;
-}
-
-/// Destroys input context for the current thread.
-/// @implemented
-BOOL CALLBACK CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam)
-{
- PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
- pData->m_pBridge->DestroyInputContext(pData->m_pTLS, hIMC);
- return TRUE;
-}
-
-/// @implemented
-HRESULT
-CicBridge::ActivateIMMX(
- _Inout_ TLS *pTLS,
- _Inout_ ITfThreadMgr_P *pThreadMgr)
-{
- HRESULT hr = pThreadMgr->ActivateEx(&m_cliendId, 1);
- if (hr != S_OK)
- {
- m_cliendId = 0;
- return E_FAIL;
- }
-
- if (m_cActivateLocks++ != 0)
- return S_OK;
-
- ITfSourceSingle *pSource = NULL;
- hr = pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void**)&pSource);
- if (FAILED(hr))
- {
- DeactivateIMMX(pTLS, pThreadMgr);
- return hr;
- }
-
- CFunctionProvider *pProvider = new(cicNoThrow) CFunctionProvider(m_cliendId);
- if (!pProvider)
- {
- hr = E_FAIL;
- goto Finish;
- }
-
- pSource->AdviseSingleSink(m_cliendId, IID_ITfFunctionProvider, pProvider);
- pProvider->Release();
-
- if (!m_pDocMgr)
- {
- hr = pThreadMgr->CreateDocumentMgr(&m_pDocMgr);
- if (FAILED(hr))
- {
- hr = E_FAIL;
- goto Finish;
- }
-
- SetCompartmentDWORD(m_cliendId, m_pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS,
TRUE, FALSE);
- }
-
- pThreadMgr->SetSysHookSink(this);
-
- hr = S_OK;
- if (pTLS->m_bDestroyed)
- {
- ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
- ImmEnumInputContext(0, CicBridge::EnumCreateInputContextCallback,
(LPARAM)&Data);
- }
-
-Finish:
- if (FAILED(hr))
- DeactivateIMMX(pTLS, pThreadMgr);
- if (pSource)
- pSource->Release();
- return hr;
-}
-
-/// @implemented
-HRESULT
-CicBridge::DeactivateIMMX(
- _Inout_ TLS *pTLS,
- _Inout_ ITfThreadMgr_P *pThreadMgr)
-{
- if (m_bDeactivating)
- return TRUE;
-
- m_bDeactivating = TRUE;
-
- if (m_cliendId)
- {
- ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
- ImmEnumInputContext(0, CicBridge::EnumDestroyInputContextCallback,
(LPARAM)&Data);
- pTLS->m_bDestroyed = TRUE;
-
- ITfSourceSingle *pSource = NULL;
- if (pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void **)&pSource) ==
S_OK)
- pSource->UnadviseSingleSink(m_cliendId, IID_ITfFunctionProvider);
-
- m_cliendId = 0;
-
- while (m_cActivateLocks > 0)
- {
- --m_cActivateLocks;
- pThreadMgr->Deactivate();
- }
-
- if (pSource)
- pSource->Release();
- }
-
- if (m_pDocMgr)
- {
- m_pDocMgr->Release();
- m_pDocMgr = NULL;
- }
-
- pThreadMgr->SetSysHookSink(NULL);
-
- m_bDeactivating = FALSE;
-
- return S_OK;
-}
-
-/// @implemented
-HRESULT
-CicBridge::InitIMMX(_Inout_ TLS *pTLS)
-{
- if (m_bImmxInited)
- return S_OK;
-
- HRESULT hr = S_OK;
- if (!pTLS->m_pThreadMgr)
- {
- ITfThreadMgr *pThreadMgr = NULL;
- hr = TF_CreateThreadMgr(&pThreadMgr);
- if (FAILED(hr))
- return E_FAIL;
-
- hr = pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void
**)&pTLS->m_pThreadMgr);
- if (pThreadMgr)
- pThreadMgr->Release();
- if (FAILED(hr))
- return E_FAIL;
- }
-
- if (!m_pThreadMgrEventSink)
- {
- m_pThreadMgrEventSink =
- new(cicNoThrow) CThreadMgrEventSink(CThreadMgrEventSink::DIMCallback, NULL,
NULL);
- if (!m_pThreadMgrEventSink)
- {
- UnInitIMMX(pTLS);
- return E_FAIL;
- }
- }
-
- m_pThreadMgrEventSink->SetCallbackPV(m_pThreadMgrEventSink);
- m_pThreadMgrEventSink->_Advise(pTLS->m_pThreadMgr);
-
- if (!pTLS->m_pProfile)
- {
- pTLS->m_pProfile = new(cicNoThrow) CicProfile();
- if (!pTLS->m_pProfile)
- return E_OUTOFMEMORY;
-
- hr = pTLS->m_pProfile->InitProfileInstance(pTLS);
- if (FAILED(hr))
- {
- UnInitIMMX(pTLS);
- return E_FAIL;
- }
- }
-
- hr = pTLS->m_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr_P, (void
**)&m_pKeystrokeMgr);
- if (FAILED(hr))
- {
- UnInitIMMX(pTLS);
- return E_FAIL;
- }
-
- hr = InitDisplayAttrbuteLib(&m_LibThread);
- if (FAILED(hr))
- {
- UnInitIMMX(pTLS);
- return E_FAIL;
- }
-
- m_bImmxInited = TRUE;
- return S_OK;
-}
-
-/// @implemented
-BOOL CicBridge::UnInitIMMX(_Inout_ TLS *pTLS)
-{
- UninitDisplayAttrbuteLib(&m_LibThread);
- TFUninitLib_Thread(&m_LibThread);
-
- if (m_pKeystrokeMgr)
- {
- m_pKeystrokeMgr->Release();
- m_pKeystrokeMgr = NULL;
- }
-
- if (pTLS->m_pProfile)
- {
- pTLS->m_pProfile->Release();
- pTLS->m_pProfile = NULL;
- }
-
- if (m_pThreadMgrEventSink)
- {
- m_pThreadMgrEventSink->_Unadvise();
- m_pThreadMgrEventSink->Release();
- m_pThreadMgrEventSink = NULL;
- }
-
- if (pTLS->m_pThreadMgr)
- {
- pTLS->m_pThreadMgr->Release();
- pTLS->m_pThreadMgr = NULL;
- }
-
- m_bImmxInited = FALSE;
- return TRUE;
-}
-
-/// @implemented
-STDMETHODIMP CicBridge::OnPreFocusDIM(HWND hwnd)
-{
- return S_OK;
-}
-
-/// @unimplemented
-STDMETHODIMP CicBridge::OnSysKeyboardProc(UINT, LONG)
-{
- return E_NOTIMPL;
+ return hr;
}
-/// @implemented
-STDMETHODIMP CicBridge::OnSysShellProc(INT, UINT, LONG)
+HIMC GetActiveContext(VOID)
{
- return S_OK;
+ HWND hwndFocus = ::GetFocus();
+ if (!hwndFocus)
+ hwndFocus = ::GetActiveWindow();
+ return ::ImmGetContext(hwndFocus);
}
/// @implemented
-void
-CicBridge::PostTransMsg(
- _In_ HWND hWnd,
- _In_ INT cTransMsgs,
- _In_ const TRANSMSG *pTransMsgs)
+HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
{
- for (INT i = 0; i < cTransMsgs; ++i, ++pTransMsgs)
+ if (!pLibThread)
+ return E_FAIL;
+
+ if (pLibThread->m_pDisplayAttrMgr)
{
- ::PostMessageW(hWnd, pTransMsgs->message, pTransMsgs->wParam,
pTransMsgs->lParam);
+ pLibThread->m_pDisplayAttrMgr->Release();
+ pLibThread->m_pDisplayAttrMgr = NULL;
}
+
+ return S_OK;
}
+/// Gets the charset from a language ID.
/// @implemented
-HRESULT
-CicBridge::ConfigureGeneral(
- _Inout_ TLS* pTLS,
- _In_ ITfThreadMgr *pThreadMgr,
- _In_ HKL hKL,
- _In_ HWND hWnd)
+BYTE GetCharsetFromLangId(_In_ DWORD dwValue)
{
- CicProfile *pProfile = pTLS->m_pProfile;
- if (!pProfile)
- return E_OUTOFMEMORY;
-
- TF_LANGUAGEPROFILE profile;
- HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD,
&profile);
- if (FAILED(hr))
- return hr;
-
- ITfFunctionProvider *pProvider = NULL;
- hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
- if (FAILED(hr))
- return hr;
-
- ITfFnConfigure *pFnConfigure = NULL;
- hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigure,
(IUnknown**)&pFnConfigure);
- if (FAILED(hr))
- {
- pProvider->Release();
- return hr;
- }
-
- hr = pFnConfigure->Show(hWnd, profile.langid, profile.guidProfile);
-
- pFnConfigure->Release();
- pProvider->Release();
- return hr;
+ CHARSETINFO info;
+ if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, TCI_SRCLOCALE))
+ return 0;
+ return info.ciCharset;
}
+/// Selects or unselects the input context.
/// @implemented
HRESULT
-CicBridge::ConfigureRegisterWord(
- _Inout_ TLS* pTLS,
- _In_ ITfThreadMgr *pThreadMgr,
- _In_ HKL hKL,
- _In_ HWND hWnd,
- _Inout_opt_ LPVOID lpData)
+InternalSelectEx(
+ _In_ HIMC hIMC,
+ _In_ BOOL fSelect,
+ _In_ LANGID LangID)
{
- CicProfile *pProfile = pTLS->m_pProfile;
- if (!pProfile)
- return E_OUTOFMEMORY;
-
- TF_LANGUAGEPROFILE profile;
- HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD,
&profile);
- if (FAILED(hr))
- return hr;
+ CicIMCLock imcLock(hIMC);
+ if (!imcLock)
+ imcLock.m_hr = E_FAIL;
+ if (FAILED(imcLock.m_hr))
+ return imcLock.m_hr;
- ITfFunctionProvider *pProvider = NULL;
- hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
- if (FAILED(hr))
- return hr;
+ if (PRIMARYLANGID(LangID) == LANG_CHINESE)
+ {
+ imcLock.get().cfCandForm[0].dwStyle = 0;
+ imcLock.get().cfCandForm[0].dwIndex = (DWORD)-1;
+ }
- ITfFnConfigureRegisterWord *pFunction = NULL;
- hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigureRegisterWord,
(IUnknown**)&pFunction);
- if (FAILED(hr))
+ if (!fSelect)
{
- pProvider->Release();
- return hr;
+ imcLock.get().fdwInit &= ~INIT_GUIDMAP;
+ return imcLock.m_hr;
}
- REGISTERWORDW* pRegWord = (REGISTERWORDW*)lpData;
- if (pRegWord)
+ if (!imcLock.ClearCand())
+ return imcLock.m_hr;
+
+ // Populate conversion mode
+ if (!(imcLock.get().fdwInit & INIT_CONVERSION))
{
- if (pRegWord->lpWord)
+ DWORD dwConv = (imcLock.get().fdwConversion & IME_CMODE_SOFTKBD);
+ if (LangID)
{
- hr = E_OUTOFMEMORY;
- BSTR bstrWord = SysAllocString(pRegWord->lpWord);
- if (bstrWord)
+ if (PRIMARYLANGID(LangID) == LANG_JAPANESE)
{
- hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile,
bstrWord);
- SysFreeString(bstrWord);
+ dwConv |= IME_CMODE_ROMAN | IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
+ }
+ else if (PRIMARYLANGID(LangID) != LANG_KOREAN)
+ {
+ dwConv |= IME_CMODE_NATIVE;
}
}
- else
- {
- hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, NULL);
- }
+ imcLock.get().fdwConversion |= dwConv;
+ imcLock.get().fdwInit |= INIT_CONVERSION;
}
- pProvider->Release();
- pFunction->Release();
- return hr;
-}
+ // Populate sentence mode
+ imcLock.get().fdwSentence |= IME_SMODE_PHRASEPREDICT;
-/***********************************************************************
- * CicProfile
- */
+ // Populate LOGFONT
+ if (!(imcLock.get().fdwInit & INIT_LOGFONT))
+ {
+ // Get logical font
+ LOGFONTW lf;
+ HDC hDC = ::GetDC(imcLock.get().hWnd);
+ HGDIOBJ hFont = GetCurrentObject(hDC, OBJ_FONT);
+ ::GetObjectW(hFont, sizeof(LOGFONTW), &lf);
+ ::ReleaseDC(imcLock.get().hWnd, hDC);
-/// @unimplemented
-HRESULT
-CicProfile::GetActiveLanguageProfile(
- _In_ HKL hKL,
- _In_ REFGUID rguid,
- _Out_ TF_LANGUAGEPROFILE *pProfile)
-{
- return E_NOTIMPL;
+ imcLock.get().lfFont.W = lf;
+ imcLock.get().fdwInit |= INIT_LOGFONT;
+ }
+ imcLock.get().lfFont.W.lfCharSet = GetCharsetFromLangId(LangID);
+
+ imcLock.InitContext();
+
+ return imcLock.m_hr;
}
+class TLS;
+
/***********************************************************************
* ImeInquire (MSCTFIME.@)
*
@@ -3332,367 +858,6 @@ CtfImeThreadDetach(VOID)
return S_OK;
}
-/***********************************************************************
- * UIComposition
- */
-struct UIComposition
-{
- void OnImeStartComposition(CicIMCLock& imcLock, HWND hUIWnd);
- void OnImeCompositionUpdate(CicIMCLock& imcLock);
- void OnImeEndComposition();
- void OnImeSetContext(CicIMCLock& imcLock, HWND hUIWnd, WPARAM wParam, LPARAM
lParam);
- void OnPaintTheme(WPARAM wParam);
- void OnDestroy();
-
- static LRESULT CALLBACK CompWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam);
-};
-
-/// @unimplemented
-void UIComposition::OnImeStartComposition(CicIMCLock& imcLock, HWND hUIWnd)
-{
- //FIXME
-}
-
-/// @unimplemented
-void UIComposition::OnImeCompositionUpdate(CicIMCLock& imcLock)
-{
- //FIXME
-}
-
-/// @unimplemented
-void UIComposition::OnImeEndComposition()
-{
- //FIXME
-}
-
-/// @unimplemented
-void UIComposition::OnImeSetContext(CicIMCLock& imcLock, HWND hUIWnd, WPARAM wParam,
LPARAM lParam)
-{
- //FIXME
-}
-
-/// @unimplemented
-void UIComposition::OnPaintTheme(WPARAM wParam)
-{
- //FIXME
-}
-
-/// @unimplemented
-void UIComposition::OnDestroy()
-{
- //FIXME
-}
-
-/// @unimplemented
-LRESULT CALLBACK
-UIComposition::CompWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- if (uMsg == WM_CREATE)
- return -1; // FIXME
- return 0;
-}
-
-/***********************************************************************
- * UI
- */
-struct UI
-{
- HWND m_hWnd;
- UIComposition *m_pComp;
-
- UI(HWND hWnd);
- virtual ~UI();
-
- HRESULT _Create();
- void _Destroy();
-
- static void OnCreate(HWND hWnd);
- static void OnDestroy(HWND hWnd);
- void OnImeSetContext(CicIMCLock& imcLock, WPARAM wParam, LPARAM lParam);
-};
-
-// For GetWindowLongPtr/SetWindowLongPtr
-#define UIGWLP_HIMC 0
-#define UIGWLP_UI sizeof(HIMC)
-#define UIGWLP_SIZE (UIGWLP_UI + sizeof(UI*))
-
-/// @implemented
-UI::UI(HWND hWnd) : m_hWnd(hWnd)
-{
-}
-
-/// @implemented
-UI::~UI()
-{
- delete m_pComp;
-}
-
-/// @unimplemented
-HRESULT UI::_Create()
-{
- m_pComp = new(cicNoThrow) UIComposition();
- if (!m_pComp)
- return E_OUTOFMEMORY;
-
- SetWindowLongPtrW(m_hWnd, UIGWLP_UI, (LONG_PTR)this);
- //FIXME
- return S_OK;
-}
-
-/// @implemented
-void UI::_Destroy()
-{
- m_pComp->OnDestroy();
- SetWindowLongPtrW(m_hWnd, UIGWLP_UI, 0);
-}
-
-/// @implemented
-void UI::OnCreate(HWND hWnd)
-{
- UI *pUI = (UI*)GetWindowLongPtrW(hWnd, UIGWLP_UI);
- if (pUI)
- return;
- pUI = new(cicNoThrow) UI(hWnd);
- if (pUI)
- pUI->_Create();
-}
-
-/// @implemented
-void UI::OnDestroy(HWND hWnd)
-{
- UI *pUI = (UI*)GetWindowLongPtrW(hWnd, UIGWLP_UI);
- if (!pUI)
- return;
-
- pUI->_Destroy();
- delete pUI;
-}
-
-/// @implemented
-void UI::OnImeSetContext(CicIMCLock& imcLock, WPARAM wParam, LPARAM lParam)
-{
- m_pComp->OnImeSetContext(imcLock, m_hWnd, wParam, lParam);
-}
-
-/***********************************************************************
- * CIMEUIWindowHandler
- */
-
-struct CIMEUIWindowHandler
-{
- static LRESULT CALLBACK ImeUIMsImeHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam);
- static LRESULT CALLBACK ImeUIMsImeMouseHandler(HWND hWnd, WPARAM wParam, LPARAM
lParam);
- static LRESULT CALLBACK ImeUIMsImeModeBiasHandler(HWND hWnd, WPARAM wParam, LPARAM
lParam);
- static LRESULT CALLBACK ImeUIMsImeReconvertRequest(HWND hWnd, WPARAM wParam, LPARAM
lParam);
- static LRESULT CALLBACK ImeUIWndProcWorker(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
-};
-
-/// @unimplemented
-LRESULT CALLBACK
-CIMEUIWindowHandler::ImeUIMsImeMouseHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
-{
- return 0; //FIXME
-}
-
-/// @unimplemented
-LRESULT CALLBACK
-CIMEUIWindowHandler::ImeUIMsImeModeBiasHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
-{
- return 0; //FIXME
-}
-
-/// @unimplemented
-LRESULT CALLBACK
-CIMEUIWindowHandler::ImeUIMsImeReconvertRequest(HWND hWnd, WPARAM wParam, LPARAM lParam)
-{
- return 0; //FIXME
-}
-
-/// @implemented
-LRESULT CALLBACK
-CIMEUIWindowHandler::ImeUIMsImeHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
-{
- if (uMsg == WM_MSIME_MOUSE)
- return ImeUIMsImeMouseHandler(hWnd, wParam, lParam);
- if (uMsg == WM_MSIME_MODEBIAS)
- return ImeUIMsImeModeBiasHandler(hWnd, wParam, lParam);
- if (uMsg == WM_MSIME_RECONVERTREQUEST)
- return ImeUIMsImeReconvertRequest(hWnd, wParam, lParam);
- if (uMsg == WM_MSIME_SERVICE)
- {
- TLS *pTLS = TLS::GetTLS();
- if (pTLS && pTLS->m_pProfile)
- {
- LANGID LangID;
- pTLS->m_pProfile->GetLangId(&LangID);
- if (PRIMARYLANGID(LangID) == LANG_KOREAN)
- return FALSE;
- }
- return TRUE;
- }
- return 0;
-}
-
-/// @unimplemented
-LRESULT CALLBACK
-CIMEUIWindowHandler::ImeUIWndProcWorker(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
-{
- TLS *pTLS = TLS::GetTLS();
- if (pTLS && (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON))
- {
- if (uMsg == WM_CREATE)
- return -1;
- return DefWindowProcW(hWnd, uMsg, wParam, lParam);
- }
-
- switch (uMsg)
- {
- case WM_CREATE:
- {
- UI::OnCreate(hWnd);
- break;
- }
- case WM_DESTROY:
- case WM_ENDSESSION:
- {
- UI::OnDestroy(hWnd);
- break;
- }
- case WM_IME_STARTCOMPOSITION:
- case WM_IME_COMPOSITION:
- case WM_IME_ENDCOMPOSITION:
- case WM_IME_SETCONTEXT:
- case WM_IME_NOTIFY:
- case WM_IME_SELECT:
- case WM_TIMER:
- {
- HIMC hIMC = (HIMC)GetWindowLongPtrW(hWnd, UIGWLP_HIMC);
- UI* pUI = (UI*)GetWindowLongPtrW(hWnd, UIGWLP_UI);
- CicIMCLock imcLock(hIMC);
- switch (uMsg)
- {
- case WM_IME_STARTCOMPOSITION:
- {
- pUI->m_pComp->OnImeStartComposition(imcLock, pUI->m_hWnd);
- break;
- }
- case WM_IME_COMPOSITION:
- {
- if (lParam & GCS_COMPSTR)
- {
- pUI->m_pComp->OnImeCompositionUpdate(imcLock);
- ::SetTimer(hWnd, 0, 10, NULL);
- //FIXME
- }
- break;
- }
- case WM_IME_ENDCOMPOSITION:
- {
- ::KillTimer(hWnd, 0);
- pUI->m_pComp->OnImeEndComposition();
- break;
- }
- case WM_IME_SETCONTEXT:
- {
- pUI->OnImeSetContext(imcLock, wParam, lParam);
- ::KillTimer(hWnd, 1);
- ::SetTimer(hWnd, 1, 300, NULL);
- break;
- }
- case WM_TIMER:
- {
- //FIXME
- ::KillTimer(hWnd, wParam);
- break;
- }
- case WM_IME_NOTIFY:
- case WM_IME_SELECT:
- default:
- {
- pUI->m_pComp->OnPaintTheme(wParam);
- break;
- }
- }
- break;
- }
- default:
- {
- if (IsMsImeMessage(uMsg))
- return CIMEUIWindowHandler::ImeUIMsImeHandler(hWnd, uMsg, wParam,
lParam);
- return DefWindowProcW(hWnd, uMsg, wParam, lParam);
- }
- }
-
- return 0;
-}
-
-/// @implemented
-EXTERN_C LRESULT CALLBACK
-UIWndProc(
- _In_ HWND hWnd,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam)
-{
- return CIMEUIWindowHandler::ImeUIWndProcWorker(hWnd, uMsg, wParam, lParam);
-}
-
-/// @unimplemented
-BOOL RegisterImeClass(VOID)
-{
- WNDCLASSEXW wcx;
-
- if (!GetClassInfoExW(g_hInst, L"MSCTFIME UI", &wcx))
- {
- ZeroMemory(&wcx, sizeof(wcx));
- wcx.cbSize = sizeof(WNDCLASSEXW);
- wcx.cbWndExtra = UIGWLP_SIZE;
- wcx.hIcon = LoadIconW(0, (LPCWSTR)IDC_ARROW);
- wcx.hInstance = g_hInst;
- wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
- wcx.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
- wcx.style = CS_IME | CS_GLOBALCLASS;
- wcx.lpfnWndProc = UIWndProc;
- wcx.lpszClassName = L"MSCTFIME UI";
- if (!RegisterClassExW(&wcx))
- return FALSE;
- }
-
- if (!GetClassInfoExW(g_hInst, L"MSCTFIME Composition", &wcx))
- {
- ZeroMemory(&wcx, sizeof(wcx));
- wcx.cbSize = sizeof(WNDCLASSEXW);
- wcx.cbWndExtra = sizeof(DWORD);
- wcx.hIcon = NULL;
- wcx.hInstance = g_hInst;
- wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_IBEAM);
- wcx.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
- wcx.style = CS_IME | CS_HREDRAW | CS_VREDRAW;
- wcx.lpfnWndProc = UIComposition::CompWndProc;
- wcx.lpszClassName = L"MSCTFIME Composition";
- if (!RegisterClassExW(&wcx))
- return FALSE;
- }
-
- return TRUE;
-}
-
-/// @implemented
-VOID UnregisterImeClass(VOID)
-{
- WNDCLASSEXW wcx;
-
- GetClassInfoExW(g_hInst, L"MSCTFIME UI", &wcx);
- UnregisterClassW(L"MSCTFIME UI", g_hInst);
- DestroyIcon(wcx.hIcon);
- DestroyIcon(wcx.hIconSm);
-
- GetClassInfoExW(g_hInst, L"MSCTFIME Composition", &wcx);
- UnregisterClassW(L"MSCTFIME Composition", g_hInst);
- DestroyIcon(wcx.hIcon);
- DestroyIcon(wcx.hIconSm);
-}
-
/// @implemented
BOOL AttachIME(VOID)
{
diff --git a/dll/ime/msctfime/msctfime.h b/dll/ime/msctfime/msctfime.h
index 040ecc11c96..f7ada8fbd6e 100644
--- a/dll/ime/msctfime/msctfime.h
+++ b/dll/ime/msctfime/msctfime.h
@@ -34,6 +34,23 @@
#include <wine/debug.h>
+EXTERN_C BOOLEAN WINAPI DllShutdownInProgress(VOID);
+
+HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
+HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
+
+DEFINE_GUID(GUID_COMPARTMENT_CTFIME_DIMFLAGS, 0xA94C5FD2, 0xC471, 0x4031, 0x95,
0x46, 0x70, 0x9C, 0x17, 0x30, 0x0C, 0xB9);
+DEFINE_GUID(GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT, 0x85A688F7, 0x6DC8, 0x4F17, 0xA8,
0x3A, 0xB1, 0x1C, 0x09, 0xCD, 0xD7, 0xBF);
+
#include "resource.h"
+#include "bridge.h"
+#include "compartment.h"
+#include "functions.h"
+#include "inputcontext.h"
+#include "profile.h"
+#include "sinks.h"
+#include "tls.h"
+#include "ui.h"
+
extern HINSTANCE g_hInst;
diff --git a/dll/ime/msctfime/profile.cpp b/dll/ime/msctfime/profile.cpp
new file mode 100644
index 00000000000..9ec7cd12ff3
--- /dev/null
+++ b/dll/ime/msctfime/profile.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "msctfime.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
+
+/// @implemented
+CicProfile::CicProfile()
+{
+ m_dwFlags &= 0xFFFFFFF0;
+ m_cRefs = 1;
+ m_pIPProfiles = NULL;
+ m_pActiveLanguageProfileNotifySink = NULL;
+ m_LangID1 = 0;
+ m_nCodePage = CP_ACP;
+ m_LangID2 = 0;
+ m_dwUnknown1 = 0;
+}
+
+/// @implemented
+CicProfile::~CicProfile()
+{
+ if (m_pIPProfiles)
+ {
+ if (m_LangID1)
+ m_pIPProfiles->ChangeCurrentLanguage(m_LangID1);
+
+ m_pIPProfiles->Release();
+ m_pIPProfiles = NULL;
+ }
+
+ if (m_pActiveLanguageProfileNotifySink)
+ {
+ m_pActiveLanguageProfileNotifySink->_Unadvise();
+ m_pActiveLanguageProfileNotifySink->Release();
+ m_pActiveLanguageProfileNotifySink = NULL;
+ }
+}
+
+/// @implemented
+STDMETHODIMP CicProfile::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicProfile::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CicProfile::Release()
+{
+ if (::InterlockedDecrement(&m_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRefs;
+}
+
+/// @implemented
+INT CALLBACK
+CicProfile::ActiveLanguageProfileNotifySinkCallback(
+ REFGUID rguid1,
+ REFGUID rguid2,
+ BOOL fActivated,
+ LPVOID pUserData)
+{
+ CicProfile *pThis = (CicProfile *)pUserData;
+ pThis->m_dwFlags &= ~0xE;
+ return 0;
+}
+
+/// @implemented
+HRESULT CicProfile::GetCodePageA(_Out_ UINT *puCodePage)
+{
+ if (!puCodePage)
+ return E_INVALIDARG;
+
+ if (m_dwFlags & 2)
+ {
+ *puCodePage = m_nCodePage;
+ return S_OK;
+ }
+
+ *puCodePage = 0;
+
+ LANGID LangID;
+ HRESULT hr = GetLangId(&LangID);
+ if (FAILED(hr))
+ return E_FAIL;
+
+ WCHAR szBuff[12];
+ INT cch = ::GetLocaleInfoW(LangID, LOCALE_IDEFAULTANSICODEPAGE, szBuff,
_countof(szBuff));
+ if (cch)
+ {
+ szBuff[cch] = 0;
+ m_nCodePage = *puCodePage = wcstoul(szBuff, NULL, 10);
+ m_dwFlags |= 2;
+ }
+
+ return S_OK;
+}
+
+/// @implemented
+HRESULT CicProfile::GetLangId(_Out_ LANGID *pLangID)
+{
+ *pLangID = 0;
+
+ if (!m_pIPProfiles)
+ return E_FAIL;
+
+ if (m_dwFlags & 4)
+ {
+ *pLangID = m_LangID2;
+ return S_OK;
+ }
+
+ HRESULT hr = m_pIPProfiles->GetCurrentLanguage(pLangID);
+ if (SUCCEEDED(hr))
+ {
+ m_dwFlags |= 4;
+ m_LangID2 = *pLangID;
+ }
+
+ return hr;
+}
+
+/// @implemented
+HRESULT
+CicProfile::InitProfileInstance(_Inout_ TLS *pTLS)
+{
+ HRESULT hr = TF_CreateInputProcessorProfiles(&m_pIPProfiles);
+ if (FAILED(hr))
+ return hr;
+
+ if (!m_pActiveLanguageProfileNotifySink)
+ {
+ CActiveLanguageProfileNotifySink *pSink =
+ new(cicNoThrow) CActiveLanguageProfileNotifySink(
+ CicProfile::ActiveLanguageProfileNotifySinkCallback, this);
+ if (!pSink)
+ {
+ m_pIPProfiles->Release();
+ m_pIPProfiles = NULL;
+ return E_FAIL;
+ }
+ m_pActiveLanguageProfileNotifySink = pSink;
+ }
+
+ if (pTLS->m_pThreadMgr)
+ m_pActiveLanguageProfileNotifySink->_Advise(pTLS->m_pThreadMgr);
+
+ return hr;
+}
+
+/// @unimplemented
+HRESULT
+CicProfile::GetActiveLanguageProfile(
+ _In_ HKL hKL,
+ _In_ REFGUID rguid,
+ _Out_ TF_LANGUAGEPROFILE *pProfile)
+{
+ return E_NOTIMPL;
+}
diff --git a/dll/ime/msctfime/profile.h b/dll/ime/msctfime/profile.h
new file mode 100644
index 00000000000..2943750ad46
--- /dev/null
+++ b/dll/ime/msctfime/profile.h
@@ -0,0 +1,51 @@
+/*
+ * 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
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#pragma once
+
+#include "sinks.h"
+
+class CicProfile : public IUnknown
+{
+protected:
+ ITfInputProcessorProfiles *m_pIPProfiles;
+ CActiveLanguageProfileNotifySink *m_pActiveLanguageProfileNotifySink;
+ LANGID m_LangID1;
+ WORD m_padding1;
+ DWORD m_dwFlags;
+ UINT m_nCodePage;
+ LANGID m_LangID2;
+ WORD m_padding2;
+ DWORD m_dwUnknown1;
+ LONG m_cRefs;
+
+ static INT CALLBACK
+ ActiveLanguageProfileNotifySinkCallback(
+ REFGUID rguid1,
+ REFGUID rguid2,
+ BOOL fActivated,
+ LPVOID pUserData);
+
+public:
+ CicProfile();
+ virtual ~CicProfile();
+
+ // IUnknown interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ HRESULT
+ GetActiveLanguageProfile(
+ _In_ HKL hKL,
+ _In_ REFGUID rguid,
+ _Out_ TF_LANGUAGEPROFILE *pProfile);
+ HRESULT GetLangId(_Out_ LANGID *pLangID);
+ HRESULT GetCodePageA(_Out_ UINT *puCodePage);
+
+ HRESULT InitProfileInstance(_Inout_ TLS *pTLS);
+};
diff --git a/dll/ime/msctfime/sinks.cpp b/dll/ime/msctfime/sinks.cpp
new file mode 100644
index 00000000000..235079c4d94
--- /dev/null
+++ b/dll/ime/msctfime/sinks.cpp
@@ -0,0 +1,539 @@
+/*
... 1325 lines suppressed ...