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

Side by Side 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: Fix build break pulling in TOT Created 6 years, 4 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/widget/desktop_aura/desktop_keyboard_capture_win.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/synchronization/lock.h"
11 #include "base/task_runner.h"
12
13 namespace views {
14
15 base::Lock DesktopKeyboardCaptureWin::registration_lock_;
16
17 base::ScopedPtrHashMap<HWND,
18 DesktopKeyboardCaptureWin::KeyboardInterceptRegistration>
19 DesktopKeyboardCaptureWin::registrations_;
20
21 class VIEWS_EXPORT DesktopKeyboardCaptureWin::KeyboardInterceptRegistration {
sky 2014/07/29 23:07:25 You don't need VIEWS_EXPORT in a .cc file.
Sriram 2014/07/31 00:21:13 Done.
22 public:
23 KeyboardInterceptRegistration() : hook_handle_(NULL) {}
24
25 ~KeyboardInterceptRegistration() {
26 if (hook_handle_ != NULL) {
sky 2014/07/29 23:07:25 no {}
Sriram 2014/07/31 00:21:13 Done.
27 Unhook();
28 }
29 }
30
31 bool Hook(HOOKPROC callback_function) {
32 DCHECK(hook_handle_ == NULL) << "Keyboard hook already registered";
33 hook_handle_ = SetWindowsHookEx(WH_KEYBOARD_LL, callback_function, NULL, 0);
cpu_(ooo_6.6-7.5) 2014/07/31 00:14:48 check that this is a thread with a UI style messag
Sriram 2014/07/31 00:55:42 I am not sure as how I could check this. Could you
cpu_(ooo_6.6-7.5) 2014/07/31 21:45:21 DCHECK(base::MessageLoopForUI::IsCurrent())
34 if (hook_handle_ == NULL) {
35 DLOG(ERROR) << "Error calling SetWindowsHookEx() - GLE = "
sky 2014/07/29 23:07:25 DVLOG
Sriram 2014/07/31 00:21:13 Done.
36 << GetLastError();
37 return false;
38 }
39 return true;
40 }
41
42 bool Unhook() {
43 DCHECK(hook_handle_ != NULL) << "Unhook called without registring hooks";
44 BOOL result = UnhookWindowsHookEx(hook_handle_);
45 if (!result) {
46 DLOG(ERROR) << "Error calling UnhookWindowsHookEx() - GLE = "
47 << GetLastError();
48 return false;
49 }
50 hook_handle_ = NULL;
51 return true;
52 }
53
54 private:
55 // Hook returned when it was installed
56 HHOOK hook_handle_;
57
58 DISALLOW_COPY_AND_ASSIGN(KeyboardInterceptRegistration);
59 };
60
61 // static
62 void DesktopKeyboardCaptureWin::Capture(HWND window_handle,
63 base::TaskRunner* task_runner) {
64 if (AddToRegistrationList(window_handle)) {
65 // Task to register from thread which should be active for the duration
66 // of the registration.
67 task_runner->PostTask(
sky 2014/07/29 23:07:25 Why do you PostTask here?
Sriram 2014/07/31 00:21:13 Hook callbacks happen in the thread that calls Set
sky 2014/07/31 15:21:22 I'm still confused by your use of threads. At the
Sriram 2014/07/31 19:40:05 Done.
68 FROM_HERE,
69 base::Bind(&DesktopKeyboardCaptureWin::RegisterExistingHandle,
70 window_handle));
71 }
72 }
73
74 // static
75 void DesktopKeyboardCaptureWin::RegisterExistingHandle(HWND window_handle) {
76 base::AutoLock lock(registration_lock_);
sky 2014/07/29 23:07:25 Why are you using a lock?
Sriram 2014/07/31 00:21:13 The registration is accessed from UI thread (as pa
77 KeyboardInterceptRegistration* registration =
78 registrations_.get(window_handle);
79 if (registration != NULL) {
80 VLOG(1) << "Registered keyboard hook for handle = " << window_handle;
81 registration->Hook(KeyboardHook);
82 }
83 }
84
85 // static
86 void DesktopKeyboardCaptureWin::Release(HWND window_handle) {
87 base::AutoLock lock(registration_lock_);
88 registrations_.erase(window_handle);
89 VLOG(1) << "Keyboard hook unregistered for handle = " << window_handle;
90 }
91
92 // static
93 bool DesktopKeyboardCaptureWin::AddToRegistrationList(HWND handle) {
94 base::AutoLock lock(registration_lock_);
95 if (registrations_.contains(handle)) {
sky 2014/07/29 23:07:25 no {}
Sriram 2014/07/31 00:21:14 Done.
96 return false;
97 }
98 scoped_ptr<KeyboardInterceptRegistration> registration(
99 new KeyboardInterceptRegistration());
100
101 return registrations_.add(handle, registration.Pass()).second;
102 }
103
104 // static
105 bool DesktopKeyboardCaptureWin::IsRegistered(HWND handle) {
106 base::AutoLock lock(registration_lock_);
107 return registrations_.contains(handle);
108 }
109
110 // static
111 bool DesktopKeyboardCaptureWin::IsKeyUp(WPARAM w_param) {
sky 2014/07/29 23:07:25 Move functions like this that don't need any state
Sriram 2014/07/31 00:21:13 Done.
112 return (w_param == WM_KEYUP) || (w_param == WM_SYSKEYUP);
113 }
114
115 // static
116 bool DesktopKeyboardCaptureWin::IsBitSet(ULONG value, ULONG mask) {
117 return ((value & mask) != 0);
118 }
119
120 // static
121 LPARAM DesktopKeyboardCaptureWin::GetLParamFromHookStruct(
122 WPARAM w_param,
123 KBDLLHOOKSTRUCT hook_struct) {
124 ULONG key_state = 0;
125 // There is no way to get repeat count so always set it to 1.
126 key_state = 1;
127
128 // Scan code
129 key_state |= (hook_struct.scanCode & 0xFF) << 16;
130
131 // Extended key when the event is received as part window event and so skip it
cpu_(ooo_6.6-7.5) 2014/07/31 00:14:48 comments need periods at the end.
Sriram 2014/07/31 00:49:59 Done.
132
133 // Context code
134 key_state |= IsBitSet(hook_struct.flags, LLKHF_ALTDOWN) << 29;
135
136 // Previous key state - set to 1 for KEYUP events
137 key_state |= IsKeyUp(w_param) << 30;
138
139 // Transition state
140 key_state |= IsBitSet(hook_struct.flags, LLKHF_UP) << 31;
141 return static_cast<LPARAM>(key_state);
142 }
143
144 // static
145 DWORD DesktopKeyboardCaptureWin::RemoveLocationOnKeycode(DWORD vk_code) {
146 // Virtual keycode from low level hook include location while window messages
147 // does not. So convert them to be without location.
148 switch (vk_code) {
149 case VK_LSHIFT:
150 case VK_RSHIFT:
151 return VK_SHIFT;
152 case VK_LCONTROL:
153 case VK_RCONTROL:
154 return VK_CONTROL;
155 case VK_LMENU:
156 case VK_RMENU:
157 return VK_MENU;
158 }
159 return vk_code;
160 }
161
162 // static
163 bool DesktopKeyboardCaptureWin::UpdateThreadKeyboardState() {
164 const int kKeyboardStateLength = 256;
cpu_(ooo_6.6-7.5) 2014/07/31 00:14:48 what is this function trying to do? A full fledge
Sriram 2014/07/31 00:55:42 Done.
165 BYTE keyboard_state[kKeyboardStateLength];
166 if (!GetKeyboardState(keyboard_state)) {
167 PLOG(ERROR) << "Error getting keyboard state";
168 return false;
169 }
170
171 int keys_to_update[] = {VK_SHIFT, VK_CONTROL, VK_MENU};
172 for (int index = 0; index < _countof(keys_to_update); index++) {
cpu_(ooo_6.6-7.5) 2014/07/31 00:14:48 dont use _countof()
Sriram 2014/07/31 00:50:00 Done.
173 int key = keys_to_update[index];
174 SHORT key_state = GetAsyncKeyState(key);
175 keyboard_state[key] = (IsBitSet(key_state, 0x8000) ? 0x80 : 0) |
176 (IsBitSet(key_state, 0x1) ? 1 : 0);
177 }
178
179 if (!SetKeyboardState(keyboard_state)) {
180 PLOG(ERROR) << "Error setting keyboard state";
181 return false;
182 }
183
184 return true;
185 }
186
187 // static
188 LRESULT CALLBACK DesktopKeyboardCaptureWin::KeyboardHook(int code,
189 WPARAM w_param,
190 LPARAM l_param) {
191 HWND current_active_window = GetActiveWindow();
sky 2014/07/29 23:07:25 I think we should uninstall the hook when we don't
Sriram 2014/07/31 00:21:13 We do uninstall the hook as soon as the window los
192 if ((code >= 0) && IsRegistered(current_active_window)) {
193 UpdateThreadKeyboardState();
194
195 KBDLLHOOKSTRUCT hook_struct = *reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param);
196 PostMessage(current_active_window,
197 w_param,
198 RemoveLocationOnKeycode(hook_struct.vkCode),
199 GetLParamFromHookStruct(w_param, hook_struct));
200
201 return 1;
202 }
203
204 return CallNextHookEx(NULL, code, w_param, l_param);
205 }
206
207 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698