Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / components / test_runner / event_sender.cc
blobb648b89512f76e0acd0af237eee2b9f5924c5a56
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/test_runner/event_sender.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/test_runner/mock_spell_check.h"
12 #include "components/test_runner/test_interfaces.h"
13 #include "components/test_runner/web_test_delegate.h"
14 #include "components/test_runner/web_test_proxy.h"
15 #include "gin/handle.h"
16 #include "gin/object_template_builder.h"
17 #include "gin/wrappable.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
19 #include "third_party/WebKit/public/platform/WebVector.h"
20 #include "third_party/WebKit/public/web/WebContextMenuData.h"
21 #include "third_party/WebKit/public/web/WebFrame.h"
22 #include "third_party/WebKit/public/web/WebKit.h"
23 #include "third_party/WebKit/public/web/WebPagePopup.h"
24 #include "third_party/WebKit/public/web/WebView.h"
25 #include "ui/events/keycodes/dom/keycode_converter.h"
26 #include "ui/events/keycodes/keyboard_codes.h"
27 #include "v8/include/v8.h"
29 using blink::WebContextMenuData;
30 using blink::WebDragData;
31 using blink::WebDragOperationsMask;
32 using blink::WebFloatPoint;
33 using blink::WebFrame;
34 using blink::WebGestureEvent;
35 using blink::WebInputEvent;
36 using blink::WebKeyboardEvent;
37 using blink::WebMenuItemInfo;
38 using blink::WebMouseEvent;
39 using blink::WebMouseWheelEvent;
40 using blink::WebPagePopup;
41 using blink::WebPoint;
42 using blink::WebString;
43 using blink::WebTouchEvent;
44 using blink::WebTouchPoint;
45 using blink::WebVector;
46 using blink::WebView;
48 namespace test_runner {
50 namespace {
52 void InitMouseEvent(WebInputEvent::Type t,
53 WebMouseEvent::Button b,
54 const WebPoint& pos,
55 double time_stamp,
56 int click_count,
57 int modifiers,
58 WebMouseEvent* e) {
59 e->type = t;
60 e->button = b;
61 e->modifiers = modifiers;
62 e->x = pos.x;
63 e->y = pos.y;
64 e->globalX = pos.x;
65 e->globalY = pos.y;
66 e->timeStampSeconds = time_stamp;
67 e->clickCount = click_count;
70 int GetKeyModifier(const std::string& modifier_name) {
71 const char* characters = modifier_name.c_str();
72 if (!strcmp(characters, "ctrlKey")
73 #ifndef __APPLE__
74 || !strcmp(characters, "addSelectionKey")
75 #endif
76 ) {
77 return WebInputEvent::ControlKey;
78 } else if (!strcmp(characters, "shiftKey") ||
79 !strcmp(characters, "rangeSelectionKey")) {
80 return WebInputEvent::ShiftKey;
81 } else if (!strcmp(characters, "altKey")) {
82 return WebInputEvent::AltKey;
83 #ifdef __APPLE__
84 } else if (!strcmp(characters, "metaKey") ||
85 !strcmp(characters, "addSelectionKey")) {
86 return WebInputEvent::MetaKey;
87 #else
88 } else if (!strcmp(characters, "metaKey")) {
89 return WebInputEvent::MetaKey;
90 #endif
91 } else if (!strcmp(characters, "autoRepeat")) {
92 return WebInputEvent::IsAutoRepeat;
93 } else if (!strcmp(characters, "copyKey")) {
94 #ifdef __APPLE__
95 return WebInputEvent::AltKey;
96 #else
97 return WebInputEvent::ControlKey;
98 #endif
99 } else if (!strcmp(characters, "leftButton")) {
100 return WebInputEvent::LeftButtonDown;
101 } else if (!strcmp(characters, "middleButton")) {
102 return WebInputEvent::MiddleButtonDown;
103 } else if (!strcmp(characters, "rightButton")) {
104 return WebInputEvent::RightButtonDown;
107 return 0;
110 int GetKeyModifiers(const std::vector<std::string>& modifier_names) {
111 int modifiers = 0;
112 for (std::vector<std::string>::const_iterator it = modifier_names.begin();
113 it != modifier_names.end(); ++it) {
114 modifiers |= GetKeyModifier(*it);
116 return modifiers;
119 int GetKeyModifiersFromV8(v8::Isolate* isolate, v8::Local<v8::Value> value) {
120 std::vector<std::string> modifier_names;
121 if (value->IsString()) {
122 modifier_names.push_back(gin::V8ToString(value));
123 } else if (value->IsArray()) {
124 gin::Converter<std::vector<std::string> >::FromV8(
125 isolate, value, &modifier_names);
127 return GetKeyModifiers(modifier_names);
130 // Maximum distance (in space and time) for a mouse click to register as a
131 // double or triple click.
132 const double kMultipleClickTimeSec = 1;
133 const int kMultipleClickRadiusPixels = 5;
134 const char kSubMenuDepthIdentifier[] = "_";
135 const char kSubMenuIdentifier[] = " >";
136 const char kSeparatorIdentifier[] = "---------";
137 const char kDisabledIdentifier[] = "#";
138 const char kCheckedIdentifier[] = "*";
140 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
141 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
142 kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
145 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
146 const std::string& prefix, std::vector<std::string>* strings) {
147 for (size_t i = 0; i < customItems.size(); ++i) {
148 std::string prefixCopy = prefix;
149 if (!customItems[i].enabled)
150 prefixCopy = kDisabledIdentifier + prefix;
151 if (customItems[i].checked)
152 prefixCopy = kCheckedIdentifier + prefix;
153 if (customItems[i].type == blink::WebMenuItemInfo::Separator) {
154 strings->push_back(prefixCopy + kSeparatorIdentifier);
155 } else if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
156 strings->push_back(prefixCopy + customItems[i].label.utf8() +
157 customItems[i].icon.utf8() + kSubMenuIdentifier);
158 PopulateCustomItems(customItems[i].subMenuItems, prefixCopy +
159 kSubMenuDepthIdentifier, strings);
160 } else {
161 strings->push_back(prefixCopy + customItems[i].label.utf8() +
162 customItems[i].icon.utf8());
167 // Because actual context menu is implemented by the browser side,
168 // this function does only what LayoutTests are expecting:
169 // - Many test checks the count of items. So returning non-zero value makes
170 // sense.
171 // - Some test compares the count before and after some action. So changing the
172 // count based on flags also makes sense. This function is doing such for some
173 // flags.
174 // - Some test even checks actual string content. So providing it would be also
175 // helpful.
176 std::vector<std::string> MakeMenuItemStringsFor(
177 WebContextMenuData* context_menu,
178 WebTestDelegate* delegate) {
179 // These constants are based on Safari's context menu because tests are made
180 // for it.
181 static const char* kNonEditableMenuStrings[] = {
182 "Back",
183 "Reload Page",
184 "Open in Dashbaord",
185 "<separator>",
186 "View Source",
187 "Save Page As",
188 "Print Page",
189 "Inspect Element",
192 static const char* kEditableMenuStrings[] = {
193 "Cut",
194 "Copy",
195 "<separator>",
196 "Paste",
197 "Spelling and Grammar",
198 "Substitutions, Transformations",
199 "Font",
200 "Speech",
201 "Paragraph Direction",
202 "<separator>",
206 // This is possible because mouse events are cancelleable.
207 if (!context_menu)
208 return std::vector<std::string>();
210 std::vector<std::string> strings;
212 // Populate custom menu items if provided by blink.
213 PopulateCustomItems(context_menu->customItems, "", &strings);
215 if (context_menu->isEditable) {
216 for (const char** item = kEditableMenuStrings; *item; ++item) {
217 strings.push_back(*item);
219 WebVector<WebString> suggestions;
220 MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
221 &suggestions);
222 for (size_t i = 0; i < suggestions.size(); ++i) {
223 strings.push_back(suggestions[i].utf8());
225 } else {
226 for (const char** item = kNonEditableMenuStrings; *item; ++item) {
227 strings.push_back(*item);
231 return strings;
234 // How much we should scroll per event - the value here is chosen to match the
235 // WebKit impl and layout test results.
236 const float kScrollbarPixelsPerTick = 40.0f;
238 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
239 if (!button_code)
240 return WebMouseEvent::ButtonLeft;
241 if (button_code == 2)
242 return WebMouseEvent::ButtonRight;
243 return WebMouseEvent::ButtonMiddle;
246 class MouseDownTask : public WebMethodTask<EventSender> {
247 public:
248 MouseDownTask(EventSender* obj, int button_number, int modifiers)
249 : WebMethodTask<EventSender>(obj),
250 button_number_(button_number),
251 modifiers_(modifiers) {}
253 void RunIfValid() override { object_->MouseDown(button_number_, modifiers_); }
255 private:
256 int button_number_;
257 int modifiers_;
260 class MouseUpTask : public WebMethodTask<EventSender> {
261 public:
262 MouseUpTask(EventSender* obj, int button_number, int modifiers)
263 : WebMethodTask<EventSender>(obj),
264 button_number_(button_number),
265 modifiers_(modifiers) {}
267 void RunIfValid() override { object_->MouseUp(button_number_, modifiers_); }
269 private:
270 int button_number_;
271 int modifiers_;
274 class KeyDownTask : public WebMethodTask<EventSender> {
275 public:
276 KeyDownTask(EventSender* obj,
277 const std::string code_str,
278 int modifiers,
279 KeyLocationCode location)
280 : WebMethodTask<EventSender>(obj),
281 code_str_(code_str),
282 modifiers_(modifiers),
283 location_(location) {}
285 void RunIfValid() override {
286 object_->KeyDown(code_str_, modifiers_, location_);
289 private:
290 std::string code_str_;
291 int modifiers_;
292 KeyLocationCode location_;
295 bool NeedsShiftModifier(int keyCode) {
296 // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
297 return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
300 // Get the edit command corresponding to a keyboard event.
301 // Returns true if the specified event corresponds to an edit command, the name
302 // of the edit command will be stored in |*name|.
303 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
304 #if defined(OS_MACOSX)
305 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
306 // modifiers. These key events correspond to some special movement and
307 // selection editor commands. These keys will be marked as system key, which
308 // prevents them from being handled. Thus they must be handled specially.
309 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
310 WebKeyboardEvent::MetaKey)
311 return false;
313 switch (event.windowsKeyCode) {
314 case ui::VKEY_LEFT:
315 *name = "MoveToBeginningOfLine";
316 break;
317 case ui::VKEY_RIGHT:
318 *name = "MoveToEndOfLine";
319 break;
320 case ui::VKEY_UP:
321 *name = "MoveToBeginningOfDocument";
322 break;
323 case ui::VKEY_DOWN:
324 *name = "MoveToEndOfDocument";
325 break;
326 default:
327 return false;
330 if (event.modifiers & WebKeyboardEvent::ShiftKey)
331 name->append("AndModifySelection");
333 return true;
334 #else
335 return false;
336 #endif
339 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
340 #if defined(OS_MACOSX)
341 return event.modifiers & WebInputEvent::MetaKey &&
342 event.windowsKeyCode != ui::VKEY_B &&
343 event.windowsKeyCode != ui::VKEY_I;
344 #else
345 return !!(event.modifiers & WebInputEvent::AltKey);
346 #endif
349 const char* kSourceDeviceStringTouchpad = "touchpad";
350 const char* kSourceDeviceStringTouchscreen = "touchscreen";
352 const char* kPointerTypeStringUnknown = "";
353 const char* kPointerTypeStringMouse = "mouse";
354 const char* kPointerTypeStringPen = "pen";
355 const char* kPointerTypeStringTouch = "touch";
357 } // namespace
359 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
360 public:
361 static gin::WrapperInfo kWrapperInfo;
363 static void Install(base::WeakPtr<EventSender> sender,
364 blink::WebFrame* frame);
366 private:
367 explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
368 ~EventSenderBindings() override;
370 // gin::Wrappable:
371 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
372 v8::Isolate* isolate) override;
374 // Bound methods:
375 void EnableDOMUIEventLogging();
376 void FireKeyboardEventsToElement();
377 void ClearKillRing();
378 std::vector<std::string> ContextClick();
379 void TextZoomIn();
380 void TextZoomOut();
381 void ZoomPageIn();
382 void ZoomPageOut();
383 void SetPageZoomFactor(double factor);
384 void ClearTouchPoints();
385 void ReleaseTouchPoint(unsigned index);
386 void UpdateTouchPoint(unsigned index,
387 double x,
388 double y,
389 gin::Arguments* args);
390 void CancelTouchPoint(unsigned index);
391 void SetTouchModifier(const std::string& key_name, bool set_mask);
392 void SetTouchCancelable(bool cancelable);
393 void DumpFilenameBeingDragged();
394 void GestureFlingCancel();
395 void GestureFlingStart(float x,
396 float y,
397 float velocity_x,
398 float velocity_y,
399 gin::Arguments* args);
400 void GestureScrollFirstPoint(int x, int y);
401 void TouchStart();
402 void TouchMove();
403 void TouchMoveCausingScrollIfUncanceled();
404 void TouchCancel();
405 void TouchEnd();
406 void LeapForward(int milliseconds);
407 void BeginDragWithFiles(const std::vector<std::string>& files);
408 void AddTouchPoint(double x, double y, gin::Arguments* args);
409 void MouseDragBegin();
410 void MouseDragEnd();
411 void GestureScrollBegin(gin::Arguments* args);
412 void GestureScrollEnd(gin::Arguments* args);
413 void GestureScrollUpdate(gin::Arguments* args);
414 void GesturePinchBegin(gin::Arguments* args);
415 void GesturePinchEnd(gin::Arguments* args);
416 void GesturePinchUpdate(gin::Arguments* args);
417 void GestureTap(gin::Arguments* args);
418 void GestureTapDown(gin::Arguments* args);
419 void GestureShowPress(gin::Arguments* args);
420 void GestureTapCancel(gin::Arguments* args);
421 void GestureLongPress(gin::Arguments* args);
422 void GestureLongTap(gin::Arguments* args);
423 void GestureTwoFingerTap(gin::Arguments* args);
424 void ContinuousMouseScrollBy(gin::Arguments* args);
425 void MouseMoveTo(gin::Arguments* args);
426 void MouseLeave();
427 void TrackpadScrollBegin();
428 void TrackpadScroll(gin::Arguments* args);
429 void TrackpadScrollEnd();
430 void MouseScrollBy(gin::Arguments* args);
431 // TODO(erikchen): Remove MouseMomentumBegin once CL 282743002 has landed.
432 void MouseMomentumBegin();
433 void MouseMomentumBegin2(gin::Arguments* args);
434 void MouseMomentumScrollBy(gin::Arguments* args);
435 void MouseMomentumEnd();
436 void ScheduleAsynchronousClick(gin::Arguments* args);
437 void ScheduleAsynchronousKeyDown(gin::Arguments* args);
438 void MouseDown(gin::Arguments* args);
439 void MouseUp(gin::Arguments* args);
440 void KeyDown(gin::Arguments* args);
442 // Binding properties:
443 bool ForceLayoutOnEvents() const;
444 void SetForceLayoutOnEvents(bool force);
445 bool IsDragMode() const;
446 void SetIsDragMode(bool drag_mode);
448 #if defined(OS_WIN)
449 int WmKeyDown() const;
450 void SetWmKeyDown(int key_down);
452 int WmKeyUp() const;
453 void SetWmKeyUp(int key_up);
455 int WmChar() const;
456 void SetWmChar(int wm_char);
458 int WmDeadChar() const;
459 void SetWmDeadChar(int dead_char);
461 int WmSysKeyDown() const;
462 void SetWmSysKeyDown(int key_down);
464 int WmSysKeyUp() const;
465 void SetWmSysKeyUp(int key_up);
467 int WmSysChar() const;
468 void SetWmSysChar(int sys_char);
470 int WmSysDeadChar() const;
471 void SetWmSysDeadChar(int sys_dead_char);
472 #endif
474 base::WeakPtr<EventSender> sender_;
476 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
479 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
481 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
482 : sender_(sender) {
485 EventSenderBindings::~EventSenderBindings() {}
487 // static
488 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
489 WebFrame* frame) {
490 v8::Isolate* isolate = blink::mainThreadIsolate();
491 v8::HandleScope handle_scope(isolate);
492 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
493 if (context.IsEmpty())
494 return;
496 v8::Context::Scope context_scope(context);
498 gin::Handle<EventSenderBindings> bindings =
499 gin::CreateHandle(isolate, new EventSenderBindings(sender));
500 if (bindings.IsEmpty())
501 return;
502 v8::Local<v8::Object> global = context->Global();
503 global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
506 gin::ObjectTemplateBuilder
507 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
508 return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
509 .SetMethod("enableDOMUIEventLogging",
510 &EventSenderBindings::EnableDOMUIEventLogging)
511 .SetMethod("fireKeyboardEventsToElement",
512 &EventSenderBindings::FireKeyboardEventsToElement)
513 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
514 .SetMethod("contextClick", &EventSenderBindings::ContextClick)
515 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
516 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
517 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
518 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
519 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
520 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
521 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
522 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
523 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
524 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
525 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
526 .SetMethod("dumpFilenameBeingDragged",
527 &EventSenderBindings::DumpFilenameBeingDragged)
528 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
529 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
530 .SetMethod("gestureScrollFirstPoint",
531 &EventSenderBindings::GestureScrollFirstPoint)
532 .SetMethod("touchStart", &EventSenderBindings::TouchStart)
533 .SetMethod("touchMove", &EventSenderBindings::TouchMove)
534 .SetMethod("touchMoveCausingScrollIfUncanceled",
535 &EventSenderBindings::TouchMoveCausingScrollIfUncanceled)
536 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
537 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
538 .SetMethod("leapForward", &EventSenderBindings::LeapForward)
539 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
540 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
541 .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin)
542 .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd)
543 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
544 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
545 .SetMethod("gestureScrollUpdate",
546 &EventSenderBindings::GestureScrollUpdate)
547 .SetMethod("gesturePinchBegin", &EventSenderBindings::GesturePinchBegin)
548 .SetMethod("gesturePinchEnd", &EventSenderBindings::GesturePinchEnd)
549 .SetMethod("gesturePinchUpdate", &EventSenderBindings::GesturePinchUpdate)
550 .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
551 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
552 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
553 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
554 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
555 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
556 .SetMethod("gestureTwoFingerTap",
557 &EventSenderBindings::GestureTwoFingerTap)
558 .SetMethod("continuousMouseScrollBy",
559 &EventSenderBindings::ContinuousMouseScrollBy)
560 .SetMethod("keyDown", &EventSenderBindings::KeyDown)
561 .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
562 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
563 .SetMethod("mouseLeave", &EventSenderBindings::MouseLeave)
564 .SetMethod("trackpadScrollBegin",
565 &EventSenderBindings::TrackpadScrollBegin)
566 .SetMethod("trackpadScroll", &EventSenderBindings::TrackpadScroll)
567 .SetMethod("trackpadScrollEnd", &EventSenderBindings::TrackpadScrollEnd)
568 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
569 .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
570 .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin)
571 .SetMethod("mouseMomentumBegin2",
572 &EventSenderBindings::MouseMomentumBegin2)
573 .SetMethod("mouseMomentumScrollBy",
574 &EventSenderBindings::MouseMomentumScrollBy)
575 .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd)
576 .SetMethod("scheduleAsynchronousClick",
577 &EventSenderBindings::ScheduleAsynchronousClick)
578 .SetMethod("scheduleAsynchronousKeyDown",
579 &EventSenderBindings::ScheduleAsynchronousKeyDown)
580 .SetProperty("forceLayoutOnEvents",
581 &EventSenderBindings::ForceLayoutOnEvents,
582 &EventSenderBindings::SetForceLayoutOnEvents)
583 .SetProperty("dragMode", &EventSenderBindings::IsDragMode,
584 &EventSenderBindings::SetIsDragMode)
585 #if defined(OS_WIN)
586 .SetProperty("WM_KEYDOWN", &EventSenderBindings::WmKeyDown,
587 &EventSenderBindings::SetWmKeyDown)
588 .SetProperty("WM_KEYUP", &EventSenderBindings::WmKeyUp,
589 &EventSenderBindings::SetWmKeyUp)
590 .SetProperty("WM_CHAR", &EventSenderBindings::WmChar,
591 &EventSenderBindings::SetWmChar)
592 .SetProperty("WM_DEADCHAR", &EventSenderBindings::WmDeadChar,
593 &EventSenderBindings::SetWmDeadChar)
594 .SetProperty("WM_SYSKEYDOWN", &EventSenderBindings::WmSysKeyDown,
595 &EventSenderBindings::SetWmSysKeyDown)
596 .SetProperty("WM_SYSKEYUP", &EventSenderBindings::WmSysKeyUp,
597 &EventSenderBindings::SetWmSysKeyUp)
598 .SetProperty("WM_SYSCHAR", &EventSenderBindings::WmSysChar,
599 &EventSenderBindings::SetWmSysChar)
600 .SetProperty("WM_SYSDEADCHAR", &EventSenderBindings::WmSysDeadChar,
601 &EventSenderBindings::SetWmSysDeadChar);
602 #else
604 #endif
607 void EventSenderBindings::EnableDOMUIEventLogging() {
608 if (sender_)
609 sender_->EnableDOMUIEventLogging();
612 void EventSenderBindings::FireKeyboardEventsToElement() {
613 if (sender_)
614 sender_->FireKeyboardEventsToElement();
617 void EventSenderBindings::ClearKillRing() {
618 if (sender_)
619 sender_->ClearKillRing();
622 std::vector<std::string> EventSenderBindings::ContextClick() {
623 if (sender_)
624 return sender_->ContextClick();
625 return std::vector<std::string>();
628 void EventSenderBindings::TextZoomIn() {
629 if (sender_)
630 sender_->TextZoomIn();
633 void EventSenderBindings::TextZoomOut() {
634 if (sender_)
635 sender_->TextZoomOut();
638 void EventSenderBindings::ZoomPageIn() {
639 if (sender_)
640 sender_->ZoomPageIn();
643 void EventSenderBindings::ZoomPageOut() {
644 if (sender_)
645 sender_->ZoomPageOut();
648 void EventSenderBindings::SetPageZoomFactor(double factor) {
649 if (sender_)
650 sender_->SetPageZoomFactor(factor);
653 void EventSenderBindings::ClearTouchPoints() {
654 if (sender_)
655 sender_->ClearTouchPoints();
658 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
659 if (sender_)
660 sender_->ReleaseTouchPoint(index);
663 void EventSenderBindings::UpdateTouchPoint(unsigned index,
664 double x,
665 double y,
666 gin::Arguments* args) {
667 if (sender_) {
668 sender_->UpdateTouchPoint(index, static_cast<float>(x),
669 static_cast<float>(y), args);
673 void EventSenderBindings::CancelTouchPoint(unsigned index) {
674 if (sender_)
675 sender_->CancelTouchPoint(index);
678 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
679 bool set_mask) {
680 if (sender_)
681 sender_->SetTouchModifier(key_name, set_mask);
684 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
685 if (sender_)
686 sender_->SetTouchCancelable(cancelable);
689 void EventSenderBindings::DumpFilenameBeingDragged() {
690 if (sender_)
691 sender_->DumpFilenameBeingDragged();
694 void EventSenderBindings::GestureFlingCancel() {
695 if (sender_)
696 sender_->GestureFlingCancel();
699 void EventSenderBindings::GestureFlingStart(float x,
700 float y,
701 float velocity_x,
702 float velocity_y,
703 gin::Arguments* args) {
704 if (sender_)
705 sender_->GestureFlingStart(x, y, velocity_x, velocity_y, args);
708 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
709 if (sender_)
710 sender_->GestureScrollFirstPoint(x, y);
713 void EventSenderBindings::TouchStart() {
714 if (sender_)
715 sender_->TouchStart();
718 void EventSenderBindings::TouchMove() {
719 if (sender_)
720 sender_->TouchMove();
723 void EventSenderBindings::TouchMoveCausingScrollIfUncanceled() {
724 if (sender_)
725 sender_->TouchMoveCausingScrollIfUncanceled();
728 void EventSenderBindings::TouchCancel() {
729 if (sender_)
730 sender_->TouchCancel();
733 void EventSenderBindings::TouchEnd() {
734 if (sender_)
735 sender_->TouchEnd();
738 void EventSenderBindings::LeapForward(int milliseconds) {
739 if (sender_)
740 sender_->LeapForward(milliseconds);
743 void EventSenderBindings::BeginDragWithFiles(
744 const std::vector<std::string>& files) {
745 if (sender_)
746 sender_->BeginDragWithFiles(files);
749 void EventSenderBindings::AddTouchPoint(double x,
750 double y,
751 gin::Arguments* args) {
752 if (sender_)
753 sender_->AddTouchPoint(static_cast<float>(x), static_cast<float>(y), args);
756 void EventSenderBindings::MouseDragBegin() {
757 if (sender_)
758 sender_->MouseDragBegin();
761 void EventSenderBindings::MouseDragEnd() {
762 if (sender_)
763 sender_->MouseDragEnd();
766 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
767 if (sender_)
768 sender_->GestureScrollBegin(args);
771 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
772 if (sender_)
773 sender_->GestureScrollEnd(args);
776 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
777 if (sender_)
778 sender_->GestureScrollUpdate(args);
781 void EventSenderBindings::GesturePinchBegin(gin::Arguments* args) {
782 if (sender_)
783 sender_->GesturePinchBegin(args);
786 void EventSenderBindings::GesturePinchEnd(gin::Arguments* args) {
787 if (sender_)
788 sender_->GesturePinchEnd(args);
791 void EventSenderBindings::GesturePinchUpdate(gin::Arguments* args) {
792 if (sender_)
793 sender_->GesturePinchUpdate(args);
796 void EventSenderBindings::GestureTap(gin::Arguments* args) {
797 if (sender_)
798 sender_->GestureTap(args);
801 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
802 if (sender_)
803 sender_->GestureTapDown(args);
806 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
807 if (sender_)
808 sender_->GestureShowPress(args);
811 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
812 if (sender_)
813 sender_->GestureTapCancel(args);
816 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
817 if (sender_)
818 sender_->GestureLongPress(args);
821 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
822 if (sender_)
823 sender_->GestureLongTap(args);
826 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
827 if (sender_)
828 sender_->GestureTwoFingerTap(args);
831 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
832 if (sender_)
833 sender_->ContinuousMouseScrollBy(args);
836 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
837 if (sender_)
838 sender_->MouseMoveTo(args);
841 void EventSenderBindings::MouseLeave() {
842 if (sender_)
843 sender_->MouseLeave();
846 void EventSenderBindings::TrackpadScrollBegin() {
847 if (sender_)
848 sender_->TrackpadScrollBegin();
851 void EventSenderBindings::TrackpadScroll(gin::Arguments* args) {
852 if (sender_)
853 sender_->TrackpadScroll(args);
856 void EventSenderBindings::TrackpadScrollEnd() {
857 if (sender_)
858 sender_->TrackpadScrollEnd();
861 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
862 if (sender_)
863 sender_->MouseScrollBy(args);
866 void EventSenderBindings::MouseMomentumBegin() {
867 if (sender_)
868 sender_->MouseMomentumBegin();
871 void EventSenderBindings::MouseMomentumBegin2(gin::Arguments* args) {
872 if (sender_)
873 sender_->MouseMomentumBegin2(args);
876 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) {
877 if (sender_)
878 sender_->MouseMomentumScrollBy(args);
881 void EventSenderBindings::MouseMomentumEnd() {
882 if (sender_)
883 sender_->MouseMomentumEnd();
886 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
887 if (!sender_)
888 return;
890 int button_number = 0;
891 int modifiers = 0;
892 if (!args->PeekNext().IsEmpty()) {
893 args->GetNext(&button_number);
894 if (!args->PeekNext().IsEmpty())
895 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
897 sender_->ScheduleAsynchronousClick(button_number, modifiers);
900 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
901 if (!sender_)
902 return;
904 std::string code_str;
905 int modifiers = 0;
906 int location = DOMKeyLocationStandard;
907 args->GetNext(&code_str);
908 if (!args->PeekNext().IsEmpty()) {
909 v8::Local<v8::Value> value;
910 args->GetNext(&value);
911 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
912 if (!args->PeekNext().IsEmpty())
913 args->GetNext(&location);
915 sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
916 static_cast<KeyLocationCode>(location));
919 void EventSenderBindings::MouseDown(gin::Arguments* args) {
920 if (!sender_)
921 return;
923 int button_number = 0;
924 int modifiers = 0;
925 if (!args->PeekNext().IsEmpty()) {
926 args->GetNext(&button_number);
927 if (!args->PeekNext().IsEmpty())
928 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
930 sender_->MouseDown(button_number, modifiers);
933 void EventSenderBindings::MouseUp(gin::Arguments* args) {
934 if (!sender_)
935 return;
937 int button_number = 0;
938 int modifiers = 0;
939 if (!args->PeekNext().IsEmpty()) {
940 args->GetNext(&button_number);
941 if (!args->PeekNext().IsEmpty())
942 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
944 sender_->MouseUp(button_number, modifiers);
947 void EventSenderBindings::KeyDown(gin::Arguments* args) {
948 if (!sender_)
949 return;
951 std::string code_str;
952 int modifiers = 0;
953 int location = DOMKeyLocationStandard;
954 args->GetNext(&code_str);
955 if (!args->PeekNext().IsEmpty()) {
956 v8::Local<v8::Value> value;
957 args->GetNext(&value);
958 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
959 if (!args->PeekNext().IsEmpty())
960 args->GetNext(&location);
962 sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
965 bool EventSenderBindings::ForceLayoutOnEvents() const {
966 if (sender_)
967 return sender_->force_layout_on_events();
968 return false;
971 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
972 if (sender_)
973 sender_->set_force_layout_on_events(force);
976 bool EventSenderBindings::IsDragMode() const {
977 if (sender_)
978 return sender_->is_drag_mode();
979 return true;
982 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
983 if (sender_)
984 sender_->set_is_drag_mode(drag_mode);
987 #if defined(OS_WIN)
988 int EventSenderBindings::WmKeyDown() const {
989 if (sender_)
990 return sender_->wm_key_down();
991 return 0;
994 void EventSenderBindings::SetWmKeyDown(int key_down) {
995 if (sender_)
996 sender_->set_wm_key_down(key_down);
999 int EventSenderBindings::WmKeyUp() const {
1000 if (sender_)
1001 return sender_->wm_key_up();
1002 return 0;
1005 void EventSenderBindings::SetWmKeyUp(int key_up) {
1006 if (sender_)
1007 sender_->set_wm_key_up(key_up);
1010 int EventSenderBindings::WmChar() const {
1011 if (sender_)
1012 return sender_->wm_char();
1013 return 0;
1016 void EventSenderBindings::SetWmChar(int wm_char) {
1017 if (sender_)
1018 sender_->set_wm_char(wm_char);
1021 int EventSenderBindings::WmDeadChar() const {
1022 if (sender_)
1023 return sender_->wm_dead_char();
1024 return 0;
1027 void EventSenderBindings::SetWmDeadChar(int dead_char) {
1028 if (sender_)
1029 sender_->set_wm_dead_char(dead_char);
1032 int EventSenderBindings::WmSysKeyDown() const {
1033 if (sender_)
1034 return sender_->wm_sys_key_down();
1035 return 0;
1038 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1039 if (sender_)
1040 sender_->set_wm_sys_key_down(key_down);
1043 int EventSenderBindings::WmSysKeyUp() const {
1044 if (sender_)
1045 return sender_->wm_sys_key_up();
1046 return 0;
1049 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1050 if (sender_)
1051 sender_->set_wm_sys_key_up(key_up);
1054 int EventSenderBindings::WmSysChar() const {
1055 if (sender_)
1056 return sender_->wm_sys_char();
1057 return 0;
1060 void EventSenderBindings::SetWmSysChar(int sys_char) {
1061 if (sender_)
1062 sender_->set_wm_sys_char(sys_char);
1065 int EventSenderBindings::WmSysDeadChar() const {
1066 if (sender_)
1067 return sender_->wm_sys_dead_char();
1068 return 0;
1071 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1072 if (sender_)
1073 sender_->set_wm_sys_dead_char(sys_dead_char);
1075 #endif
1077 // EventSender -----------------------------------------------------------------
1079 WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone;
1080 int EventSender::modifiers_ = 0;
1082 WebPoint EventSender::last_mouse_pos_;
1084 WebMouseEvent::Button EventSender::last_button_type_ =
1085 WebMouseEvent::ButtonNone;
1087 EventSender::SavedEvent::SavedEvent()
1088 : type(TYPE_UNSPECIFIED),
1089 button_type(WebMouseEvent::ButtonNone),
1090 milliseconds(0),
1091 modifiers(0) {}
1093 EventSender::EventSender(TestInterfaces* interfaces)
1095 #if defined(OS_WIN)
1096 wm_key_down_(0),
1097 wm_key_up_(0),
1098 wm_char_(0),
1099 wm_dead_char_(0),
1100 wm_sys_key_down_(0),
1101 wm_sys_key_up_(0),
1102 wm_sys_char_(0),
1103 wm_sys_dead_char_(0),
1104 #endif
1105 interfaces_(interfaces),
1106 delegate_(NULL),
1107 view_(NULL),
1108 force_layout_on_events_(false),
1109 is_drag_mode_(true),
1110 touch_modifiers_(0),
1111 touch_cancelable_(true),
1112 replaying_saved_events_(false),
1113 current_drag_effects_allowed_(blink::WebDragOperationNone),
1114 last_click_time_sec_(0),
1115 current_drag_effect_(blink::WebDragOperationNone),
1116 time_offset_ms_(0),
1117 click_count_(0),
1118 weak_factory_(this) {
1121 EventSender::~EventSender() {}
1123 void EventSender::Reset() {
1124 DCHECK(current_drag_data_.isNull());
1125 current_drag_data_.reset();
1126 current_drag_effect_ = blink::WebDragOperationNone;
1127 current_drag_effects_allowed_ = blink::WebDragOperationNone;
1128 if (view_ && pressed_button_ != WebMouseEvent::ButtonNone)
1129 view_->mouseCaptureLost();
1130 pressed_button_ = WebMouseEvent::ButtonNone;
1131 is_drag_mode_ = true;
1132 force_layout_on_events_ = true;
1134 #if defined(OS_WIN)
1135 wm_key_down_ = WM_KEYDOWN;
1136 wm_key_up_ = WM_KEYUP;
1137 wm_char_ = WM_CHAR;
1138 wm_dead_char_ = WM_DEADCHAR;
1139 wm_sys_key_down_ = WM_SYSKEYDOWN;
1140 wm_sys_key_up_ = WM_SYSKEYUP;
1141 wm_sys_char_ = WM_SYSCHAR;
1142 wm_sys_dead_char_ = WM_SYSDEADCHAR;
1143 #endif
1145 last_mouse_pos_ = WebPoint(0, 0);
1146 last_click_time_sec_ = 0;
1147 last_click_pos_ = WebPoint(0, 0);
1148 last_button_type_ = WebMouseEvent::ButtonNone;
1149 touch_points_.clear();
1150 last_context_menu_data_.reset();
1151 task_list_.RevokeAll();
1152 current_gesture_location_ = WebPoint(0, 0);
1153 mouse_event_queue_.clear();
1155 time_offset_ms_ = 0;
1156 click_count_ = 0;
1158 touch_modifiers_ = 0;
1159 touch_cancelable_ = true;
1160 touch_points_.clear();
1163 void EventSender::Install(WebFrame* frame) {
1164 EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1167 void EventSender::SetDelegate(WebTestDelegate* delegate) {
1168 delegate_ = delegate;
1171 void EventSender::SetWebView(WebView* view) {
1172 view_ = view;
1175 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1176 last_context_menu_data_.reset(new WebContextMenuData(data));
1179 void EventSender::DoDragDrop(const WebDragData& drag_data,
1180 WebDragOperationsMask mask) {
1181 WebMouseEvent event;
1182 InitMouseEvent(WebInputEvent::MouseDown,
1183 pressed_button_,
1184 last_mouse_pos_,
1185 GetCurrentEventTimeSec(),
1186 click_count_,
1187 modifiers_,
1188 &event);
1189 WebPoint client_point(event.x, event.y);
1190 WebPoint screen_point(event.globalX, event.globalY);
1191 current_drag_data_ = drag_data;
1192 current_drag_effects_allowed_ = mask;
1193 current_drag_effect_ = view_->dragTargetDragEnter(
1194 drag_data,
1195 client_point,
1196 screen_point,
1197 current_drag_effects_allowed_,
1198 modifiers_);
1200 // Finish processing events.
1201 ReplaySavedEvents();
1204 void EventSender::MouseDown(int button_number, int modifiers) {
1205 if (force_layout_on_events_)
1206 view_->layout();
1208 DCHECK_NE(-1, button_number);
1210 WebMouseEvent::Button button_type =
1211 GetButtonTypeFromButtonNumber(button_number);
1213 UpdateClickCountForButton(button_type);
1215 pressed_button_ = button_type;
1216 modifiers_ = modifiers;
1218 WebMouseEvent event;
1219 InitMouseEvent(WebInputEvent::MouseDown,
1220 button_type,
1221 last_mouse_pos_,
1222 GetCurrentEventTimeSec(),
1223 click_count_,
1224 modifiers,
1225 &event);
1226 HandleInputEventOnViewOrPopup(event);
1229 void EventSender::MouseUp(int button_number, int modifiers) {
1230 if (force_layout_on_events_)
1231 view_->layout();
1233 DCHECK_NE(-1, button_number);
1235 WebMouseEvent::Button button_type =
1236 GetButtonTypeFromButtonNumber(button_number);
1238 if (is_drag_mode_ && !replaying_saved_events_) {
1239 SavedEvent saved_event;
1240 saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1241 saved_event.button_type = button_type;
1242 saved_event.modifiers = modifiers;
1243 mouse_event_queue_.push_back(saved_event);
1244 ReplaySavedEvents();
1245 } else {
1246 WebMouseEvent event;
1247 InitMouseEvent(WebInputEvent::MouseUp,
1248 button_type,
1249 last_mouse_pos_,
1250 GetCurrentEventTimeSec(),
1251 click_count_,
1252 modifiers,
1253 &event);
1254 DoMouseUp(event);
1258 void EventSender::KeyDown(const std::string& code_str,
1259 int modifiers,
1260 KeyLocationCode location) {
1261 // FIXME: I'm not exactly sure how we should convert the string to a key
1262 // event. This seems to work in the cases I tested.
1263 // FIXME: Should we also generate a KEY_UP?
1265 bool generate_char = false;
1267 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1268 // Windows uses \r for "Enter".
1269 int code = 0;
1270 int text = 0;
1271 bool needs_shift_key_modifier = false;
1272 std::string domString;
1274 if ("\n" == code_str) {
1275 generate_char = true;
1276 text = code = ui::VKEY_RETURN;
1277 domString.assign("Enter");
1278 } else if ("rightArrow" == code_str) {
1279 code = ui::VKEY_RIGHT;
1280 domString.assign("ArrowRight");
1281 } else if ("downArrow" == code_str) {
1282 code = ui::VKEY_DOWN;
1283 domString.assign("ArrowDown");
1284 } else if ("leftArrow" == code_str) {
1285 code = ui::VKEY_LEFT;
1286 domString.assign("ArrowLeft");
1287 } else if ("upArrow" == code_str) {
1288 code = ui::VKEY_UP;
1289 domString.assign("ArrowUp");
1290 } else if ("insert" == code_str) {
1291 code = ui::VKEY_INSERT;
1292 domString.assign("Insert");
1293 } else if ("delete" == code_str) {
1294 code = ui::VKEY_DELETE;
1295 domString.assign("Delete");
1296 } else if ("pageUp" == code_str) {
1297 code = ui::VKEY_PRIOR;
1298 domString.assign("PageUp");
1299 } else if ("pageDown" == code_str) {
1300 code = ui::VKEY_NEXT;
1301 domString.assign("PageDown");
1302 } else if ("home" == code_str) {
1303 code = ui::VKEY_HOME;
1304 domString.assign("Home");
1305 } else if ("end" == code_str) {
1306 code = ui::VKEY_END;
1307 domString.assign("End");
1308 } else if ("printScreen" == code_str) {
1309 code = ui::VKEY_SNAPSHOT;
1310 domString.assign("PrintScreen");
1311 } else if ("menu" == code_str) {
1312 code = ui::VKEY_APPS;
1313 domString.assign("ContextMenu");
1314 } else if ("leftControl" == code_str) {
1315 code = ui::VKEY_CONTROL;
1316 domString.assign("ControlLeft");
1317 location = DOMKeyLocationLeft;
1318 } else if ("rightControl" == code_str) {
1319 code = ui::VKEY_CONTROL;
1320 domString.assign("ControlRight");
1321 location = DOMKeyLocationRight;
1322 } else if ("leftShift" == code_str) {
1323 code = ui::VKEY_SHIFT;
1324 domString.assign("ShiftLeft");
1325 location = DOMKeyLocationLeft;
1326 } else if ("rightShift" == code_str) {
1327 code = ui::VKEY_SHIFT;
1328 domString.assign("ShiftRight");
1329 location = DOMKeyLocationRight;
1330 } else if ("leftAlt" == code_str) {
1331 code = ui::VKEY_MENU;
1332 domString.assign("AltLeft");
1333 location = DOMKeyLocationLeft;
1334 } else if ("rightAlt" == code_str) {
1335 code = ui::VKEY_MENU;
1336 domString.assign("AltRight");
1337 location = DOMKeyLocationRight;
1338 } else if ("numLock" == code_str) {
1339 code = ui::VKEY_NUMLOCK;
1340 domString.assign("NumLock");
1341 } else if ("backspace" == code_str) {
1342 code = ui::VKEY_BACK;
1343 domString.assign("Backspace");
1344 } else if ("escape" == code_str) {
1345 code = ui::VKEY_ESCAPE;
1346 domString.assign("Escape");
1347 } else {
1348 // Compare the input string with the function-key names defined by the
1349 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1350 // name, set its key code.
1351 for (int i = 1; i <= 24; ++i) {
1352 std::string function_key_name = base::StringPrintf("F%d", i);
1353 if (function_key_name == code_str) {
1354 code = ui::VKEY_F1 + (i - 1);
1355 domString = function_key_name;
1356 break;
1359 if (!code) {
1360 WebString web_code_str =
1361 WebString::fromUTF8(code_str.data(), code_str.size());
1362 if (web_code_str.length() != 1u) {
1363 v8::Isolate* isolate = blink::mainThreadIsolate();
1364 isolate->ThrowException(v8::Exception::TypeError(
1365 gin::StringToV8(isolate, "Invalid web code.")));
1366 return;
1368 text = code = web_code_str.at(0);
1369 needs_shift_key_modifier = NeedsShiftModifier(code);
1370 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
1371 code -= 'a' - 'A';
1372 if ((code >= 'A' && code <= 'Z') || (code >= 'a' && code <= 'z')) {
1373 domString.assign("Key");
1374 domString.push_back(
1375 base::ToUpperASCII(static_cast<base::char16>(code)));
1376 } else if (code >= '0' && code <= '9') {
1377 domString.assign("Digit");
1378 domString.push_back(code);
1379 } else if (code == ' ') {
1380 domString.assign("Space");
1381 } else if (code == 9) {
1382 domString.assign("Tab");
1384 generate_char = true;
1387 if ("(" == code_str) {
1388 code = '9';
1389 needs_shift_key_modifier = true;
1393 // For one generated keyboard event, we need to generate a keyDown/keyUp
1394 // pair;
1395 // On Windows, we might also need to generate a char event to mimic the
1396 // Windows event flow; on other platforms we create a merged event and test
1397 // the event flow that that platform provides.
1398 WebKeyboardEvent event_down;
1399 event_down.timeStampSeconds = GetCurrentEventTimeSec();
1400 event_down.type = WebInputEvent::RawKeyDown;
1401 event_down.modifiers = modifiers;
1402 event_down.windowsKeyCode = code;
1403 event_down.domCode = static_cast<int>(
1404 ui::KeycodeConverter::CodeStringToDomCode(domString.c_str()));
1406 if (generate_char) {
1407 event_down.text[0] = text;
1408 event_down.unmodifiedText[0] = text;
1411 event_down.setKeyIdentifierFromWindowsKeyCode();
1413 if (event_down.modifiers != 0)
1414 event_down.isSystemKey = IsSystemKeyEvent(event_down);
1416 if (needs_shift_key_modifier)
1417 event_down.modifiers |= WebInputEvent::ShiftKey;
1419 // See if KeyLocation argument is given.
1420 switch(location) {
1421 case DOMKeyLocationStandard:
1422 break;
1423 case DOMKeyLocationLeft:
1424 event_down.modifiers |= WebInputEvent::IsLeft;
1425 break;
1426 case DOMKeyLocationRight:
1427 event_down.modifiers |= WebInputEvent::IsRight;
1428 break;
1429 case DOMKeyLocationNumpad:
1430 event_down.modifiers |= WebInputEvent::IsKeyPad;
1431 break;
1434 WebKeyboardEvent event_up;
1435 event_up = event_down;
1436 event_up.type = WebInputEvent::KeyUp;
1437 // EventSender.m forces a layout here, with at least one
1438 // test (fast/forms/focus-control-to-page.html) relying on this.
1439 if (force_layout_on_events_)
1440 view_->layout();
1442 // In the browser, if a keyboard event corresponds to an editor command,
1443 // the command will be dispatched to the renderer just before dispatching
1444 // the keyboard event, and then it will be executed in the
1445 // RenderView::handleCurrentKeyboardEvent() method.
1446 // We just simulate the same behavior here.
1447 std::string edit_command;
1448 if (GetEditCommand(event_down, &edit_command))
1449 delegate_->SetEditCommand(edit_command, "");
1451 HandleInputEventOnViewOrPopup(event_down);
1453 if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1454 WebMouseEvent event;
1455 InitMouseEvent(WebInputEvent::MouseDown,
1456 pressed_button_,
1457 last_mouse_pos_,
1458 GetCurrentEventTimeSec(),
1459 click_count_,
1461 &event);
1462 FinishDragAndDrop(event, blink::WebDragOperationNone);
1465 delegate_->ClearEditCommand();
1467 if (generate_char) {
1468 WebKeyboardEvent event_char = event_up;
1469 event_char.type = WebInputEvent::Char;
1470 // keyIdentifier is an empty string, unless the Enter key was pressed.
1471 // This behavior is not standard (keyIdentifier itself is not even a
1472 // standard any more), but it matches the actual behavior in Blink.
1473 if (code != ui::VKEY_RETURN)
1474 event_char.keyIdentifier[0] = '\0';
1475 HandleInputEventOnViewOrPopup(event_char);
1478 HandleInputEventOnViewOrPopup(event_up);
1481 void EventSender::EnableDOMUIEventLogging() {}
1483 void EventSender::FireKeyboardEventsToElement() {}
1485 void EventSender::ClearKillRing() {}
1487 std::vector<std::string> EventSender::ContextClick() {
1488 if (force_layout_on_events_) {
1489 view_->layout();
1492 UpdateClickCountForButton(WebMouseEvent::ButtonRight);
1494 // Clears last context menu data because we need to know if the context menu
1495 // be requested after following mouse events.
1496 last_context_menu_data_.reset();
1498 // Generate right mouse down and up.
1499 WebMouseEvent event;
1500 // This is a hack to work around only allowing a single pressed button since
1501 // we want to test the case where both the left and right mouse buttons are
1502 // pressed.
1503 if (pressed_button_ == WebMouseEvent::ButtonNone) {
1504 pressed_button_ = WebMouseEvent::ButtonRight;
1506 InitMouseEvent(WebInputEvent::MouseDown,
1507 WebMouseEvent::ButtonRight,
1508 last_mouse_pos_,
1509 GetCurrentEventTimeSec(),
1510 click_count_,
1512 &event);
1513 HandleInputEventOnViewOrPopup(event);
1515 #if defined(OS_WIN)
1516 InitMouseEvent(WebInputEvent::MouseUp,
1517 WebMouseEvent::ButtonRight,
1518 last_mouse_pos_,
1519 GetCurrentEventTimeSec(),
1520 click_count_,
1522 &event);
1523 HandleInputEventOnViewOrPopup(event);
1525 pressed_button_= WebMouseEvent::ButtonNone;
1526 #endif
1528 std::vector<std::string> menu_items =
1529 MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate_);
1530 last_context_menu_data_.reset();
1531 return menu_items;
1534 void EventSender::TextZoomIn() {
1535 view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f);
1538 void EventSender::TextZoomOut() {
1539 view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f);
1542 void EventSender::ZoomPageIn() {
1543 const std::vector<WebTestProxyBase*>& window_list =
1544 interfaces_->GetWindowList();
1546 for (size_t i = 0; i < window_list.size(); ++i) {
1547 window_list.at(i)->GetWebView()->setZoomLevel(
1548 window_list.at(i)->GetWebView()->zoomLevel() + 1);
1552 void EventSender::ZoomPageOut() {
1553 const std::vector<WebTestProxyBase*>& window_list =
1554 interfaces_->GetWindowList();
1556 for (size_t i = 0; i < window_list.size(); ++i) {
1557 window_list.at(i)->GetWebView()->setZoomLevel(
1558 window_list.at(i)->GetWebView()->zoomLevel() - 1);
1562 void EventSender::SetPageZoomFactor(double zoom_factor) {
1563 const std::vector<WebTestProxyBase*>& window_list =
1564 interfaces_->GetWindowList();
1566 for (size_t i = 0; i < window_list.size(); ++i) {
1567 window_list.at(i)->GetWebView()->setZoomLevel(
1568 std::log(zoom_factor) / std::log(1.2));
1572 void EventSender::ClearTouchPoints() {
1573 touch_points_.clear();
1576 void EventSender::ThrowTouchPointError() {
1577 v8::Isolate* isolate = blink::mainThreadIsolate();
1578 isolate->ThrowException(v8::Exception::TypeError(
1579 gin::StringToV8(isolate, "Invalid touch point.")));
1582 void EventSender::ReleaseTouchPoint(unsigned index) {
1583 if (index >= touch_points_.size()) {
1584 ThrowTouchPointError();
1585 return;
1588 WebTouchPoint* touch_point = &touch_points_[index];
1589 touch_point->state = WebTouchPoint::StateReleased;
1592 void EventSender::UpdateTouchPoint(unsigned index,
1593 float x,
1594 float y,
1595 gin::Arguments* args) {
1596 if (index >= touch_points_.size()) {
1597 ThrowTouchPointError();
1598 return;
1601 WebTouchPoint* touch_point = &touch_points_[index];
1602 touch_point->state = WebTouchPoint::StateMoved;
1603 touch_point->position = WebFloatPoint(x, y);
1604 touch_point->screenPosition = touch_point->position;
1606 InitPointerProperties(args, touch_point, &touch_point->radiusX,
1607 &touch_point->radiusY);
1610 void EventSender::CancelTouchPoint(unsigned index) {
1611 if (index >= touch_points_.size()) {
1612 ThrowTouchPointError();
1613 return;
1616 WebTouchPoint* touch_point = &touch_points_[index];
1617 touch_point->state = WebTouchPoint::StateCancelled;
1620 void EventSender::SetTouchModifier(const std::string& key_name,
1621 bool set_mask) {
1622 int mask = 0;
1623 if (key_name == "shift")
1624 mask = WebInputEvent::ShiftKey;
1625 else if (key_name == "alt")
1626 mask = WebInputEvent::AltKey;
1627 else if (key_name == "ctrl")
1628 mask = WebInputEvent::ControlKey;
1629 else if (key_name == "meta")
1630 mask = WebInputEvent::MetaKey;
1632 if (set_mask)
1633 touch_modifiers_ |= mask;
1634 else
1635 touch_modifiers_ &= ~mask;
1638 void EventSender::SetTouchCancelable(bool cancelable) {
1639 touch_cancelable_ = cancelable;
1642 void EventSender::DumpFilenameBeingDragged() {
1643 if (current_drag_data_.isNull())
1644 return;
1646 WebString filename;
1647 WebVector<WebDragData::Item> items = current_drag_data_.items();
1648 for (size_t i = 0; i < items.size(); ++i) {
1649 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1650 filename = items[i].title;
1651 break;
1654 delegate_->PrintMessage(std::string("Filename being dragged: ") +
1655 filename.utf8().data() + "\n");
1658 void EventSender::GestureFlingCancel() {
1659 WebGestureEvent event;
1660 event.type = WebInputEvent::GestureFlingCancel;
1661 event.timeStampSeconds = GetCurrentEventTimeSec();
1663 if (force_layout_on_events_)
1664 view_->layout();
1666 HandleInputEventOnViewOrPopup(event);
1669 void EventSender::GestureFlingStart(float x,
1670 float y,
1671 float velocity_x,
1672 float velocity_y,
1673 gin::Arguments* args) {
1674 WebGestureEvent event;
1675 event.type = WebInputEvent::GestureFlingStart;
1677 std::string device_string;
1678 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString())
1679 args->GetNext(&device_string);
1681 if (device_string == kSourceDeviceStringTouchpad) {
1682 event.sourceDevice = blink::WebGestureDeviceTouchpad;
1683 } else if (device_string == kSourceDeviceStringTouchscreen) {
1684 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
1685 } else {
1686 args->ThrowError();
1687 return;
1690 event.x = x;
1691 event.y = y;
1692 event.globalX = event.x;
1693 event.globalY = event.y;
1695 event.data.flingStart.velocityX = velocity_x;
1696 event.data.flingStart.velocityY = velocity_y;
1697 event.timeStampSeconds = GetCurrentEventTimeSec();
1699 if (force_layout_on_events_)
1700 view_->layout();
1702 HandleInputEventOnViewOrPopup(event);
1705 void EventSender::GestureScrollFirstPoint(int x, int y) {
1706 current_gesture_location_ = WebPoint(x, y);
1709 void EventSender::TouchStart() {
1710 SendCurrentTouchEvent(WebInputEvent::TouchStart, false);
1713 void EventSender::TouchMove() {
1714 SendCurrentTouchEvent(WebInputEvent::TouchMove, false);
1717 void EventSender::TouchMoveCausingScrollIfUncanceled() {
1718 SendCurrentTouchEvent(WebInputEvent::TouchMove, true);
1721 void EventSender::TouchCancel() {
1722 SendCurrentTouchEvent(WebInputEvent::TouchCancel, false);
1725 void EventSender::TouchEnd() {
1726 SendCurrentTouchEvent(WebInputEvent::TouchEnd, false);
1729 void EventSender::LeapForward(int milliseconds) {
1730 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1731 !replaying_saved_events_) {
1732 SavedEvent saved_event;
1733 saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
1734 saved_event.milliseconds = milliseconds;
1735 mouse_event_queue_.push_back(saved_event);
1736 } else {
1737 DoLeapForward(milliseconds);
1741 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
1742 current_drag_data_.initialize();
1743 WebVector<WebString> absolute_filenames(files.size());
1744 for (size_t i = 0; i < files.size(); ++i) {
1745 WebDragData::Item item;
1746 item.storageType = WebDragData::Item::StorageTypeFilename;
1747 item.filenameData = delegate_->GetAbsoluteWebStringFromUTF8Path(files[i]);
1748 current_drag_data_.addItem(item);
1749 absolute_filenames[i] = item.filenameData;
1751 current_drag_data_.setFilesystemId(
1752 delegate_->RegisterIsolatedFileSystem(absolute_filenames));
1753 current_drag_effects_allowed_ = blink::WebDragOperationCopy;
1755 // Provide a drag source.
1756 view_->dragTargetDragEnter(current_drag_data_,
1757 last_mouse_pos_,
1758 last_mouse_pos_,
1759 current_drag_effects_allowed_,
1761 // |is_drag_mode_| saves events and then replays them later. We don't
1762 // need/want that.
1763 is_drag_mode_ = false;
1765 // Make the rest of eventSender think a drag is in progress.
1766 pressed_button_ = WebMouseEvent::ButtonLeft;
1769 void EventSender::AddTouchPoint(float x, float y, gin::Arguments* args) {
1770 WebTouchPoint touch_point;
1771 touch_point.state = WebTouchPoint::StatePressed;
1772 touch_point.position = WebFloatPoint(x, y);
1773 touch_point.screenPosition = touch_point.position;
1775 int highest_id = -1;
1776 for (size_t i = 0; i < touch_points_.size(); i++) {
1777 if (touch_points_[i].id > highest_id)
1778 highest_id = touch_points_[i].id;
1780 touch_point.id = highest_id + 1;
1782 InitPointerProperties(args, &touch_point, &touch_point.radiusX,
1783 &touch_point.radiusY);
1785 touch_points_.push_back(touch_point);
1788 void EventSender::MouseDragBegin() {
1789 WebMouseWheelEvent event;
1790 InitMouseEvent(WebInputEvent::MouseWheel,
1791 WebMouseEvent::ButtonNone,
1792 last_mouse_pos_,
1793 GetCurrentEventTimeSec(),
1794 click_count_,
1796 &event);
1797 event.phase = WebMouseWheelEvent::PhaseBegan;
1798 event.hasPreciseScrollingDeltas = true;
1799 HandleInputEventOnViewOrPopup(event);
1802 void EventSender::MouseDragEnd() {
1803 WebMouseWheelEvent event;
1804 InitMouseEvent(WebInputEvent::MouseWheel,
1805 WebMouseEvent::ButtonNone,
1806 last_mouse_pos_,
1807 GetCurrentEventTimeSec(),
1808 click_count_,
1810 &event);
1811 event.phase = WebMouseWheelEvent::PhaseEnded;
1812 event.hasPreciseScrollingDeltas = true;
1813 HandleInputEventOnViewOrPopup(event);
1816 void EventSender::GestureScrollBegin(gin::Arguments* args) {
1817 GestureEvent(WebInputEvent::GestureScrollBegin, args);
1820 void EventSender::GestureScrollEnd(gin::Arguments* args) {
1821 GestureEvent(WebInputEvent::GestureScrollEnd, args);
1824 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
1825 GestureEvent(WebInputEvent::GestureScrollUpdate, args);
1828 void EventSender::GesturePinchBegin(gin::Arguments* args) {
1829 GestureEvent(WebInputEvent::GesturePinchBegin, args);
1832 void EventSender::GesturePinchEnd(gin::Arguments* args) {
1833 GestureEvent(WebInputEvent::GesturePinchEnd, args);
1836 void EventSender::GesturePinchUpdate(gin::Arguments* args) {
1837 GestureEvent(WebInputEvent::GesturePinchUpdate, args);
1840 void EventSender::GestureTap(gin::Arguments* args) {
1841 GestureEvent(WebInputEvent::GestureTap, args);
1844 void EventSender::GestureTapDown(gin::Arguments* args) {
1845 GestureEvent(WebInputEvent::GestureTapDown, args);
1848 void EventSender::GestureShowPress(gin::Arguments* args) {
1849 GestureEvent(WebInputEvent::GestureShowPress, args);
1852 void EventSender::GestureTapCancel(gin::Arguments* args) {
1853 GestureEvent(WebInputEvent::GestureTapCancel, args);
1856 void EventSender::GestureLongPress(gin::Arguments* args) {
1857 GestureEvent(WebInputEvent::GestureLongPress, args);
1860 void EventSender::GestureLongTap(gin::Arguments* args) {
1861 GestureEvent(WebInputEvent::GestureLongTap, args);
1864 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
1865 GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
1868 void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) {
1869 WebMouseWheelEvent event;
1870 InitMouseWheelEvent(args, true, &event);
1871 HandleInputEventOnViewOrPopup(event);
1874 void EventSender::MouseMoveTo(gin::Arguments* args) {
1875 if (force_layout_on_events_)
1876 view_->layout();
1878 double x;
1879 double y;
1880 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1881 args->ThrowError();
1882 return;
1884 WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
1886 int modifiers = 0;
1887 if (!args->PeekNext().IsEmpty())
1888 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1890 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1891 !replaying_saved_events_) {
1892 SavedEvent saved_event;
1893 saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
1894 saved_event.pos = mouse_pos;
1895 saved_event.modifiers = modifiers;
1896 mouse_event_queue_.push_back(saved_event);
1897 } else {
1898 WebMouseEvent event;
1899 InitMouseEvent(WebInputEvent::MouseMove,
1900 pressed_button_,
1901 mouse_pos,
1902 GetCurrentEventTimeSec(),
1903 click_count_,
1904 modifiers,
1905 &event);
1906 DoMouseMove(event);
1910 void EventSender::MouseLeave() {
1911 if (force_layout_on_events_)
1912 view_->layout();
1914 WebMouseEvent event;
1915 InitMouseEvent(WebInputEvent::MouseLeave,
1916 WebMouseEvent::ButtonNone,
1917 last_mouse_pos_,
1918 GetCurrentEventTimeSec(),
1919 click_count_,
1921 &event);
1922 view_->handleInputEvent(event);
1926 void EventSender::TrackpadScrollBegin() {
1927 WebMouseWheelEvent event;
1928 InitMouseEvent(WebInputEvent::MouseWheel,
1929 WebMouseEvent::ButtonNone,
1930 last_mouse_pos_,
1931 GetCurrentEventTimeSec(),
1932 click_count_,
1934 &event);
1935 event.phase = blink::WebMouseWheelEvent::PhaseBegan;
1936 event.hasPreciseScrollingDeltas = true;
1937 HandleInputEventOnViewOrPopup(event);
1940 void EventSender::TrackpadScroll(gin::Arguments* args) {
1941 WebMouseWheelEvent event;
1942 InitMouseWheelEvent(args, true, &event);
1943 event.phase = blink::WebMouseWheelEvent::PhaseChanged;
1944 event.hasPreciseScrollingDeltas = true;
1945 HandleInputEventOnViewOrPopup(event);
1948 void EventSender::TrackpadScrollEnd() {
1949 WebMouseWheelEvent event;
1950 InitMouseEvent(WebInputEvent::MouseWheel,
1951 WebMouseEvent::ButtonNone,
1952 last_mouse_pos_,
1953 GetCurrentEventTimeSec(),
1954 click_count_,
1956 &event);
1957 event.phase = WebMouseWheelEvent::PhaseEnded;
1958 event.hasPreciseScrollingDeltas = true;
1959 HandleInputEventOnViewOrPopup(event);
1962 void EventSender::MouseScrollBy(gin::Arguments* args) {
1963 WebMouseWheelEvent event;
1964 InitMouseWheelEvent(args, false, &event);
1965 HandleInputEventOnViewOrPopup(event);
1968 void EventSender::MouseMomentumBegin() {
1969 WebMouseWheelEvent event;
1970 InitMouseEvent(WebInputEvent::MouseWheel,
1971 WebMouseEvent::ButtonNone,
1972 last_mouse_pos_,
1973 GetCurrentEventTimeSec(),
1974 click_count_,
1976 &event);
1977 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1978 event.hasPreciseScrollingDeltas = true;
1979 HandleInputEventOnViewOrPopup(event);
1982 void EventSender::MouseMomentumBegin2(gin::Arguments* args) {
1983 WebMouseWheelEvent event;
1984 InitMouseWheelEvent(args, true, &event);
1985 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1986 event.hasPreciseScrollingDeltas = true;
1987 HandleInputEventOnViewOrPopup(event);
1990 void EventSender::MouseMomentumScrollBy(gin::Arguments* args) {
1991 WebMouseWheelEvent event;
1992 InitMouseWheelEvent(args, true, &event);
1993 event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1994 event.hasPreciseScrollingDeltas = true;
1995 HandleInputEventOnViewOrPopup(event);
1998 void EventSender::MouseMomentumEnd() {
1999 WebMouseWheelEvent event;
2000 InitMouseEvent(WebInputEvent::MouseWheel,
2001 WebMouseEvent::ButtonNone,
2002 last_mouse_pos_,
2003 GetCurrentEventTimeSec(),
2004 click_count_,
2006 &event);
2007 event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
2008 event.hasPreciseScrollingDeltas = true;
2009 HandleInputEventOnViewOrPopup(event);
2012 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
2013 delegate_->PostTask(new MouseDownTask(this, button_number, modifiers));
2014 delegate_->PostTask(new MouseUpTask(this, button_number, modifiers));
2017 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
2018 int modifiers,
2019 KeyLocationCode location) {
2020 delegate_->PostTask(new KeyDownTask(this, code_str, modifiers, location));
2023 double EventSender::GetCurrentEventTimeSec() {
2024 return (delegate_->GetCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0;
2027 void EventSender::DoLeapForward(int milliseconds) {
2028 time_offset_ms_ += milliseconds;
2031 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type,
2032 bool causesScrollingIfUncanceled) {
2033 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap),
2034 touch_points_.size());
2035 if (force_layout_on_events_)
2036 view_->layout();
2038 WebTouchEvent touch_event;
2039 touch_event.type = type;
2040 touch_event.modifiers = touch_modifiers_;
2041 touch_event.cancelable = touch_cancelable_;
2042 touch_event.timeStampSeconds = GetCurrentEventTimeSec();
2043 touch_event.causesScrollingIfUncanceled = causesScrollingIfUncanceled;
2044 touch_event.touchesLength = touch_points_.size();
2045 for (size_t i = 0; i < touch_points_.size(); ++i)
2046 touch_event.touches[i] = touch_points_[i];
2047 HandleInputEventOnViewOrPopup(touch_event);
2049 for (size_t i = 0; i < touch_points_.size(); ++i) {
2050 WebTouchPoint* touch_point = &touch_points_[i];
2051 if (touch_point->state == WebTouchPoint::StateReleased
2052 || touch_point->state == WebTouchPoint::StateCancelled) {
2053 touch_points_.erase(touch_points_.begin() + i);
2054 --i;
2055 } else
2056 touch_point->state = WebTouchPoint::StateStationary;
2060 void EventSender::GestureEvent(WebInputEvent::Type type,
2061 gin::Arguments* args) {
2062 WebGestureEvent event;
2063 event.type = type;
2065 // If the first argument is a string, it is to specify the device, otherwise
2066 // the device is assumed to be a touchscreen (since most tests were written
2067 // assuming this).
2068 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2069 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString()) {
2070 std::string device_string;
2071 if (!args->GetNext(&device_string)) {
2072 args->ThrowError();
2073 return;
2075 if (device_string == kSourceDeviceStringTouchpad) {
2076 event.sourceDevice = blink::WebGestureDeviceTouchpad;
2077 } else if (device_string == kSourceDeviceStringTouchscreen) {
2078 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2079 } else {
2080 args->ThrowError();
2081 return;
2085 double x;
2086 double y;
2087 if (!args->GetNext(&x) || !args->GetNext(&y)) {
2088 args->ThrowError();
2089 return;
2092 switch (type) {
2093 case WebInputEvent::GestureScrollUpdate:
2095 bool preventPropagation = false;
2096 if (!args->PeekNext().IsEmpty()) {
2097 if (!args->GetNext(&preventPropagation)) {
2098 args->ThrowError();
2099 return;
2103 event.data.scrollUpdate.deltaX = static_cast<float>(x);
2104 event.data.scrollUpdate.deltaY = static_cast<float>(y);
2105 event.data.scrollUpdate.preventPropagation = preventPropagation;
2106 event.x = current_gesture_location_.x;
2107 event.y = current_gesture_location_.y;
2108 current_gesture_location_.x =
2109 current_gesture_location_.x + event.data.scrollUpdate.deltaX;
2110 current_gesture_location_.y =
2111 current_gesture_location_.y + event.data.scrollUpdate.deltaY;
2112 break;
2114 case WebInputEvent::GestureScrollBegin:
2115 current_gesture_location_ = WebPoint(x, y);
2116 event.x = current_gesture_location_.x;
2117 event.y = current_gesture_location_.y;
2118 break;
2119 case WebInputEvent::GestureScrollEnd:
2120 case WebInputEvent::GestureFlingStart:
2121 event.x = current_gesture_location_.x;
2122 event.y = current_gesture_location_.y;
2123 break;
2124 case WebInputEvent::GesturePinchBegin:
2125 case WebInputEvent::GesturePinchEnd:
2126 current_gesture_location_ = WebPoint(x, y);
2127 event.x = current_gesture_location_.x;
2128 event.y = current_gesture_location_.y;
2129 break;
2130 case WebInputEvent::GesturePinchUpdate:
2132 float scale = 1;
2133 if (!args->PeekNext().IsEmpty()) {
2134 if (!args->GetNext(&scale)) {
2135 args->ThrowError();
2136 return;
2139 event.data.pinchUpdate.scale = scale;
2140 current_gesture_location_ = WebPoint(x, y);
2141 event.x = current_gesture_location_.x;
2142 event.y = current_gesture_location_.y;
2143 break;
2145 case WebInputEvent::GestureTap:
2147 float tap_count = 1;
2148 float width = 30;
2149 float height = 30;
2150 if (!args->PeekNext().IsEmpty()) {
2151 if (!args->GetNext(&tap_count)) {
2152 args->ThrowError();
2153 return;
2156 if (!args->PeekNext().IsEmpty()) {
2157 if (!args->GetNext(&width)) {
2158 args->ThrowError();
2159 return;
2162 if (!args->PeekNext().IsEmpty()) {
2163 if (!args->GetNext(&height)) {
2164 args->ThrowError();
2165 return;
2168 event.data.tap.tapCount = tap_count;
2169 event.data.tap.width = width;
2170 event.data.tap.height = height;
2171 event.x = x;
2172 event.y = y;
2173 break;
2175 case WebInputEvent::GestureTapUnconfirmed:
2176 if (!args->PeekNext().IsEmpty()) {
2177 float tap_count;
2178 if (!args->GetNext(&tap_count)) {
2179 args->ThrowError();
2180 return;
2182 event.data.tap.tapCount = tap_count;
2183 } else {
2184 event.data.tap.tapCount = 1;
2186 event.x = x;
2187 event.y = y;
2188 break;
2189 case WebInputEvent::GestureTapDown:
2191 float width = 30;
2192 float height = 30;
2193 if (!args->PeekNext().IsEmpty()) {
2194 if (!args->GetNext(&width)) {
2195 args->ThrowError();
2196 return;
2199 if (!args->PeekNext().IsEmpty()) {
2200 if (!args->GetNext(&height)) {
2201 args->ThrowError();
2202 return;
2205 event.x = x;
2206 event.y = y;
2207 event.data.tapDown.width = width;
2208 event.data.tapDown.height = height;
2209 break;
2211 case WebInputEvent::GestureShowPress:
2213 float width = 30;
2214 float height = 30;
2215 if (!args->PeekNext().IsEmpty()) {
2216 if (!args->GetNext(&width)) {
2217 args->ThrowError();
2218 return;
2220 if (!args->PeekNext().IsEmpty()) {
2221 if (!args->GetNext(&height)) {
2222 args->ThrowError();
2223 return;
2227 event.x = x;
2228 event.y = y;
2229 event.data.showPress.width = width;
2230 event.data.showPress.height = height;
2231 break;
2233 case WebInputEvent::GestureTapCancel:
2234 event.x = x;
2235 event.y = y;
2236 break;
2237 case WebInputEvent::GestureLongPress:
2238 event.x = x;
2239 event.y = y;
2240 if (!args->PeekNext().IsEmpty()) {
2241 float width;
2242 if (!args->GetNext(&width)) {
2243 args->ThrowError();
2244 return;
2246 event.data.longPress.width = width;
2247 if (!args->PeekNext().IsEmpty()) {
2248 float height;
2249 if (!args->GetNext(&height)) {
2250 args->ThrowError();
2251 return;
2253 event.data.longPress.height = height;
2256 break;
2257 case WebInputEvent::GestureLongTap:
2258 event.x = x;
2259 event.y = y;
2260 if (!args->PeekNext().IsEmpty()) {
2261 float width;
2262 if (!args->GetNext(&width)) {
2263 args->ThrowError();
2264 return;
2266 event.data.longPress.width = width;
2267 if (!args->PeekNext().IsEmpty()) {
2268 float height;
2269 if (!args->GetNext(&height)) {
2270 args->ThrowError();
2271 return;
2273 event.data.longPress.height = height;
2276 break;
2277 case WebInputEvent::GestureTwoFingerTap:
2278 event.x = x;
2279 event.y = y;
2280 if (!args->PeekNext().IsEmpty()) {
2281 float first_finger_width;
2282 if (!args->GetNext(&first_finger_width)) {
2283 args->ThrowError();
2284 return;
2286 event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2287 if (!args->PeekNext().IsEmpty()) {
2288 float first_finger_height;
2289 if (!args->GetNext(&first_finger_height)) {
2290 args->ThrowError();
2291 return;
2293 event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2296 break;
2297 default:
2298 NOTREACHED();
2301 event.globalX = event.x;
2302 event.globalY = event.y;
2303 event.timeStampSeconds = GetCurrentEventTimeSec();
2305 if (force_layout_on_events_)
2306 view_->layout();
2308 bool result = HandleInputEventOnViewOrPopup(event);
2310 // Long press might start a drag drop session. Complete it if so.
2311 if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2312 WebMouseEvent mouse_event;
2313 InitMouseEvent(WebInputEvent::MouseDown,
2314 pressed_button_,
2315 WebPoint(x, y),
2316 GetCurrentEventTimeSec(),
2317 click_count_,
2319 &mouse_event);
2321 FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2323 args->Return(result);
2326 void EventSender::UpdateClickCountForButton(
2327 WebMouseEvent::Button button_type) {
2328 if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2329 kMultipleClickTimeSec) &&
2330 (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) &&
2331 (button_type == last_button_type_)) {
2332 ++click_count_;
2333 } else {
2334 click_count_ = 1;
2335 last_button_type_ = button_type;
2339 void EventSender::InitMouseWheelEvent(gin::Arguments* args,
2340 bool continuous,
2341 WebMouseWheelEvent* event) {
2342 // Force a layout here just to make sure every position has been
2343 // determined before we send events (as well as all the other methods
2344 // that send an event do).
2345 if (force_layout_on_events_)
2346 view_->layout();
2348 double horizontal;
2349 if (!args->GetNext(&horizontal)) {
2350 args->ThrowError();
2351 return;
2353 double vertical;
2354 if (!args->GetNext(&vertical)) {
2355 args->ThrowError();
2356 return;
2359 bool paged = false;
2360 bool has_precise_scrolling_deltas = false;
2361 int modifiers = 0;
2362 bool can_scroll = true;
2363 if (!args->PeekNext().IsEmpty()) {
2364 args->GetNext(&paged);
2365 if (!args->PeekNext().IsEmpty()) {
2366 args->GetNext(&has_precise_scrolling_deltas);
2367 if (!args->PeekNext().IsEmpty()) {
2368 v8::Local<v8::Value> value;
2369 args->GetNext(&value);
2370 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
2371 if (!args->PeekNext().IsEmpty())
2372 args->GetNext(&can_scroll);
2377 InitMouseEvent(WebInputEvent::MouseWheel,
2378 pressed_button_,
2379 last_mouse_pos_,
2380 GetCurrentEventTimeSec(),
2381 click_count_,
2382 modifiers,
2383 event);
2384 event->wheelTicksX = static_cast<float>(horizontal);
2385 event->wheelTicksY = static_cast<float>(vertical);
2386 event->deltaX = event->wheelTicksX;
2387 event->deltaY = event->wheelTicksY;
2388 event->scrollByPage = paged;
2389 event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2390 event->canScroll = can_scroll;
2391 if (continuous) {
2392 event->wheelTicksX /= kScrollbarPixelsPerTick;
2393 event->wheelTicksY /= kScrollbarPixelsPerTick;
2394 } else {
2395 event->deltaX *= kScrollbarPixelsPerTick;
2396 event->deltaY *= kScrollbarPixelsPerTick;
2400 // Radius fields radius_x and radius_y should eventually be moved to
2401 // WebPointerProperties.
2402 // TODO(e_hakkinen): Drop radius_{x,y}_pointer parameters once that happens.
2403 void EventSender::InitPointerProperties(gin::Arguments* args,
2404 blink::WebPointerProperties* e,
2405 float* radius_x_pointer,
2406 float* radius_y_pointer) {
2407 if (!args->PeekNext().IsEmpty()) {
2408 double radius_x;
2409 if (!args->GetNext(&radius_x)) {
2410 args->ThrowError();
2411 return;
2414 double radius_y = radius_x;
2415 if (!args->PeekNext().IsEmpty()) {
2416 if (!args->GetNext(&radius_y)) {
2417 args->ThrowError();
2418 return;
2422 *radius_x_pointer = static_cast<float>(radius_x);
2423 *radius_y_pointer = static_cast<float>(radius_y);
2426 if (!args->PeekNext().IsEmpty()) {
2427 double force;
2428 if (!args->GetNext(&force)) {
2429 args->ThrowError();
2430 return;
2432 e->force = static_cast<float>(force);
2435 if (!args->PeekNext().IsEmpty()) {
2436 int tiltX, tiltY;
2437 if (!args->GetNext(&tiltX) || !args->GetNext(&tiltY)) {
2438 args->ThrowError();
2439 return;
2441 e->tiltX = tiltX;
2442 e->tiltY = tiltY;
2445 if (!args->PeekNext().IsEmpty()) {
2446 std::string pointer_type_string;
2447 if (!args->GetNext(&pointer_type_string)) {
2448 args->ThrowError();
2449 return;
2451 if (pointer_type_string == kPointerTypeStringUnknown) {
2452 e->pointerType = WebMouseEvent::PointerTypeUnknown;
2453 } else if (pointer_type_string == kPointerTypeStringMouse) {
2454 e->pointerType = WebMouseEvent::PointerTypeMouse;
2455 } else if (pointer_type_string == kPointerTypeStringPen) {
2456 e->pointerType = WebMouseEvent::PointerTypePen;
2457 } else if (pointer_type_string == kPointerTypeStringTouch) {
2458 e->pointerType = WebMouseEvent::PointerTypeTouch;
2459 } else {
2460 args->ThrowError();
2461 return;
2466 void EventSender::FinishDragAndDrop(const WebMouseEvent& e,
2467 blink::WebDragOperation drag_effect) {
2468 WebPoint client_point(e.x, e.y);
2469 WebPoint screen_point(e.globalX, e.globalY);
2470 current_drag_effect_ = drag_effect;
2471 if (current_drag_effect_) {
2472 // Specifically pass any keyboard modifiers to the drop method. This allows
2473 // tests to control the drop type (i.e. copy or move).
2474 view_->dragTargetDrop(client_point, screen_point, e.modifiers);
2475 } else {
2476 view_->dragTargetDragLeave();
2478 view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_);
2479 view_->dragSourceSystemDragEnded();
2481 current_drag_data_.reset();
2484 void EventSender::DoMouseUp(const WebMouseEvent& e) {
2485 HandleInputEventOnViewOrPopup(e);
2487 pressed_button_ = WebMouseEvent::ButtonNone;
2488 last_click_time_sec_ = e.timeStampSeconds;
2489 last_click_pos_ = last_mouse_pos_;
2491 // If we're in a drag operation, complete it.
2492 if (current_drag_data_.isNull())
2493 return;
2495 WebPoint client_point(e.x, e.y);
2496 WebPoint screen_point(e.globalX, e.globalY);
2497 FinishDragAndDrop(
2499 view_->dragTargetDragOver(
2500 client_point,
2501 screen_point,
2502 current_drag_effects_allowed_,
2503 e.modifiers));
2506 void EventSender::DoMouseMove(const WebMouseEvent& e) {
2507 last_mouse_pos_ = WebPoint(e.x, e.y);
2509 HandleInputEventOnViewOrPopup(e);
2511 if (pressed_button_ == WebMouseEvent::ButtonNone ||
2512 current_drag_data_.isNull()) {
2513 return;
2516 WebPoint client_point(e.x, e.y);
2517 WebPoint screen_point(e.globalX, e.globalY);
2518 current_drag_effect_ = view_->dragTargetDragOver(
2519 client_point, screen_point, current_drag_effects_allowed_, e.modifiers);
2522 void EventSender::ReplaySavedEvents() {
2523 replaying_saved_events_ = true;
2524 while (!mouse_event_queue_.empty()) {
2525 SavedEvent e = mouse_event_queue_.front();
2526 mouse_event_queue_.pop_front();
2528 switch (e.type) {
2529 case SavedEvent::TYPE_MOUSE_MOVE: {
2530 WebMouseEvent event;
2531 InitMouseEvent(WebInputEvent::MouseMove,
2532 pressed_button_,
2533 e.pos,
2534 GetCurrentEventTimeSec(),
2535 click_count_,
2536 e.modifiers,
2537 &event);
2538 DoMouseMove(event);
2539 break;
2541 case SavedEvent::TYPE_LEAP_FORWARD:
2542 DoLeapForward(e.milliseconds);
2543 break;
2544 case SavedEvent::TYPE_MOUSE_UP: {
2545 WebMouseEvent event;
2546 InitMouseEvent(WebInputEvent::MouseUp,
2547 e.button_type,
2548 last_mouse_pos_,
2549 GetCurrentEventTimeSec(),
2550 click_count_,
2551 e.modifiers,
2552 &event);
2553 DoMouseUp(event);
2554 break;
2556 default:
2557 NOTREACHED();
2561 replaying_saved_events_ = false;
2564 bool EventSender::HandleInputEventOnViewOrPopup(const WebInputEvent& event) {
2565 if (WebPagePopup* popup = view_->pagePopup()) {
2566 if (!WebInputEvent::isKeyboardEventType(event.type))
2567 return popup->handleInputEvent(event);
2569 return view_->handleInputEvent(event);
2572 } // namespace test_runner