1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "win8/metro_driver/ime/input_source.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/observer_list.h"
16 #include "base/win/scoped_comptr.h"
17 #include "ui/base/win/atl_module.h"
18 #include "win8/metro_driver/ime/input_source_observer.h"
20 namespace metro_driver
{
23 // An implementation of ITfLanguageProfileNotifySink interface, which will be
24 // used to receive notifications when the text input source is changed.
25 class ATL_NO_VTABLE InputSourceMonitor
26 : public CComObjectRootEx
<CComMultiThreadModel
>,
27 public ITfLanguageProfileNotifySink
{
30 : cookie_(TF_INVALID_COOKIE
) {
33 BEGIN_COM_MAP(InputSourceMonitor
)
34 COM_INTERFACE_ENTRY(ITfLanguageProfileNotifySink
)
37 bool Initialize(ITfSource
* source
) {
38 DWORD cookie
= TF_INVALID_COOKIE
;
39 HRESULT hr
= source
->AdviseSink(IID_ITfLanguageProfileNotifySink
,
43 LOG(ERROR
) << "ITfSource::AdviseSink failed. hr = " << hr
;
51 void SetCallback(base::Closure on_language_chanaged
) {
52 on_language_chanaged_
= on_language_chanaged
;
56 if (cookie_
== TF_INVALID_COOKIE
|| !source_
.get())
58 if (FAILED(source_
->UnadviseSink(cookie_
)))
60 cookie_
= TF_INVALID_COOKIE
;
65 // ITfLanguageProfileNotifySink overrides:
66 STDMETHOD(OnLanguageChange
)(LANGID langid
, BOOL
*accept
) override
{
73 STDMETHOD(OnLanguageChanged
)() override
{
74 if (!on_language_chanaged_
.is_null())
75 on_language_chanaged_
.Run();
79 base::Closure on_language_chanaged_
;
80 base::win::ScopedComPtr
<ITfSource
> source_
;
83 DISALLOW_COPY_AND_ASSIGN(InputSourceMonitor
);
86 class InputSourceImpl
: public InputSource
{
88 InputSourceImpl(ITfInputProcessorProfileMgr
* profile_manager
,
89 InputSourceMonitor
* monitor
)
90 : profile_manager_(profile_manager
),
92 monitor_
->SetCallback(base::Bind(&InputSourceImpl::OnLanguageChanged
,
93 base::Unretained(this)));
95 virtual ~InputSourceImpl() {
96 monitor_
->SetCallback(base::Closure());
101 // InputSource overrides.
102 virtual bool GetActiveSource(LANGID
* langid
, bool* is_ime
) override
{
103 TF_INPUTPROCESSORPROFILE profile
= {};
104 HRESULT hr
= profile_manager_
->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD
,
107 LOG(ERROR
) << "ITfInputProcessorProfileMgr::GetActiveProfile failed."
111 *langid
= profile
.langid
;
112 *is_ime
= profile
.dwProfileType
== TF_PROFILETYPE_INPUTPROCESSOR
;
115 virtual void AddObserver(InputSourceObserver
* observer
) override
{
116 observer_list_
.AddObserver(observer
);
118 virtual void RemoveObserver(InputSourceObserver
* observer
) override
{
119 observer_list_
.RemoveObserver(observer
);
121 void OnLanguageChanged() {
122 FOR_EACH_OBSERVER(InputSourceObserver
,
124 OnInputSourceChanged());
127 base::win::ScopedComPtr
<ITfInputProcessorProfileMgr
> profile_manager_
;
128 scoped_refptr
<InputSourceMonitor
> monitor_
;
129 ObserverList
<InputSourceObserver
> observer_list_
;
131 DISALLOW_COPY_AND_ASSIGN(InputSourceImpl
);
137 scoped_ptr
<InputSource
> InputSource::Create() {
138 ui::win::CreateATLModuleIfNeeded();
140 base::win::ScopedComPtr
<ITfInputProcessorProfileMgr
> profile_manager
;
141 HRESULT hr
= profile_manager
.CreateInstance(CLSID_TF_InputProcessorProfiles
);
143 LOG(ERROR
) << "Failed to instantiate CLSID_TF_InputProcessorProfiles."
145 return scoped_ptr
<InputSource
>();
147 base::win::ScopedComPtr
<ITfSource
> profiles_source
;
148 hr
= profiles_source
.QueryFrom(profile_manager
.get());
150 LOG(ERROR
) << "QueryFrom to ITfSource failed. hr = " << hr
;
151 return scoped_ptr
<InputSource
>();
154 CComObject
<InputSourceMonitor
>* monitor
= NULL
;
155 hr
= CComObject
<InputSourceMonitor
>::CreateInstance(&monitor
);
157 LOG(ERROR
) << "CComObject<InputSourceMonitor>::CreateInstance failed."
159 return scoped_ptr
<InputSource
>();
161 if (!monitor
->Initialize(profiles_source
.get())) {
162 LOG(ERROR
) << "Failed to initialize the monitor.";
163 return scoped_ptr
<InputSource
>();
166 // Transfer the ownership.
167 return scoped_ptr
<InputSource
>(
168 new InputSourceImpl(profile_manager
.get(), monitor
));
171 } // namespace metro_driver