| 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 |