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

Side by Side Diff: chrome/browser/automation/ui_controls.cc

Issue 164371: Checkpoint for event automation porting.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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 "chrome/browser/automation/ui_controls.h"
6
7 #include "base/logging.h"
8 #include "base/message_loop.h"
9 #include "base/ref_counted.h"
10 #include "base/task.h"
11 #include "views/view.h"
12
13 namespace ui_controls {
14
15 namespace {
16
17 // InputDispatcher ------------------------------------------------------------
18
19 // InputDispatcher is used to listen for a mouse/keyboard event. When the
20 // appropriate event is received the task is notified.
21 class InputDispatcher : public base::RefCounted<InputDispatcher> {
22 public:
23 InputDispatcher(Task* task, WPARAM message_waiting_for);
24
25 ~InputDispatcher();
26
27 // Invoked from the hook. If mouse_message matches message_waiting_for_
28 // MatchingMessageFound is invoked.
29 void DispatchedMessage(WPARAM mouse_message);
30
31 // Invoked when a matching event is found. Uninstalls the hook and schedules
32 // an event that notifies the task.
33 void MatchingMessageFound();
34
35 private:
36 // Notifies the task and release this (which should delete it).
37 void NotifyTask();
38
39 // The task we notify.
40 scoped_ptr<Task> task_;
41
42 // Message we're waiting for. Not used for keyboard events.
43 const WPARAM message_waiting_for_;
44
45 DISALLOW_COPY_AND_ASSIGN(InputDispatcher);
46 };
47
48 // Have we installed the hook?
49 bool installed_hook_ = false;
50
51 // Return value from SetWindowsHookEx.
52 HHOOK next_hook_ = NULL;
53
54 // If a hook is installed, this is the dispatcher.
55 InputDispatcher* current_dispatcher_ = NULL;
56
57 // Callback from hook when a mouse message is received.
58 LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param) {
59 HHOOK next_hook = next_hook_;
60 if (n_code == HC_ACTION) {
61 DCHECK(current_dispatcher_);
62 current_dispatcher_->DispatchedMessage(w_param);
63 }
64 return CallNextHookEx(next_hook, n_code, w_param, l_param);
65 }
66
67 // Callback from hook when a key message is received.
68 LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) {
69 HHOOK next_hook = next_hook_;
70 if (n_code == HC_ACTION) {
71 DCHECK(current_dispatcher_);
72 if (l_param & (1 << 30)) // Only send on key up.
73 current_dispatcher_->MatchingMessageFound();
74 }
75 return CallNextHookEx(next_hook, n_code, w_param, l_param);
76 }
77
78 // Installs dispatcher as the current hook.
79 void InstallHook(InputDispatcher* dispatcher, bool key_hook) {
80 DCHECK(!installed_hook_);
81 current_dispatcher_ = dispatcher;
82 installed_hook_ = true;
83 if (key_hook) {
84 next_hook_ = SetWindowsHookEx(WH_KEYBOARD, &KeyHook, NULL,
85 GetCurrentThreadId());
86 } else {
87 // NOTE: I originally tried WH_CALLWNDPROCRET, but for some reason I
88 // didn't get a mouse message like I do with MouseHook.
89 next_hook_ = SetWindowsHookEx(WH_MOUSE, &MouseHook, NULL,
90 GetCurrentThreadId());
91 }
92 DCHECK(next_hook_);
93 }
94
95 // Uninstalls the hook set in InstallHook.
96 void UninstallHook(InputDispatcher* dispatcher) {
97 if (current_dispatcher_ == dispatcher) {
98 installed_hook_ = false;
99 current_dispatcher_ = NULL;
100 UnhookWindowsHookEx(next_hook_);
101 }
102 }
103
104 InputDispatcher::InputDispatcher(Task* task, UINT message_waiting_for)
105 : task_(task), message_waiting_for_(message_waiting_for) {
106 InstallHook(this, message_waiting_for == WM_KEYUP);
107 }
108
109 InputDispatcher::~InputDispatcher() {
110 // Make sure the hook isn't installed.
111 UninstallHook(this);
112 }
113
114 void InputDispatcher::DispatchedMessage(WPARAM message) {
115 if (message == message_waiting_for_)
116 MatchingMessageFound();
117 }
118
119 void InputDispatcher::MatchingMessageFound() {
120 UninstallHook(this);
121 // At the time we're invoked the event has not actually been processed.
122 // Use PostTask to make sure the event has been processed before notifying.
123 MessageLoop::current()->PostDelayedTask(
124 FROM_HERE, NewRunnableMethod(this, &InputDispatcher::NotifyTask), 0);
125 }
126
127 void InputDispatcher::NotifyTask() {
128 task_->Run();
129 Release();
130 }
131
132 // Private functions ----------------------------------------------------------
133
134 // Populate the INPUT structure with the appropriate keyboard event
135 // parameters required by SendInput
136 bool FillKeyboardInput(wchar_t key, INPUT* input, bool key_up) {
137 memset(input, 0, sizeof(INPUT));
138 input->type = INPUT_KEYBOARD;
139 input->ki.wVk = static_cast<WORD>(key);
140 input->ki.dwFlags = key_up ? KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP :
141 KEYEVENTF_EXTENDEDKEY;
142
143 return true;
144 }
145
146 // Send a key event (up/down)
147 bool SendKeyEvent(wchar_t key, bool up) {
148 INPUT input = { 0 };
149
150 if (!FillKeyboardInput(key, &input, up))
151 return false;
152
153 if (!::SendInput(1, &input, sizeof(INPUT)))
154 return false;
155
156 return true;
157 }
158
159 bool SendKeyPressImpl(wchar_t key, bool control, bool shift, bool alt,
160 Task* task) {
161 scoped_refptr<InputDispatcher> dispatcher(
162 task ? new InputDispatcher(task, WM_KEYUP) : NULL);
163
164 INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated
165
166 int i = 0;
167 if (control) {
168 if (!FillKeyboardInput(VK_CONTROL, &input[i], false))
169 return false;
170 i++;
171 }
172
173 if (shift) {
174 if (!FillKeyboardInput(VK_SHIFT, &input[i], false))
175 return false;
176 i++;
177 }
178
179 if (alt) {
180 if (!FillKeyboardInput(VK_MENU, &input[i], false))
181 return false;
182 i++;
183 }
184
185 if (!FillKeyboardInput(key, &input[i], false))
186 return false;
187 i++;
188
189 if (!FillKeyboardInput(key, &input[i], true))
190 return false;
191 i++;
192
193 if (alt) {
194 if (!FillKeyboardInput(VK_MENU, &input[i], true))
195 return false;
196 i++;
197 }
198
199 if (shift) {
200 if (!FillKeyboardInput(VK_SHIFT, &input[i], true))
201 return false;
202 i++;
203 }
204
205 if (control) {
206 if (!FillKeyboardInput(VK_CONTROL, &input[i], true))
207 return false;
208 i++;
209 }
210
211 unsigned int rv = ::SendInput(i, input, sizeof(INPUT));
212
213 if (rv != i)
214 return false;
215
216 if (dispatcher.get())
217 dispatcher->AddRef();
218 return true;
219 }
220
221 bool SendMouseMoveImpl(long x, long y, Task* task) {
222 INPUT input = { 0 };
223
224 int screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1;
225 int screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1;
226 LONG pixel_x = static_cast<LONG>(x * (65535.0f / screen_width));
227 LONG pixel_y = static_cast<LONG>(y * (65535.0f / screen_height));
228
229 input.type = INPUT_MOUSE;
230 input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
231 input.mi.dx = pixel_x;
232 input.mi.dy = pixel_y;
233
234 scoped_refptr<InputDispatcher> dispatcher(
235 task ? new InputDispatcher(task, WM_MOUSEMOVE) : NULL);
236
237 if (!::SendInput(1, &input, sizeof(INPUT)))
238 return false;
239
240 if (dispatcher.get())
241 dispatcher->AddRef();
242
243 return true;
244 }
245
246 bool SendMouseEventsImpl(MouseButton type, int state, Task* task) {
247 DWORD down_flags = MOUSEEVENTF_ABSOLUTE;
248 DWORD up_flags = MOUSEEVENTF_ABSOLUTE;
249 UINT last_event;
250
251 switch(type) {
252 case LEFT:
253 down_flags |= MOUSEEVENTF_LEFTDOWN;
254 up_flags |= MOUSEEVENTF_LEFTUP;
255 last_event = (state & UP) ? WM_LBUTTONUP : WM_LBUTTONDOWN;
256 break;
257
258 case MIDDLE:
259 down_flags |= MOUSEEVENTF_MIDDLEDOWN;
260 up_flags |= MOUSEEVENTF_MIDDLEUP;
261 last_event = (state & UP) ? WM_MBUTTONUP : WM_MBUTTONDOWN;
262 break;
263
264 case RIGHT:
265 down_flags |= MOUSEEVENTF_RIGHTDOWN;
266 up_flags |= MOUSEEVENTF_RIGHTUP;
267 last_event = (state & UP) ? WM_RBUTTONUP : WM_RBUTTONDOWN;
268 break;
269
270 default:
271 NOTREACHED();
272 return false;
273 }
274
275 scoped_refptr<InputDispatcher> dispatcher(
276 task ? new InputDispatcher(task, last_event) : NULL);
277
278 INPUT input = { 0 };
279 input.type = INPUT_MOUSE;
280 input.mi.dwFlags = down_flags;
281 if ((state & DOWN) && !::SendInput(1, &input, sizeof(INPUT)))
282 return false;
283
284 input.mi.dwFlags = up_flags;
285 if ((state & UP) && !::SendInput(1, &input, sizeof(INPUT)))
286 return false;
287
288 if (dispatcher.get())
289 dispatcher->AddRef();
290
291 return true;
292 }
293
294 } // namespace
295
296 // public functions -----------------------------------------------------------
297
298 bool SendKeyPress(wchar_t key, bool control, bool shift, bool alt) {
299 return SendKeyPressImpl(key, control, shift, alt, NULL);
300 }
301
302 bool SendKeyPressNotifyWhenDone(wchar_t key, bool control, bool shift,
303 bool alt, Task* task) {
304 return SendKeyPressImpl(key, control, shift, alt, task);
305 }
306
307 bool SendKeyDown(wchar_t key) {
308 return SendKeyEvent(key, false);
309 }
310
311 bool SendKeyUp(wchar_t key) {
312 return SendKeyEvent(key, true);
313 }
314
315 bool SendMouseMove(long x, long y) {
316 return SendMouseMoveImpl(x, y, NULL);
317 }
318
319 void SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
320 SendMouseMoveImpl(x, y, task);
321 }
322
323 bool SendMouseEvents(MouseButton type, int state) {
324 return SendMouseEventsImpl(type, state, NULL);
325 }
326
327 void SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
328 SendMouseEventsImpl(type, state, task);
329 }
330
331 bool SendMouseClick(MouseButton type) {
332 return SendMouseEventsImpl(type, UP | DOWN, NULL);
333 }
334
335 void MoveMouseToCenterAndPress(views::View* view, MouseButton button,
336 int state, Task* task) {
337 DCHECK(view);
338 DCHECK(view->GetWidget());
339 gfx::Point view_center(view->width() / 2, view->height() / 2);
340 views::View::ConvertPointToScreen(view, &view_center);
341 SendMouseMove(view_center.x(), view_center.y());
342 SendMouseEventsNotifyWhenDone(button, state, task);
343 }
344
345 } // ui_controls
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698