| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/automation/ui_controls.h" | 5 #include "chrome/browser/automation/ui_controls.h" |
| 6 | 6 |
| 7 #include "app/keyboard_code_conversion_win.h" | 7 #include "app/keyboard_code_conversion_win.h" |
| 8 #include "app/keyboard_codes.h" | 8 #include "app/keyboard_codes.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/string_util.h" | |
| 12 #include "base/win_util.h" | 11 #include "base/win_util.h" |
| 13 #include "base/ref_counted.h" | 12 #include "base/ref_counted.h" |
| 14 #include "base/task.h" | 13 #include "base/task.h" |
| 15 #include "views/view.h" | 14 #include "views/view.h" |
| 16 | 15 |
| 17 namespace ui_controls { | 16 namespace ui_controls { |
| 18 | 17 |
| 19 namespace { | 18 namespace { |
| 20 | 19 |
| 21 void Checkpoint(const char* message, const base::TimeTicks& start_time) { | |
| 22 LOG(INFO) << message << " : " | |
| 23 << (base::TimeTicks::Now() - start_time).InMilliseconds() | |
| 24 << " ms" << std::flush; | |
| 25 } | |
| 26 | |
| 27 // InputDispatcher ------------------------------------------------------------ | 20 // InputDispatcher ------------------------------------------------------------ |
| 28 | 21 |
| 29 // InputDispatcher is used to listen for a mouse/keyboard event. When the | 22 // InputDispatcher is used to listen for a mouse/keyboard event. When the |
| 30 // appropriate event is received the task is notified. | 23 // appropriate event is received the task is notified. |
| 31 class InputDispatcher : public base::RefCounted<InputDispatcher> { | 24 class InputDispatcher : public base::RefCounted<InputDispatcher> { |
| 32 public: | 25 public: |
| 33 InputDispatcher(Task* task, WPARAM message_waiting_for); | 26 InputDispatcher(Task* task, WPARAM message_waiting_for); |
| 34 | 27 |
| 35 // Invoked from the hook. If mouse_message matches message_waiting_for_ | 28 // Invoked from the hook. If mouse_message matches message_waiting_for_ |
| 36 // MatchingMessageFound is invoked. | 29 // MatchingMessageFound is invoked. |
| 37 void DispatchedMessage(WPARAM mouse_message); | 30 void DispatchedMessage(WPARAM mouse_message); |
| 38 | 31 |
| 39 // Invoked when a matching event is found. Uninstalls the hook and schedules | 32 // Invoked when a matching event is found. Uninstalls the hook and schedules |
| 40 // an event that notifies the task. | 33 // an event that notifies the task. |
| 41 void MatchingMessageFound(); | 34 void MatchingMessageFound(); |
| 42 | 35 |
| 43 private: | 36 private: |
| 44 friend class base::RefCounted<InputDispatcher>; | 37 friend class base::RefCounted<InputDispatcher>; |
| 45 | 38 |
| 46 ~InputDispatcher(); | 39 ~InputDispatcher(); |
| 47 | 40 |
| 48 // Notifies the task and release this (which should delete it). | 41 // Notifies the task and release this (which should delete it). |
| 49 void NotifyTask(); | 42 void NotifyTask(); |
| 50 | 43 |
| 51 // The task we notify. | 44 // The task we notify. |
| 52 scoped_ptr<Task> task_; | 45 scoped_ptr<Task> task_; |
| 53 | 46 |
| 54 // Message we're waiting for. Not used for keyboard events. | 47 // Message we're waiting for. Not used for keyboard events. |
| 55 const WPARAM message_waiting_for_; | 48 const WPARAM message_waiting_for_; |
| 56 | 49 |
| 57 DISALLOW_COPY_AND_ASSIGN(InputDispatcher); | 50 DISALLOW_COPY_AND_ASSIGN(InputDispatcher); |
| 58 }; | 51 }; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 71 HHOOK next_hook = next_hook_; | 64 HHOOK next_hook = next_hook_; |
| 72 if (n_code == HC_ACTION) { | 65 if (n_code == HC_ACTION) { |
| 73 DCHECK(current_dispatcher_); | 66 DCHECK(current_dispatcher_); |
| 74 current_dispatcher_->DispatchedMessage(w_param); | 67 current_dispatcher_->DispatchedMessage(w_param); |
| 75 } | 68 } |
| 76 return CallNextHookEx(next_hook, n_code, w_param, l_param); | 69 return CallNextHookEx(next_hook, n_code, w_param, l_param); |
| 77 } | 70 } |
| 78 | 71 |
| 79 // Callback from hook when a key message is received. | 72 // Callback from hook when a key message is received. |
| 80 LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) { | 73 LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) { |
| 81 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 82 char msg[512]; | |
| 83 base::snprintf(msg, 512, "KeyHook starts: %d", n_code); | |
| 84 Checkpoint(msg, start_time); | |
| 85 | |
| 86 HHOOK next_hook = next_hook_; | 74 HHOOK next_hook = next_hook_; |
| 87 base::snprintf(msg, 512, "n_code == HC_ACTION: %d, %d", | |
| 88 l_param, !!(l_param & (1 << 30))); | |
| 89 Checkpoint(msg, start_time); | |
| 90 if (n_code == HC_ACTION) { | 75 if (n_code == HC_ACTION) { |
| 91 DCHECK(current_dispatcher_); | 76 DCHECK(current_dispatcher_); |
| 92 if (l_param & (1 << 30)) { // Only send on key up. | 77 if (l_param & (1 << 30)) { |
| 93 Checkpoint("MatchingMessageFound", start_time); | 78 // Only send on key up. |
| 94 current_dispatcher_->MatchingMessageFound(); | 79 current_dispatcher_->MatchingMessageFound(); |
| 95 } else { | |
| 96 Checkpoint("Not key up", start_time); | |
| 97 } | 80 } |
| 98 } | 81 } |
| 99 Checkpoint("KeyHook ends, calling next hook.", start_time); | |
| 100 return CallNextHookEx(next_hook, n_code, w_param, l_param); | 82 return CallNextHookEx(next_hook, n_code, w_param, l_param); |
| 101 } | 83 } |
| 102 | 84 |
| 103 // Installs dispatcher as the current hook. | 85 // Installs dispatcher as the current hook. |
| 104 void InstallHook(InputDispatcher* dispatcher, bool key_hook) { | 86 void InstallHook(InputDispatcher* dispatcher, bool key_hook) { |
| 105 DCHECK(!installed_hook_); | 87 DCHECK(!installed_hook_); |
| 106 current_dispatcher_ = dispatcher; | 88 current_dispatcher_ = dispatcher; |
| 107 installed_hook_ = true; | 89 installed_hook_ = true; |
| 108 if (key_hook) { | 90 if (key_hook) { |
| 109 next_hook_ = SetWindowsHookEx(WH_KEYBOARD, &KeyHook, NULL, | 91 next_hook_ = SetWindowsHookEx(WH_KEYBOARD, &KeyHook, NULL, |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 | 159 |
| 178 if (!::SendInput(1, &input, sizeof(INPUT))) | 160 if (!::SendInput(1, &input, sizeof(INPUT))) |
| 179 return false; | 161 return false; |
| 180 | 162 |
| 181 return true; | 163 return true; |
| 182 } | 164 } |
| 183 | 165 |
| 184 bool SendKeyPressImpl(app::KeyboardCode key, | 166 bool SendKeyPressImpl(app::KeyboardCode key, |
| 185 bool control, bool shift, bool alt, | 167 bool control, bool shift, bool alt, |
| 186 Task* task) { | 168 Task* task) { |
| 187 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 188 Checkpoint("SendKeyPressImpl starts", start_time); | |
| 189 | |
| 190 scoped_refptr<InputDispatcher> dispatcher( | 169 scoped_refptr<InputDispatcher> dispatcher( |
| 191 task ? new InputDispatcher(task, WM_KEYUP) : NULL); | 170 task ? new InputDispatcher(task, WM_KEYUP) : NULL); |
| 192 | 171 |
| 193 // If a pop-up menu is open, it won't receive events sent using SendInput. | 172 // If a pop-up menu is open, it won't receive events sent using SendInput. |
| 194 // Check for a pop-up menu using its window class (#32768) and if one | 173 // Check for a pop-up menu using its window class (#32768) and if one |
| 195 // exists, send the key event directly there. | 174 // exists, send the key event directly there. |
| 196 Checkpoint("FindWindow", start_time); | |
| 197 HWND popup_menu = ::FindWindow(L"#32768", 0); | 175 HWND popup_menu = ::FindWindow(L"#32768", 0); |
| 198 if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) { | 176 if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) { |
| 199 Checkpoint("Found popup window", start_time); | |
| 200 WPARAM w_param = app::WindowsKeyCodeForKeyboardCode(key); | 177 WPARAM w_param = app::WindowsKeyCodeForKeyboardCode(key); |
| 201 LPARAM l_param = 0; | 178 LPARAM l_param = 0; |
| 202 Checkpoint("Send WM_KEYDOWN", start_time); | |
| 203 ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param); | 179 ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param); |
| 204 Checkpoint("Send WM_KEYUP", start_time); | |
| 205 ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param); | 180 ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param); |
| 206 | 181 |
| 207 Checkpoint("Send Done", start_time); | |
| 208 if (dispatcher.get()) | 182 if (dispatcher.get()) |
| 209 dispatcher->AddRef(); | 183 dispatcher->AddRef(); |
| 210 return true; | 184 return true; |
| 211 } | 185 } |
| 212 | 186 |
| 213 Checkpoint("Found no popup window", start_time); | 187 INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated. |
| 214 | |
| 215 INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated | |
| 216 | 188 |
| 217 UINT i = 0; | 189 UINT i = 0; |
| 218 if (control) { | 190 if (control) { |
| 219 Checkpoint("FillKeyboardInput Control", start_time); | |
| 220 if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], false)) | 191 if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], false)) |
| 221 return false; | 192 return false; |
| 222 i++; | 193 i++; |
| 223 } | 194 } |
| 224 | 195 |
| 225 if (shift) { | 196 if (shift) { |
| 226 Checkpoint("FillKeyboardInput Shift", start_time); | |
| 227 if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], false)) | 197 if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], false)) |
| 228 return false; | 198 return false; |
| 229 i++; | 199 i++; |
| 230 } | 200 } |
| 231 | 201 |
| 232 if (alt) { | 202 if (alt) { |
| 233 Checkpoint("FillKeyboardInput Alt", start_time); | |
| 234 if (!FillKeyboardInput(app::VKEY_MENU, &input[i], false)) | 203 if (!FillKeyboardInput(app::VKEY_MENU, &input[i], false)) |
| 235 return false; | 204 return false; |
| 236 i++; | 205 i++; |
| 237 } | 206 } |
| 238 | 207 |
| 239 Checkpoint("FillKeyboardInput 1", start_time); | |
| 240 if (!FillKeyboardInput(key, &input[i], false)) | 208 if (!FillKeyboardInput(key, &input[i], false)) |
| 241 return false; | 209 return false; |
| 242 i++; | 210 i++; |
| 243 | 211 |
| 244 Checkpoint("FillKeyboardInput 2", start_time); | |
| 245 if (!FillKeyboardInput(key, &input[i], true)) | 212 if (!FillKeyboardInput(key, &input[i], true)) |
| 246 return false; | 213 return false; |
| 247 i++; | 214 i++; |
| 248 | 215 |
| 249 if (alt) { | 216 if (alt) { |
| 250 Checkpoint("FillKeyboardInput Alt2", start_time); | |
| 251 if (!FillKeyboardInput(app::VKEY_MENU, &input[i], true)) | 217 if (!FillKeyboardInput(app::VKEY_MENU, &input[i], true)) |
| 252 return false; | 218 return false; |
| 253 i++; | 219 i++; |
| 254 } | 220 } |
| 255 | 221 |
| 256 if (shift) { | 222 if (shift) { |
| 257 Checkpoint("FillKeyboardInput Shift2", start_time); | |
| 258 if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], true)) | 223 if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], true)) |
| 259 return false; | 224 return false; |
| 260 i++; | 225 i++; |
| 261 } | 226 } |
| 262 | 227 |
| 263 if (control) { | 228 if (control) { |
| 264 Checkpoint("FillKeyboardInput Ctrl2", start_time); | |
| 265 if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], true)) | 229 if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], true)) |
| 266 return false; | 230 return false; |
| 267 i++; | 231 i++; |
| 268 } | 232 } |
| 269 | 233 |
| 270 Checkpoint("SendInput called", start_time); | |
| 271 if (::SendInput(i, input, sizeof(INPUT)) != i) | 234 if (::SendInput(i, input, sizeof(INPUT)) != i) |
| 272 return false; | 235 return false; |
| 273 | 236 |
| 274 Checkpoint("SendInput done", start_time); | |
| 275 | |
| 276 if (dispatcher.get()) | 237 if (dispatcher.get()) |
| 277 dispatcher->AddRef(); | 238 dispatcher->AddRef(); |
| 278 | 239 |
| 279 Checkpoint("Test done", start_time); | |
| 280 return true; | 240 return true; |
| 281 } | 241 } |
| 282 | 242 |
| 283 bool SendMouseMoveImpl(long x, long y, Task* task) { | 243 bool SendMouseMoveImpl(long x, long y, Task* task) { |
| 284 // First check if the mouse is already there. | 244 // First check if the mouse is already there. |
| 285 POINT current_pos; | 245 POINT current_pos; |
| 286 ::GetCursorPos(¤t_pos); | 246 ::GetCursorPos(¤t_pos); |
| 287 if (x == current_pos.x && y == current_pos.y) { | 247 if (x == current_pos.x && y == current_pos.y) { |
| 288 if (task) | 248 if (task) |
| 289 MessageLoop::current()->PostTask(FROM_HERE, task); | 249 MessageLoop::current()->PostTask(FROM_HERE, task); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 int state, Task* task) { | 365 int state, Task* task) { |
| 406 DCHECK(view); | 366 DCHECK(view); |
| 407 DCHECK(view->GetWidget()); | 367 DCHECK(view->GetWidget()); |
| 408 gfx::Point view_center(view->width() / 2, view->height() / 2); | 368 gfx::Point view_center(view->width() / 2, view->height() / 2); |
| 409 views::View::ConvertPointToScreen(view, &view_center); | 369 views::View::ConvertPointToScreen(view, &view_center); |
| 410 SendMouseMove(view_center.x(), view_center.y()); | 370 SendMouseMove(view_center.x(), view_center.y()); |
| 411 SendMouseEventsNotifyWhenDone(button, state, task); | 371 SendMouseEventsNotifyWhenDone(button, state, task); |
| 412 } | 372 } |
| 413 | 373 |
| 414 } // ui_controls | 374 } // ui_controls |
| OLD | NEW |