| Index: chrome/browser/automation/ui_controls_linux.cc
|
| ===================================================================
|
| --- chrome/browser/automation/ui_controls_linux.cc (revision 24583)
|
| +++ chrome/browser/automation/ui_controls_linux.cc (working copy)
|
| @@ -28,7 +28,10 @@
|
|
|
| class EventWaiter : public MessageLoopForUI::Observer {
|
| public:
|
| - EventWaiter(Task* task, GdkEventType type) : task_(task), type_(type) {
|
| + EventWaiter(Task* task, GdkEventType type, int count)
|
| + : task_(task),
|
| + type_(type),
|
| + count_(count) {
|
| MessageLoopForUI::current()->AddObserver(this);
|
| }
|
|
|
| @@ -38,7 +41,7 @@
|
|
|
| // MessageLoop::Observer implementation:
|
| virtual void WillProcessEvent(GdkEvent* event) {
|
| - if (event->type == type_) {
|
| + if ((event->type == type_) && (--count_ == 0)) {
|
| // At the time we're invoked the event has not actually been processed.
|
| // Use PostTask to make sure the event has been processed before
|
| // notifying.
|
| @@ -59,6 +62,8 @@
|
| // received.
|
| Task *task_;
|
| GdkEventType type_;
|
| + // The number of events of this type to wait for.
|
| + int count_;
|
| };
|
|
|
| class ClickTask : public Task {
|
| @@ -82,68 +87,118 @@
|
| Task* followup_;
|
| };
|
|
|
| +
|
| +bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) {
|
| + GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
|
| +
|
| + event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
|
| + event->key.window = window;
|
| + g_object_ref(event->key.window);
|
| + event->key.send_event = false;
|
| + event->key.time = EventTimeNow();
|
| +
|
| + event->key.state = state;
|
| + event->key.keyval = key;
|
| +
|
| + GdkKeymapKey* keys;
|
| + gint n_keys;
|
| + if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
|
| + event->key.keyval, &keys, &n_keys)) {
|
| + return false;
|
| + }
|
| + event->key.hardware_keycode = keys[0].keycode;
|
| + event->key.group = keys[0].group;
|
| + g_free(keys);
|
| +
|
| + gdk_event_put(event);
|
| + // gdk_event_put appends a copy of the event.
|
| + gdk_event_free(event);
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| namespace ui_controls {
|
|
|
| bool SendKeyPress(gfx::NativeWindow window,
|
| wchar_t key, bool control, bool shift, bool alt) {
|
| - // TODO(estade): send a release as well?
|
| - GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
|
| -
|
| - event->key.type = GDK_KEY_PRESS;
|
| + GdkWindow* event_window = NULL;
|
| GtkWidget* grab_widget = gtk_grab_get_current();
|
| if (grab_widget) {
|
| // If there is a grab, send all events to the grabbed widget.
|
| - event->key.window = grab_widget->window;
|
| + event_window = grab_widget->window;
|
| } else if (window) {
|
| - event->key.window = GTK_WIDGET(window)->window;
|
| + event_window = GTK_WIDGET(window)->window;
|
| } else {
|
| - // No target was specified. Send the events to the focused window.
|
| + // No target was specified. Send the events to the active toplevel.
|
| GList* windows = gtk_window_list_toplevels();
|
| for (GList* element = windows; element; element = g_list_next(element)) {
|
| - GtkWindow* window = GTK_WINDOW(element->data);
|
| - if (gtk_window_is_active(window)) {
|
| - event->key.window = GTK_WIDGET(window)->window;
|
| + GtkWindow* this_window = GTK_WINDOW(element->data);
|
| + if (gtk_window_is_active(this_window)) {
|
| + event_window = GTK_WIDGET(this_window)->window;
|
| break;
|
| }
|
| }
|
| g_list_free(windows);
|
| }
|
| - DCHECK(event->key.window);
|
| - g_object_ref(event->key.window);
|
| - event->key.send_event = false;
|
| - event->key.time = EventTimeNow();
|
| + if (!event_window) {
|
| + NOTREACHED() << "Window not specified and none is active";
|
| + return false;
|
| + }
|
|
|
| + bool rv = true;
|
| +
|
| + if (control)
|
| + rv = rv && SendKeyEvent(event_window, true, GDK_Control_L, 0);
|
| +
|
| + if (shift) {
|
| + rv = rv && SendKeyEvent(event_window, true, GDK_Shift_L,
|
| + control ? GDK_CONTROL_MASK : 0);
|
| + }
|
| +
|
| + if (alt) {
|
| + guint state = (control ? GDK_CONTROL_MASK : 0) |
|
| + (shift ? GDK_SHIFT_MASK : 0);
|
| + rv = rv && SendKeyEvent(event_window, true, GDK_Alt_L, state);
|
| + }
|
| +
|
| // TODO(estade): handle other state flags besides control, shift, alt?
|
| // For example caps lock.
|
| - event->key.state = (control ? GDK_CONTROL_MASK : 0) |
|
| - (shift ? GDK_SHIFT_MASK : 0) |
|
| - (alt ? GDK_MOD1_MASK : 0);
|
| - event->key.keyval = key;
|
| - // TODO(estade): fill in the string?
|
| + guint state = (control ? GDK_CONTROL_MASK : 0) |
|
| + (shift ? GDK_SHIFT_MASK : 0) |
|
| + (alt ? GDK_MOD1_MASK : 0);
|
| + rv = rv && SendKeyEvent(event_window, true, key, state);
|
| + rv = rv && SendKeyEvent(event_window, false, key, state);
|
|
|
| - GdkKeymapKey* keys;
|
| - gint n_keys;
|
| - if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
|
| - event->key.keyval, &keys, &n_keys)) {
|
| - return false;
|
| + if (alt) {
|
| + guint state = (control ? GDK_CONTROL_MASK : 0) |
|
| + (shift ? GDK_SHIFT_MASK : 0);
|
| + rv = rv && SendKeyEvent(event_window, false, GDK_Alt_L, state);
|
| }
|
| - event->key.hardware_keycode = keys[0].keycode;
|
| - event->key.group = keys[0].group;
|
| - g_free(keys);
|
|
|
| - gdk_event_put(event);
|
| - // gdk_event_put appends a copy of the event.
|
| - gdk_event_free(event);
|
| - return true;
|
| + if (shift) {
|
| + rv = rv && SendKeyEvent(event_window, false, GDK_Shift_L,
|
| + control ? GDK_CONTROL_MASK : 0);
|
| + }
|
| +
|
| + if (control)
|
| + rv = rv && SendKeyEvent(event_window, false, GDK_Control_L, 0);
|
| +
|
| + return rv;
|
| }
|
|
|
| bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, wchar_t key,
|
| bool control, bool shift,
|
| bool alt, Task* task) {
|
| + int release_count = 1;
|
| + if (control)
|
| + release_count++;
|
| + if (shift)
|
| + release_count++;
|
| + if (alt)
|
| + release_count++;
|
| // This object will delete itself after running |task|.
|
| - new EventWaiter(task, GDK_KEY_PRESS);
|
| + new EventWaiter(task, GDK_KEY_RELEASE, release_count);
|
| return SendKeyPress(window, key, control, shift, alt);
|
| }
|
|
|
| @@ -223,7 +278,7 @@
|
| else
|
| wait_type = GDK_3BUTTON_PRESS;
|
| }
|
| - new EventWaiter(task, wait_type);
|
| + new EventWaiter(task, wait_type, 1);
|
| return rv;
|
| }
|
|
|
|
|