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