Index: ui/base/ime/win/tsf_event_router.cc |
diff --git a/ui/base/ime/win/tsf_event_router.cc b/ui/base/ime/win/tsf_event_router.cc |
index 92e20f31ca5e53d3e0e7cdff3630e3685d1cc190..4cf625ecb16d3ce6d724e86fa430a82d8a949822 100644 |
--- a/ui/base/ime/win/tsf_event_router.cc |
+++ b/ui/base/ime/win/tsf_event_router.cc |
@@ -11,6 +11,7 @@ |
#include "base/bind.h" |
#include "base/win/scoped_comptr.h" |
#include "base/win/metro.h" |
+#include "ui/base/range/range.h" |
#include "ui/base/win/atl_module.h" |
namespace ui { |
@@ -56,8 +57,9 @@ class ATL_NO_VTABLE TsfEventRouter::TsfEventRouterDelegate |
void SetRouter(TsfEventRouter* router); |
private: |
- // Returns true if the given |context| is composing. |
- static bool IsImeComposingInternal(ITfContext* context); |
+ // Returns current composition range. Returns ui::Range::InvalidRange if there |
+ // is no composition. |
+ static ui::Range GetCompositionRange(ITfContext* context); |
// Returns true if the given |element_id| represents the candidate window. |
bool IsCandidateWindowInternal(DWORD element_id); |
@@ -84,6 +86,7 @@ class ATL_NO_VTABLE TsfEventRouter::TsfEventRouterDelegate |
DWORD ui_source_cookie_; |
TsfEventRouter* router_; |
+ ui::Range previous_composition_range_; |
DISALLOW_COPY_AND_ASSIGN(TsfEventRouterDelegate); |
}; |
@@ -91,7 +94,8 @@ class ATL_NO_VTABLE TsfEventRouter::TsfEventRouterDelegate |
TsfEventRouter::TsfEventRouterDelegate::TsfEventRouterDelegate() |
: context_source_cookie_(TF_INVALID_COOKIE), |
ui_source_cookie_(TF_INVALID_COOKIE), |
- router_(NULL) { |
+ router_(NULL), |
+ previous_composition_range_(ui::Range::InvalidRange()) { |
} |
TsfEventRouter::TsfEventRouterDelegate::~TsfEventRouterDelegate() {} |
@@ -123,10 +127,20 @@ STDMETHODIMP TsfEventRouter::TsfEventRouterDelegate::OnEndEdit( |
if (FAILED(ranges->Next(1, range.Receive(), &fetched_count))) |
return S_OK; // Don't care about failures. |
+ const ui::Range composition_range = GetCompositionRange(context); |
+ |
+ if (!previous_composition_range_.IsValid() && composition_range.IsValid()) |
+ router_->OnTsfStartComposition(); |
+ |
// |fetched_count| != 0 means there is at least one range that contains |
// updated text. |
if (fetched_count != 0) |
- router_->OnTextUpdated(); |
+ router_->OnTextUpdated(composition_range); |
+ |
+ if (previous_composition_range_.IsValid() && !composition_range.IsValid()) |
+ router_->OnTsfEndComposition(); |
+ |
+ previous_composition_range_ = composition_range; |
return S_OK; |
} |
@@ -198,23 +212,39 @@ void TsfEventRouter::TsfEventRouterDelegate::SetManager( |
} |
bool TsfEventRouter::TsfEventRouterDelegate::IsImeComposing() { |
- return context_ && IsImeComposingInternal(context_); |
+ return context_ && GetCompositionRange(context_).IsValid(); |
} |
// static |
-bool TsfEventRouter::TsfEventRouterDelegate::IsImeComposingInternal( |
+ui::Range TsfEventRouter::TsfEventRouterDelegate::GetCompositionRange( |
ITfContext* context) { |
DCHECK(context); |
base::win::ScopedComPtr<ITfContextComposition> context_composition; |
if (FAILED(context_composition.QueryFrom(context))) |
- return false; |
+ return ui::Range::InvalidRange(); |
base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view; |
if (FAILED(context_composition->EnumCompositions( |
enum_composition_view.Receive()))) |
- return false; |
+ return ui::Range::InvalidRange(); |
base::win::ScopedComPtr<ITfCompositionView> composition_view; |
- return enum_composition_view->Next(1, composition_view.Receive(), |
- NULL) == S_OK; |
+ if (enum_composition_view->Next(1, composition_view.Receive(), |
+ NULL) != S_OK) |
+ return ui::Range::InvalidRange(); |
+ |
+ base::win::ScopedComPtr<ITfRange> range; |
+ if (FAILED(composition_view->GetRange(range.Receive()))) |
+ return ui::Range::InvalidRange(); |
+ |
+ base::win::ScopedComPtr<ITfRangeACP> range_acp; |
+ if (FAILED(range_acp.QueryFrom(range))) |
+ return ui::Range::InvalidRange(); |
+ |
+ LONG start = 0; |
+ LONG length = 0; |
+ if (FAILED(range_acp->GetExtent(&start, &length))) |
+ return ui::Range::InvalidRange(); |
+ |
+ return ui::Range(start, start + length); |
} |
bool TsfEventRouter::TsfEventRouterDelegate::IsCandidateWindowInternal( |
@@ -254,20 +284,28 @@ TsfEventRouter::~TsfEventRouter() { |
} |
} |
-void TsfEventRouter::SetManager(ITfThreadMgr* thread_manager) { |
- delegate_->SetManager(thread_manager); |
-} |
- |
bool TsfEventRouter::IsImeComposing() { |
return delegate_->IsImeComposing(); |
} |
-void TsfEventRouter::OnTextUpdated() { |
- observer_->OnTextUpdated(); |
-} |
- |
void TsfEventRouter::OnCandidateWindowCountChanged(size_t window_count) { |
observer_->OnCandidateWindowCountChanged(window_count); |
} |
+void TsfEventRouter::OnTsfStartComposition() { |
+ observer_->OnTsfStartComposition(); |
+} |
+ |
+void TsfEventRouter::OnTextUpdated(const ui::Range& composition_range) { |
+ observer_->OnTextUpdated(composition_range); |
+} |
+ |
+void TsfEventRouter::OnTsfEndComposition() { |
+ observer_->OnTsfEndComposition(); |
+} |
+ |
+void TsfEventRouter::SetManager(ITfThreadMgr* thread_manager) { |
+ delegate_->SetManager(thread_manager); |
+} |
+ |
} // namespace ui |