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 "content/shell/renderer/test_runner/event_sender.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/public/common/page_zoom.h"
11 #include "content/shell/renderer/test_runner/mock_spell_check.h"
12 #include "content/shell/renderer/test_runner/test_interfaces.h"
13 #include "content/shell/renderer/test_runner/web_test_delegate.h"
14 #include "content/shell/renderer/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/WebView.h"
24 #include "ui/events/keycodes/keyboard_codes.h"
25 #include "v8/include/v8.h"
27 using blink::WebContextMenuData;
28 using blink::WebDragData;
29 using blink::WebDragOperationsMask;
30 using blink::WebFloatPoint;
31 using blink::WebFrame;
32 using blink::WebGestureEvent;
33 using blink::WebInputEvent;
34 using blink::WebKeyboardEvent;
35 using blink::WebMenuItemInfo;
36 using blink::WebMouseEvent;
37 using blink::WebMouseWheelEvent;
38 using blink::WebPoint;
39 using blink::WebString;
40 using blink::WebTouchEvent;
41 using blink::WebTouchPoint;
42 using blink::WebVector;
49 void InitMouseEvent(WebInputEvent::Type t,
50 WebMouseEvent::Button b,
58 e->modifiers = modifiers;
63 e->timeStampSeconds = time_stamp;
64 e->clickCount = click_count;
67 int GetKeyModifier(const std::string& modifier_name) {
68 const char* characters = modifier_name.c_str();
69 if (!strcmp(characters, "ctrlKey")
71 || !strcmp(characters, "addSelectionKey")
74 return WebInputEvent::ControlKey;
75 } else if (!strcmp(characters, "shiftKey") ||
76 !strcmp(characters, "rangeSelectionKey")) {
77 return WebInputEvent::ShiftKey;
78 } else if (!strcmp(characters, "altKey")) {
79 return WebInputEvent::AltKey;
81 } else if (!strcmp(characters, "metaKey") ||
82 !strcmp(characters, "addSelectionKey")) {
83 return WebInputEvent::MetaKey;
85 } else if (!strcmp(characters, "metaKey")) {
86 return WebInputEvent::MetaKey;
88 } else if (!strcmp(characters, "autoRepeat")) {
89 return WebInputEvent::IsAutoRepeat;
90 } else if (!strcmp(characters, "copyKey")) {
92 return WebInputEvent::AltKey;
94 return WebInputEvent::ControlKey;
101 int GetKeyModifiers(const std::vector<std::string>& modifier_names) {
103 for (std::vector<std::string>::const_iterator it = modifier_names.begin();
104 it != modifier_names.end(); ++it) {
105 modifiers |= GetKeyModifier(*it);
110 int GetKeyModifiersFromV8(v8::Handle<v8::Value> value) {
111 std::vector<std::string> modifier_names;
112 if (value->IsString()) {
113 modifier_names.push_back(gin::V8ToString(value));
114 } else if (value->IsArray()) {
115 gin::Converter<std::vector<std::string> >::FromV8(
116 NULL, value, &modifier_names);
118 return GetKeyModifiers(modifier_names);
121 // Maximum distance (in space and time) for a mouse click to register as a
122 // double or triple click.
123 const double kMultipleClickTimeSec = 1;
124 const int kMultipleClickRadiusPixels = 5;
125 const char kSubMenuDepthIdentifier[] = "_";
126 const char kSubMenuIdentifier[] = " >";
127 const char kSeparatorIdentifier[] = "---------";
129 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
130 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
131 kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
134 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
135 const std::string& prefix, std::vector<std::string>* strings) {
136 for (size_t i = 0; i < customItems.size(); ++i) {
137 if (customItems[i].type == blink::WebMenuItemInfo::Separator) {
138 strings->push_back(prefix + kSeparatorIdentifier);
139 } else if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
140 strings->push_back(prefix + customItems[i].label.utf8() +
142 PopulateCustomItems(customItems[i].subMenuItems, prefix +
143 kSubMenuDepthIdentifier, strings);
145 strings->push_back(prefix + customItems[i].label.utf8());
150 // Because actual context menu is implemented by the browser side,
151 // this function does only what LayoutTests are expecting:
152 // - Many test checks the count of items. So returning non-zero value makes
154 // - Some test compares the count before and after some action. So changing the
155 // count based on flags also makes sense. This function is doing such for some
157 // - Some test even checks actual string content. So providing it would be also
159 std::vector<std::string> MakeMenuItemStringsFor(
160 WebContextMenuData* context_menu,
161 WebTestDelegate* delegate) {
162 // These constants are based on Safari's context menu because tests are made
164 static const char* kNonEditableMenuStrings[] = {
175 static const char* kEditableMenuStrings[] = {
180 "Spelling and Grammar",
181 "Substitutions, Transformations",
184 "Paragraph Direction",
189 // This is possible because mouse events are cancelleable.
191 return std::vector<std::string>();
193 std::vector<std::string> strings;
195 // Populate custom menu items if provided by blink.
196 PopulateCustomItems(context_menu->customItems, "", &strings);
198 if (context_menu->isEditable) {
199 for (const char** item = kEditableMenuStrings; *item; ++item) {
200 strings.push_back(*item);
202 WebVector<WebString> suggestions;
203 MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
205 for (size_t i = 0; i < suggestions.size(); ++i) {
206 strings.push_back(suggestions[i].utf8());
209 for (const char** item = kNonEditableMenuStrings; *item; ++item) {
210 strings.push_back(*item);
217 // How much we should scroll per event - the value here is chosen to match the
218 // WebKit impl and layout test results.
219 const float kScrollbarPixelsPerTick = 40.0f;
221 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
223 return WebMouseEvent::ButtonLeft;
224 if (button_code == 2)
225 return WebMouseEvent::ButtonRight;
226 return WebMouseEvent::ButtonMiddle;
229 class MouseDownTask : public WebMethodTask<EventSender> {
231 MouseDownTask(EventSender* obj, int button_number, int modifiers)
232 : WebMethodTask<EventSender>(obj),
233 button_number_(button_number),
234 modifiers_(modifiers) {}
236 void RunIfValid() override { object_->MouseDown(button_number_, modifiers_); }
243 class MouseUpTask : public WebMethodTask<EventSender> {
245 MouseUpTask(EventSender* obj, int button_number, int modifiers)
246 : WebMethodTask<EventSender>(obj),
247 button_number_(button_number),
248 modifiers_(modifiers) {}
250 void RunIfValid() override { object_->MouseUp(button_number_, modifiers_); }
257 class KeyDownTask : public WebMethodTask<EventSender> {
259 KeyDownTask(EventSender* obj,
260 const std::string code_str,
262 KeyLocationCode location)
263 : WebMethodTask<EventSender>(obj),
265 modifiers_(modifiers),
266 location_(location) {}
268 void RunIfValid() override {
269 object_->KeyDown(code_str_, modifiers_, location_);
273 std::string code_str_;
275 KeyLocationCode location_;
278 bool NeedsShiftModifier(int keyCode) {
279 // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
280 return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
283 // Get the edit command corresponding to a keyboard event.
284 // Returns true if the specified event corresponds to an edit command, the name
285 // of the edit command will be stored in |*name|.
286 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
287 #if defined(OS_MACOSX)
288 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
289 // modifiers. These key events correspond to some special movement and
290 // selection editor commands. These keys will be marked as system key, which
291 // prevents them from being handled. Thus they must be handled specially.
292 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
293 WebKeyboardEvent::MetaKey)
296 switch (event.windowsKeyCode) {
298 *name = "MoveToBeginningOfLine";
301 *name = "MoveToEndOfLine";
304 *name = "MoveToBeginningOfDocument";
307 *name = "MoveToEndOfDocument";
313 if (event.modifiers & WebKeyboardEvent::ShiftKey)
314 name->append("AndModifySelection");
322 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
323 #if defined(OS_MACOSX)
324 return event.modifiers & WebInputEvent::MetaKey &&
325 event.windowsKeyCode != ui::VKEY_B &&
326 event.windowsKeyCode != ui::VKEY_I;
328 return !!(event.modifiers & WebInputEvent::AltKey);
334 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
336 static gin::WrapperInfo kWrapperInfo;
338 static void Install(base::WeakPtr<EventSender> sender,
339 blink::WebFrame* frame);
342 explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
343 ~EventSenderBindings() override;
346 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
347 v8::Isolate* isolate) override;
350 void EnableDOMUIEventLogging();
351 void FireKeyboardEventsToElement();
352 void ClearKillRing();
353 std::vector<std::string> ContextClick();
358 void SetPageZoomFactor(double factor);
359 void SetPageScaleFactor(gin::Arguments* args);
360 void ClearTouchPoints();
361 void ReleaseTouchPoint(unsigned index);
362 void UpdateTouchPoint(unsigned index, double x, double y);
363 void CancelTouchPoint(unsigned index);
364 void SetTouchModifier(const std::string& key_name, bool set_mask);
365 void SetTouchCancelable(bool cancelable);
366 void DumpFilenameBeingDragged();
367 void GestureFlingCancel();
368 void GestureFlingStart(float x, float y, float velocity_x, float velocity_y);
369 void GestureScrollFirstPoint(int x, int y);
374 void LeapForward(int milliseconds);
375 void BeginDragWithFiles(const std::vector<std::string>& files);
376 void AddTouchPoint(gin::Arguments* args);
377 void MouseDragBegin();
379 void GestureScrollBegin(gin::Arguments* args);
380 void GestureScrollEnd(gin::Arguments* args);
381 void GestureScrollUpdate(gin::Arguments* args);
382 void GestureScrollUpdateWithoutPropagation(gin::Arguments* args);
383 void GestureTap(gin::Arguments* args);
384 void GestureTapDown(gin::Arguments* args);
385 void GestureShowPress(gin::Arguments* args);
386 void GestureTapCancel(gin::Arguments* args);
387 void GestureLongPress(gin::Arguments* args);
388 void GestureLongTap(gin::Arguments* args);
389 void GestureTwoFingerTap(gin::Arguments* args);
390 void ContinuousMouseScrollBy(gin::Arguments* args);
391 void MouseMoveTo(gin::Arguments* args);
392 void TrackpadScrollBegin();
393 void TrackpadScroll(gin::Arguments* args);
394 void TrackpadScrollEnd();
395 void MouseScrollBy(gin::Arguments* args);
396 // TODO(erikchen): Remove MouseMomentumBegin once CL 282743002 has landed.
397 void MouseMomentumBegin();
398 void MouseMomentumBegin2(gin::Arguments* args);
399 void MouseMomentumScrollBy(gin::Arguments* args);
400 void MouseMomentumEnd();
401 void ScheduleAsynchronousClick(gin::Arguments* args);
402 void ScheduleAsynchronousKeyDown(gin::Arguments* args);
403 void MouseDown(gin::Arguments* args);
404 void MouseUp(gin::Arguments* args);
405 void KeyDown(gin::Arguments* args);
407 // Binding properties:
408 bool ForceLayoutOnEvents() const;
409 void SetForceLayoutOnEvents(bool force);
410 bool IsDragMode() const;
411 void SetIsDragMode(bool drag_mode);
414 int WmKeyDown() const;
415 void SetWmKeyDown(int key_down);
418 void SetWmKeyUp(int key_up);
421 void SetWmChar(int wm_char);
423 int WmDeadChar() const;
424 void SetWmDeadChar(int dead_char);
426 int WmSysKeyDown() const;
427 void SetWmSysKeyDown(int key_down);
429 int WmSysKeyUp() const;
430 void SetWmSysKeyUp(int key_up);
432 int WmSysChar() const;
433 void SetWmSysChar(int sys_char);
435 int WmSysDeadChar() const;
436 void SetWmSysDeadChar(int sys_dead_char);
439 base::WeakPtr<EventSender> sender_;
441 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
444 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
446 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
450 EventSenderBindings::~EventSenderBindings() {}
453 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
455 v8::Isolate* isolate = blink::mainThreadIsolate();
456 v8::HandleScope handle_scope(isolate);
457 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
458 if (context.IsEmpty())
461 v8::Context::Scope context_scope(context);
463 gin::Handle<EventSenderBindings> bindings =
464 gin::CreateHandle(isolate, new EventSenderBindings(sender));
465 if (bindings.IsEmpty())
467 v8::Handle<v8::Object> global = context->Global();
468 global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
471 gin::ObjectTemplateBuilder
472 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
473 return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
474 .SetMethod("enableDOMUIEventLogging",
475 &EventSenderBindings::EnableDOMUIEventLogging)
476 .SetMethod("fireKeyboardEventsToElement",
477 &EventSenderBindings::FireKeyboardEventsToElement)
478 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
479 .SetMethod("contextClick", &EventSenderBindings::ContextClick)
480 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
481 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
482 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
483 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
484 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
485 .SetMethod("setPageScaleFactor", &EventSenderBindings::SetPageScaleFactor)
486 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
487 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
488 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
489 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
490 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
491 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
492 .SetMethod("dumpFilenameBeingDragged",
493 &EventSenderBindings::DumpFilenameBeingDragged)
494 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
495 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
496 .SetMethod("gestureScrollFirstPoint",
497 &EventSenderBindings::GestureScrollFirstPoint)
498 .SetMethod("touchStart", &EventSenderBindings::TouchStart)
499 .SetMethod("touchMove", &EventSenderBindings::TouchMove)
500 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
501 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
502 .SetMethod("leapForward", &EventSenderBindings::LeapForward)
503 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
504 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
505 .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin)
506 .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd)
507 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
508 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
509 .SetMethod("gestureScrollUpdate",
510 &EventSenderBindings::GestureScrollUpdate)
511 .SetMethod("gestureScrollUpdateWithoutPropagation",
512 &EventSenderBindings::GestureScrollUpdateWithoutPropagation)
513 .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
514 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
515 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
516 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
517 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
518 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
519 .SetMethod("gestureTwoFingerTap",
520 &EventSenderBindings::GestureTwoFingerTap)
521 .SetMethod("continuousMouseScrollBy",
522 &EventSenderBindings::ContinuousMouseScrollBy)
523 .SetMethod("keyDown", &EventSenderBindings::KeyDown)
524 .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
525 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
526 .SetMethod("trackpadScrollBegin",
527 &EventSenderBindings::TrackpadScrollBegin)
528 .SetMethod("trackpadScroll", &EventSenderBindings::TrackpadScroll)
529 .SetMethod("trackpadScrollEnd", &EventSenderBindings::TrackpadScrollEnd)
530 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
531 .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
532 .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin)
533 .SetMethod("mouseMomentumBegin2",
534 &EventSenderBindings::MouseMomentumBegin2)
535 .SetMethod("mouseMomentumScrollBy",
536 &EventSenderBindings::MouseMomentumScrollBy)
537 .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd)
538 .SetMethod("scheduleAsynchronousClick",
539 &EventSenderBindings::ScheduleAsynchronousClick)
540 .SetMethod("scheduleAsynchronousKeyDown",
541 &EventSenderBindings::ScheduleAsynchronousKeyDown)
542 .SetProperty("forceLayoutOnEvents",
543 &EventSenderBindings::ForceLayoutOnEvents,
544 &EventSenderBindings::SetForceLayoutOnEvents)
545 .SetProperty("dragMode",
546 &EventSenderBindings::IsDragMode,
547 &EventSenderBindings::SetIsDragMode)
549 .SetProperty("WM_KEYDOWN",
550 &EventSenderBindings::WmKeyDown,
551 &EventSenderBindings::SetWmKeyDown)
552 .SetProperty("WM_KEYUP",
553 &EventSenderBindings::WmKeyUp,
554 &EventSenderBindings::SetWmKeyUp)
555 .SetProperty("WM_CHAR",
556 &EventSenderBindings::WmChar,
557 &EventSenderBindings::SetWmChar)
558 .SetProperty("WM_DEADCHAR",
559 &EventSenderBindings::WmDeadChar,
560 &EventSenderBindings::SetWmDeadChar)
561 .SetProperty("WM_SYSKEYDOWN",
562 &EventSenderBindings::WmSysKeyDown,
563 &EventSenderBindings::SetWmSysKeyDown)
564 .SetProperty("WM_SYSKEYUP",
565 &EventSenderBindings::WmSysKeyUp,
566 &EventSenderBindings::SetWmSysKeyUp)
567 .SetProperty("WM_SYSCHAR",
568 &EventSenderBindings::WmSysChar,
569 &EventSenderBindings::SetWmSysChar)
570 .SetProperty("WM_SYSDEADCHAR",
571 &EventSenderBindings::WmSysDeadChar,
572 &EventSenderBindings::SetWmSysDeadChar);
578 void EventSenderBindings::EnableDOMUIEventLogging() {
580 sender_->EnableDOMUIEventLogging();
583 void EventSenderBindings::FireKeyboardEventsToElement() {
585 sender_->FireKeyboardEventsToElement();
588 void EventSenderBindings::ClearKillRing() {
590 sender_->ClearKillRing();
593 std::vector<std::string> EventSenderBindings::ContextClick() {
595 return sender_->ContextClick();
596 return std::vector<std::string>();
599 void EventSenderBindings::TextZoomIn() {
601 sender_->TextZoomIn();
604 void EventSenderBindings::TextZoomOut() {
606 sender_->TextZoomOut();
609 void EventSenderBindings::ZoomPageIn() {
611 sender_->ZoomPageIn();
614 void EventSenderBindings::ZoomPageOut() {
616 sender_->ZoomPageOut();
619 void EventSenderBindings::SetPageZoomFactor(double factor) {
621 sender_->SetPageZoomFactor(factor);
624 void EventSenderBindings::SetPageScaleFactor(gin::Arguments* args) {
630 if (args->PeekNext().IsEmpty())
632 args->GetNext(&scale_factor);
633 if (args->PeekNext().IsEmpty())
636 if (args->PeekNext().IsEmpty())
639 sender_->SetPageScaleFactor(scale_factor,
640 static_cast<int>(x), static_cast<int>(y));
643 void EventSenderBindings::ClearTouchPoints() {
645 sender_->ClearTouchPoints();
648 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
650 sender_->ReleaseTouchPoint(index);
653 void EventSenderBindings::UpdateTouchPoint(unsigned index, double x, double y) {
655 sender_->UpdateTouchPoint(index, static_cast<float>(x), static_cast<float>(y));
658 void EventSenderBindings::CancelTouchPoint(unsigned index) {
660 sender_->CancelTouchPoint(index);
663 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
666 sender_->SetTouchModifier(key_name, set_mask);
669 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
671 sender_->SetTouchCancelable(cancelable);
674 void EventSenderBindings::DumpFilenameBeingDragged() {
676 sender_->DumpFilenameBeingDragged();
679 void EventSenderBindings::GestureFlingCancel() {
681 sender_->GestureFlingCancel();
684 void EventSenderBindings::GestureFlingStart(float x,
689 sender_->GestureFlingStart(x, y, velocity_x, velocity_y);
692 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
694 sender_->GestureScrollFirstPoint(x, y);
697 void EventSenderBindings::TouchStart() {
699 sender_->TouchStart();
702 void EventSenderBindings::TouchMove() {
704 sender_->TouchMove();
707 void EventSenderBindings::TouchCancel() {
709 sender_->TouchCancel();
712 void EventSenderBindings::TouchEnd() {
717 void EventSenderBindings::LeapForward(int milliseconds) {
719 sender_->LeapForward(milliseconds);
722 void EventSenderBindings::BeginDragWithFiles(
723 const std::vector<std::string>& files) {
725 sender_->BeginDragWithFiles(files);
728 void EventSenderBindings::AddTouchPoint(gin::Arguments* args) {
730 sender_->AddTouchPoint(args);
733 void EventSenderBindings::MouseDragBegin() {
735 sender_->MouseDragBegin();
738 void EventSenderBindings::MouseDragEnd() {
740 sender_->MouseDragEnd();
743 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
745 sender_->GestureScrollBegin(args);
748 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
750 sender_->GestureScrollEnd(args);
753 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
755 sender_->GestureScrollUpdate(args);
758 void EventSenderBindings::GestureScrollUpdateWithoutPropagation(
759 gin::Arguments* args) {
761 sender_->GestureScrollUpdateWithoutPropagation(args);
764 void EventSenderBindings::GestureTap(gin::Arguments* args) {
766 sender_->GestureTap(args);
769 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
771 sender_->GestureTapDown(args);
774 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
776 sender_->GestureShowPress(args);
779 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
781 sender_->GestureTapCancel(args);
784 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
786 sender_->GestureLongPress(args);
789 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
791 sender_->GestureLongTap(args);
794 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
796 sender_->GestureTwoFingerTap(args);
799 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
801 sender_->ContinuousMouseScrollBy(args);
804 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
806 sender_->MouseMoveTo(args);
809 void EventSenderBindings::TrackpadScrollBegin() {
811 sender_->TrackpadScrollBegin();
814 void EventSenderBindings::TrackpadScroll(gin::Arguments* args) {
816 sender_->TrackpadScroll(args);
819 void EventSenderBindings::TrackpadScrollEnd() {
821 sender_->TrackpadScrollEnd();
824 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
826 sender_->MouseScrollBy(args);
829 void EventSenderBindings::MouseMomentumBegin() {
831 sender_->MouseMomentumBegin();
834 void EventSenderBindings::MouseMomentumBegin2(gin::Arguments* args) {
836 sender_->MouseMomentumBegin2(args);
839 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) {
841 sender_->MouseMomentumScrollBy(args);
844 void EventSenderBindings::MouseMomentumEnd() {
846 sender_->MouseMomentumEnd();
849 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
853 int button_number = 0;
855 if (!args->PeekNext().IsEmpty()) {
856 args->GetNext(&button_number);
857 if (!args->PeekNext().IsEmpty())
858 modifiers = GetKeyModifiersFromV8(args->PeekNext());
860 sender_->ScheduleAsynchronousClick(button_number, modifiers);
863 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
867 std::string code_str;
869 int location = DOMKeyLocationStandard;
870 args->GetNext(&code_str);
871 if (!args->PeekNext().IsEmpty()) {
872 v8::Handle<v8::Value> value;
873 args->GetNext(&value);
874 modifiers = GetKeyModifiersFromV8(value);
875 if (!args->PeekNext().IsEmpty())
876 args->GetNext(&location);
878 sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
879 static_cast<KeyLocationCode>(location));
882 void EventSenderBindings::MouseDown(gin::Arguments* args) {
886 int button_number = 0;
888 if (!args->PeekNext().IsEmpty()) {
889 args->GetNext(&button_number);
890 if (!args->PeekNext().IsEmpty())
891 modifiers = GetKeyModifiersFromV8(args->PeekNext());
893 sender_->MouseDown(button_number, modifiers);
896 void EventSenderBindings::MouseUp(gin::Arguments* args) {
900 int button_number = 0;
902 if (!args->PeekNext().IsEmpty()) {
903 args->GetNext(&button_number);
904 if (!args->PeekNext().IsEmpty())
905 modifiers = GetKeyModifiersFromV8(args->PeekNext());
907 sender_->MouseUp(button_number, modifiers);
910 void EventSenderBindings::KeyDown(gin::Arguments* args) {
914 std::string code_str;
916 int location = DOMKeyLocationStandard;
917 args->GetNext(&code_str);
918 if (!args->PeekNext().IsEmpty()) {
919 v8::Handle<v8::Value> value;
920 args->GetNext(&value);
921 modifiers = GetKeyModifiersFromV8(value);
922 if (!args->PeekNext().IsEmpty())
923 args->GetNext(&location);
925 sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
928 bool EventSenderBindings::ForceLayoutOnEvents() const {
930 return sender_->force_layout_on_events();
934 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
936 sender_->set_force_layout_on_events(force);
939 bool EventSenderBindings::IsDragMode() const {
941 return sender_->is_drag_mode();
945 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
947 sender_->set_is_drag_mode(drag_mode);
951 int EventSenderBindings::WmKeyDown() const {
953 return sender_->wm_key_down();
957 void EventSenderBindings::SetWmKeyDown(int key_down) {
959 sender_->set_wm_key_down(key_down);
962 int EventSenderBindings::WmKeyUp() const {
964 return sender_->wm_key_up();
968 void EventSenderBindings::SetWmKeyUp(int key_up) {
970 sender_->set_wm_key_up(key_up);
973 int EventSenderBindings::WmChar() const {
975 return sender_->wm_char();
979 void EventSenderBindings::SetWmChar(int wm_char) {
981 sender_->set_wm_char(wm_char);
984 int EventSenderBindings::WmDeadChar() const {
986 return sender_->wm_dead_char();
990 void EventSenderBindings::SetWmDeadChar(int dead_char) {
992 sender_->set_wm_dead_char(dead_char);
995 int EventSenderBindings::WmSysKeyDown() const {
997 return sender_->wm_sys_key_down();
1001 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1003 sender_->set_wm_sys_key_down(key_down);
1006 int EventSenderBindings::WmSysKeyUp() const {
1008 return sender_->wm_sys_key_up();
1012 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1014 sender_->set_wm_sys_key_up(key_up);
1017 int EventSenderBindings::WmSysChar() const {
1019 return sender_->wm_sys_char();
1023 void EventSenderBindings::SetWmSysChar(int sys_char) {
1025 sender_->set_wm_sys_char(sys_char);
1028 int EventSenderBindings::WmSysDeadChar() const {
1030 return sender_->wm_sys_dead_char();
1034 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1036 sender_->set_wm_sys_dead_char(sys_dead_char);
1040 // EventSender -----------------------------------------------------------------
1042 WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone;
1044 WebPoint EventSender::last_mouse_pos_;
1046 WebMouseEvent::Button EventSender::last_button_type_ =
1047 WebMouseEvent::ButtonNone;
1049 EventSender::SavedEvent::SavedEvent()
1050 : type(TYPE_UNSPECIFIED),
1051 button_type(WebMouseEvent::ButtonNone),
1055 EventSender::EventSender(TestInterfaces* interfaces)
1056 : interfaces_(interfaces),
1059 force_layout_on_events_(false),
1060 is_drag_mode_(true),
1061 touch_modifiers_(0),
1062 touch_cancelable_(true),
1063 replaying_saved_events_(false),
1064 current_drag_effects_allowed_(blink::WebDragOperationNone),
1065 last_click_time_sec_(0),
1066 current_drag_effect_(blink::WebDragOperationNone),
1074 wm_sys_key_down_(0),
1077 wm_sys_dead_char_(0),
1079 weak_factory_(this) {}
1081 EventSender::~EventSender() {}
1083 void EventSender::Reset() {
1084 DCHECK(current_drag_data_.isNull());
1085 current_drag_data_.reset();
1086 current_drag_effect_ = blink::WebDragOperationNone;
1087 current_drag_effects_allowed_ = blink::WebDragOperationNone;
1088 if (view_ && pressed_button_ != WebMouseEvent::ButtonNone)
1089 view_->mouseCaptureLost();
1090 pressed_button_ = WebMouseEvent::ButtonNone;
1091 is_drag_mode_ = true;
1092 force_layout_on_events_ = true;
1095 wm_key_down_ = WM_KEYDOWN;
1096 wm_key_up_ = WM_KEYUP;
1098 wm_dead_char_ = WM_DEADCHAR;
1099 wm_sys_key_down_ = WM_SYSKEYDOWN;
1100 wm_sys_key_up_ = WM_SYSKEYUP;
1101 wm_sys_char_ = WM_SYSCHAR;
1102 wm_sys_dead_char_ = WM_SYSDEADCHAR;
1105 last_mouse_pos_ = WebPoint(0, 0);
1106 last_click_time_sec_ = 0;
1107 last_click_pos_ = WebPoint(0, 0);
1108 last_button_type_ = WebMouseEvent::ButtonNone;
1109 touch_points_.clear();
1110 last_context_menu_data_.reset();
1111 task_list_.RevokeAll();
1112 current_gesture_location_ = WebPoint(0, 0);
1113 mouse_event_queue_.clear();
1115 time_offset_ms_ = 0;
1118 touch_modifiers_ = 0;
1119 touch_cancelable_ = true;
1120 touch_points_.clear();
1123 void EventSender::Install(WebFrame* frame) {
1124 EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1127 void EventSender::SetDelegate(WebTestDelegate* delegate) {
1128 delegate_ = delegate;
1131 void EventSender::SetWebView(WebView* view) {
1135 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1136 last_context_menu_data_.reset(new WebContextMenuData(data));
1139 void EventSender::DoDragDrop(const WebDragData& drag_data,
1140 WebDragOperationsMask mask) {
1141 WebMouseEvent event;
1142 InitMouseEvent(WebInputEvent::MouseDown,
1145 GetCurrentEventTimeSec(),
1149 WebPoint client_point(event.x, event.y);
1150 WebPoint screen_point(event.globalX, event.globalY);
1151 current_drag_data_ = drag_data;
1152 current_drag_effects_allowed_ = mask;
1153 current_drag_effect_ = view_->dragTargetDragEnter(
1154 drag_data, client_point, screen_point, current_drag_effects_allowed_, 0);
1156 // Finish processing events.
1157 ReplaySavedEvents();
1160 void EventSender::MouseDown(int button_number, int modifiers) {
1161 if (force_layout_on_events_)
1164 DCHECK_NE(-1, button_number);
1166 WebMouseEvent::Button button_type =
1167 GetButtonTypeFromButtonNumber(button_number);
1169 UpdateClickCountForButton(button_type);
1171 pressed_button_ = button_type;
1173 WebMouseEvent event;
1174 InitMouseEvent(WebInputEvent::MouseDown,
1177 GetCurrentEventTimeSec(),
1181 view_->handleInputEvent(event);
1184 void EventSender::MouseUp(int button_number, int modifiers) {
1185 if (force_layout_on_events_)
1188 DCHECK_NE(-1, button_number);
1190 WebMouseEvent::Button button_type =
1191 GetButtonTypeFromButtonNumber(button_number);
1193 if (is_drag_mode_ && !replaying_saved_events_) {
1194 SavedEvent saved_event;
1195 saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1196 saved_event.button_type = button_type;
1197 saved_event.modifiers = modifiers;
1198 mouse_event_queue_.push_back(saved_event);
1199 ReplaySavedEvents();
1201 WebMouseEvent event;
1202 InitMouseEvent(WebInputEvent::MouseUp,
1205 GetCurrentEventTimeSec(),
1213 void EventSender::KeyDown(const std::string& code_str,
1215 KeyLocationCode location) {
1216 // FIXME: I'm not exactly sure how we should convert the string to a key
1217 // event. This seems to work in the cases I tested.
1218 // FIXME: Should we also generate a KEY_UP?
1220 bool generate_char = false;
1222 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1223 // Windows uses \r for "Enter".
1226 bool needs_shift_key_modifier = false;
1228 if ("\n" == code_str) {
1229 generate_char = true;
1230 text = code = ui::VKEY_RETURN;
1231 } else if ("rightArrow" == code_str) {
1232 code = ui::VKEY_RIGHT;
1233 } else if ("downArrow" == code_str) {
1234 code = ui::VKEY_DOWN;
1235 } else if ("leftArrow" == code_str) {
1236 code = ui::VKEY_LEFT;
1237 } else if ("upArrow" == code_str) {
1239 } else if ("insert" == code_str) {
1240 code = ui::VKEY_INSERT;
1241 } else if ("delete" == code_str) {
1242 code = ui::VKEY_DELETE;
1243 } else if ("pageUp" == code_str) {
1244 code = ui::VKEY_PRIOR;
1245 } else if ("pageDown" == code_str) {
1246 code = ui::VKEY_NEXT;
1247 } else if ("home" == code_str) {
1248 code = ui::VKEY_HOME;
1249 } else if ("end" == code_str) {
1250 code = ui::VKEY_END;
1251 } else if ("printScreen" == code_str) {
1252 code = ui::VKEY_SNAPSHOT;
1253 } else if ("menu" == code_str) {
1254 code = ui::VKEY_APPS;
1255 } else if ("leftControl" == code_str) {
1256 code = ui::VKEY_LCONTROL;
1257 } else if ("rightControl" == code_str) {
1258 code = ui::VKEY_RCONTROL;
1259 } else if ("leftShift" == code_str) {
1260 code = ui::VKEY_LSHIFT;
1261 } else if ("rightShift" == code_str) {
1262 code = ui::VKEY_RSHIFT;
1263 } else if ("leftAlt" == code_str) {
1264 code = ui::VKEY_LMENU;
1265 } else if ("rightAlt" == code_str) {
1266 code = ui::VKEY_RMENU;
1267 } else if ("numLock" == code_str) {
1268 code = ui::VKEY_NUMLOCK;
1269 } else if ("backspace" == code_str) {
1270 code = ui::VKEY_BACK;
1271 } else if ("escape" == code_str) {
1272 code = ui::VKEY_ESCAPE;
1274 // Compare the input string with the function-key names defined by the
1275 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1276 // name, set its key code.
1277 for (int i = 1; i <= 24; ++i) {
1278 std::string function_key_name = base::StringPrintf("F%d", i);
1279 if (function_key_name == code_str) {
1280 code = ui::VKEY_F1 + (i - 1);
1285 WebString web_code_str =
1286 WebString::fromUTF8(code_str.data(), code_str.size());
1287 DCHECK_EQ(1u, web_code_str.length());
1288 text = code = web_code_str.at(0);
1289 needs_shift_key_modifier = NeedsShiftModifier(code);
1290 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
1292 generate_char = true;
1295 if ("(" == code_str) {
1297 needs_shift_key_modifier = true;
1301 // For one generated keyboard event, we need to generate a keyDown/keyUp
1303 // On Windows, we might also need to generate a char event to mimic the
1304 // Windows event flow; on other platforms we create a merged event and test
1305 // the event flow that that platform provides.
1306 WebKeyboardEvent event_down;
1307 event_down.type = WebInputEvent::RawKeyDown;
1308 event_down.modifiers = modifiers;
1309 event_down.windowsKeyCode = code;
1311 if (generate_char) {
1312 event_down.text[0] = text;
1313 event_down.unmodifiedText[0] = text;
1316 event_down.setKeyIdentifierFromWindowsKeyCode();
1318 if (event_down.modifiers != 0)
1319 event_down.isSystemKey = IsSystemKeyEvent(event_down);
1321 if (needs_shift_key_modifier)
1322 event_down.modifiers |= WebInputEvent::ShiftKey;
1324 // See if KeyLocation argument is given.
1325 if (location == DOMKeyLocationNumpad)
1326 event_down.modifiers |= WebInputEvent::IsKeyPad;
1328 WebKeyboardEvent event_up;
1329 event_up = event_down;
1330 event_up.type = WebInputEvent::KeyUp;
1331 // EventSender.m forces a layout here, with at least one
1332 // test (fast/forms/focus-control-to-page.html) relying on this.
1333 if (force_layout_on_events_)
1336 // In the browser, if a keyboard event corresponds to an editor command,
1337 // the command will be dispatched to the renderer just before dispatching
1338 // the keyboard event, and then it will be executed in the
1339 // RenderView::handleCurrentKeyboardEvent() method.
1340 // We just simulate the same behavior here.
1341 std::string edit_command;
1342 if (GetEditCommand(event_down, &edit_command))
1343 delegate_->SetEditCommand(edit_command, "");
1345 view_->handleInputEvent(event_down);
1347 if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1348 WebMouseEvent event;
1349 InitMouseEvent(WebInputEvent::MouseDown,
1352 GetCurrentEventTimeSec(),
1356 FinishDragAndDrop(event, blink::WebDragOperationNone);
1359 delegate_->ClearEditCommand();
1361 if (generate_char) {
1362 WebKeyboardEvent event_char = event_up;
1363 event_char.type = WebInputEvent::Char;
1364 // keyIdentifier is an empty string, unless the Enter key was pressed.
1365 // This behavior is not standard (keyIdentifier itself is not even a
1366 // standard any more), but it matches the actual behavior in Blink.
1367 if (code != ui::VKEY_RETURN)
1368 event_char.keyIdentifier[0] = '\0';
1369 view_->handleInputEvent(event_char);
1372 view_->handleInputEvent(event_up);
1375 void EventSender::EnableDOMUIEventLogging() {}
1377 void EventSender::FireKeyboardEventsToElement() {}
1379 void EventSender::ClearKillRing() {}
1381 std::vector<std::string> EventSender::ContextClick() {
1382 if (force_layout_on_events_) {
1386 UpdateClickCountForButton(WebMouseEvent::ButtonRight);
1388 // Clears last context menu data because we need to know if the context menu
1389 // be requested after following mouse events.
1390 last_context_menu_data_.reset();
1392 // Generate right mouse down and up.
1393 WebMouseEvent event;
1394 // This is a hack to work around only allowing a single pressed button since
1395 // we want to test the case where both the left and right mouse buttons are
1397 if (pressed_button_ == WebMouseEvent::ButtonNone) {
1398 pressed_button_ = WebMouseEvent::ButtonRight;
1400 InitMouseEvent(WebInputEvent::MouseDown,
1401 WebMouseEvent::ButtonRight,
1403 GetCurrentEventTimeSec(),
1407 view_->handleInputEvent(event);
1410 InitMouseEvent(WebInputEvent::MouseUp,
1411 WebMouseEvent::ButtonRight,
1413 GetCurrentEventTimeSec(),
1417 view_->handleInputEvent(event);
1419 pressed_button_= WebMouseEvent::ButtonNone;
1422 std::vector<std::string> menu_items = MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate_);
1423 last_context_menu_data_.reset();
1427 void EventSender::TextZoomIn() {
1428 view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f);
1431 void EventSender::TextZoomOut() {
1432 view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f);
1435 void EventSender::ZoomPageIn() {
1436 const std::vector<WebTestProxyBase*>& window_list =
1437 interfaces_->GetWindowList();
1439 for (size_t i = 0; i < window_list.size(); ++i) {
1440 window_list.at(i)->GetWebView()->setZoomLevel(
1441 window_list.at(i)->GetWebView()->zoomLevel() + 1);
1445 void EventSender::ZoomPageOut() {
1446 const std::vector<WebTestProxyBase*>& window_list =
1447 interfaces_->GetWindowList();
1449 for (size_t i = 0; i < window_list.size(); ++i) {
1450 window_list.at(i)->GetWebView()->setZoomLevel(
1451 window_list.at(i)->GetWebView()->zoomLevel() - 1);
1455 void EventSender::SetPageZoomFactor(double zoom_factor) {
1456 const std::vector<WebTestProxyBase*>& window_list =
1457 interfaces_->GetWindowList();
1459 for (size_t i = 0; i < window_list.size(); ++i) {
1460 window_list.at(i)->GetWebView()->setZoomLevel(
1461 ZoomFactorToZoomLevel(zoom_factor));
1465 void EventSender::SetPageScaleFactor(float scale_factor, int x, int y) {
1466 view_->setPageScaleFactorLimits(scale_factor, scale_factor);
1467 view_->setPageScaleFactor(scale_factor, WebPoint(x, y));
1470 void EventSender::ClearTouchPoints() {
1471 touch_points_.clear();
1474 void EventSender::ThrowTouchPointError() {
1475 v8::Isolate* isolate = blink::mainThreadIsolate();
1476 isolate->ThrowException(v8::Exception::TypeError(
1477 gin::StringToV8(isolate, "Invalid touch point.")));
1480 void EventSender::ReleaseTouchPoint(unsigned index) {
1481 if (index >= touch_points_.size()) {
1482 ThrowTouchPointError();
1486 WebTouchPoint* touch_point = &touch_points_[index];
1487 touch_point->state = WebTouchPoint::StateReleased;
1490 void EventSender::UpdateTouchPoint(unsigned index, float x, float y) {
1491 if (index >= touch_points_.size()) {
1492 ThrowTouchPointError();
1496 WebTouchPoint* touch_point = &touch_points_[index];
1497 touch_point->state = WebTouchPoint::StateMoved;
1498 touch_point->position = WebFloatPoint(x, y);
1499 touch_point->screenPosition = touch_point->position;
1502 void EventSender::CancelTouchPoint(unsigned index) {
1503 if (index >= touch_points_.size()) {
1504 ThrowTouchPointError();
1508 WebTouchPoint* touch_point = &touch_points_[index];
1509 touch_point->state = WebTouchPoint::StateCancelled;
1512 void EventSender::SetTouchModifier(const std::string& key_name,
1515 if (key_name == "shift")
1516 mask = WebInputEvent::ShiftKey;
1517 else if (key_name == "alt")
1518 mask = WebInputEvent::AltKey;
1519 else if (key_name == "ctrl")
1520 mask = WebInputEvent::ControlKey;
1521 else if (key_name == "meta")
1522 mask = WebInputEvent::MetaKey;
1525 touch_modifiers_ |= mask;
1527 touch_modifiers_ &= ~mask;
1530 void EventSender::SetTouchCancelable(bool cancelable) {
1531 touch_cancelable_ = cancelable;
1534 void EventSender::DumpFilenameBeingDragged() {
1536 WebVector<WebDragData::Item> items = current_drag_data_.items();
1537 for (size_t i = 0; i < items.size(); ++i) {
1538 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1539 filename = items[i].title;
1543 delegate_->PrintMessage(std::string("Filename being dragged: ") +
1544 filename.utf8().data() + "\n");
1547 void EventSender::GestureFlingCancel() {
1548 WebGestureEvent event;
1549 event.type = WebInputEvent::GestureFlingCancel;
1550 event.timeStampSeconds = GetCurrentEventTimeSec();
1552 if (force_layout_on_events_)
1555 view_->handleInputEvent(event);
1558 void EventSender::GestureFlingStart(float x,
1562 WebGestureEvent event;
1563 event.type = WebInputEvent::GestureFlingStart;
1567 event.globalX = event.x;
1568 event.globalY = event.y;
1570 event.data.flingStart.velocityX = velocity_x;
1571 event.data.flingStart.velocityY = velocity_y;
1572 event.timeStampSeconds = GetCurrentEventTimeSec();
1574 if (force_layout_on_events_)
1577 view_->handleInputEvent(event);
1580 void EventSender::GestureScrollFirstPoint(int x, int y) {
1581 current_gesture_location_ = WebPoint(x, y);
1584 void EventSender::TouchStart() {
1585 SendCurrentTouchEvent(WebInputEvent::TouchStart);
1588 void EventSender::TouchMove() {
1589 SendCurrentTouchEvent(WebInputEvent::TouchMove);
1592 void EventSender::TouchCancel() {
1593 SendCurrentTouchEvent(WebInputEvent::TouchCancel);
1596 void EventSender::TouchEnd() {
1597 SendCurrentTouchEvent(WebInputEvent::TouchEnd);
1600 void EventSender::LeapForward(int milliseconds) {
1601 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1602 !replaying_saved_events_) {
1603 SavedEvent saved_event;
1604 saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
1605 saved_event.milliseconds = milliseconds;
1606 mouse_event_queue_.push_back(saved_event);
1608 DoLeapForward(milliseconds);
1612 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
1613 current_drag_data_.initialize();
1614 WebVector<WebString> absolute_filenames(files.size());
1615 for (size_t i = 0; i < files.size(); ++i) {
1616 WebDragData::Item item;
1617 item.storageType = WebDragData::Item::StorageTypeFilename;
1618 item.filenameData = delegate_->GetAbsoluteWebStringFromUTF8Path(files[i]);
1619 current_drag_data_.addItem(item);
1620 absolute_filenames[i] = item.filenameData;
1622 current_drag_data_.setFilesystemId(
1623 delegate_->RegisterIsolatedFileSystem(absolute_filenames));
1624 current_drag_effects_allowed_ = blink::WebDragOperationCopy;
1626 // Provide a drag source.
1627 view_->dragTargetDragEnter(current_drag_data_,
1630 current_drag_effects_allowed_,
1632 // |is_drag_mode_| saves events and then replays them later. We don't
1634 is_drag_mode_ = false;
1636 // Make the rest of eventSender think a drag is in progress.
1637 pressed_button_ = WebMouseEvent::ButtonLeft;
1640 void EventSender::AddTouchPoint(gin::Arguments* args) {
1643 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1648 WebTouchPoint touch_point;
1649 touch_point.state = WebTouchPoint::StatePressed;
1650 touch_point.position = WebFloatPoint(static_cast<float>(x),
1651 static_cast<float>(y));
1652 touch_point.screenPosition = touch_point.position;
1654 if (!args->PeekNext().IsEmpty()) {
1656 if (!args->GetNext(&radius_x)) {
1661 double radius_y = radius_x;
1662 if (!args->PeekNext().IsEmpty()) {
1663 if (!args->GetNext(&radius_y)) {
1669 touch_point.radiusX = static_cast<float>(radius_x);
1670 touch_point.radiusY = static_cast<float>(radius_y);
1674 for (size_t i = 0; i < touch_points_.size(); i++) {
1675 if (touch_points_[i].id == lowest_id)
1678 touch_point.id = lowest_id;
1679 touch_points_.push_back(touch_point);
1682 void EventSender::MouseDragBegin() {
1683 WebMouseWheelEvent event;
1684 InitMouseEvent(WebInputEvent::MouseWheel,
1685 WebMouseEvent::ButtonNone,
1687 GetCurrentEventTimeSec(),
1691 event.phase = WebMouseWheelEvent::PhaseBegan;
1692 event.hasPreciseScrollingDeltas = true;
1693 view_->handleInputEvent(event);
1696 void EventSender::MouseDragEnd() {
1697 WebMouseWheelEvent event;
1698 InitMouseEvent(WebInputEvent::MouseWheel,
1699 WebMouseEvent::ButtonNone,
1701 GetCurrentEventTimeSec(),
1705 event.phase = WebMouseWheelEvent::PhaseEnded;
1706 event.hasPreciseScrollingDeltas = true;
1707 view_->handleInputEvent(event);
1710 void EventSender::GestureScrollBegin(gin::Arguments* args) {
1711 GestureEvent(WebInputEvent::GestureScrollBegin, args);
1714 void EventSender::GestureScrollEnd(gin::Arguments* args) {
1715 GestureEvent(WebInputEvent::GestureScrollEnd, args);
1718 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
1719 GestureEvent(WebInputEvent::GestureScrollUpdate, args);
1722 void EventSender::GestureScrollUpdateWithoutPropagation(gin::Arguments* args) {
1723 GestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, args);
1726 void EventSender::GestureTap(gin::Arguments* args) {
1727 GestureEvent(WebInputEvent::GestureTap, args);
1730 void EventSender::GestureTapDown(gin::Arguments* args) {
1731 GestureEvent(WebInputEvent::GestureTapDown, args);
1734 void EventSender::GestureShowPress(gin::Arguments* args) {
1735 GestureEvent(WebInputEvent::GestureShowPress, args);
1738 void EventSender::GestureTapCancel(gin::Arguments* args) {
1739 GestureEvent(WebInputEvent::GestureTapCancel, args);
1742 void EventSender::GestureLongPress(gin::Arguments* args) {
1743 GestureEvent(WebInputEvent::GestureLongPress, args);
1746 void EventSender::GestureLongTap(gin::Arguments* args) {
1747 GestureEvent(WebInputEvent::GestureLongTap, args);
1750 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
1751 GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
1754 void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) {
1755 WebMouseWheelEvent event;
1756 InitMouseWheelEvent(args, true, &event);
1757 view_->handleInputEvent(event);
1760 void EventSender::MouseMoveTo(gin::Arguments* args) {
1761 if (force_layout_on_events_)
1766 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1770 WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
1773 if (!args->PeekNext().IsEmpty())
1774 modifiers = GetKeyModifiersFromV8(args->PeekNext());
1776 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1777 !replaying_saved_events_) {
1778 SavedEvent saved_event;
1779 saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
1780 saved_event.pos = mouse_pos;
1781 saved_event.modifiers = modifiers;
1782 mouse_event_queue_.push_back(saved_event);
1784 WebMouseEvent event;
1785 InitMouseEvent(WebInputEvent::MouseMove,
1788 GetCurrentEventTimeSec(),
1796 void EventSender::TrackpadScrollBegin() {
1797 WebMouseWheelEvent event;
1798 InitMouseEvent(WebInputEvent::MouseWheel,
1799 WebMouseEvent::ButtonNone,
1801 GetCurrentEventTimeSec(),
1805 event.phase = blink::WebMouseWheelEvent::PhaseBegan;
1806 event.hasPreciseScrollingDeltas = true;
1807 view_->handleInputEvent(event);
1810 void EventSender::TrackpadScroll(gin::Arguments* args) {
1811 WebMouseWheelEvent event;
1812 InitMouseWheelEvent(args, true, &event);
1813 event.phase = blink::WebMouseWheelEvent::PhaseChanged;
1814 event.hasPreciseScrollingDeltas = true;
1815 view_->handleInputEvent(event);
1818 void EventSender::TrackpadScrollEnd() {
1819 WebMouseWheelEvent event;
1820 InitMouseEvent(WebInputEvent::MouseWheel,
1821 WebMouseEvent::ButtonNone,
1823 GetCurrentEventTimeSec(),
1827 event.phase = WebMouseWheelEvent::PhaseEnded;
1828 event.hasPreciseScrollingDeltas = true;
1829 view_->handleInputEvent(event);
1832 void EventSender::MouseScrollBy(gin::Arguments* args) {
1833 WebMouseWheelEvent event;
1834 InitMouseWheelEvent(args, false, &event);
1835 view_->handleInputEvent(event);
1838 void EventSender::MouseMomentumBegin() {
1839 WebMouseWheelEvent event;
1840 InitMouseEvent(WebInputEvent::MouseWheel,
1841 WebMouseEvent::ButtonNone,
1843 GetCurrentEventTimeSec(),
1847 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1848 event.hasPreciseScrollingDeltas = true;
1849 view_->handleInputEvent(event);
1852 void EventSender::MouseMomentumBegin2(gin::Arguments* args) {
1853 WebMouseWheelEvent event;
1854 InitMouseWheelEvent(args, true, &event);
1855 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1856 event.hasPreciseScrollingDeltas = true;
1857 view_->handleInputEvent(event);
1860 void EventSender::MouseMomentumScrollBy(gin::Arguments* args) {
1861 WebMouseWheelEvent event;
1862 InitMouseWheelEvent(args, true, &event);
1863 event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1864 event.hasPreciseScrollingDeltas = true;
1865 view_->handleInputEvent(event);
1868 void EventSender::MouseMomentumEnd() {
1869 WebMouseWheelEvent event;
1870 InitMouseEvent(WebInputEvent::MouseWheel,
1871 WebMouseEvent::ButtonNone,
1873 GetCurrentEventTimeSec(),
1877 event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1878 event.hasPreciseScrollingDeltas = true;
1879 view_->handleInputEvent(event);
1882 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
1883 delegate_->PostTask(new MouseDownTask(this, button_number, modifiers));
1884 delegate_->PostTask(new MouseUpTask(this, button_number, modifiers));
1887 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
1889 KeyLocationCode location) {
1890 delegate_->PostTask(new KeyDownTask(this, code_str, modifiers, location));
1893 double EventSender::GetCurrentEventTimeSec() {
1894 return (delegate_->GetCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0;
1897 void EventSender::DoLeapForward(int milliseconds) {
1898 time_offset_ms_ += milliseconds;
1901 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type) {
1902 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap),
1903 touch_points_.size());
1904 if (force_layout_on_events_)
1907 WebTouchEvent touch_event;
1908 touch_event.type = type;
1909 touch_event.modifiers = touch_modifiers_;
1910 touch_event.cancelable = touch_cancelable_;
1911 touch_event.timeStampSeconds = GetCurrentEventTimeSec();
1912 touch_event.touchesLength = touch_points_.size();
1913 for (size_t i = 0; i < touch_points_.size(); ++i)
1914 touch_event.touches[i] = touch_points_[i];
1915 view_->handleInputEvent(touch_event);
1917 for (size_t i = 0; i < touch_points_.size(); ++i) {
1918 WebTouchPoint* touch_point = &touch_points_[i];
1919 if (touch_point->state == WebTouchPoint::StateReleased) {
1920 touch_points_.erase(touch_points_.begin() + i);
1923 touch_point->state = WebTouchPoint::StateStationary;
1927 void EventSender::GestureEvent(WebInputEvent::Type type,
1928 gin::Arguments* args) {
1931 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1936 WebGestureEvent event;
1940 case WebInputEvent::GestureScrollUpdate:
1941 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
1942 event.data.scrollUpdate.deltaX = static_cast<float>(x);
1943 event.data.scrollUpdate.deltaY = static_cast<float>(y);
1944 event.x = current_gesture_location_.x;
1945 event.y = current_gesture_location_.y;
1946 current_gesture_location_.x =
1947 current_gesture_location_.x + event.data.scrollUpdate.deltaX;
1948 current_gesture_location_.y =
1949 current_gesture_location_.y + event.data.scrollUpdate.deltaY;
1951 case WebInputEvent::GestureScrollBegin:
1952 current_gesture_location_ = WebPoint(x, y);
1953 event.x = current_gesture_location_.x;
1954 event.y = current_gesture_location_.y;
1956 case WebInputEvent::GestureScrollEnd:
1957 case WebInputEvent::GestureFlingStart:
1958 event.x = current_gesture_location_.x;
1959 event.y = current_gesture_location_.y;
1961 case WebInputEvent::GestureTap:
1963 float tap_count = 1;
1966 if (!args->PeekNext().IsEmpty()) {
1967 if (!args->GetNext(&tap_count)) {
1972 if (!args->PeekNext().IsEmpty()) {
1973 if (!args->GetNext(&width)) {
1978 if (!args->PeekNext().IsEmpty()) {
1979 if (!args->GetNext(&height)) {
1984 event.data.tap.tapCount = tap_count;
1985 event.data.tap.width = width;
1986 event.data.tap.height = height;
1991 case WebInputEvent::GestureTapUnconfirmed:
1992 if (!args->PeekNext().IsEmpty()) {
1994 if (!args->GetNext(&tap_count)) {
1998 event.data.tap.tapCount = tap_count;
2000 event.data.tap.tapCount = 1;
2005 case WebInputEvent::GestureTapDown:
2009 if (!args->PeekNext().IsEmpty()) {
2010 if (!args->GetNext(&width)) {
2015 if (!args->PeekNext().IsEmpty()) {
2016 if (!args->GetNext(&height)) {
2023 event.data.tapDown.width = width;
2024 event.data.tapDown.height = height;
2027 case WebInputEvent::GestureShowPress:
2031 if (!args->PeekNext().IsEmpty()) {
2032 if (!args->GetNext(&width)) {
2036 if (!args->PeekNext().IsEmpty()) {
2037 if (!args->GetNext(&height)) {
2045 event.data.showPress.width = width;
2046 event.data.showPress.height = height;
2049 case WebInputEvent::GestureTapCancel:
2053 case WebInputEvent::GestureLongPress:
2056 if (!args->PeekNext().IsEmpty()) {
2058 if (!args->GetNext(&width)) {
2062 event.data.longPress.width = width;
2063 if (!args->PeekNext().IsEmpty()) {
2065 if (!args->GetNext(&height)) {
2069 event.data.longPress.height = height;
2073 case WebInputEvent::GestureLongTap:
2076 if (!args->PeekNext().IsEmpty()) {
2078 if (!args->GetNext(&width)) {
2082 event.data.longPress.width = width;
2083 if (!args->PeekNext().IsEmpty()) {
2085 if (!args->GetNext(&height)) {
2089 event.data.longPress.height = height;
2093 case WebInputEvent::GestureTwoFingerTap:
2096 if (!args->PeekNext().IsEmpty()) {
2097 float first_finger_width;
2098 if (!args->GetNext(&first_finger_width)) {
2102 event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2103 if (!args->PeekNext().IsEmpty()) {
2104 float first_finger_height;
2105 if (!args->GetNext(&first_finger_height)) {
2109 event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2117 event.globalX = event.x;
2118 event.globalY = event.y;
2119 event.timeStampSeconds = GetCurrentEventTimeSec();
2121 if (force_layout_on_events_)
2124 bool result = view_->handleInputEvent(event);
2126 // Long press might start a drag drop session. Complete it if so.
2127 if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2128 WebMouseEvent mouse_event;
2129 InitMouseEvent(WebInputEvent::MouseDown,
2132 GetCurrentEventTimeSec(),
2137 FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2139 args->Return(result);
2142 void EventSender::UpdateClickCountForButton(
2143 WebMouseEvent::Button button_type) {
2144 if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2145 kMultipleClickTimeSec) &&
2146 (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) &&
2147 (button_type == last_button_type_)) {
2151 last_button_type_ = button_type;
2155 void EventSender::InitMouseWheelEvent(gin::Arguments* args,
2157 WebMouseWheelEvent* event) {
2158 // Force a layout here just to make sure every position has been
2159 // determined before we send events (as well as all the other methods
2160 // that send an event do).
2161 if (force_layout_on_events_)
2165 if (!args->GetNext(&horizontal)) {
2170 if (!args->GetNext(&vertical)) {
2176 bool has_precise_scrolling_deltas = false;
2178 if (!args->PeekNext().IsEmpty()) {
2179 args->GetNext(&paged);
2180 if (!args->PeekNext().IsEmpty()) {
2181 args->GetNext(&has_precise_scrolling_deltas);
2182 if (!args->PeekNext().IsEmpty())
2183 modifiers = GetKeyModifiersFromV8(args->PeekNext());
2187 InitMouseEvent(WebInputEvent::MouseWheel,
2190 GetCurrentEventTimeSec(),
2194 event->wheelTicksX = static_cast<float>(horizontal);
2195 event->wheelTicksY = static_cast<float>(vertical);
2196 event->deltaX = event->wheelTicksX;
2197 event->deltaY = event->wheelTicksY;
2198 event->scrollByPage = paged;
2199 event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2202 event->wheelTicksX /= kScrollbarPixelsPerTick;
2203 event->wheelTicksY /= kScrollbarPixelsPerTick;
2205 event->deltaX *= kScrollbarPixelsPerTick;
2206 event->deltaY *= kScrollbarPixelsPerTick;
2210 void EventSender::FinishDragAndDrop(const WebMouseEvent& e,
2211 blink::WebDragOperation drag_effect) {
2212 WebPoint client_point(e.x, e.y);
2213 WebPoint screen_point(e.globalX, e.globalY);
2214 current_drag_effect_ = drag_effect;
2215 if (current_drag_effect_) {
2216 // Specifically pass any keyboard modifiers to the drop method. This allows
2217 // tests to control the drop type (i.e. copy or move).
2218 view_->dragTargetDrop(client_point, screen_point, e.modifiers);
2220 view_->dragTargetDragLeave();
2222 view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_);
2223 view_->dragSourceSystemDragEnded();
2225 current_drag_data_.reset();
2228 void EventSender::DoMouseUp(const WebMouseEvent& e) {
2229 view_->handleInputEvent(e);
2231 pressed_button_ = WebMouseEvent::ButtonNone;
2232 last_click_time_sec_ = e.timeStampSeconds;
2233 last_click_pos_ = last_mouse_pos_;
2235 // If we're in a drag operation, complete it.
2236 if (current_drag_data_.isNull())
2239 WebPoint client_point(e.x, e.y);
2240 WebPoint screen_point(e.globalX, e.globalY);
2243 view_->dragTargetDragOver(
2244 client_point, screen_point, current_drag_effects_allowed_, 0));
2247 void EventSender::DoMouseMove(const WebMouseEvent& e) {
2248 last_mouse_pos_ = WebPoint(e.x, e.y);
2250 view_->handleInputEvent(e);
2252 if (pressed_button_ == WebMouseEvent::ButtonNone ||
2253 current_drag_data_.isNull()) {
2257 WebPoint client_point(e.x, e.y);
2258 WebPoint screen_point(e.globalX, e.globalY);
2259 current_drag_effect_ = view_->dragTargetDragOver(
2260 client_point, screen_point, current_drag_effects_allowed_, 0);
2263 void EventSender::ReplaySavedEvents() {
2264 replaying_saved_events_ = true;
2265 while (!mouse_event_queue_.empty()) {
2266 SavedEvent e = mouse_event_queue_.front();
2267 mouse_event_queue_.pop_front();
2270 case SavedEvent::TYPE_MOUSE_MOVE: {
2271 WebMouseEvent event;
2272 InitMouseEvent(WebInputEvent::MouseMove,
2275 GetCurrentEventTimeSec(),
2282 case SavedEvent::TYPE_LEAP_FORWARD:
2283 DoLeapForward(e.milliseconds);
2285 case SavedEvent::TYPE_MOUSE_UP: {
2286 WebMouseEvent event;
2287 InitMouseEvent(WebInputEvent::MouseUp,
2290 GetCurrentEventTimeSec(),
2302 replaying_saved_events_ = false;
2305 } // namespace content