Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Unified Diff: ui/views/widget/desktop_aura/desktop_keyboard_capture_win.cc

Issue 297123002: API proposal for chrome.app.window to intercept all keys. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sync to TOT Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/views/widget/desktop_aura/desktop_keyboard_capture_win.cc
diff --git a/ui/views/widget/desktop_aura/desktop_keyboard_capture_win.cc b/ui/views/widget/desktop_aura/desktop_keyboard_capture_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8e3f6913cc32e0b2af382319a896587a89297886
--- /dev/null
+++ b/ui/views/widget/desktop_aura/desktop_keyboard_capture_win.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 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 "ui/views/widget/desktop_aura/desktop_keyboard_capture_win.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+
+namespace views {
+
+base::Lock DesktopKeyboardCaptureWin::registration_lock_;
+
+base::ScopedPtrHashMap<HWND,
+ DesktopKeyboardCaptureWin::KeyboardInterceptRegistration>
+ DesktopKeyboardCaptureWin::registrations_;
sadrul 2014/07/29 22:22:41 I don't think you can have non-POD globals like th
Sriram 2014/07/31 00:21:13 Done.
+
+class VIEWS_EXPORT DesktopKeyboardCaptureWin::KeyboardInterceptRegistration {
+ public:
+ KeyboardInterceptRegistration() : hook_handle_(NULL) {}
+
+ ~KeyboardInterceptRegistration() {
+ if (hook_handle_ != NULL) {
+ Unhook();
+ }
+ }
+
+ bool Hook(HOOKPROC callback_function) {
+ DCHECK(hook_handle_ == NULL) << "Keyboard hook already registered";
+ hook_handle_ = SetWindowsHookEx(WH_KEYBOARD_LL, callback_function, NULL, 0);
+ if (hook_handle_ == NULL) {
+ DLOG(ERROR) << "Error calling SetWindowsHookEx() - GLE = "
+ << GetLastError();
+ return false;
+ }
+ return true;
+ }
+
+ bool Unhook() {
+ DCHECK(hook_handle_ != NULL) << "Unhook called without registring hooks";
+ BOOL result = UnhookWindowsHookEx(hook_handle_);
+ if (!result) {
+ DLOG(ERROR) << "Error calling UnhookWindowsHookEx() - GLE = "
+ << GetLastError();
+ return false;
+ }
+ hook_handle_ = NULL;
+ return true;
+ }
+
+ private:
+ // Hook returned when it was installed
+ HHOOK hook_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardInterceptRegistration);
+};
+
+// static
+void DesktopKeyboardCaptureWin::Capture(HWND window_handle,
+ base::TaskRunner* task_runner) {
+ if (AddToRegistrationList(window_handle)) {
+ // Task to register from thread which should be active for the duration
+ // of the registration.
+ task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&DesktopKeyboardCaptureWin::RegisterExistingHandle,
+ window_handle));
+ }
+}
+
+// static
+void DesktopKeyboardCaptureWin::RegisterExistingHandle(HWND window_handle) {
+ base::AutoLock lock(registration_lock_);
+ KeyboardInterceptRegistration* registration =
+ registrations_.get(window_handle);
+ if (registration != NULL) {
+ VLOG(1) << "Registered keyboard hook for handle = " << window_handle;
+ registration->Hook(KeyboardHook);
+ }
+}
+
+// static
+void DesktopKeyboardCaptureWin::Release(HWND window_handle) {
+ base::AutoLock lock(registration_lock_);
+ registrations_.erase(window_handle);
+ VLOG(1) << "Keyboard hook unregistered for handle = " << window_handle;
+}
+
+// static
+bool DesktopKeyboardCaptureWin::AddToRegistrationList(HWND handle) {
+ base::AutoLock lock(registration_lock_);
+ if (registrations_.contains(handle)) {
+ return false;
+ }
+ scoped_ptr<KeyboardInterceptRegistration> registration(
+ new KeyboardInterceptRegistration());
+
+ return registrations_.add(handle, registration.Pass()).second;
+}
+
+// static
+bool DesktopKeyboardCaptureWin::IsRegistered(HWND handle) {
+ base::AutoLock lock(registration_lock_);
+ return registrations_.contains(handle);
+}
+
+// static
+bool DesktopKeyboardCaptureWin::IsKeyUp(WPARAM w_param) {
+ return (w_param == WM_KEYUP) || (w_param == WM_SYSKEYUP);
+}
+
+// static
+bool DesktopKeyboardCaptureWin::IsBitSet(ULONG value, ULONG mask) {
+ return ((value & mask) != 0);
+}
+
+// static
+LPARAM DesktopKeyboardCaptureWin::GetLParamFromHookStruct(
+ WPARAM w_param,
+ KBDLLHOOKSTRUCT hook_struct) {
+ ULONG key_state = 0;
+ // There is no way to get repeat count so always set it to 1.
+ key_state = 1;
+
+ // Scan code
+ key_state |= (hook_struct.scanCode & 0xFF) << 16;
+
+ // Extended key when the event is received as part window event and so skip it
+
+ // Context code
+ key_state |= IsBitSet(hook_struct.flags, LLKHF_ALTDOWN) << 29;
+
+ // Previous key state - set to 1 for KEYUP events
+ key_state |= IsKeyUp(w_param) << 30;
+
+ // Transition state
+ key_state |= IsBitSet(hook_struct.flags, LLKHF_UP) << 31;
+ return static_cast<LPARAM>(key_state);
+}
+
+// static
+DWORD DesktopKeyboardCaptureWin::RemoveLocationOnKeycode(DWORD vk_code) {
+ // Virtual keycode from low level hook include location while window messages
+ // does not. So convert them to be without location.
+ switch (vk_code) {
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ return VK_SHIFT;
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ return VK_CONTROL;
+ case VK_LMENU:
+ case VK_RMENU:
+ return VK_MENU;
+ }
+ return vk_code;
+}
+
+// static
+bool DesktopKeyboardCaptureWin::UpdateThreadKeyboardState() {
+ const int kKeyboardStateLength = 256;
+ BYTE keyboard_state[kKeyboardStateLength];
+ if (!GetKeyboardState(keyboard_state)) {
+ PLOG(ERROR) << "Error getting keyboard state";
+ return false;
+ }
+
+ int keys_to_update[] = {VK_SHIFT, VK_CONTROL, VK_MENU};
+ for (int index = 0; index < _countof(keys_to_update); index++) {
+ int key = keys_to_update[index];
+ SHORT key_state = GetAsyncKeyState(key);
+ keyboard_state[key] = (IsBitSet(key_state, 0x8000) ? 0x80 : 0) |
+ (IsBitSet(key_state, 0x1) ? 1 : 0);
+ }
+
+ if (!SetKeyboardState(keyboard_state)) {
+ PLOG(ERROR) << "Error setting keyboard state";
+ return false;
+ }
+
+ return true;
+}
+
+// static
+LRESULT CALLBACK DesktopKeyboardCaptureWin::KeyboardHook(int code,
+ WPARAM w_param,
+ LPARAM l_param) {
+ HWND current_active_window = GetActiveWindow();
+ if ((code >= 0) && IsRegistered(current_active_window)) {
+ UpdateThreadKeyboardState();
+
+ KBDLLHOOKSTRUCT hook_struct = *reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param);
+ PostMessage(current_active_window,
+ w_param,
+ RemoveLocationOnKeycode(hook_struct.vkCode),
+ GetLParamFromHookStruct(w_param, hook_struct));
+
+ return 1;
+ }
+
+ return CallNextHookEx(NULL, code, w_param, l_param);
+}
+
+} // namespace views

Powered by Google App Engine
This is Rietveld 408576698