OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/ime/win/tsf_event_router.h" | 5 #include "ui/base/ime/win/tsf_event_router.h" |
6 | 6 |
7 #include <msctf.h> | 7 #include <msctf.h> |
8 #include <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/win/scoped_comptr.h" | 12 #include "base/win/scoped_comptr.h" |
13 #include "base/win/metro.h" | 13 #include "base/win/metro.h" |
| 14 #include "ui/base/range/range.h" |
14 #include "ui/base/win/atl_module.h" | 15 #include "ui/base/win/atl_module.h" |
15 | 16 |
16 namespace ui { | 17 namespace ui { |
17 | 18 |
18 | 19 |
19 // TsfEventRouter::TsfEventRouterDelegate ------------------------------------ | 20 // TsfEventRouter::TsfEventRouterDelegate ------------------------------------ |
20 | 21 |
21 // The implementation class of ITfUIElementSink, whose member functions will be | 22 // The implementation class of ITfUIElementSink, whose member functions will be |
22 // called back by TSF when the UI element status is changed, for example when | 23 // called back by TSF when the UI element status is changed, for example when |
23 // the candidate window is opened or closed. This class also implements | 24 // the candidate window is opened or closed. This class also implements |
(...skipping 25 matching lines...) Expand all Loading... |
49 // Sets |thread_manager| to be monitored. |thread_manager| can be NULL. | 50 // Sets |thread_manager| to be monitored. |thread_manager| can be NULL. |
50 void SetManager(ITfThreadMgr* thread_manager); | 51 void SetManager(ITfThreadMgr* thread_manager); |
51 | 52 |
52 // Returns true if the IME is composing text. | 53 // Returns true if the IME is composing text. |
53 bool IsImeComposing(); | 54 bool IsImeComposing(); |
54 | 55 |
55 // Sets |router| to be forwarded TSF-related events. | 56 // Sets |router| to be forwarded TSF-related events. |
56 void SetRouter(TsfEventRouter* router); | 57 void SetRouter(TsfEventRouter* router); |
57 | 58 |
58 private: | 59 private: |
59 // Returns true if the given |context| is composing. | 60 // Returns current composition range. Returns ui::Range::InvalidRange if there |
60 static bool IsImeComposingInternal(ITfContext* context); | 61 // is no composition. |
| 62 static ui::Range GetCompositionRange(ITfContext* context); |
61 | 63 |
62 // Returns true if the given |element_id| represents the candidate window. | 64 // Returns true if the given |element_id| represents the candidate window. |
63 bool IsCandidateWindowInternal(DWORD element_id); | 65 bool IsCandidateWindowInternal(DWORD element_id); |
64 | 66 |
65 // A context associated with this class. | 67 // A context associated with this class. |
66 base::win::ScopedComPtr<ITfContext> context_; | 68 base::win::ScopedComPtr<ITfContext> context_; |
67 | 69 |
68 // The ITfSource associated with |context_|. | 70 // The ITfSource associated with |context_|. |
69 base::win::ScopedComPtr<ITfSource> context_source_; | 71 base::win::ScopedComPtr<ITfSource> context_source_; |
70 | 72 |
71 // The cookie for |context_source_|. | 73 // The cookie for |context_source_|. |
72 DWORD context_source_cookie_; | 74 DWORD context_source_cookie_; |
73 | 75 |
74 // A UIElementMgr associated with this class. | 76 // A UIElementMgr associated with this class. |
75 base::win::ScopedComPtr<ITfUIElementMgr> ui_element_manager_; | 77 base::win::ScopedComPtr<ITfUIElementMgr> ui_element_manager_; |
76 | 78 |
77 // The ITfSouce associated with |ui_element_manager_|. | 79 // The ITfSouce associated with |ui_element_manager_|. |
78 base::win::ScopedComPtr<ITfSource> ui_source_; | 80 base::win::ScopedComPtr<ITfSource> ui_source_; |
79 | 81 |
80 // The set of currently opened candidate window ids. | 82 // The set of currently opened candidate window ids. |
81 std::set<DWORD> open_candidate_window_ids_; | 83 std::set<DWORD> open_candidate_window_ids_; |
82 | 84 |
83 // The cookie for |ui_source_|. | 85 // The cookie for |ui_source_|. |
84 DWORD ui_source_cookie_; | 86 DWORD ui_source_cookie_; |
85 | 87 |
86 TsfEventRouter* router_; | 88 TsfEventRouter* router_; |
| 89 ui::Range previous_composition_range_; |
87 | 90 |
88 DISALLOW_COPY_AND_ASSIGN(TsfEventRouterDelegate); | 91 DISALLOW_COPY_AND_ASSIGN(TsfEventRouterDelegate); |
89 }; | 92 }; |
90 | 93 |
91 TsfEventRouter::TsfEventRouterDelegate::TsfEventRouterDelegate() | 94 TsfEventRouter::TsfEventRouterDelegate::TsfEventRouterDelegate() |
92 : context_source_cookie_(TF_INVALID_COOKIE), | 95 : context_source_cookie_(TF_INVALID_COOKIE), |
93 ui_source_cookie_(TF_INVALID_COOKIE), | 96 ui_source_cookie_(TF_INVALID_COOKIE), |
94 router_(NULL) { | 97 router_(NULL), |
| 98 previous_composition_range_(ui::Range::InvalidRange()) { |
95 } | 99 } |
96 | 100 |
97 TsfEventRouter::TsfEventRouterDelegate::~TsfEventRouterDelegate() {} | 101 TsfEventRouter::TsfEventRouterDelegate::~TsfEventRouterDelegate() {} |
98 | 102 |
99 void TsfEventRouter::TsfEventRouterDelegate::SetRouter(TsfEventRouter* router) { | 103 void TsfEventRouter::TsfEventRouterDelegate::SetRouter(TsfEventRouter* router) { |
100 router_ = router; | 104 router_ = router; |
101 } | 105 } |
102 | 106 |
103 STDMETHODIMP TsfEventRouter::TsfEventRouterDelegate::OnEndEdit( | 107 STDMETHODIMP TsfEventRouter::TsfEventRouterDelegate::OnEndEdit( |
104 ITfContext* context, | 108 ITfContext* context, |
(...skipping 11 matching lines...) Expand all Loading... |
116 base::win::ScopedComPtr<IEnumTfRanges> ranges; | 120 base::win::ScopedComPtr<IEnumTfRanges> ranges; |
117 if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, | 121 if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, |
118 ranges.Receive()))) | 122 ranges.Receive()))) |
119 return S_OK; // Don't care about failures. | 123 return S_OK; // Don't care about failures. |
120 | 124 |
121 ULONG fetched_count = 0; | 125 ULONG fetched_count = 0; |
122 base::win::ScopedComPtr<ITfRange> range; | 126 base::win::ScopedComPtr<ITfRange> range; |
123 if (FAILED(ranges->Next(1, range.Receive(), &fetched_count))) | 127 if (FAILED(ranges->Next(1, range.Receive(), &fetched_count))) |
124 return S_OK; // Don't care about failures. | 128 return S_OK; // Don't care about failures. |
125 | 129 |
| 130 const ui::Range composition_range = GetCompositionRange(context); |
| 131 |
| 132 if (!previous_composition_range_.IsValid() && composition_range.IsValid()) |
| 133 router_->OnTsfStartComposition(); |
| 134 |
126 // |fetched_count| != 0 means there is at least one range that contains | 135 // |fetched_count| != 0 means there is at least one range that contains |
127 // updated text. | 136 // updated text. |
128 if (fetched_count != 0) | 137 if (fetched_count != 0) |
129 router_->OnTextUpdated(); | 138 router_->OnTextUpdated(composition_range); |
| 139 |
| 140 if (previous_composition_range_.IsValid() && !composition_range.IsValid()) |
| 141 router_->OnTsfEndComposition(); |
| 142 |
| 143 previous_composition_range_ = composition_range; |
130 return S_OK; | 144 return S_OK; |
131 } | 145 } |
132 | 146 |
133 STDMETHODIMP TsfEventRouter::TsfEventRouterDelegate::BeginUIElement( | 147 STDMETHODIMP TsfEventRouter::TsfEventRouterDelegate::BeginUIElement( |
134 DWORD element_id, | 148 DWORD element_id, |
135 BOOL* is_show) { | 149 BOOL* is_show) { |
136 if (is_show) | 150 if (is_show) |
137 *is_show = TRUE; // Without this the UI element will not be shown. | 151 *is_show = TRUE; // Without this the UI element will not be shown. |
138 | 152 |
139 if (!IsCandidateWindowInternal(element_id)) | 153 if (!IsCandidateWindowInternal(element_id)) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 205 |
192 if (FAILED(ui_element_manager_.QueryFrom(thread_manager)) || | 206 if (FAILED(ui_element_manager_.QueryFrom(thread_manager)) || |
193 FAILED(ui_source_.QueryFrom(ui_element_manager_))) | 207 FAILED(ui_source_.QueryFrom(ui_element_manager_))) |
194 return; | 208 return; |
195 ui_source_->AdviseSink(IID_ITfUIElementSink, | 209 ui_source_->AdviseSink(IID_ITfUIElementSink, |
196 static_cast<ITfUIElementSink*>(this), | 210 static_cast<ITfUIElementSink*>(this), |
197 &ui_source_cookie_); | 211 &ui_source_cookie_); |
198 } | 212 } |
199 | 213 |
200 bool TsfEventRouter::TsfEventRouterDelegate::IsImeComposing() { | 214 bool TsfEventRouter::TsfEventRouterDelegate::IsImeComposing() { |
201 return context_ && IsImeComposingInternal(context_); | 215 return context_ && GetCompositionRange(context_).IsValid(); |
202 } | 216 } |
203 | 217 |
204 // static | 218 // static |
205 bool TsfEventRouter::TsfEventRouterDelegate::IsImeComposingInternal( | 219 ui::Range TsfEventRouter::TsfEventRouterDelegate::GetCompositionRange( |
206 ITfContext* context) { | 220 ITfContext* context) { |
207 DCHECK(context); | 221 DCHECK(context); |
208 base::win::ScopedComPtr<ITfContextComposition> context_composition; | 222 base::win::ScopedComPtr<ITfContextComposition> context_composition; |
209 if (FAILED(context_composition.QueryFrom(context))) | 223 if (FAILED(context_composition.QueryFrom(context))) |
210 return false; | 224 return ui::Range::InvalidRange(); |
211 base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view; | 225 base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view; |
212 if (FAILED(context_composition->EnumCompositions( | 226 if (FAILED(context_composition->EnumCompositions( |
213 enum_composition_view.Receive()))) | 227 enum_composition_view.Receive()))) |
214 return false; | 228 return ui::Range::InvalidRange(); |
215 base::win::ScopedComPtr<ITfCompositionView> composition_view; | 229 base::win::ScopedComPtr<ITfCompositionView> composition_view; |
216 return enum_composition_view->Next(1, composition_view.Receive(), | 230 if (enum_composition_view->Next(1, composition_view.Receive(), |
217 NULL) == S_OK; | 231 NULL) != S_OK) |
| 232 return ui::Range::InvalidRange(); |
| 233 |
| 234 base::win::ScopedComPtr<ITfRange> range; |
| 235 if (FAILED(composition_view->GetRange(range.Receive()))) |
| 236 return ui::Range::InvalidRange(); |
| 237 |
| 238 base::win::ScopedComPtr<ITfRangeACP> range_acp; |
| 239 if (FAILED(range_acp.QueryFrom(range))) |
| 240 return ui::Range::InvalidRange(); |
| 241 |
| 242 LONG start = 0; |
| 243 LONG length = 0; |
| 244 if (FAILED(range_acp->GetExtent(&start, &length))) |
| 245 return ui::Range::InvalidRange(); |
| 246 |
| 247 return ui::Range(start, start + length); |
218 } | 248 } |
219 | 249 |
220 bool TsfEventRouter::TsfEventRouterDelegate::IsCandidateWindowInternal( | 250 bool TsfEventRouter::TsfEventRouterDelegate::IsCandidateWindowInternal( |
221 DWORD element_id) { | 251 DWORD element_id) { |
222 DCHECK(ui_element_manager_.get()); | 252 DCHECK(ui_element_manager_.get()); |
223 base::win::ScopedComPtr<ITfUIElement> ui_element; | 253 base::win::ScopedComPtr<ITfUIElement> ui_element; |
224 if (FAILED(ui_element_manager_->GetUIElement(element_id, | 254 if (FAILED(ui_element_manager_->GetUIElement(element_id, |
225 ui_element.Receive()))) | 255 ui_element.Receive()))) |
226 return false; | 256 return false; |
227 base::win::ScopedComPtr<ITfCandidateListUIElement> candidate_list_ui_element; | 257 base::win::ScopedComPtr<ITfCandidateListUIElement> candidate_list_ui_element; |
(...skipping 19 matching lines...) Expand all Loading... |
247 } | 277 } |
248 } | 278 } |
249 | 279 |
250 TsfEventRouter::~TsfEventRouter() { | 280 TsfEventRouter::~TsfEventRouter() { |
251 if (delegate_) { | 281 if (delegate_) { |
252 delegate_->SetManager(NULL); | 282 delegate_->SetManager(NULL); |
253 delegate_->SetRouter(NULL); | 283 delegate_->SetRouter(NULL); |
254 } | 284 } |
255 } | 285 } |
256 | 286 |
| 287 bool TsfEventRouter::IsImeComposing() { |
| 288 return delegate_->IsImeComposing(); |
| 289 } |
| 290 |
| 291 void TsfEventRouter::OnCandidateWindowCountChanged(size_t window_count) { |
| 292 observer_->OnCandidateWindowCountChanged(window_count); |
| 293 } |
| 294 |
| 295 void TsfEventRouter::OnTsfStartComposition() { |
| 296 observer_->OnTsfStartComposition(); |
| 297 } |
| 298 |
| 299 void TsfEventRouter::OnTextUpdated(const ui::Range& composition_range) { |
| 300 observer_->OnTextUpdated(composition_range); |
| 301 } |
| 302 |
| 303 void TsfEventRouter::OnTsfEndComposition() { |
| 304 observer_->OnTsfEndComposition(); |
| 305 } |
| 306 |
257 void TsfEventRouter::SetManager(ITfThreadMgr* thread_manager) { | 307 void TsfEventRouter::SetManager(ITfThreadMgr* thread_manager) { |
258 delegate_->SetManager(thread_manager); | 308 delegate_->SetManager(thread_manager); |
259 } | 309 } |
260 | 310 |
261 bool TsfEventRouter::IsImeComposing() { | |
262 return delegate_->IsImeComposing(); | |
263 } | |
264 | |
265 void TsfEventRouter::OnTextUpdated() { | |
266 observer_->OnTextUpdated(); | |
267 } | |
268 | |
269 void TsfEventRouter::OnCandidateWindowCountChanged(size_t window_count) { | |
270 observer_->OnCandidateWindowCountChanged(window_count); | |
271 } | |
272 | |
273 } // namespace ui | 311 } // namespace ui |
OLD | NEW |