Index: win8/metro_driver/ime/ime_popup_monitor.cc |
diff --git a/win8/metro_driver/ime/ime_popup_monitor.cc b/win8/metro_driver/ime/ime_popup_monitor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..19a35336fef6b4f2e01d0a4852523319d3dd9549 |
--- /dev/null |
+++ b/win8/metro_driver/ime/ime_popup_monitor.cc |
@@ -0,0 +1,75 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "win8/metro_driver/ime/ime_popup_monitor.h" |
+ |
+#include <msctf.h> |
+ |
+#include "base/logging.h" |
+#include "base/message_loop/message_loop.h" |
+#include "win8/metro_driver/ime/ime_popup_observer.h" |
+ |
+namespace metro_driver { |
+namespace { |
+ |
+ImePopupObserver* g_observer_ = NULL; |
+HWINEVENTHOOK g_hook_handle_ = NULL; |
+ |
+void CALLBACK ImeEventCallback(HWINEVENTHOOK win_event_hook_handle, |
+ DWORD event, |
+ HWND window_handle, |
+ LONG object_id, |
+ LONG child_id, |
+ DWORD event_thread, |
+ DWORD event_time) { |
+ DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); |
+ if (!g_observer_) |
+ return; |
+ switch (event) { |
+ case EVENT_OBJECT_IME_SHOW: |
+ g_observer_->OnCandidatePopupChanged(true); |
+ return; |
+ case EVENT_OBJECT_IME_HIDE: |
+ g_observer_->OnCandidatePopupChanged(false); |
+ return; |
+ // Note: we never see EVENT_OBJECT_IME_CHANGE here because it is filtered |
+ // out when SetWinEventHook API is called. |
+ } |
+} |
+ |
+} // namespace |
+ |
+void AddImePopupObserver(ImePopupObserver* observer) { |
+ CHECK(g_observer_ == NULL) << |
+ "Currently only one observer is supported at the same time."; |
+ g_observer_ = observer; |
+ |
+ // Unfortunately MS-IME in immersive mode does not fully support |
+ // ITfUIElementSink. EVENT_OBJECT_IME_SHOW/EVENT_OBJECT_IME_HIDE is more |
+ // reliable in practice. |
+ // Caveats: EVENT_OBJECT_IME_SHOW/EVENT_OBJECT_IME_HIDE are supported on |
+ // Windows 8 and later. |
+ |
+ g_hook_handle_ = SetWinEventHook( |
+ EVENT_OBJECT_IME_SHOW, |
+ EVENT_OBJECT_IME_HIDE, |
+ NULL, |
+ ImeEventCallback, |
+ ::GetCurrentProcessId(), |
+ 0, // Hook all threads because MS-IME emits WinEvent in worker thread |
+ WINEVENT_OUTOFCONTEXT); // allows us to receive message in the UI thread |
+} |
+ |
+void RemoveImePopupObserver(ImePopupObserver* observer) { |
+ if (g_observer_ != observer) |
+ return; |
+ g_observer_ = NULL; |
+ if (!g_hook_handle_) |
+ return; |
+ UnhookWinEvent(g_hook_handle_); |
+ g_hook_handle_ = NULL; |
+} |
+ |
+} // namespace metro_driver |
+ |