diff --git a/WeaselTSF/CandidateList.cpp b/WeaselTSF/CandidateList.cpp index b86443582..09dd3cd24 100644 --- a/WeaselTSF/CandidateList.cpp +++ b/WeaselTSF/CandidateList.cpp @@ -255,7 +255,8 @@ void CandidateList::UpdateInputPosition(RECT const & rc) void CandidateList::Destroy() { - Show(false); + //_EndUI(); + Show(FALSE); _ui->Destroy(); _curp = NULL; } @@ -332,3 +333,8 @@ void WeaselTSF::_UpdateUI(const Context & ctx, const Status & status) { _cand->UpdateUI(ctx, status); } + +void WeaselTSF::_DeleteCandidateList() +{ + _cand->Destroy(); +} diff --git a/WeaselTSF/Compartment.cpp b/WeaselTSF/Compartment.cpp index 06b294371..2387a5cf0 100644 --- a/WeaselTSF/Compartment.cpp +++ b/WeaselTSF/Compartment.cpp @@ -1,5 +1,102 @@ #include "stdafx.h" #include "WeaselTSF.h" +#include "Compartment.h" +#include +#include +#include + +STDAPI CCompartmentEventSink::QueryInterface(REFIID riid, _Outptr_ void **ppvObj) +{ + if (ppvObj == nullptr) + return E_INVALIDARG; + + *ppvObj = nullptr; + + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_ITfCompartmentEventSink)) + { + *ppvObj = (CCompartmentEventSink *)this; + } + + if (*ppvObj) + { + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +STDAPI_(ULONG) CCompartmentEventSink::AddRef() +{ + return ++_refCount; +} + +STDAPI_(ULONG) CCompartmentEventSink::Release() +{ + LONG cr = --_refCount; + + assert(_refCount >= 0); + + if (_refCount == 0) + { + delete this; + } + + return cr; +} + +STDAPI CCompartmentEventSink::OnChange(_In_ REFGUID guidCompartment) +{ + return _callback(guidCompartment); +} + +HRESULT CCompartmentEventSink::_Advise(_In_ IUnknown *punk, _In_ REFGUID guidCompartment) +{ + HRESULT hr = S_OK; + ITfCompartmentMgr* pCompartmentMgr = nullptr; + ITfSource* pSource = nullptr; + + hr = punk->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompartmentMgr); + if (FAILED(hr)) + { + return hr; + } + + hr = pCompartmentMgr->GetCompartment(guidCompartment, &_compartment); + if (SUCCEEDED(hr)) + { + hr = _compartment->QueryInterface(IID_ITfSource, (void **)&pSource); + if (SUCCEEDED(hr)) + { + hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &_cookie); + pSource->Release(); + } + } + + pCompartmentMgr->Release(); + + return hr; +} +HRESULT CCompartmentEventSink::_Unadvise() +{ + HRESULT hr = S_OK; + ITfSource* pSource = nullptr; + + hr = _compartment->QueryInterface(IID_ITfSource, (void **)&pSource); + if (SUCCEEDED(hr)) + { + hr = pSource->UnadviseSink(_cookie); + pSource->Release(); + } + + _compartment->Release(); + _compartment = nullptr; + _cookie = 0; + + return hr; +} + BOOL WeaselTSF::_IsKeyboardDisabled() { @@ -100,4 +197,42 @@ HRESULT WeaselTSF::_SetKeyboardOpen(BOOL fOpen) } return hr; -} \ No newline at end of file +} + +BOOL WeaselTSF::_InitCompartment() +{ + using namespace std::placeholders; + + auto callback = std::bind(&WeaselTSF::_HandleCompartment, this, _1); + _pKeyboardCompartmentSink = new CCompartmentEventSink(callback); + if (!_pKeyboardCompartmentSink) + return FALSE; + DWORD hr = _pKeyboardCompartmentSink->_Advise( + _pThreadMgr, + GUID_COMPARTMENT_KEYBOARD_OPENCLOSE + ); + return SUCCEEDED(hr); +} + +void WeaselTSF::_UninitCompartment() +{ + if (_pKeyboardCompartmentSink) { + _pKeyboardCompartmentSink->_Unadvise(); + _pKeyboardCompartmentSink->Release(); + _pKeyboardCompartmentSink = NULL; + } + +} + +HRESULT WeaselTSF::_HandleCompartment(REFGUID guidCompartment) +{ + if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE)) + { + BOOL isOpen = _IsKeyboardOpen(); + if (isOpen) { + m_client.TrayCommand(ID_WEASELTRAY_DISABLE_ASCII); + } + _EnableLanguageBar(isOpen); + } + return S_OK; +} diff --git a/WeaselTSF/Compartment.h b/WeaselTSF/Compartment.h new file mode 100644 index 000000000..bda694a8d --- /dev/null +++ b/WeaselTSF/Compartment.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include + +class CCompartmentEventSink : public ITfCompartmentEventSink +{ +public: + using Callback = std::function; + CCompartmentEventSink(Callback callback) + : _callback(callback), _refCount(1) {}; + ~CCompartmentEventSink() = default; + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void **ppvObj); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // ITfCompartmentEventSink + STDMETHODIMP OnChange(_In_ REFGUID guid); + + // function + HRESULT _Advise(_In_ IUnknown *punk, _In_ REFGUID guidCompartment); + HRESULT _Unadvise(); + +private: + ITfCompartment * _compartment; + DWORD _cookie; + Callback _callback; + + LONG _refCount; +}; diff --git a/WeaselTSF/EditSession.cpp b/WeaselTSF/EditSession.cpp index e35cdce00..e2e15a237 100644 --- a/WeaselTSF/EditSession.cpp +++ b/WeaselTSF/EditSession.cpp @@ -7,15 +7,14 @@ STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) { // get commit string from server std::wstring commit; - weasel::Status status; weasel::Config config; auto context = std::make_shared(); - weasel::ResponseParser parser(&commit, context.get(), &status, &config, &_cand->style()); + weasel::ResponseParser parser(&commit, context.get(), &_status, &config, &_cand->style()); bool ok = m_client.GetResponseData(std::ref(parser)); - _UpdateUI(*context, status); - _UpdateLanguageBar(status); + _UpdateUI(*context, _status); + _UpdateLanguageBar(_status); if (ok) { @@ -29,11 +28,11 @@ STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) _InsertText(_pEditSessionContext, commit); _EndComposition(_pEditSessionContext, false); } - if (status.composing && !_IsComposing()) + if (_status.composing && !_IsComposing()) { _StartComposition(_pEditSessionContext, _fCUASWorkaroundEnabled && !config.inline_preedit); } - else if (!status.composing && _IsComposing()) + else if (!_status.composing && _IsComposing()) { _EndComposition(_pEditSessionContext, true); } diff --git a/WeaselTSF/Globals.cpp b/WeaselTSF/Globals.cpp index ec41b1bb8..923fccda7 100644 --- a/WeaselTSF/Globals.cpp +++ b/WeaselTSF/Globals.cpp @@ -32,3 +32,6 @@ const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT = const GUID GUID_LBI_INPUTMODE = { 0x2C77A81E, 0x41CC, 0x4178, { 0xA3, 0xA7, 0x5F, 0x8A, 0x98, 0x75, 0x68, 0xE6 } }; + +const GUID GUID_IME_MODE_PRESERVED_KEY = +{ 0x0bd899fc, 0xa8f7, 0x4b42, { 0xa9, 0x6d, 0xce, 0xc7, 0xc5, 0x0e, 0x0e, 0xae } }; diff --git a/WeaselTSF/Globals.h b/WeaselTSF/Globals.h index d828997b3..fc8980e88 100644 --- a/WeaselTSF/Globals.h +++ b/WeaselTSF/Globals.h @@ -35,4 +35,5 @@ extern const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT; #endif extern const GUID GUID_LBI_INPUTMODE; +extern const GUID GUID_IME_MODE_PRESERVED_KEY; diff --git a/WeaselTSF/KeyEventSink.cpp b/WeaselTSF/KeyEventSink.cpp index a97a4add0..1cd4d5ac8 100644 --- a/WeaselTSF/KeyEventSink.cpp +++ b/WeaselTSF/KeyEventSink.cpp @@ -135,6 +135,25 @@ void WeaselTSF::_UninitKeyEventSink() BOOL WeaselTSF::_InitPreservedKey() { return TRUE; +#if 0 + ComPtr pKeystrokeMgr; + if (_pThreadMgr->QueryInterface(pKeystrokeMgr.GetAddressOf()) != S_OK) + { + return FALSE; + } + TF_PRESERVEDKEY preservedKeyImeMode; + + /* Define SHIFT ONLY for now */ + preservedKeyImeMode.uVKey = VK_SHIFT; + preservedKeyImeMode.uModifiers = TF_MOD_ON_KEYUP; + + auto hr = pKeystrokeMgr->PreserveKey( + _tfClientId, + GUID_IME_MODE_PRESERVED_KEY, + &preservedKeyImeMode, L"", 0); + + return SUCCEEDED(hr); +#endif } void WeaselTSF::_UninitPreservedKey() diff --git a/WeaselTSF/LanguageBar.cpp b/WeaselTSF/LanguageBar.cpp index 896abb1a7..1aa019196 100644 --- a/WeaselTSF/LanguageBar.cpp +++ b/WeaselTSF/LanguageBar.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include #include "WeaselTSF.h" +#include "Compartment.h" static const DWORD LANGBARITEMSINK_COOKIE = 0x42424242; @@ -60,16 +61,19 @@ class CLangBarItemButton: public ITfLangBarItemButton, public ITfSource STDMETHODIMP UnadviseSink(DWORD dwCookie); void UpdateStatus(weasel::Status stat); + void SetStatus(DWORD dwStatus, BOOL fSet); private: GUID _guid; WeaselTSF *_pTextService; ITfLangBarItemSink *_pLangBarItemSink; LONG _cRef; /* COM Reference count */ + DWORD _status; bool ascii_mode; }; CLangBarItemButton::CLangBarItemButton(WeaselTSF *pTextService, REFGUID guid) + : _status(0) { DllAddRef(); @@ -130,13 +134,14 @@ STDAPI CLangBarItemButton::GetInfo(TF_LANGBARITEMINFO *pInfo) STDAPI CLangBarItemButton::GetStatus(DWORD *pdwStatus) { - *pdwStatus = 0; + *pdwStatus = _status; return S_OK; } STDAPI CLangBarItemButton::Show(BOOL fShow) { - return E_NOTIMPL; + SetStatus(TF_LBI_STATUS_HIDDEN, fShow ? FALSE : TRUE); + return S_OK; } STDAPI CLangBarItemButton::GetTooltipString(BSTR *pbstrToolTip) @@ -233,6 +238,34 @@ void CLangBarItemButton::UpdateStatus(weasel::Status stat) } } +void CLangBarItemButton::SetStatus(DWORD dwStatus, BOOL fSet) +{ + BOOL isChange = FALSE; + + if (fSet) + { + if (!(_status & dwStatus)) + { + _status |= dwStatus; + isChange = TRUE; + } + } + else + { + if (_status & dwStatus) + { + _status &= ~dwStatus; + isChange = TRUE; + } + } + + if (isChange && _pLangBarItemSink) + { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + + return; +} void WeaselTSF::_HandleLangBarMenuSelect(UINT wID) @@ -288,6 +321,7 @@ BOOL WeaselTSF::_InitLanguageBar() goto Exit; } + _pLangBarButton->Show(TRUE); fRet = TRUE; Exit: @@ -317,3 +351,16 @@ void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) if (!_pLangBarButton) return; _pLangBarButton->UpdateStatus(stat); } + +void WeaselTSF::_ShowLanguageBar(BOOL show) +{ + if (!_pLangBarButton) return; + _pLangBarButton->Show(show); + +} + +void WeaselTSF::_EnableLanguageBar(BOOL enable) +{ + if (!_pLangBarButton) return; + _pLangBarButton->SetStatus(TF_LBI_STATUS_DISABLED, !enable); +} diff --git a/WeaselTSF/WeaselTSF.cpp b/WeaselTSF/WeaselTSF.cpp index ca77da240..2dade8be1 100644 --- a/WeaselTSF/WeaselTSF.cpp +++ b/WeaselTSF/WeaselTSF.cpp @@ -113,6 +113,8 @@ STDAPI WeaselTSF::Deactivate() _UninitLanguageBar(); + _UninitCompartment(); + if (_pThreadMgr != NULL) { _pThreadMgr->Release(); @@ -150,7 +152,6 @@ STDAPI WeaselTSF::ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DW if (!_InitPreservedKey()) goto ExitError; - // TODO not yet complete _pLangBarButton = NULL; if (!_InitLanguageBar()) goto ExitError; @@ -158,6 +159,9 @@ STDAPI WeaselTSF::ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DW if (!_IsKeyboardOpen()) _SetKeyboardOpen(TRUE); + if (!_InitCompartment()) + goto ExitError; + _EnsureServerConnected(); return S_OK; @@ -177,6 +181,22 @@ STDMETHODIMP WeaselTSF::OnKillThreadFocus() return S_OK; } +STDMETHODIMP WeaselTSF::OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL isActivated) +{ + if (!IsEqualCLSID(clsid, c_clsidTextService)) + { + return S_OK; + } + + if (isActivated) { + _ShowLanguageBar(TRUE); + } + else { + _DeleteCandidateList(); + _ShowLanguageBar(FALSE); + } + return S_OK; +} void WeaselTSF::_EnsureServerConnected() { @@ -185,11 +205,10 @@ void WeaselTSF::_EnsureServerConnected() m_client.Disconnect(); m_client.Connect(NULL); m_client.StartSession(); - weasel::Status status; - weasel::ResponseParser parser(NULL, NULL, &status, NULL, &_cand->style()); + weasel::ResponseParser parser(NULL, NULL, &_status, NULL, &_cand->style()); bool ok = m_client.GetResponseData(std::ref(parser)); if (ok) { - _UpdateLanguageBar(status); + _UpdateLanguageBar(_status); } } } \ No newline at end of file diff --git a/WeaselTSF/WeaselTSF.h b/WeaselTSF/WeaselTSF.h index e7dcac2d0..b6e08e893 100644 --- a/WeaselTSF/WeaselTSF.h +++ b/WeaselTSF/WeaselTSF.h @@ -4,10 +4,13 @@ #include "Globals.h" #include "WeaselIPC.h" +#include + namespace weasel { class CandidateList; } class CLangBarItemButton; +class CCompartmentEventSink; class WeaselTSF: public ITfTextInputProcessorEx, @@ -17,6 +20,7 @@ class WeaselTSF: public ITfKeyEventSink, public ITfCompositionSink, public ITfThreadFocusSink, + public ITfActiveLanguageProfileNotifySink, public ITfEditSession { public: @@ -65,6 +69,12 @@ class WeaselTSF: /* ITfEditSession */ STDMETHODIMP DoEditSession(TfEditCookie ec); + + /* ITfActiveLanguageProfileNotifySink */ + STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL isActivated); + + ///* ITfCompartmentEventSink */ + //STDMETHODIMP OnChange(_In_ REFGUID guid); /* Compartments */ BOOL _IsKeyboardDisabled(); @@ -111,10 +121,18 @@ class WeaselTSF: BOOL _InitLanguageBar(); void _UninitLanguageBar(); void _UpdateLanguageBar(weasel::Status stat); - + void _ShowLanguageBar(BOOL show); + void _EnableLanguageBar(BOOL enable); + BOOL _InsertText(ITfContext *pContext, const std::wstring& ext); void _AbortComposition(bool clear = true); + void _DeleteCandidateList(); + + BOOL _InitCompartment(); + void _UninitCompartment(); + HRESULT _HandleCompartment(REFGUID guidCompartment); + bool isImmersive() const { return (_activateFlags & TF_TMF_IMMERSIVEMODE) != 0; } @@ -131,6 +149,8 @@ class WeaselTSF: ITfContext *_pEditSessionContext; std::wstring _editSessionText; + CCompartmentEventSink *_pKeyboardCompartmentSink; + ITfComposition *_pComposition; CLangBarItemButton *_pLangBarButton; @@ -145,4 +165,7 @@ class WeaselTSF: /* Weasel Related */ weasel::Client m_client; DWORD _activateFlags; + + /* IME status */ + weasel::Status _status; }; diff --git a/WeaselTSF/WeaselTSF.vcxproj b/WeaselTSF/WeaselTSF.vcxproj index 06abfca4d..1d7e831de 100644 --- a/WeaselTSF/WeaselTSF.vcxproj +++ b/WeaselTSF/WeaselTSF.vcxproj @@ -434,6 +434,7 @@ + diff --git a/WeaselTSF/WeaselTSF.vcxproj.filters b/WeaselTSF/WeaselTSF.vcxproj.filters index a062a2d8d..20bf7b0f4 100644 --- a/WeaselTSF/WeaselTSF.vcxproj.filters +++ b/WeaselTSF/WeaselTSF.vcxproj.filters @@ -83,6 +83,9 @@ Header Files + + Header Files + diff --git a/include/ComPtr.h b/include/ComPtr.h index 654b416be..c1c656e14 100644 --- a/include/ComPtr.h +++ b/include/ComPtr.h @@ -72,6 +72,11 @@ class ComPtr return m_ptr == null; } + bool operator!=(std::nullptr_t null) noexcept + { + return m_ptr != null; + } + template ComPtr & operator=(ComPtr const & other) noexcept {