summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-31 21:00:58 +0000
committerkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-31 21:00:58 +0000
commit92e93756559df4ddd8c91ad18b6926b873fe47d3 (patch)
treee0ccc69ef5da42b2c80160888ad3ff99c9e6894f
parente6ff5a31f8298bab997b64adcd06e7694733745c (diff)
downloadchromium_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.cc26
-rw-r--r--chrome/browser/automation/automation_provider_observers.h21
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc97
-rw-r--r--chrome/browser/automation/testing_automation_provider.h7
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc5
-rw-r--r--chrome/common/automation_constants.h18
-rw-r--r--chrome/common/notification_type.h7
-rw-r--r--chrome/test/webdriver/run_webdriver_tests.py12
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,