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