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(&current_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