Index: win8/metro_driver/ime/language_profile_monitor.cc |
diff --git a/win8/metro_driver/ime/language_profile_monitor.cc b/win8/metro_driver/ime/language_profile_monitor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6f0ae5caf22895340fac0e5d91676669f65e1aaa |
--- /dev/null |
+++ b/win8/metro_driver/ime/language_profile_monitor.cc |
@@ -0,0 +1,149 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "win8/metro_driver/ime/language_profile_monitor.h" |
+ |
+#include <msctf.h> |
+ |
+#include "base/logging.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/win/scoped_comptr.h" |
+#include "win8/metro_driver/ime/language_profile_observer.h" |
+ |
+namespace metro_driver { |
+namespace { |
+ |
+class LanguageProfileMonitor; |
+LanguageProfileMonitor* g_monitor = NULL; |
+LanguageProfileObserver* g_observer_ = NULL; |
+ |
+class LanguageProfileMonitor : public ITfLanguageProfileNotifySink { |
+ public: |
+ static LanguageProfileMonitor* Create() { |
+ base::win::ScopedComPtr<ITfInputProcessorProfiles> profiles; |
+ if (FAILED(profiles.CreateInstance(CLSID_TF_InputProcessorProfiles))) |
+ return NULL; |
+ base::win::ScopedComPtr<ITfInputProcessorProfileMgr> profile_manager; |
+ if (FAILED(profile_manager.QueryFrom(profiles))) |
+ return NULL; |
+ base::win::ScopedComPtr<ITfSource> profiles_source; |
+ if (FAILED(profiles_source.QueryFrom(profiles))) |
+ return NULL; |
+ |
+ LanguageProfileMonitor* obj = new LanguageProfileMonitor(profile_manager); |
+ |
+ DWORD cookie = TF_INVALID_COOKIE; |
+ if (FAILED(profiles_source->AdviseSink(IID_ITfLanguageProfileNotifySink, |
+ obj, |
+ &cookie))) { |
+ obj->AddRef(); |
+ obj->Release(); |
+ return NULL; |
+ } |
+ |
+ obj->OnAdvise(profiles_source, cookie); |
+ return obj; |
+ } |
+ |
+ void Unadvise() { |
+ if (cookie_ == TF_INVALID_COOKIE || !source_) |
+ return; |
+ if (FAILED(source_->UnadviseSink(cookie_))) |
+ return; |
+ cookie_ = TF_INVALID_COOKIE; |
+ source_.Release(); |
+ } |
+ |
+ // IUnknown overrides: |
+ STDMETHOD_(ULONG, AddRef)() OVERRIDE{ |
+ return ::InterlockedIncrement(&ref_count_); |
+ } |
+ STDMETHOD_(ULONG, Release)() OVERRIDE { |
+ const LONG count = ::InterlockedDecrement(&ref_count_); |
+ if (!count) { |
+ delete this; |
+ return 0; |
+ } |
+ return static_cast<ULONG>(count); |
+ } |
+ STDMETHOD(QueryInterface)(REFIID iid, void** result) OVERRIDE { |
+ if (!result) |
+ return E_INVALIDARG; |
+ if (iid == IID_IUnknown) { |
+ *result = static_cast<IUnknown*>(this); |
+ } else if (iid == IID_ITfLanguageProfileNotifySink) { |
+ *result = static_cast<ITfLanguageProfileNotifySink*>(this); |
+ } else { |
+ *result = NULL; |
+ return E_NOINTERFACE; |
+ } |
+ AddRef(); |
+ return S_OK; |
+ } |
+ |
+ private: |
+ LanguageProfileMonitor(ITfInputProcessorProfileMgr* profile_manager) |
+ : ref_count_(0), |
+ profile_manager_(profile_manager) { |
+ } |
+ |
+ // ITfLanguageProfileNotifySink overrides: |
+ STDMETHOD(OnLanguageChange)(LANGID langid, BOOL *accept) OVERRIDE { |
+ if (!accept) |
+ return E_INVALIDARG; |
+ *accept = TRUE; |
+ return S_OK; |
+ } |
+ STDMETHOD(OnLanguageChanged)() OVERRIDE{ |
+ TF_INPUTPROCESSORPROFILE profile = {}; |
+ if (FAILED(profile_manager_->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, |
+ &profile))) { |
+ return S_OK; |
+ } |
+ if (!g_observer_) |
+ return S_OK; |
+ g_observer_->OnInputSourceChanged( |
+ profile.langid, |
+ profile.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR); |
+ return S_OK; |
+ } |
+ |
+ void OnAdvise(ITfSource* source, DWORD cookie) { |
+ source_ = source; |
+ cookie_ = cookie; |
+ } |
+ |
+ volatile LONG ref_count_; |
+ |
+ base::win::ScopedComPtr<ITfInputProcessorProfileMgr> profile_manager_; |
+ base::win::ScopedComPtr<ITfSource> source_; |
+ DWORD cookie_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LanguageProfileMonitor); |
+}; |
+ |
+} // namespace |
+ |
+void AddLanguageProfileObserver(LanguageProfileObserver* observer) { |
+ CHECK(g_observer_ == NULL); |
+ g_observer_ = observer; |
+ |
+ g_monitor = LanguageProfileMonitor::Create(); |
+ if (g_monitor) |
+ g_monitor->AddRef(); |
+} |
+ |
+void RemoveLanguageProfileObserver(LanguageProfileObserver* observer) { |
+ if (g_observer_ != observer) |
+ return; |
+ g_observer_ = NULL; |
+ if (!g_monitor) |
+ return; |
+ g_monitor->Unadvise(); |
+ g_monitor->Release(); |
+ g_monitor = NULL; |
+} |
+ |
+} // namespace metro_driver |
+ |