1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/automation/ui_controls.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/keycodes/keyboard_codes.h" 1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/keycodes/keyboard_code_conversion_win.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/view.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace ui_controls { 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// InputDispatcher ------------------------------------------------------------ 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// InputDispatcher is used to listen for a mouse/keyboard event. When the 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// appropriate event is received the task is notified. 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass InputDispatcher : public base::RefCounted<InputDispatcher> { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputDispatcher(Task* task, WPARAM message_waiting_for); 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Invoked from the hook. If mouse_message matches message_waiting_for_ 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // MatchingMessageFound is invoked. 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DispatchedMessage(WPARAM mouse_message); 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Invoked when a matching event is found. Uninstalls the hook and schedules 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // an event that notifies the task. 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void MatchingMessageFound(); 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch friend class base::RefCounted<InputDispatcher>; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ~InputDispatcher(); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Notifies the task and release this (which should delete it). 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void NotifyTask(); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The task we notify. 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Task> task_; 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Message we're waiting for. Not used for keyboard events. 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WPARAM message_waiting_for_; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(InputDispatcher); 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Have we installed the hook? 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool installed_hook_ = false; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return value from SetWindowsHookEx. 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHHOOK next_hook_ = NULL; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If a hook is installed, this is the dispatcher. 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochInputDispatcher* current_dispatcher_ = NULL; 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Callback from hook when a mouse message is received. 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochLRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param) { 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HHOOK next_hook = next_hook_; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (n_code == HC_ACTION) { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(current_dispatcher_); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_dispatcher_->DispatchedMessage(w_param); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CallNextHookEx(next_hook, n_code, w_param, l_param); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Callback from hook when a key message is received. 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochLRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HHOOK next_hook = next_hook_; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (n_code == HC_ACTION) { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(current_dispatcher_); 7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (l_param & (1 << 30)) { 7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Only send on key up. 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_dispatcher_->MatchingMessageFound(); 79201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CallNextHookEx(next_hook, n_code, w_param, l_param); 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Installs dispatcher as the current hook. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InstallHook(InputDispatcher* dispatcher, bool key_hook) { 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!installed_hook_); 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_dispatcher_ = dispatcher; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch installed_hook_ = true; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (key_hook) { 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch next_hook_ = SetWindowsHookEx(WH_KEYBOARD, &KeyHook, NULL, 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetCurrentThreadId()); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: I originally tried WH_CALLWNDPROCRET, but for some reason I 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // didn't get a mouse message like I do with MouseHook. 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch next_hook_ = SetWindowsHookEx(WH_MOUSE, &MouseHook, NULL, 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetCurrentThreadId()); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(next_hook_); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Uninstalls the hook set in InstallHook. 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UninstallHook(InputDispatcher* dispatcher) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_dispatcher_ == dispatcher) { 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch installed_hook_ = false; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_dispatcher_ = NULL; 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnhookWindowsHookEx(next_hook_); 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochInputDispatcher::InputDispatcher(Task* task, UINT message_waiting_for) 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : task_(task), message_waiting_for_(message_waiting_for) { 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InstallHook(this, message_waiting_for == WM_KEYUP); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochInputDispatcher::~InputDispatcher() { 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the hook isn't installed. 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UninstallHook(this); 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InputDispatcher::DispatchedMessage(WPARAM message) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (message == message_waiting_for_) 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MatchingMessageFound(); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InputDispatcher::MatchingMessageFound() { 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UninstallHook(this); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // At the time we're invoked the event has not actually been processed. 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use PostTask to make sure the event has been processed before notifying. 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostDelayedTask( 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, NewRunnableMethod(this, &InputDispatcher::NotifyTask), 0); 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InputDispatcher::NotifyTask() { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task_->Run(); 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Release(); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Private functions ---------------------------------------------------------- 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Populate the INPUT structure with the appropriate keyboard event 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// parameters required by SendInput 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool FillKeyboardInput(ui::KeyboardCode key, INPUT* input, bool key_up) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(input, 0, sizeof(INPUT)); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input->type = INPUT_KEYBOARD; 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen input->ki.wVk = ui::WindowsKeyCodeForKeyboardCode(key); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input->ki.dwFlags = key_up ? KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP : 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KEYEVENTF_EXTENDEDKEY; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Send a key event (up/down) 15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SendKeyEvent(ui::KeyboardCode key, bool up) { 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch INPUT input = { 0 }; 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!FillKeyboardInput(key, &input, up)) 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!::SendInput(1, &input, sizeof(INPUT))) 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SendKeyPressImpl(ui::KeyboardCode key, 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool control, bool shift, bool alt, 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Task* task) { 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<InputDispatcher> dispatcher( 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task ? new InputDispatcher(task, WM_KEYUP) : NULL); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If a pop-up menu is open, it won't receive events sent using SendInput. 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check for a pop-up menu using its window class (#32768) and if one 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // exists, send the key event directly there. 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HWND popup_menu = ::FindWindow(L"#32768", 0); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) { 17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen WPARAM w_param = ui::WindowsKeyCodeForKeyboardCode(key); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LPARAM l_param = 0; 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (dispatcher.get()) 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatcher->AddRef(); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated. 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UINT i = 0; 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (control) { 19072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_CONTROL, &input[i], false)) 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shift) { 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_SHIFT, &input[i], false)) 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (alt) { 20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_MENU, &input[i], false)) 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!FillKeyboardInput(key, &input[i], false)) 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!FillKeyboardInput(key, &input[i], true)) 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (alt) { 21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_MENU, &input[i], true)) 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shift) { 22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_SHIFT, &input[i], true)) 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (control) { 22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!FillKeyboardInput(ui::VKEY_CONTROL, &input[i], true)) 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i++; 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (::SendInput(i, input, sizeof(INPUT)) != i) 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (dispatcher.get()) 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatcher->AddRef(); 238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseMoveImpl(long x, long y, Task* task) { 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First check if the mouse is already there. 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch POINT current_pos; 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ::GetCursorPos(¤t_pos); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (x == current_pos.x && y == current_pos.y) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (task) 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostTask(FROM_HERE, task); 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch INPUT input = { 0 }; 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1; 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LONG pixel_x = static_cast<LONG>(x * (65535.0f / screen_width)); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LONG pixel_y = static_cast<LONG>(y * (65535.0f / screen_height)); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.type = INPUT_MOUSE; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.mi.dx = pixel_x; 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.mi.dy = pixel_y; 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<InputDispatcher> dispatcher( 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task ? new InputDispatcher(task, WM_MOUSEMOVE) : NULL); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!::SendInput(1, &input, sizeof(INPUT))) 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (dispatcher.get()) 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatcher->AddRef(); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseEventsImpl(MouseButton type, int state, Task* task) { 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DWORD down_flags = MOUSEEVENTF_ABSOLUTE; 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DWORD up_flags = MOUSEEVENTF_ABSOLUTE; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UINT last_event; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type) { 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case LEFT: 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch down_flags |= MOUSEEVENTF_LEFTDOWN; 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch up_flags |= MOUSEEVENTF_LEFTUP; 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_event = (state & UP) ? WM_LBUTTONUP : WM_LBUTTONDOWN; 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case MIDDLE: 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch down_flags |= MOUSEEVENTF_MIDDLEDOWN; 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch up_flags |= MOUSEEVENTF_MIDDLEUP; 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_event = (state & UP) ? WM_MBUTTONUP : WM_MBUTTONDOWN; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case RIGHT: 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch down_flags |= MOUSEEVENTF_RIGHTDOWN; 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch up_flags |= MOUSEEVENTF_RIGHTUP; 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_event = (state & UP) ? WM_RBUTTONUP : WM_RBUTTONDOWN; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<InputDispatcher> dispatcher( 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task ? new InputDispatcher(task, last_event) : NULL); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch INPUT input = { 0 }; 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.type = INPUT_MOUSE; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.mi.dwFlags = down_flags; 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((state & DOWN) && !::SendInput(1, &input, sizeof(INPUT))) 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.mi.dwFlags = up_flags; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((state & UP) && !::SendInput(1, &input, sizeof(INPUT))) 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (dispatcher.get()) 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatcher->AddRef(); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// public functions ----------------------------------------------------------- 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool SendKeyPress(gfx::NativeWindow window, 329dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ui::KeyboardCode key, 330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool control, 331dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool shift, 332dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool alt, 333dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool command) { 334dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(!command); // No command key on Windows 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendKeyPressImpl(key, control, shift, alt, NULL); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, 33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::KeyboardCode key, 340dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool control, 341dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool shift, 342dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool alt, 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool command, 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Task* task) { 345dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(!command); // No command key on Windows 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendKeyPressImpl(key, control, shift, alt, task); 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseMove(long x, long y) { 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendMouseMoveImpl(x, y, NULL); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) { 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendMouseMoveImpl(x, y, task); 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseEvents(MouseButton type, int state) { 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendMouseEventsImpl(type, state, NULL); 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) { 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendMouseEventsImpl(type, state, task); 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendMouseClick(MouseButton type) { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SendMouseEventsImpl(type, UP | DOWN, NULL); 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid MoveMouseToCenterAndPress(views::View* view, 370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen MouseButton button, 371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int state, 372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Task* task) { 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(view); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(view->GetWidget()); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point view_center(view->width() / 2, view->height() / 2); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToScreen(view, &view_center); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendMouseMove(view_center.x(), view_center.y()); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendMouseEventsNotifyWhenDone(button, state, task); 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // ui_controls 382