diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-31 21:00:58 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-31 21:00:58 +0000 |
commit | 92e93756559df4ddd8c91ad18b6926b873fe47d3 (patch) | |
tree | e0ccc69ef5da42b2c80160888ad3ff99c9e6894f | |
parent | e6ff5a31f8298bab997b64adcd06e7694733745c (diff) | |
download | chromium_src-92e93756559df4ddd8c91ad18b6926b873fe47d3.zip chromium_src-92e93756559df4ddd8c91ad18b6926b873fe47d3.tar.gz chromium_src-92e93756559df4ddd8c91ad18b6926b873fe47d3.tar.bz2 |
Adds a command to the AutomationProvider for sending WebKeyboardEvents to the selected tab.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6298013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73186 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/automation/automation_provider_observers.cc | 26 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_observers.h | 21 | ||||
-rw-r--r-- | chrome/browser/automation/testing_automation_provider.cc | 97 | ||||
-rw-r--r-- | chrome/browser/automation/testing_automation_provider.h | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 5 | ||||
-rw-r--r-- | chrome/common/automation_constants.h | 18 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 7 | ||||
-rw-r--r-- | chrome/test/webdriver/run_webdriver_tests.py | 12 |
8 files changed, 188 insertions, 5 deletions
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc index 3d1f780..cba209c 100644 --- a/chrome/browser/automation/automation_provider_observers.cc +++ b/chrome/browser/automation/automation_provider_observers.cc @@ -1644,6 +1644,31 @@ void RendererProcessClosedObserver::Observe( delete this; } +InputEventAckNotificationObserver::InputEventAckNotificationObserver( + AutomationProvider* automation, + IPC::Message* reply_message, + int event_type) + : automation_(automation), + reply_message_(reply_message), + event_type_(event_type) { + registrar_.Add( + this, NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, + NotificationService::AllSources()); +} + +void InputEventAckNotificationObserver::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + Details<int> request_details(details); + if (event_type_ == *request_details.ptr()) { + AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); + delete this; + } else { + LOG(WARNING) << "Ignoring unexpected event types."; + } +} + NewTabObserver::NewTabObserver(AutomationProvider* automation, IPC::Message* reply_message) : automation_(automation), @@ -1701,4 +1726,3 @@ void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() { automation_->Send(reply_message_); Release(); } - diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h index d7a0c5e..724c79e 100644 --- a/chrome/browser/automation/automation_provider_observers.h +++ b/chrome/browser/automation/automation_provider_observers.h @@ -1028,6 +1028,27 @@ class RendererProcessClosedObserver : public NotificationObserver { DISALLOW_COPY_AND_ASSIGN(RendererProcessClosedObserver); }; +// Allows the automation provider to wait for acknowledgement that a input +// event has been handled. +class InputEventAckNotificationObserver : public NotificationObserver { + public: + InputEventAckNotificationObserver(AutomationProvider* automation, + IPC::Message* reply_message, + int event_type); + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + NotificationRegistrar registrar_; + AutomationProvider* automation_; + IPC::Message* reply_message_; + int event_type_; + + DISALLOW_COPY_AND_ASSIGN(InputEventAckNotificationObserver); +}; + // Observer used to listen for new tab creation to complete. class NewTabObserver : public NotificationObserver { public: diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index d4c946b..9c2e9a1 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -78,6 +78,7 @@ #include "chrome/common/automation_messages.h" #include "net/base/cookie_store.h" #include "net/url_request/url_request_context.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "ui/base/message_box_flags.h" #include "views/event.h" #include "webkit/plugins/npapi/plugin_list.h" @@ -2096,6 +2097,9 @@ void TestingAutomationProvider::SendJSONRequest(int handle, handler_map["KillRendererProcess"] = &TestingAutomationProvider::KillRendererProcess; + handler_map["SendKeyEventToActiveTab"] = + &TestingAutomationProvider::SendKeyEventToActiveTab; + if (handler_map.find(std::string(command)) != handler_map.end()) { (this->*handler_map[command])(browser, dict_value, reply_message); } else { @@ -4373,6 +4377,99 @@ void TestingAutomationProvider::KillRendererProcess( base::CloseProcessHandle(process); } +void TestingAutomationProvider::SendKeyEventToActiveTab( + Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + int type, modifiers; + bool is_system_key; + string16 unmodified_text, text; + std::string key_identifier; + NativeWebKeyboardEvent event; + if (!args->GetInteger("type", &type)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'type' missing or invalid."); + return; + } + if (!args->GetBoolean("isSystemKey", &is_system_key)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'isSystemKey' missing or invalid."); + return; + } + if (!args->GetString("unmodifiedText", &unmodified_text)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'unmodifiedText' missing or invalid."); + return; + } + if (!args->GetString("text", &text)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'text' missing or invalid."); + return; + } + if (!args->GetInteger("nativeKeyCode", &event.nativeKeyCode)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'nativeKeyCode' missing or invalid."); + return; + } + if (!args->GetInteger("windowsKeyCode", &event.windowsKeyCode)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'windowsKeyCode' missing or invalid."); + return; + } + if (!args->GetInteger("modifiers", &modifiers)) { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'modifiers' missing or invalid."); + return; + } + if (args->GetString("keyIdentifier", &key_identifier)) { + base::strlcpy(event.keyIdentifier, + key_identifier.c_str(), + WebKit::WebKeyboardEvent::keyIdentifierLengthCap); + } else { + event.setKeyIdentifierFromWindowsKeyCode(); + } + + if (type == automation::kRawKeyDownType) { + event.type = WebKit::WebInputEvent::RawKeyDown; + } else if (type == automation::kKeyDownType) { + event.type = WebKit::WebInputEvent::KeyDown; + } else if (type == automation::kKeyUpType) { + event.type = WebKit::WebInputEvent::KeyUp; + } else if (type == automation::kCharType) { + event.type = WebKit::WebInputEvent::Char; + } else { + AutomationJSONReply reply(this, reply_message); + reply.SendError("'type' refers to an unrecognized keyboard event type"); + return; + } + + string16 unmodified_text_truncated = unmodified_text.substr( + 0, WebKit::WebKeyboardEvent::textLengthCap - 1); + memcpy(event.unmodifiedText, + unmodified_text_truncated.c_str(), + unmodified_text_truncated.length() + 1); + string16 text_truncated = text.substr( + 0, WebKit::WebKeyboardEvent::textLengthCap - 1); + memcpy(event.text, text_truncated.c_str(), text_truncated.length() + 1); + + event.modifiers = 0; + if (modifiers & automation::kShiftKeyMask) + event.modifiers |= WebKit::WebInputEvent::ShiftKey; + if (modifiers & automation::kControlKeyMask) + event.modifiers |= WebKit::WebInputEvent::ControlKey; + if (modifiers & automation::kAltKeyMask) + event.modifiers |= WebKit::WebInputEvent::AltKey; + if (modifiers & automation::kMetaKeyMask) + event.modifiers |= WebKit::WebInputEvent::MetaKey; + + event.isSystemKey = is_system_key; + event.timeStampSeconds = base::Time::Now().ToDoubleT(); + event.skip_in_browser = true; + new InputEventAckNotificationObserver(this, reply_message, event.type); + browser->GetSelectedTabContents()->render_view_host()-> + ForwardKeyboardEvent(event); +} + void TestingAutomationProvider::WaitForTabCountToBecome( int browser_handle, int target_tab_count, diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h index 27252ef..98c272e 100644 --- a/chrome/browser/automation/testing_automation_provider.h +++ b/chrome/browser/automation/testing_automation_provider.h @@ -750,6 +750,13 @@ class TestingAutomationProvider : public AutomationProvider, DictionaryValue* args, IPC::Message* reply_message); + // Sends a web keyboard event to the active tab. This should not trigger any + // browser hotkeys. + // Uses the JSON interface for input/output. + void SendKeyEventToActiveTab(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message); + void WaitForTabCountToBecome(int browser_handle, int target_tab_count, IPC::Message* reply_message); diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 8985d44..65e55df 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -961,6 +961,11 @@ void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { ProcessKeyboardEventAck(type, processed); } + // This is used only for testing. + NotificationService::current()->Notify( + NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, + Source<RenderWidgetHost>(this), + Details<int>(&type)); } void RenderWidgetHost::ProcessWheelAck() { diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h index 6579776..c4aa683 100644 --- a/chrome/common/automation_constants.h +++ b/chrome/common/automation_constants.h @@ -26,6 +26,24 @@ extern const char kNamedInterfacePrefix[]; // Amount of time to wait before querying the browser. static const int kSleepTime = 250; +// Recognized by the AutomationProvider's SendWebKeyboardEventToSelectedTab +// command. Specifies the type of the keyboard event. +enum KeyEventTypes { + kRawKeyDownType = 0, + kKeyDownType, + kCharType, + kKeyUpType, +}; + +// Recognized by the AutomationProvider's SendWebKeyboardEventToSelectedTab +// command. Specifies masks to be used in constructing keyboard event modifiers. +enum KeyModifierMasks { + kShiftKeyMask = 1 << 0, + kControlKeyMask = 1 << 1, + kAltKeyMask = 1 << 2, + kMetaKeyMask = 1 << 3, +}; + } // namespace automation // Used by AutomationProxy, declared here so that other headers don't need diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index ddfe7b3..174138c 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -472,6 +472,13 @@ class NotificationType { // RenderWidgetHost::PaintAtSizeAckDetails. RENDER_WIDGET_HOST_DID_RECEIVE_PAINT_AT_SIZE_ACK, + // This notifies the observer that a HandleInputEventACK was received. The + // source is the RenderWidgetHost, the details are the type of event + // received. + // Note: The RenderWidgetHost may be deallocated at this point. + // Used only in testing. + RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, + // Sent from ~RenderViewHost. The source is the TabContents. RENDER_VIEW_HOST_DELETED, diff --git a/chrome/test/webdriver/run_webdriver_tests.py b/chrome/test/webdriver/run_webdriver_tests.py index 97faa3b..34eb7c4 100644 --- a/chrome/test/webdriver/run_webdriver_tests.py +++ b/chrome/test/webdriver/run_webdriver_tests.py @@ -92,6 +92,8 @@ class Main(object): TEST_PREFIX = 'test.selenium.webdriver.common.' def __init__(self): + self._tests_path = os.path.join(os.path.dirname(__file__), + self.TESTS_FILENAME) self._ParseArgs() self._Run() @@ -257,11 +259,11 @@ class Main(object): These modules or test cases or tests should be importable """ if not args: # Load tests ourselves - logging.debug("Reading %s", self.TESTS_FILENAME) - if not os.path.exists(self.TESTS_FILENAME): - logging.warn("%s missing. Cannot load tests." % self.TESTS_FILENAME) + logging.debug("Reading %s", self._tests_path) + if not os.path.exists(self._tests_path): + logging.warn("%s missing. Cannot load tests." % self._tests_path) else: - args = self._GetTestNamesFrom(self.TESTS_FILENAME) + args = self._GetTestNamesFrom(self._tests_path) return args @staticmethod @@ -303,6 +305,8 @@ class Main(object): # The tests expect to run with preset 'driver' and 'webserver' class # properties. + import pdb + pdb.set_trace() launcher = ChromeDriverLauncher(self._options.driver_exe) driver = WebDriver(launcher.GetURL(), 'chrome', 'any') # The tests expect a webserver. Since ChromeDriver also operates as one, |