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

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

Issue 178002: Send release events as well as press events in linux event mocking infrastruc... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: style Created 11 years, 3 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 #include <gdk/gdkkeysyms.h> 8 #include <gdk/gdkkeysyms.h>
9 9
10 #include "base/gfx/rect.h" 10 #include "base/gfx/rect.h"
(...skipping 10 matching lines...) Expand all
21 namespace { 21 namespace {
22 22
23 guint32 EventTimeNow() { 23 guint32 EventTimeNow() {
24 struct timespec ts; 24 struct timespec ts;
25 clock_gettime(CLOCK_MONOTONIC, &ts); 25 clock_gettime(CLOCK_MONOTONIC, &ts);
26 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 26 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
27 } 27 }
28 28
29 class EventWaiter : public MessageLoopForUI::Observer { 29 class EventWaiter : public MessageLoopForUI::Observer {
30 public: 30 public:
31 EventWaiter(Task* task, GdkEventType type) : task_(task), type_(type) { 31 EventWaiter(Task* task, GdkEventType type, int count)
32 : task_(task),
33 type_(type),
34 count_(count) {
32 MessageLoopForUI::current()->AddObserver(this); 35 MessageLoopForUI::current()->AddObserver(this);
33 } 36 }
34 37
35 virtual ~EventWaiter() { 38 virtual ~EventWaiter() {
36 MessageLoopForUI::current()->RemoveObserver(this); 39 MessageLoopForUI::current()->RemoveObserver(this);
37 } 40 }
38 41
39 // MessageLoop::Observer implementation: 42 // MessageLoop::Observer implementation:
40 virtual void WillProcessEvent(GdkEvent* event) { 43 virtual void WillProcessEvent(GdkEvent* event) {
41 if (event->type == type_) { 44 if ((event->type == type_) && (--count_ == 0)) {
42 // At the time we're invoked the event has not actually been processed. 45 // At the time we're invoked the event has not actually been processed.
43 // Use PostTask to make sure the event has been processed before 46 // Use PostTask to make sure the event has been processed before
44 // notifying. 47 // notifying.
45 // NOTE: if processing a message results in running a nested message 48 // NOTE: if processing a message results in running a nested message
46 // loop, then DidProcessEvent isn't immediately sent. As such, we do 49 // loop, then DidProcessEvent isn't immediately sent. As such, we do
47 // the processing in WillProcessEvent rather than DidProcessEvent. 50 // the processing in WillProcessEvent rather than DidProcessEvent.
48 MessageLoop::current()->PostTask(FROM_HERE, task_); 51 MessageLoop::current()->PostTask(FROM_HERE, task_);
49 delete this; 52 delete this;
50 } 53 }
51 } 54 }
52 55
53 virtual void DidProcessEvent(GdkEvent* event) { 56 virtual void DidProcessEvent(GdkEvent* event) {
54 // No-op. 57 // No-op.
55 } 58 }
56 59
57 private: 60 private:
58 // We pass ownership of task_ to MessageLoop when the corrent event is 61 // We pass ownership of task_ to MessageLoop when the corrent event is
59 // received. 62 // received.
60 Task *task_; 63 Task *task_;
61 GdkEventType type_; 64 GdkEventType type_;
65 // The number of events of this type to wait for.
66 int count_;
62 }; 67 };
63 68
64 class ClickTask : public Task { 69 class ClickTask : public Task {
65 public: 70 public:
66 ClickTask(ui_controls::MouseButton button, int state, Task* followup) 71 ClickTask(ui_controls::MouseButton button, int state, Task* followup)
67 : button_(button), state_(state), followup_(followup) { 72 : button_(button), state_(state), followup_(followup) {
68 } 73 }
69 74
70 virtual ~ClickTask() {} 75 virtual ~ClickTask() {}
71 76
72 virtual void Run() { 77 virtual void Run() {
73 if (followup_) 78 if (followup_)
74 ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_); 79 ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_);
75 else 80 else
76 ui_controls::SendMouseEvents(button_, state_); 81 ui_controls::SendMouseEvents(button_, state_);
77 } 82 }
78 83
79 private: 84 private:
80 ui_controls::MouseButton button_; 85 ui_controls::MouseButton button_;
81 int state_; 86 int state_;
82 Task* followup_; 87 Task* followup_;
83 }; 88 };
84 89
85 } // namespace
86 90
87 namespace ui_controls { 91 bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) {
92 GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
88 93
89 bool SendKeyPress(gfx::NativeWindow window, 94 event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
90 wchar_t key, bool control, bool shift, bool alt) { 95 event->key.window = window;
91 // TODO(estade): send a release as well?
92 GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
93
94 event->key.type = GDK_KEY_PRESS;
95 GtkWidget* grab_widget = gtk_grab_get_current();
96 if (grab_widget) {
97 // If there is a grab, send all events to the grabbed widget.
98 event->key.window = grab_widget->window;
99 } else if (window) {
100 event->key.window = GTK_WIDGET(window)->window;
101 } else {
102 // No target was specified. Send the events to the focused window.
103 GList* windows = gtk_window_list_toplevels();
104 for (GList* element = windows; element; element = g_list_next(element)) {
105 GtkWindow* window = GTK_WINDOW(element->data);
106 if (gtk_window_is_active(window)) {
107 event->key.window = GTK_WIDGET(window)->window;
108 break;
109 }
110 }
111 g_list_free(windows);
112 }
113 DCHECK(event->key.window);
114 g_object_ref(event->key.window); 96 g_object_ref(event->key.window);
115 event->key.send_event = false; 97 event->key.send_event = false;
116 event->key.time = EventTimeNow(); 98 event->key.time = EventTimeNow();
117 99
118 // TODO(estade): handle other state flags besides control, shift, alt? 100 event->key.state = state;
119 // For example caps lock.
120 event->key.state = (control ? GDK_CONTROL_MASK : 0) |
121 (shift ? GDK_SHIFT_MASK : 0) |
122 (alt ? GDK_MOD1_MASK : 0);
123 event->key.keyval = key; 101 event->key.keyval = key;
124 // TODO(estade): fill in the string?
125 102
126 GdkKeymapKey* keys; 103 GdkKeymapKey* keys;
127 gint n_keys; 104 gint n_keys;
128 if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), 105 if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
129 event->key.keyval, &keys, &n_keys)) { 106 event->key.keyval, &keys, &n_keys)) {
130 return false; 107 return false;
131 } 108 }
132 event->key.hardware_keycode = keys[0].keycode; 109 event->key.hardware_keycode = keys[0].keycode;
133 event->key.group = keys[0].group; 110 event->key.group = keys[0].group;
134 g_free(keys); 111 g_free(keys);
135 112
136 gdk_event_put(event); 113 gdk_event_put(event);
137 // gdk_event_put appends a copy of the event. 114 // gdk_event_put appends a copy of the event.
138 gdk_event_free(event); 115 gdk_event_free(event);
139 return true; 116 return true;
140 } 117 }
141 118
119 } // namespace
120
121 namespace ui_controls {
122
123 bool SendKeyPress(gfx::NativeWindow window,
124 wchar_t key, bool control, bool shift, bool alt) {
125 GdkWindow* event_window = NULL;
126 GtkWidget* grab_widget = gtk_grab_get_current();
127 if (grab_widget) {
128 // If there is a grab, send all events to the grabbed widget.
129 event_window = grab_widget->window;
130 } else if (window) {
131 event_window = GTK_WIDGET(window)->window;
132 } else {
133 // No target was specified. Send the events to the active toplevel.
134 GList* windows = gtk_window_list_toplevels();
135 for (GList* element = windows; element; element = g_list_next(element)) {
136 GtkWindow* this_window = GTK_WINDOW(element->data);
137 if (gtk_window_is_active(this_window)) {
138 event_window = GTK_WIDGET(this_window)->window;
139 break;
140 }
141 }
142 g_list_free(windows);
143 }
144 if (!event_window) {
145 NOTREACHED() << "Window not specified and none is active";
146 return false;
147 }
148
149 bool rv = true;
150
151 if (control)
152 rv = rv && SendKeyEvent(event_window, true, GDK_Control_L, 0);
153
154 if (shift) {
155 rv = rv && SendKeyEvent(event_window, true, GDK_Shift_L,
156 control ? GDK_CONTROL_MASK : 0);
157 }
158
159 if (alt) {
160 guint state = (control ? GDK_CONTROL_MASK : 0) |
161 (shift ? GDK_SHIFT_MASK : 0);
162 rv = rv && SendKeyEvent(event_window, true, GDK_Alt_L, state);
163 }
164
165 // TODO(estade): handle other state flags besides control, shift, alt?
166 // For example caps lock.
167 guint state = (control ? GDK_CONTROL_MASK : 0) |
168 (shift ? GDK_SHIFT_MASK : 0) |
169 (alt ? GDK_MOD1_MASK : 0);
170 rv = rv && SendKeyEvent(event_window, true, key, state);
171 rv = rv && SendKeyEvent(event_window, false, key, state);
172
173 if (alt) {
174 guint state = (control ? GDK_CONTROL_MASK : 0) |
175 (shift ? GDK_SHIFT_MASK : 0);
176 rv = rv && SendKeyEvent(event_window, false, GDK_Alt_L, state);
177 }
178
179 if (shift) {
180 rv = rv && SendKeyEvent(event_window, false, GDK_Shift_L,
181 control ? GDK_CONTROL_MASK : 0);
182 }
183
184 if (control)
185 rv = rv && SendKeyEvent(event_window, false, GDK_Control_L, 0);
186
187 return rv;
188 }
189
142 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, wchar_t key, 190 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, wchar_t key,
143 bool control, bool shift, 191 bool control, bool shift,
144 bool alt, Task* task) { 192 bool alt, Task* task) {
193 int release_count = 1;
194 if (control)
195 release_count++;
196 if (shift)
197 release_count++;
198 if (alt)
199 release_count++;
145 // This object will delete itself after running |task|. 200 // This object will delete itself after running |task|.
146 new EventWaiter(task, GDK_KEY_PRESS); 201 new EventWaiter(task, GDK_KEY_RELEASE, release_count);
147 return SendKeyPress(window, key, control, shift, alt); 202 return SendKeyPress(window, key, control, shift, alt);
148 } 203 }
149 204
150 bool SendMouseMove(long x, long y) { 205 bool SendMouseMove(long x, long y) {
151 gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), 206 gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(),
152 x, y); 207 x, y);
153 return true; 208 return true;
154 } 209 }
155 210
156 bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) { 211 bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 if (state & UP) { 271 if (state & UP) {
217 wait_type = GDK_BUTTON_RELEASE; 272 wait_type = GDK_BUTTON_RELEASE;
218 } else { 273 } else {
219 if (type == LEFT) 274 if (type == LEFT)
220 wait_type = GDK_BUTTON_PRESS; 275 wait_type = GDK_BUTTON_PRESS;
221 else if (type == MIDDLE) 276 else if (type == MIDDLE)
222 wait_type = GDK_2BUTTON_PRESS; 277 wait_type = GDK_2BUTTON_PRESS;
223 else 278 else
224 wait_type = GDK_3BUTTON_PRESS; 279 wait_type = GDK_3BUTTON_PRESS;
225 } 280 }
226 new EventWaiter(task, wait_type); 281 new EventWaiter(task, wait_type, 1);
227 return rv; 282 return rv;
228 } 283 }
229 284
230 bool SendMouseClick(MouseButton type) { 285 bool SendMouseClick(MouseButton type) {
231 return SendMouseEvents(type, UP | DOWN); 286 return SendMouseEvents(type, UP | DOWN);
232 } 287 }
233 288
234 #if defined(TOOLKIT_VIEWS) 289 #if defined(TOOLKIT_VIEWS)
235 void MoveMouseToCenterAndPress(views::View* view, MouseButton button, 290 void MoveMouseToCenterAndPress(views::View* view, MouseButton button,
236 int state, Task* task) { 291 int state, Task* task) {
237 gfx::Point view_center(view->width() / 2, view->height() / 2); 292 gfx::Point view_center(view->width() / 2, view->height() / 2);
238 views::View::ConvertPointToScreen(view, &view_center); 293 views::View::ConvertPointToScreen(view, &view_center);
239 SendMouseMoveNotifyWhenDone(view_center.x(), view_center.y(), 294 SendMouseMoveNotifyWhenDone(view_center.x(), view_center.y(),
240 new ClickTask(button, state, task)); 295 new ClickTask(button, state, task));
241 } 296 }
242 #else 297 #else
243 void MoveMouseToCenterAndPress(GtkWidget* widget, 298 void MoveMouseToCenterAndPress(GtkWidget* widget,
244 MouseButton button, 299 MouseButton button,
245 int state, 300 int state,
246 Task* task) { 301 Task* task) {
247 gfx::Rect bounds = gtk_util::GetWidgetScreenBounds(widget); 302 gfx::Rect bounds = gtk_util::GetWidgetScreenBounds(widget);
248 SendMouseMoveNotifyWhenDone(bounds.x() + bounds.width() / 2, 303 SendMouseMoveNotifyWhenDone(bounds.x() + bounds.width() / 2,
249 bounds.y() + bounds.height() / 2, 304 bounds.y() + bounds.height() / 2,
250 new ClickTask(button, state, task)); 305 new ClickTask(button, state, task));
251 } 306 }
252 #endif 307 #endif
253 308
254 } // namespace ui_controls 309 } // namespace ui_controls
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698