From 202bb6442ab506e2c156fb7d04e82a0151d6e16f Mon Sep 17 00:00:00 2001 From: "estade@chromium.org" Date: Thu, 27 Aug 2009 19:52:05 +0000 Subject: Send release events as well as press events in linux event mocking infrastructure. Also send events for the modifier keys. This matches Windows more closely. I needed this for an test I was writing which I decided to throw away as it was using the wrong approach. Review URL: http://codereview.chromium.org/178002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24650 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/automation/ui_controls_linux.cc | 125 ++++++++++++++++++------- 1 file changed, 90 insertions(+), 35 deletions(-) (limited to 'chrome') diff --git a/chrome/browser/automation/ui_controls_linux.cc b/chrome/browser/automation/ui_controls_linux.cc index 9b5418e..aa18ce2 100644 --- a/chrome/browser/automation/ui_controls_linux.cc +++ b/chrome/browser/automation/ui_controls_linux.cc @@ -28,7 +28,10 @@ guint32 EventTimeNow() { 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 @@ class EventWaiter : public MessageLoopForUI::Observer { // 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 @@ class EventWaiter : public MessageLoopForUI::Observer { // 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 @@ class ClickTask : public Task { 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); + + if (alt) { + guint state = (control ? GDK_CONTROL_MASK : 0) | + (shift ? GDK_SHIFT_MASK : 0); + rv = rv && SendKeyEvent(event_window, false, GDK_Alt_L, 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 (shift) { + rv = rv && SendKeyEvent(event_window, false, GDK_Shift_L, + control ? GDK_CONTROL_MASK : 0); } - 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 (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 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) { else wait_type = GDK_3BUTTON_PRESS; } - new EventWaiter(task, wait_type); + new EventWaiter(task, wait_type, 1); return rv; } -- cgit v1.1