Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(380)

Side by Side Diff: ui/base/win/tsf_event_router.cc

Issue 11148012: Introduce TsfEventRouter. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "ui/base/win/tsf_event_router.h"
6
7 #include <msctf.h>
8 #include <set>
9 #include <utility>
10 #include "base/bind.h"
sky 2012/10/15 22:00:07 newline between 9/10.
Seigo Nonaka 2012/10/16 02:20:47 Done.
11 #include "base/win/scoped_comptr.h"
12 #include "base/win/metro.h"
13
14 namespace ui {
15
16 class TsfEventRouterImpl : public TsfEventRouter,
17 public ITfUIElementSink,
18 public ITfTextEditSink {
19 public:
20 TsfEventRouterImpl()
21 : context_source_cookie_(TF_INVALID_COOKIE),
22 ui_source_cookie_(TF_INVALID_COOKIE),
23 ref_count_(0) {}
24
25 virtual ~TsfEventRouterImpl() {}
26
27 // ITfTextEditSink override.
28 virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE {
29 return InterlockedIncrement(&ref_count_);
30 }
31
32 // ITfTextEditSink override.
33 virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE {
34 const LONG count = InterlockedDecrement(&ref_count_);
35 if (!count) {
36 delete this;
37 return 0;
38 }
39 return static_cast<ULONG>(count);
40 }
41
42 // ITfTextEditSink override.
43 virtual STDMETHODIMP QueryInterface(REFIID iid, void** result) OVERRIDE {
44 if (!result)
45 return E_INVALIDARG;
46 if (iid == IID_IUnknown || iid == IID_ITfTextEditSink) {
47 *result = static_cast<ITfTextEditSink*>(this);
48 } else if (iid == IID_ITfUIElementSink) {
49 *result = static_cast<ITfUIElementSink*>(this);
50 } else {
51 *result = NULL;
52 return E_NOINTERFACE;
53 }
54 AddRef();
55 return S_OK;
56 }
57
58 // ITfTextEditSink override.
59 virtual STDMETHODIMP OnEndEdit(ITfContext* context,
60 TfEditCookie read_only_cookie,
61 ITfEditRecord* edit_record) OVERRIDE {
62 if (!edit_record || !context)
63 return E_INVALIDARG;
64 if (text_updated_callback_.is_null())
65 return S_OK;
66
67 // |edit_record| can be used to obtain updated ranges in terms of text
68 // contents and/or text attributes. Here we are interested only in text
69 // update so we use TF_GTP_INCL_TEXT and check if there is any range which
70 // contains updated text.
71 base::win::ScopedComPtr<IEnumTfRanges> ranges;
72 if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT,
73 NULL,
74 0,
75 ranges.Receive()))) {
76 return S_OK; // don't care about failures.
77 }
78
79 ULONG fetched_count = 0;
80 base::win::ScopedComPtr<ITfRange> range;
81 if (FAILED(ranges->Next(1, range.Receive(), &fetched_count)))
82 return S_OK; // don't care about failures.
83
84 // |fetched_count| != 0 means there is at least one range that contains
85 // updated texts.
86 if (fetched_count != 0)
87 text_updated_callback_.Run();
88 return S_OK;
89 }
90
91 // ITfUiElementSink override.
92 virtual STDMETHODIMP BeginUIElement(DWORD element_id, BOOL* is_show) {
93 if (is_show)
94 *is_show = TRUE; // without this the UI element will not be shown.
95
96 if (!IsCandidateWindowInternal(element_id))
97 return S_OK;
98
99 std::pair<std::set<DWORD>::iterator, bool> insert_result =
100 open_candidate_window_ids_.insert(element_id);
101
102 if (candidat_window_count_changed_callback_.is_null())
103 return S_OK;
104
105 // Don't call if |element_id| is already handled.
106 if (!insert_result.second)
107 return S_OK;
108
109 candidat_window_count_changed_callback_.Run(
110 open_candidate_window_ids_.size());
111
112 return S_OK;
113 }
114
115 // ITfUiElementSink override.
116 virtual STDMETHODIMP UpdateUIElement(DWORD element_id) {
117 return S_OK;
118 }
119
120 // ITfUiElementSink override.
121 virtual STDMETHODIMP EndUIElement(DWORD element_id) {
122 if (open_candidate_window_ids_.erase(element_id) == 0)
123 return S_OK;
124
125 if (candidat_window_count_changed_callback_.is_null())
126 return S_OK;
127
128 candidat_window_count_changed_callback_.Run(
129 open_candidate_window_ids_.size());
130
131 return S_OK;
132 }
133
134 // TsfEventRouter override.
135 virtual void Associate(ITfThreadMgr* thread_manager) OVERRIDE {
136 DCHECK(base::win::IsTsfAwareRequired())
137 << "Do not call without TSF environment.";
138 DCHECK(thread_manager);
139
140 base::win::ScopedComPtr<ITfDocumentMgr> document_manager;
141 if (FAILED(thread_manager->GetFocus(document_manager.Receive())))
142 return;
143 EnsureDeassociated();
144
145 if (FAILED(document_manager->GetBase(context_.Receive())))
146 return;
147 if (FAILED(context_source_.QueryFrom(context_)))
148 return;
149 context_source_->AdviseSink(IID_ITfTextEditSink,
150 static_cast<ITfTextEditSink*>(this),
151 &context_source_cookie_);
152
153 if (FAILED(ui_element_manager_.QueryFrom(thread_manager)))
154 return;
155 if (FAILED(ui_source_.QueryFrom(ui_element_manager_)))
156 return;
157 ui_source_->AdviseSink(IID_ITfUIElementSink,
158 static_cast<ITfUIElementSink*>(this),
159 &ui_source_cookie_);
160 }
161
162 // TsfEventRouter override.
163 virtual void EnsureDeassociated() OVERRIDE {
164 DCHECK(base::win::IsTsfAwareRequired())
165 << "Do not call without TSF environment.";
166
167 context_.Release();
168
169 if (context_source_) {
170 context_source_->UnadviseSink(context_source_cookie_);
171 context_source_.Release();
172 }
173 context_source_cookie_ = TF_INVALID_COOKIE;
174
175 ui_element_manager_.Release();
176 if (ui_source_) {
177 ui_source_->UnadviseSink(ui_source_cookie_);
178 ui_source_.Release();
179 }
180 ui_source_cookie_ = TF_INVALID_COOKIE;
181 }
182
183 // TsfEventRouter override.
184 virtual bool IsImeComposing() OVERRIDE {
185 DCHECK(base::win::IsTsfAwareRequired())
186 << "Do not call without TSF environment.";
187 if (!context_)
188 return false;
189 return IsImeComposingInternal(context_);
190 }
191
192 // TsfEventRouter override.
193 virtual void SetTextUpdatedCallback(
194 const TextUpdatedCallback& callback) OVERRIDE {
195 text_updated_callback_ = callback;
196 }
197
198 // TsfEventRouter override.
199 virtual void SetCandidateWindowStatusChangedCallback(
200 const CandidateWindowCountChangedCallback& callback) OVERRIDE {
201 candidat_window_count_changed_callback_ = callback;
202 }
203
204 private:
205 // Returns true if the given |context| is in composing.
206 static bool IsImeComposingInternal(ITfContext* context) {
207 DCHECK(base::win::IsTsfAwareRequired())
208 << "Do not call without TSF environment.";
209 DCHECK(context);
210 base::win::ScopedComPtr<ITfContextComposition> context_composition;
211 if (FAILED(context_composition.QueryFrom(context)))
212 return false;
213 base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view;
214 if (FAILED(context_composition->EnumCompositions(
215 enum_composition_view.Receive())))
216 return false;
217 base::win::ScopedComPtr<ITfCompositionView> composition_view;
218 return enum_composition_view->Next(1, composition_view.Receive(),
219 NULL) == S_OK;
220 }
221
222 // Returns true if the given |element_id| represents candidate window.
223 bool IsCandidateWindowInternal(DWORD element_id) {
224 DCHECK(ui_element_manager_.get());
225 base::win::ScopedComPtr<ITfUIElement> ui_element;
226 if (FAILED(ui_element_manager_->GetUIElement(element_id,
227 ui_element.Receive()))) {
228 return false;
229 }
230 base::win::ScopedComPtr<ITfCandidateListUIElement>
231 candidate_list_ui_element;
232 return SUCCEEDED(candidate_list_ui_element.QueryFrom(ui_element));
233 }
234
235 // Callback function fired when the text contents are updated.
236 TextUpdatedCallback text_updated_callback_;
237
238 CandidateWindowCountChangedCallback candidat_window_count_changed_callback_;
239
240 // A context associated with this class.
241 base::win::ScopedComPtr<ITfContext> context_;
242
243 // The ITfSource associated with |context_|.
244 base::win::ScopedComPtr<ITfSource> context_source_;
245
246 // The cookie for |context_source_|.
247 DWORD context_source_cookie_;
248
249 // A UiElementMgr associated with this class.
250 base::win::ScopedComPtr<ITfUIElementMgr> ui_element_manager_;
251
252 // The ITfSouce associated with |ui_element_manager_|.
253 base::win::ScopedComPtr<ITfSource> ui_source_;
254
255 // The cookie for |ui_source_|.
256 DWORD ui_source_cookie_;
257
258 // The set of currently opend candidate window ids.
259 std::set<DWORD> open_candidate_window_ids_;
260
261 // The reference count of this instance.
262 volatile LONG ref_count_;
263
264 DISALLOW_COPY_AND_ASSIGN(TsfEventRouterImpl);
265 };
266
267 ///////////////////////////////////////////////////////////////////////////////
268 // TsfEventRouter
269
270 TsfEventRouter::TsfEventRouter() {
271 }
272
273 TsfEventRouter::~TsfEventRouter() {
274 }
275
276 TsfEventRouter* TsfEventRouter::Create() {
277 return new TsfEventRouterImpl();
278 }
279
280 } // namespace ui
OLDNEW
« ui/base/win/tsf_event_router.h ('K') | « ui/base/win/tsf_event_router.h ('k') | ui/ui.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698