/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef TSFStaticSink_h #define TSFStaticSink_h #include #include #include #include "TSFTextInputProcessorList.h" #include "WinUtils.h" #include "mozilla/RefPtr.h" #include "mozilla/StaticPtr.h" namespace mozilla::widget { class TSFStaticSink final : public ITfInputProcessorProfileActivationSink { public: static TSFStaticSink* GetInstance(); static void Shutdown() { if (sInstance) { sInstance->Destroy(); sInstance = nullptr; } } bool Init(ITfThreadMgr* aThreadMgr, ITfInputProcessorProfiles* aInputProcessorProfiles); STDMETHODIMP QueryInterface(REFIID riid, void** ppv) { *ppv = nullptr; if (IID_IUnknown == riid || IID_ITfInputProcessorProfileActivationSink == riid) { *ppv = static_cast(this); } if (*ppv) { AddRef(); return S_OK; } return E_NOINTERFACE; } NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFStaticSink) [[nodiscard]] const nsString& GetActiveTIPKeyboardDescription() const { return mActiveTIPKeyboardDescription; } [[nodiscard]] static bool IsIMM_IMEActive() { // Use IMM API until TSFStaticSink starts to work. if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) { return IsIMM_IME(::GetKeyboardLayout(0)); } return sInstance->mIsIMM_IME; } [[nodiscard]] static bool IsIMM_IME(HKL aHKL) { return (::ImmGetIMEFileNameW(aHKL, nullptr, 0) > 0); } [[nodiscard]] static bool IsTraditionalChinese() { EnsureInstance(); return sInstance && sInstance->IsTraditionalChineseInternal(); } [[nodiscard]] static bool IsSimplifiedChinese() { EnsureInstance(); return sInstance && sInstance->IsSimplifiedChineseInternal(); } [[nodiscard]] static bool IsJapanese() { EnsureInstance(); return sInstance && sInstance->IsJapaneseInternal(); } [[nodiscard]] static bool IsKorean() { EnsureInstance(); return sInstance && sInstance->IsKoreanInternal(); } /** * ActiveTIP() returns an ID for currently active TIP. * Please note that this method is expensive due to needs a lot of GUID * comparisons if active language ID is one of CJKT. If you need to * check TIPs for a specific language, you should check current language * first. */ [[nodiscard]] static TextInputProcessorID ActiveTIP() { EnsureInstance(); if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) { return TextInputProcessorID::Unknown; } sInstance->ComputeActiveTextInputProcessor(); if (NS_WARN_IF(sInstance->mActiveTIP == TextInputProcessorID::NotComputed)) { return TextInputProcessorID::Unknown; } return sInstance->mActiveTIP; } static bool GetActiveTIPNameForTelemetry(nsAString& aName); static bool IsMSChangJieOrMSQuickActive(); static bool IsMSPinyinOrMSWubiActive(); static bool IsMSJapaneseIMEActive(); static bool IsGoogleJapaneseInputActive(); static bool IsATOKActive(); // Note that ATOK 2011 - 2016 refers native caret position for deciding its // popup window position. static bool IsATOKReferringNativeCaretActive(); private: static void EnsureInstance() { if (!sInstance) { RefPtr staticSink = GetInstance(); Unused << staticSink; } } [[nodiscard]] bool IsTraditionalChineseInternal() const { return mLangID == 0x0404; } [[nodiscard]] bool IsSimplifiedChineseInternal() const { return mLangID == 0x0804; } [[nodiscard]] bool IsJapaneseInternal() const { return mLangID == 0x0411; } [[nodiscard]] bool IsKoreanInternal() const { return mLangID == 0x0412; } [[nodiscard]] bool IsATOKActiveInternal(); void ComputeActiveTextInputProcessor(); [[nodiscard]] TextInputProcessorID ComputeActiveTIPAsJapanese(); [[nodiscard]] TextInputProcessorID ComputeActiveTIPAsTraditionalChinese(); [[nodiscard]] TextInputProcessorID ComputeActiveTIPAsSimplifiedChinese(); [[nodiscard]] TextInputProcessorID ComputeActiveTIPAsKorean(); public: // ITfInputProcessorProfileActivationSink STDMETHODIMP OnActivated(DWORD, LANGID, REFCLSID, REFGUID, REFGUID, HKL, DWORD); private: TSFStaticSink() = default; virtual ~TSFStaticSink() = default; bool EnsureInitActiveTIPKeyboard(); void Destroy(); void GetTIPDescription(REFCLSID aTextService, LANGID aLangID, REFGUID aProfile, nsAString& aDescription); [[nodiscard]] bool IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, REFGUID aProfile); TextInputProcessorID mActiveTIP = TextInputProcessorID::NotComputed; // Cookie of installing ITfInputProcessorProfileActivationSink DWORD mIPProfileCookie = TF_INVALID_COOKIE; LANGID mLangID = 0; // True if current IME is implemented with IMM. bool mIsIMM_IME = false; // True if OnActivated() is already called bool mOnActivatedCalled = false; RefPtr mThreadMgr; RefPtr mInputProcessorProfiles; // Active TIP keyboard's description. If active language profile isn't TIP, // i.e., IMM-IME or just a keyboard layout, this is empty. nsString mActiveTIPKeyboardDescription; // Active TIP's GUID and CLSID GUID mActiveTIPGUID = GUID_NULL; CLSID mActiveTIPCLSID = CLSID_NULL; static StaticRefPtr sInstance; }; } // namespace mozilla::widget #endif // #ifndef TSFStaticSink_h