Index: win8/metro_driver/ime/keyevent_filter.cc |
diff --git a/win8/metro_driver/ime/keyevent_filter.cc b/win8/metro_driver/ime/keyevent_filter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7b974800ba689139073690c773cea9c69aee44a3 |
--- /dev/null |
+++ b/win8/metro_driver/ime/keyevent_filter.cc |
@@ -0,0 +1,80 @@ |
+// 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/keyevent_filter.h" |
+ |
+#include <Windows.h> |
+#include <msctf.h> |
+ |
+#include "base/win/scoped_comptr.h" |
+ |
+namespace metro_driver { |
+namespace { |
+ |
+ITfKeystrokeMgr* g_keystroke_manager = NULL; |
+HHOOK g_hook = NULL; |
+ |
+LRESULT CALLBACK GetMsgProc(int code, WPARAM wparam, LPARAM lparam) { |
+ MSG* msg = reinterpret_cast<MSG*>(lparam); |
+ if (code >= 0 && (wparam & PM_REMOVE) == PM_REMOVE && |
+ (msg->message == WM_KEYDOWN || msg->message == WM_KEYUP)) { |
+ HRESULT hr = S_OK; |
+ BOOL eaten = FALSE; |
+ if (msg->message == WM_KEYDOWN) |
+ hr = g_keystroke_manager->KeyDown(msg->wParam, msg->lParam, &eaten); |
+ else |
+ hr = g_keystroke_manager->KeyUp(msg->wParam, msg->lParam, &eaten); |
+ |
+ // Emulate IMM32. Any key event that is eaten by an IME will be replaced |
+ // with a key event whose virtual key code is VK_PROCESSKEY. |
+ if (SUCCEEDED(hr) && !!eaten) |
+ msg->wParam = VK_PROCESSKEY; |
+ } |
+ return CallNextHookEx(g_hook, code, wparam, lparam); |
+} |
+ |
+} // namespace |
+ |
+bool InstallKeyEventFilter() { |
+ base::win::ScopedComPtr<ITfThreadMgr2> thread_manager; |
+ if (FAILED(thread_manager.CreateInstance(CLSID_TF_ThreadMgr))) |
+ return false; |
+ base::win::ScopedComPtr<ITfKeystrokeMgr> keystroke_manager; |
+ if (FAILED(keystroke_manager.QueryFrom(thread_manager))) |
+ return false; |
+ base::win::ScopedComPtr<ITfConfigureSystemKeystrokeFeed> feed; |
+ if (FAILED(feed.QueryFrom(thread_manager))) |
+ return false; |
+ |
+ // Here we replace CUAS's message hook with our own message hook so that |
+ // ITfKeystrokeMgr::KeyDown/KeyUp can be called only once per key event. |
+ |
+ // Disables CUAS's own message hook. |
+ if (FAILED(feed->DisableSystemKeystrokeFeed())) |
+ return false; |
+ g_keystroke_manager = keystroke_manager.Detach(); |
+ |
+ // Installs our own message hook. |
+ g_hook = ::SetWindowsHookExW( |
+ WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId()); |
+ if (g_hook == NULL) { |
+ g_keystroke_manager->Release(); |
+ g_keystroke_manager = NULL; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void UninstallKeyEventFilter() { |
+ if (g_hook) { |
+ UnhookWindowsHookEx(g_hook); |
+ g_hook = NULL; |
+ } |
+ if (g_keystroke_manager) { |
+ g_keystroke_manager->Release(); |
+ g_keystroke_manager = NULL; |
+ } |
+} |
+ |
+} // namespace metro_driver |