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/WebTestDelegate.h"
12 #include "content/shell/renderer/test_runner/mock_spell_check.h"
13 #include "content/shell/renderer/test_runner/test_interfaces.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[] = " >";
128 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
129 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
130 kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
133 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
134 const std::string& prefix, std::vector<std::string>* strings) {
135 for (size_t i = 0; i < customItems.size(); ++i) {
136 if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
137 strings->push_back(prefix + customItems[i].label.utf8() +
139 PopulateCustomItems(customItems[i].subMenuItems, prefix +
140 kSubMenuDepthIdentifier, strings);
142 strings->push_back(prefix + customItems[i].label.utf8());
147 // Because actual context menu is implemented by the browser side,
148 // this function does only what LayoutTests are expecting:
149 // - Many test checks the count of items. So returning non-zero value makes
151 // - Some test compares the count before and after some action. So changing the
152 // count based on flags also makes sense. This function is doing such for some
154 // - Some test even checks actual string content. So providing it would be also
156 std::vector<std::string> MakeMenuItemStringsFor(
157 WebContextMenuData* context_menu,
158 WebTestDelegate* delegate) {
159 // These constants are based on Safari's context menu because tests are made
161 static const char* kNonEditableMenuStrings[] = {
172 static const char* kEditableMenuStrings[] = {
177 "Spelling and Grammar",
178 "Substitutions, Transformations",
181 "Paragraph Direction",
186 // This is possible because mouse events are cancelleable.
188 return std::vector<std::string>();
190 std::vector<std::string> strings;
192 // Populate custom menu items if provided by blink.
193 PopulateCustomItems(context_menu->customItems, "", &strings);
195 if (context_menu->isEditable) {
196 for (const char** item = kEditableMenuStrings; *item; ++item) {
197 strings.push_back(*item);
199 WebVector<WebString> suggestions;
200 MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
202 for (size_t i = 0; i < suggestions.size(); ++i) {
203 strings.push_back(suggestions[i].utf8());
206 for (const char** item = kNonEditableMenuStrings; *item; ++item) {
207 strings.push_back(*item);
214 // How much we should scroll per event - the value here is chosen to match the
215 // WebKit impl and layout test results.
216 const float kScrollbarPixelsPerTick = 40.0f;
218 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
220 return WebMouseEvent::ButtonLeft;
221 if (button_code == 2)
222 return WebMouseEvent::ButtonRight;
223 return WebMouseEvent::ButtonMiddle;
226 class MouseDownTask : public WebMethodTask<EventSender> {
228 MouseDownTask(EventSender* obj, int button_number, int modifiers)
229 : WebMethodTask<EventSender>(obj),
230 button_number_(button_number),
231 modifiers_(modifiers) {}
233 virtual void runIfValid() OVERRIDE {
234 m_object->MouseDown(button_number_, modifiers_);
242 class MouseUpTask : public WebMethodTask<EventSender> {
244 MouseUpTask(EventSender* obj, int button_number, int modifiers)
245 : WebMethodTask<EventSender>(obj),
246 button_number_(button_number),
247 modifiers_(modifiers) {}
249 virtual void runIfValid() OVERRIDE {
250 m_object->MouseUp(button_number_, modifiers_);
258 class KeyDownTask : public WebMethodTask<EventSender> {
260 KeyDownTask(EventSender* obj,
261 const std::string code_str,
263 KeyLocationCode location)
264 : WebMethodTask<EventSender>(obj),
266 modifiers_(modifiers),
267 location_(location) {}
269 virtual void runIfValid() OVERRIDE {
270 m_object->KeyDown(code_str_, modifiers_, location_);
274 std::string code_str_;
276 KeyLocationCode location_;
279 bool NeedsShiftModifier(int keyCode) {
280 // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
281 return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
284 // Get the edit command corresponding to a keyboard event.
285 // Returns true if the specified event corresponds to an edit command, the name
286 // of the edit command will be stored in |*name|.
287 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
288 #if defined(OS_MACOSX)
289 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
290 // modifiers. These key events correspond to some special movement and
291 // selection editor commands. These keys will be marked as system key, which
292 // prevents them from being handled. Thus they must be handled specially.
293 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
294 WebKeyboardEvent::MetaKey)
297 switch (event.windowsKeyCode) {
299 *name = "MoveToBeginningOfLine";
302 *name = "MoveToEndOfLine";
305 *name = "MoveToBeginningOfDocument";
308 *name = "MoveToEndOfDocument";
314 if (event.modifiers & WebKeyboardEvent::ShiftKey)
315 name->append("AndModifySelection");
323 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
324 #if defined(OS_MACOSX)
325 return event.modifiers & WebInputEvent::MetaKey &&
326 event.windowsKeyCode != ui::VKEY_B &&
327 event.windowsKeyCode != ui::VKEY_I;
329 return !!(event.modifiers & WebInputEvent::AltKey);
335 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
337 static gin::WrapperInfo kWrapperInfo;
339 static void Install(base::WeakPtr<EventSender> sender,
340 blink::WebFrame* frame);
343 explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
344 virtual ~EventSenderBindings();
347 virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
348 v8::Isolate* isolate) OVERRIDE;
351 void EnableDOMUIEventLogging();
352 void FireKeyboardEventsToElement();
353 void ClearKillRing();
354 std::vector<std::string> ContextClick();
359 void SetPageZoomFactor(double factor);
360 void SetPageScaleFactor(gin::Arguments* args);
361 void ClearTouchPoints();
362 void ReleaseTouchPoint(unsigned index);
363 void UpdateTouchPoint(unsigned index, double x, double y);
364 void CancelTouchPoint(unsigned index);
365 void SetTouchModifier(const std::string& key_name, bool set_mask);
366 void SetTouchCancelable(bool cancelable);
367 void DumpFilenameBeingDragged();
368 void GestureFlingCancel();
369 void GestureFlingStart(float x, float y, float velocity_x, float velocity_y);
370 void GestureScrollFirstPoint(int x, int y);
375 void LeapForward(int milliseconds);
376 void BeginDragWithFiles(const std::vector<std::string>& files);
377 void AddTouchPoint(gin::Arguments* args);
378 void MouseDragBegin();
380 void GestureScrollBegin(gin::Arguments* args);
381 void GestureScrollEnd(gin::Arguments* args);
382 void GestureScrollUpdate(gin::Arguments* args);
383 void GestureScrollUpdateWithoutPropagation(gin::Arguments* args);
384 void GestureTap(gin::Arguments* args);
385 void GestureTapDown(gin::Arguments* args);
386 void GestureShowPress(gin::Arguments* args);
387 void GestureTapCancel(gin::Arguments* args);
388 void GestureLongPress(gin::Arguments* args);
389 void GestureLongTap(gin::Arguments* args);
390 void GestureTwoFingerTap(gin::Arguments* args);
391 void ContinuousMouseScrollBy(gin::Arguments* args);
392 void MouseMoveTo(gin::Arguments* args);
393 void TrackpadScrollBegin();
394 void TrackpadScroll(gin::Arguments* args);
395 void TrackpadScrollEnd();
396 void MouseScrollBy(gin::Arguments* args);
397 // TODO(erikchen): Remove MouseMomentumBegin once CL 282743002 has landed.
398 void MouseMomentumBegin();
399 void MouseMomentumBegin2(gin::Arguments* args);
400 void MouseMomentumScrollBy(gin::Arguments* args);
401 void MouseMomentumEnd();
402 void ScheduleAsynchronousClick(gin::Arguments* args);
403 void ScheduleAsynchronousKeyDown(gin::Arguments* args);
404 void MouseDown(gin::Arguments* args);
405 void MouseUp(gin::Arguments* args);
406 void KeyDown(gin::Arguments* args);
408 // Binding properties:
409 bool ForceLayoutOnEvents() const;
410 void SetForceLayoutOnEvents(bool force);
411 bool IsDragMode() const;
412 void SetIsDragMode(bool drag_mode);
415 int WmKeyDown() const;
416 void SetWmKeyDown(int key_down);
419 void SetWmKeyUp(int key_up);
422 void SetWmChar(int wm_char);
424 int WmDeadChar() const;
425 void SetWmDeadChar(int dead_char);
427 int WmSysKeyDown() const;
428 void SetWmSysKeyDown(int key_down);
430 int WmSysKeyUp() const;
431 void SetWmSysKeyUp(int key_up);
433 int WmSysChar() const;
434 void SetWmSysChar(int sys_char);
436 int WmSysDeadChar() const;
437 void SetWmSysDeadChar(int sys_dead_char);
440 base::WeakPtr<EventSender> sender_;
442 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
445 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
447 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
451 EventSenderBindings::~EventSenderBindings() {}
454 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
456 v8::Isolate* isolate = blink::mainThreadIsolate();
457 v8::HandleScope handle_scope(isolate);
458 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
459 if (context.IsEmpty())
462 v8::Context::Scope context_scope(context);
464 gin::Handle<EventSenderBindings> bindings =
465 gin::CreateHandle(isolate, new EventSenderBindings(sender));
466 if (bindings.IsEmpty())
468 v8::Handle<v8::Object> global = context->Global();
469 global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
472 gin::ObjectTemplateBuilder
473 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
474 return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
475 .SetMethod("enableDOMUIEventLogging",
476 &EventSenderBindings::EnableDOMUIEventLogging)
477 .SetMethod("fireKeyboardEventsToElement",
478 &EventSenderBindings::FireKeyboardEventsToElement)
479 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
480 .SetMethod("contextClick", &EventSenderBindings::ContextClick)
481 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
482 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
483 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
484 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
485 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
486 .SetMethod("setPageScaleFactor", &EventSenderBindings::SetPageScaleFactor)
487 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
488 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
489 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
490 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
491 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
492 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
493 .SetMethod("dumpFilenameBeingDragged",
494 &EventSenderBindings::DumpFilenameBeingDragged)
495 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
496 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
497 .SetMethod("gestureScrollFirstPoint",
498 &EventSenderBindings::GestureScrollFirstPoint)
499 .SetMethod("touchStart", &EventSenderBindings::TouchStart)
500 .SetMethod("touchMove", &EventSenderBindings::TouchMove)
501 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
502 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
503 .SetMethod("leapForward", &EventSenderBindings::LeapForward)
504 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
505 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
506 .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin)
507 .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd)
508 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
509 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
510 .SetMethod("gestureScrollUpdate",
511 &EventSenderBindings::GestureScrollUpdate)
512 .SetMethod("gestureScrollUpdateWithoutPropagation",
513 &EventSenderBindings::GestureScrollUpdateWithoutPropagation)
514 .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
515 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
516 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
517 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
518 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
519 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
520 .SetMethod("gestureTwoFingerTap",
521 &EventSenderBindings::GestureTwoFingerTap)
522 .SetMethod("continuousMouseScrollBy",
523 &EventSenderBindings::ContinuousMouseScrollBy)
524 .SetMethod("keyDown", &EventSenderBindings::KeyDown)
525 .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
526 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
527 .SetMethod("trackpadScrollBegin",
528 &EventSenderBindings::TrackpadScrollBegin)
529 .SetMethod("trackpadScroll", &EventSenderBindings::TrackpadScroll)
530 .SetMethod("trackpadScrollEnd", &EventSenderBindings::TrackpadScrollEnd)
531 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
532 .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
533 .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin)
534 .SetMethod("mouseMomentumBegin2",
535 &EventSenderBindings::MouseMomentumBegin2)
536 .SetMethod("mouseMomentumScrollBy",
537 &EventSenderBindings::MouseMomentumScrollBy)
538 .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd)
539 .SetMethod("scheduleAsynchronousClick",
540 &EventSenderBindings::ScheduleAsynchronousClick)
541 .SetMethod("scheduleAsynchronousKeyDown",
542 &EventSenderBindings::ScheduleAsynchronousKeyDown)
543 .SetProperty("forceLayoutOnEvents",
544 &EventSenderBindings::ForceLayoutOnEvents,
545 &EventSenderBindings::SetForceLayoutOnEvents)
546 .SetProperty("dragMode",
547 &EventSenderBindings::IsDragMode,
548 &EventSenderBindings::SetIsDragMode)
550 .SetProperty("WM_KEYDOWN",
551 &EventSenderBindings::WmKeyDown,
552 &EventSenderBindings::SetWmKeyDown)
553 .SetProperty("WM_KEYUP",
554 &EventSenderBindings::WmKeyUp,
555 &EventSenderBindings::SetWmKeyUp)
556 .SetProperty("WM_CHAR",
557 &EventSenderBindings::WmChar,
558 &EventSenderBindings::SetWmChar)
559 .SetProperty("WM_DEADCHAR",
560 &EventSenderBindings::WmDeadChar,
561 &EventSenderBindings::SetWmDeadChar)
562 .SetProperty("WM_SYSKEYDOWN",
563 &EventSenderBindings::WmSysKeyDown,
564 &EventSenderBindings::SetWmSysKeyDown)
565 .SetProperty("WM_SYSKEYUP",
566 &EventSenderBindings::WmSysKeyUp,
567 &EventSenderBindings::SetWmSysKeyUp)
568 .SetProperty("WM_SYSCHAR",
569 &EventSenderBindings::WmSysChar,
570 &EventSenderBindings::SetWmSysChar)
571 .SetProperty("WM_SYSDEADCHAR",
572 &EventSenderBindings::WmSysDeadChar,
573 &EventSenderBindings::SetWmSysDeadChar);
579 void EventSenderBindings::EnableDOMUIEventLogging() {
581 sender_->EnableDOMUIEventLogging();
584 void EventSenderBindings::FireKeyboardEventsToElement() {
586 sender_->FireKeyboardEventsToElement();
589 void EventSenderBindings::ClearKillRing() {
591 sender_->ClearKillRing();
594 std::vector<std::string> EventSenderBindings::ContextClick() {
596 return sender_->ContextClick();
597 return std::vector<std::string>();
600 void EventSenderBindings::TextZoomIn() {
602 sender_->TextZoomIn();
605 void EventSenderBindings::TextZoomOut() {
607 sender_->TextZoomOut();
610 void EventSenderBindings::ZoomPageIn() {
612 sender_->ZoomPageIn();
615 void EventSenderBindings::ZoomPageOut() {
617 sender_->ZoomPageOut();
620 void EventSenderBindings::SetPageZoomFactor(double factor) {
622 sender_->SetPageZoomFactor(factor);
625 void EventSenderBindings::SetPageScaleFactor(gin::Arguments* args) {
631 if (args->PeekNext().IsEmpty())
633 args->GetNext(&scale_factor);
634 if (args->PeekNext().IsEmpty())
637 if (args->PeekNext().IsEmpty())
640 sender_->SetPageScaleFactor(scale_factor,
641 static_cast<int>(x), static_cast<int>(y));
644 void EventSenderBindings::ClearTouchPoints() {
646 sender_->ClearTouchPoints();
649 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
651 sender_->ReleaseTouchPoint(index);
654 void EventSenderBindings::UpdateTouchPoint(unsigned index, double x, double y) {
656 sender_->UpdateTouchPoint(index, static_cast<float>(x), static_cast<float>(y));
659 void EventSenderBindings::CancelTouchPoint(unsigned index) {
661 sender_->CancelTouchPoint(index);
664 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
667 sender_->SetTouchModifier(key_name, set_mask);
670 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
672 sender_->SetTouchCancelable(cancelable);
675 void EventSenderBindings::DumpFilenameBeingDragged() {
677 sender_->DumpFilenameBeingDragged();
680 void EventSenderBindings::GestureFlingCancel() {
682 sender_->GestureFlingCancel();
685 void EventSenderBindings::GestureFlingStart(float x,
690 sender_->GestureFlingStart(x, y, velocity_x, velocity_y);
693 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
695 sender_->GestureScrollFirstPoint(x, y);
698 void EventSenderBindings::TouchStart() {
700 sender_->TouchStart();
703 void EventSenderBindings::TouchMove() {
705 sender_->TouchMove();
708 void EventSenderBindings::TouchCancel() {
710 sender_->TouchCancel();
713 void EventSenderBindings::TouchEnd() {
718 void EventSenderBindings::LeapForward(int milliseconds) {
720 sender_->LeapForward(milliseconds);
723 void EventSenderBindings::BeginDragWithFiles(
724 const std::vector<std::string>& files) {
726 sender_->BeginDragWithFiles(files);
729 void EventSenderBindings::AddTouchPoint(gin::Arguments* args) {
731 sender_->AddTouchPoint(args);
734 void EventSenderBindings::MouseDragBegin() {
736 sender_->MouseDragBegin();
739 void EventSenderBindings::MouseDragEnd() {
741 sender_->MouseDragEnd();
744 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
746 sender_->GestureScrollBegin(args);
749 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
751 sender_->GestureScrollEnd(args);
754 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
756 sender_->GestureScrollUpdate(args);
759 void EventSenderBindings::GestureScrollUpdateWithoutPropagation(
760 gin::Arguments* args) {
762 sender_->GestureScrollUpdateWithoutPropagation(args);
765 void EventSenderBindings::GestureTap(gin::Arguments* args) {
767 sender_->GestureTap(args);
770 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
772 sender_->GestureTapDown(args);
775 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
777 sender_->GestureShowPress(args);
780 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
782 sender_->GestureTapCancel(args);
785 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
787 sender_->GestureLongPress(args);
790 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
792 sender_->GestureLongTap(args);
795 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
797 sender_->GestureTwoFingerTap(args);
800 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
802 sender_->ContinuousMouseScrollBy(args);
805 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
807 sender_->MouseMoveTo(args);
810 void EventSenderBindings::TrackpadScrollBegin() {
812 sender_->TrackpadScrollBegin();
815 void EventSenderBindings::TrackpadScroll(gin::Arguments* args) {
817 sender_->TrackpadScroll(args);
820 void EventSenderBindings::TrackpadScrollEnd() {
822 sender_->TrackpadScrollEnd();
825 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
827 sender_->MouseScrollBy(args);
830 void EventSenderBindings::MouseMomentumBegin() {
832 sender_->MouseMomentumBegin();
835 void EventSenderBindings::MouseMomentumBegin2(gin::Arguments* args) {
837 sender_->MouseMomentumBegin2(args);
840 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) {
842 sender_->MouseMomentumScrollBy(args);
845 void EventSenderBindings::MouseMomentumEnd() {
847 sender_->MouseMomentumEnd();
850 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
854 int button_number = 0;
856 if (!args->PeekNext().IsEmpty()) {
857 args->GetNext(&button_number);
858 if (!args->PeekNext().IsEmpty())
859 modifiers = GetKeyModifiersFromV8(args->PeekNext());
861 sender_->ScheduleAsynchronousClick(button_number, modifiers);
864 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
868 std::string code_str;
870 int location = DOMKeyLocationStandard;
871 args->GetNext(&code_str);
872 if (!args->PeekNext().IsEmpty()) {
873 v8::Handle<v8::Value> value;
874 args->GetNext(&value);
875 modifiers = GetKeyModifiersFromV8(value);
876 if (!args->PeekNext().IsEmpty())
877 args->GetNext(&location);
879 sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
880 static_cast<KeyLocationCode>(location));
883 void EventSenderBindings::MouseDown(gin::Arguments* args) {
887 int button_number = 0;
889 if (!args->PeekNext().IsEmpty()) {
890 args->GetNext(&button_number);
891 if (!args->PeekNext().IsEmpty())
892 modifiers = GetKeyModifiersFromV8(args->PeekNext());
894 sender_->MouseDown(button_number, modifiers);
897 void EventSenderBindings::MouseUp(gin::Arguments* args) {
901 int button_number = 0;
903 if (!args->PeekNext().IsEmpty()) {
904 args->GetNext(&button_number);
905 if (!args->PeekNext().IsEmpty())
906 modifiers = GetKeyModifiersFromV8(args->PeekNext());
908 sender_->MouseUp(button_number, modifiers);
911 void EventSenderBindings::KeyDown(gin::Arguments* args) {
915 std::string code_str;
917 int location = DOMKeyLocationStandard;
918 args->GetNext(&code_str);
919 if (!args->PeekNext().IsEmpty()) {
920 v8::Handle<v8::Value> value;
921 args->GetNext(&value);
922 modifiers = GetKeyModifiersFromV8(value);
923 if (!args->PeekNext().IsEmpty())
924 args->GetNext(&location);
926 sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
929 bool EventSenderBindings::ForceLayoutOnEvents() const {
931 return sender_->force_layout_on_events();
935 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
937 sender_->set_force_layout_on_events(force);
940 bool EventSenderBindings::IsDragMode() const {
942 return sender_->is_drag_mode();
946 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
948 sender_->set_is_drag_mode(drag_mode);
952 int EventSenderBindings::WmKeyDown() const {
954 return sender_->wm_key_down();
958 void EventSenderBindings::SetWmKeyDown(int key_down) {
960 sender_->set_wm_key_down(key_down);
963 int EventSenderBindings::WmKeyUp() const {
965 return sender_->wm_key_up();
969 void EventSenderBindings::SetWmKeyUp(int key_up) {
971 sender_->set_wm_key_up(key_up);
974 int EventSenderBindings::WmChar() const {
976 return sender_->wm_char();
980 void EventSenderBindings::SetWmChar(int wm_char) {
982 sender_->set_wm_char(wm_char);
985 int EventSenderBindings::WmDeadChar() const {
987 return sender_->wm_dead_char();
991 void EventSenderBindings::SetWmDeadChar(int dead_char) {
993 sender_->set_wm_dead_char(dead_char);
996 int EventSenderBindings::WmSysKeyDown() const {
998 return sender_->wm_sys_key_down();
1002 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1004 sender_->set_wm_sys_key_down(key_down);
1007 int EventSenderBindings::WmSysKeyUp() const {
1009 return sender_->wm_sys_key_up();
1013 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1015 sender_->set_wm_sys_key_up(key_up);
1018 int EventSenderBindings::WmSysChar() const {
1020 return sender_->wm_sys_char();
1024 void EventSenderBindings::SetWmSysChar(int sys_char) {
1026 sender_->set_wm_sys_char(sys_char);
1029 int EventSenderBindings::WmSysDeadChar() const {
1031 return sender_->wm_sys_dead_char();
1035 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1037 sender_->set_wm_sys_dead_char(sys_dead_char);
1041 // EventSender -----------------------------------------------------------------
1043 WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone;
1045 WebPoint EventSender::last_mouse_pos_;
1047 WebMouseEvent::Button EventSender::last_button_type_ =
1048 WebMouseEvent::ButtonNone;
1050 EventSender::SavedEvent::SavedEvent()
1051 : type(TYPE_UNSPECIFIED),
1052 button_type(WebMouseEvent::ButtonNone),
1056 EventSender::EventSender(TestInterfaces* interfaces)
1057 : interfaces_(interfaces),
1060 force_layout_on_events_(false),
1061 is_drag_mode_(true),
1062 touch_modifiers_(0),
1063 touch_cancelable_(true),
1064 replaying_saved_events_(false),
1065 current_drag_effects_allowed_(blink::WebDragOperationNone),
1066 last_click_time_sec_(0),
1067 current_drag_effect_(blink::WebDragOperationNone),
1075 wm_sys_key_down_(0),
1078 wm_sys_dead_char_(0),
1080 weak_factory_(this) {}
1082 EventSender::~EventSender() {}
1084 void EventSender::Reset() {
1085 DCHECK(current_drag_data_.isNull());
1086 current_drag_data_.reset();
1087 current_drag_effect_ = blink::WebDragOperationNone;
1088 current_drag_effects_allowed_ = blink::WebDragOperationNone;
1089 if (view_ && pressed_button_ != WebMouseEvent::ButtonNone)
1090 view_->mouseCaptureLost();
1091 pressed_button_ = WebMouseEvent::ButtonNone;
1092 is_drag_mode_ = true;
1093 force_layout_on_events_ = true;
1096 wm_key_down_ = WM_KEYDOWN;
1097 wm_key_up_ = WM_KEYUP;
1099 wm_dead_char_ = WM_DEADCHAR;
1100 wm_sys_key_down_ = WM_SYSKEYDOWN;
1101 wm_sys_key_up_ = WM_SYSKEYUP;
1102 wm_sys_char_ = WM_SYSCHAR;
1103 wm_sys_dead_char_ = WM_SYSDEADCHAR;
1106 last_mouse_pos_ = WebPoint(0, 0);
1107 last_click_time_sec_ = 0;
1108 last_click_pos_ = WebPoint(0, 0);
1109 last_button_type_ = WebMouseEvent::ButtonNone;
1110 touch_points_.clear();
1111 last_context_menu_data_.reset();
1112 task_list_.revokeAll();
1113 current_gesture_location_ = WebPoint(0, 0);
1114 mouse_event_queue_.clear();
1116 time_offset_ms_ = 0;
1119 touch_modifiers_ = 0;
1120 touch_cancelable_ = true;
1121 touch_points_.clear();
1124 void EventSender::Install(WebFrame* frame) {
1125 EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1128 void EventSender::SetDelegate(WebTestDelegate* delegate) {
1129 delegate_ = delegate;
1132 void EventSender::SetWebView(WebView* view) {
1136 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1137 last_context_menu_data_.reset(new WebContextMenuData(data));
1140 void EventSender::DoDragDrop(const WebDragData& drag_data,
1141 WebDragOperationsMask mask) {
1142 WebMouseEvent event;
1143 InitMouseEvent(WebInputEvent::MouseDown,
1146 GetCurrentEventTimeSec(),
1150 WebPoint client_point(event.x, event.y);
1151 WebPoint screen_point(event.globalX, event.globalY);
1152 current_drag_data_ = drag_data;
1153 current_drag_effects_allowed_ = mask;
1154 current_drag_effect_ = view_->dragTargetDragEnter(
1155 drag_data, client_point, screen_point, current_drag_effects_allowed_, 0);
1157 // Finish processing events.
1158 ReplaySavedEvents();
1161 void EventSender::MouseDown(int button_number, int modifiers) {
1162 if (force_layout_on_events_)
1165 DCHECK_NE(-1, button_number);
1167 WebMouseEvent::Button button_type =
1168 GetButtonTypeFromButtonNumber(button_number);
1170 UpdateClickCountForButton(button_type);
1172 pressed_button_ = button_type;
1174 WebMouseEvent event;
1175 InitMouseEvent(WebInputEvent::MouseDown,
1178 GetCurrentEventTimeSec(),
1182 view_->handleInputEvent(event);
1185 void EventSender::MouseUp(int button_number, int modifiers) {
1186 if (force_layout_on_events_)
1189 DCHECK_NE(-1, button_number);
1191 WebMouseEvent::Button button_type =
1192 GetButtonTypeFromButtonNumber(button_number);
1194 if (is_drag_mode_ && !replaying_saved_events_) {
1195 SavedEvent saved_event;
1196 saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1197 saved_event.button_type = button_type;
1198 saved_event.modifiers = modifiers;
1199 mouse_event_queue_.push_back(saved_event);
1200 ReplaySavedEvents();
1202 WebMouseEvent event;
1203 InitMouseEvent(WebInputEvent::MouseUp,
1206 GetCurrentEventTimeSec(),
1214 void EventSender::KeyDown(const std::string& code_str,
1216 KeyLocationCode location) {
1217 // FIXME: I'm not exactly sure how we should convert the string to a key
1218 // event. This seems to work in the cases I tested.
1219 // FIXME: Should we also generate a KEY_UP?
1221 bool generate_char = false;
1223 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1224 // Windows uses \r for "Enter".
1227 bool needs_shift_key_modifier = false;
1229 if ("\n" == code_str) {
1230 generate_char = true;
1231 text = code = ui::VKEY_RETURN;
1232 } else if ("rightArrow" == code_str) {
1233 code = ui::VKEY_RIGHT;
1234 } else if ("downArrow" == code_str) {
1235 code = ui::VKEY_DOWN;
1236 } else if ("leftArrow" == code_str) {
1237 code = ui::VKEY_LEFT;
1238 } else if ("upArrow" == code_str) {
1240 } else if ("insert" == code_str) {
1241 code = ui::VKEY_INSERT;
1242 } else if ("delete" == code_str) {
1243 code = ui::VKEY_DELETE;
1244 } else if ("pageUp" == code_str) {
1245 code = ui::VKEY_PRIOR;
1246 } else if ("pageDown" == code_str) {
1247 code = ui::VKEY_NEXT;
1248 } else if ("home" == code_str) {
1249 code = ui::VKEY_HOME;
1250 } else if ("end" == code_str) {
1251 code = ui::VKEY_END;
1252 } else if ("printScreen" == code_str) {
1253 code = ui::VKEY_SNAPSHOT;
1254 } else if ("menu" == code_str) {
1255 code = ui::VKEY_APPS;
1256 } else if ("leftControl" == code_str) {
1257 code = ui::VKEY_LCONTROL;
1258 } else if ("rightControl" == code_str) {
1259 code = ui::VKEY_RCONTROL;
1260 } else if ("leftShift" == code_str) {
1261 code = ui::VKEY_LSHIFT;
1262 } else if ("rightShift" == code_str) {
1263 code = ui::VKEY_RSHIFT;
1264 } else if ("leftAlt" == code_str) {
1265 code = ui::VKEY_LMENU;
1266 } else if ("rightAlt" == code_str) {
1267 code = ui::VKEY_RMENU;
1268 } else if ("numLock" == code_str) {
1269 code = ui::VKEY_NUMLOCK;
1271 // Compare the input string with the function-key names defined by the
1272 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1273 // name, set its key code.
1274 for (int i = 1; i <= 24; ++i) {
1275 std::string function_key_name = base::StringPrintf("F%d", i);
1276 if (function_key_name == code_str) {
1277 code = ui::VKEY_F1 + (i - 1);
1282 WebString web_code_str =
1283 WebString::fromUTF8(code_str.data(), code_str.size());
1284 DCHECK_EQ(1u, web_code_str.length());
1285 text = code = web_code_str.at(0);
1286 needs_shift_key_modifier = NeedsShiftModifier(code);
1287 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
1289 generate_char = true;
1292 if ("(" == code_str) {
1294 needs_shift_key_modifier = true;
1298 // For one generated keyboard event, we need to generate a keyDown/keyUp
1300 // On Windows, we might also need to generate a char event to mimic the
1301 // Windows event flow; on other platforms we create a merged event and test
1302 // the event flow that that platform provides.
1303 WebKeyboardEvent event_down;
1304 event_down.type = WebInputEvent::RawKeyDown;
1305 event_down.modifiers = modifiers;
1306 event_down.windowsKeyCode = code;
1308 if (generate_char) {
1309 event_down.text[0] = text;
1310 event_down.unmodifiedText[0] = text;
1313 event_down.setKeyIdentifierFromWindowsKeyCode();
1315 if (event_down.modifiers != 0)
1316 event_down.isSystemKey = IsSystemKeyEvent(event_down);
1318 if (needs_shift_key_modifier)
1319 event_down.modifiers |= WebInputEvent::ShiftKey;
1321 // See if KeyLocation argument is given.
1322 if (location == DOMKeyLocationNumpad)
1323 event_down.modifiers |= WebInputEvent::IsKeyPad;
1325 WebKeyboardEvent event_up;
1326 event_up = event_down;
1327 event_up.type = WebInputEvent::KeyUp;
1328 // EventSender.m forces a layout here, with at least one
1329 // test (fast/forms/focus-control-to-page.html) relying on this.
1330 if (force_layout_on_events_)
1333 // In the browser, if a keyboard event corresponds to an editor command,
1334 // the command will be dispatched to the renderer just before dispatching
1335 // the keyboard event, and then it will be executed in the
1336 // RenderView::handleCurrentKeyboardEvent() method.
1337 // We just simulate the same behavior here.
1338 std::string edit_command;
1339 if (GetEditCommand(event_down, &edit_command))
1340 delegate_->setEditCommand(edit_command, "");
1342 view_->handleInputEvent(event_down);
1344 if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1345 WebMouseEvent event;
1346 InitMouseEvent(WebInputEvent::MouseDown,
1349 GetCurrentEventTimeSec(),
1353 FinishDragAndDrop(event, blink::WebDragOperationNone);
1356 delegate_->clearEditCommand();
1358 if (generate_char) {
1359 WebKeyboardEvent event_char = event_up;
1360 event_char.type = WebInputEvent::Char;
1361 event_char.keyIdentifier[0] = '\0';
1362 view_->handleInputEvent(event_char);
1365 view_->handleInputEvent(event_up);
1368 void EventSender::EnableDOMUIEventLogging() {}
1370 void EventSender::FireKeyboardEventsToElement() {}
1372 void EventSender::ClearKillRing() {}
1374 std::vector<std::string> EventSender::ContextClick() {
1375 if (force_layout_on_events_) {
1379 UpdateClickCountForButton(WebMouseEvent::ButtonRight);
1381 // Clears last context menu data because we need to know if the context menu
1382 // be requested after following mouse events.
1383 last_context_menu_data_.reset();
1385 // Generate right mouse down and up.
1386 WebMouseEvent event;
1387 // This is a hack to work around only allowing a single pressed button since
1388 // we want to test the case where both the left and right mouse buttons are
1390 if (pressed_button_ == WebMouseEvent::ButtonNone) {
1391 pressed_button_ = WebMouseEvent::ButtonRight;
1393 InitMouseEvent(WebInputEvent::MouseDown,
1394 WebMouseEvent::ButtonRight,
1396 GetCurrentEventTimeSec(),
1400 view_->handleInputEvent(event);
1403 InitMouseEvent(WebInputEvent::MouseUp,
1404 WebMouseEvent::ButtonRight,
1406 GetCurrentEventTimeSec(),
1410 view_->handleInputEvent(event);
1412 pressed_button_= WebMouseEvent::ButtonNone;
1415 std::vector<std::string> menu_items = MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate_);
1416 last_context_menu_data_.reset();
1420 void EventSender::TextZoomIn() {
1421 view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f);
1424 void EventSender::TextZoomOut() {
1425 view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f);
1428 void EventSender::ZoomPageIn() {
1429 const std::vector<WebTestProxyBase*>& window_list =
1430 interfaces_->GetWindowList();
1432 for (size_t i = 0; i < window_list.size(); ++i) {
1433 window_list.at(i)->GetWebView()->setZoomLevel(
1434 window_list.at(i)->GetWebView()->zoomLevel() + 1);
1438 void EventSender::ZoomPageOut() {
1439 const std::vector<WebTestProxyBase*>& window_list =
1440 interfaces_->GetWindowList();
1442 for (size_t i = 0; i < window_list.size(); ++i) {
1443 window_list.at(i)->GetWebView()->setZoomLevel(
1444 window_list.at(i)->GetWebView()->zoomLevel() - 1);
1448 void EventSender::SetPageZoomFactor(double zoom_factor) {
1449 const std::vector<WebTestProxyBase*>& window_list =
1450 interfaces_->GetWindowList();
1452 for (size_t i = 0; i < window_list.size(); ++i) {
1453 window_list.at(i)->GetWebView()->setZoomLevel(
1454 ZoomFactorToZoomLevel(zoom_factor));
1458 void EventSender::SetPageScaleFactor(float scale_factor, int x, int y) {
1459 view_->setPageScaleFactorLimits(scale_factor, scale_factor);
1460 view_->setPageScaleFactor(scale_factor, WebPoint(x, y));
1463 void EventSender::ClearTouchPoints() {
1464 touch_points_.clear();
1467 void EventSender::ThrowTouchPointError() {
1468 v8::Isolate* isolate = blink::mainThreadIsolate();
1469 isolate->ThrowException(v8::Exception::TypeError(
1470 gin::StringToV8(isolate, "Invalid touch point.")));
1473 void EventSender::ReleaseTouchPoint(unsigned index) {
1474 if (index >= touch_points_.size()) {
1475 ThrowTouchPointError();
1479 WebTouchPoint* touch_point = &touch_points_[index];
1480 touch_point->state = WebTouchPoint::StateReleased;
1483 void EventSender::UpdateTouchPoint(unsigned index, float x, float y) {
1484 if (index >= touch_points_.size()) {
1485 ThrowTouchPointError();
1489 WebTouchPoint* touch_point = &touch_points_[index];
1490 touch_point->state = WebTouchPoint::StateMoved;
1491 touch_point->position = WebFloatPoint(x, y);
1492 touch_point->screenPosition = touch_point->position;
1495 void EventSender::CancelTouchPoint(unsigned index) {
1496 if (index >= touch_points_.size()) {
1497 ThrowTouchPointError();
1501 WebTouchPoint* touch_point = &touch_points_[index];
1502 touch_point->state = WebTouchPoint::StateCancelled;
1505 void EventSender::SetTouchModifier(const std::string& key_name,
1508 if (key_name == "shift")
1509 mask = WebInputEvent::ShiftKey;
1510 else if (key_name == "alt")
1511 mask = WebInputEvent::AltKey;
1512 else if (key_name == "ctrl")
1513 mask = WebInputEvent::ControlKey;
1514 else if (key_name == "meta")
1515 mask = WebInputEvent::MetaKey;
1518 touch_modifiers_ |= mask;
1520 touch_modifiers_ &= ~mask;
1523 void EventSender::SetTouchCancelable(bool cancelable) {
1524 touch_cancelable_ = cancelable;
1527 void EventSender::DumpFilenameBeingDragged() {
1529 WebVector<WebDragData::Item> items = current_drag_data_.items();
1530 for (size_t i = 0; i < items.size(); ++i) {
1531 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1532 filename = items[i].title;
1536 delegate_->printMessage(std::string("Filename being dragged: ") +
1537 filename.utf8().data() + "\n");
1540 void EventSender::GestureFlingCancel() {
1541 WebGestureEvent event;
1542 event.type = WebInputEvent::GestureFlingCancel;
1543 event.timeStampSeconds = GetCurrentEventTimeSec();
1545 if (force_layout_on_events_)
1548 view_->handleInputEvent(event);
1551 void EventSender::GestureFlingStart(float x,
1555 WebGestureEvent event;
1556 event.type = WebInputEvent::GestureFlingStart;
1560 event.globalX = event.x;
1561 event.globalY = event.y;
1563 event.data.flingStart.velocityX = velocity_x;
1564 event.data.flingStart.velocityY = velocity_y;
1565 event.timeStampSeconds = GetCurrentEventTimeSec();
1567 if (force_layout_on_events_)
1570 view_->handleInputEvent(event);
1573 void EventSender::GestureScrollFirstPoint(int x, int y) {
1574 current_gesture_location_ = WebPoint(x, y);
1577 void EventSender::TouchStart() {
1578 SendCurrentTouchEvent(WebInputEvent::TouchStart);
1581 void EventSender::TouchMove() {
1582 SendCurrentTouchEvent(WebInputEvent::TouchMove);
1585 void EventSender::TouchCancel() {
1586 SendCurrentTouchEvent(WebInputEvent::TouchCancel);
1589 void EventSender::TouchEnd() {
1590 SendCurrentTouchEvent(WebInputEvent::TouchEnd);
1593 void EventSender::LeapForward(int milliseconds) {
1594 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1595 !replaying_saved_events_) {
1596 SavedEvent saved_event;
1597 saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
1598 saved_event.milliseconds = milliseconds;
1599 mouse_event_queue_.push_back(saved_event);
1601 DoLeapForward(milliseconds);
1605 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
1606 current_drag_data_.initialize();
1607 WebVector<WebString> absolute_filenames(files.size());
1608 for (size_t i = 0; i < files.size(); ++i) {
1609 WebDragData::Item item;
1610 item.storageType = WebDragData::Item::StorageTypeFilename;
1611 item.filenameData = delegate_->getAbsoluteWebStringFromUTF8Path(files[i]);
1612 current_drag_data_.addItem(item);
1613 absolute_filenames[i] = item.filenameData;
1615 current_drag_data_.setFilesystemId(
1616 delegate_->registerIsolatedFileSystem(absolute_filenames));
1617 current_drag_effects_allowed_ = blink::WebDragOperationCopy;
1619 // Provide a drag source.
1620 view_->dragTargetDragEnter(current_drag_data_,
1623 current_drag_effects_allowed_,
1625 // |is_drag_mode_| saves events and then replays them later. We don't
1627 is_drag_mode_ = false;
1629 // Make the rest of eventSender think a drag is in progress.
1630 pressed_button_ = WebMouseEvent::ButtonLeft;
1633 void EventSender::AddTouchPoint(gin::Arguments* args) {
1639 WebTouchPoint touch_point;
1640 touch_point.state = WebTouchPoint::StatePressed;
1641 touch_point.position = WebFloatPoint(static_cast<float>(x),
1642 static_cast<float>(y));
1643 touch_point.screenPosition = touch_point.position;
1645 if (!args->PeekNext().IsEmpty()) {
1647 if (!args->GetNext(&radius_x)) {
1652 double radius_y = radius_x;
1653 if (!args->PeekNext().IsEmpty()) {
1654 if (!args->GetNext(&radius_y)) {
1660 touch_point.radiusX = static_cast<float>(radius_x);
1661 touch_point.radiusY = static_cast<float>(radius_y);
1665 for (size_t i = 0; i < touch_points_.size(); i++) {
1666 if (touch_points_[i].id == lowest_id)
1669 touch_point.id = lowest_id;
1670 touch_points_.push_back(touch_point);
1673 void EventSender::MouseDragBegin() {
1674 WebMouseWheelEvent event;
1675 InitMouseEvent(WebInputEvent::MouseWheel,
1676 WebMouseEvent::ButtonNone,
1678 GetCurrentEventTimeSec(),
1682 event.phase = WebMouseWheelEvent::PhaseBegan;
1683 event.hasPreciseScrollingDeltas = true;
1684 view_->handleInputEvent(event);
1687 void EventSender::MouseDragEnd() {
1688 WebMouseWheelEvent event;
1689 InitMouseEvent(WebInputEvent::MouseWheel,
1690 WebMouseEvent::ButtonNone,
1692 GetCurrentEventTimeSec(),
1696 event.phase = WebMouseWheelEvent::PhaseEnded;
1697 event.hasPreciseScrollingDeltas = true;
1698 view_->handleInputEvent(event);
1701 void EventSender::GestureScrollBegin(gin::Arguments* args) {
1702 GestureEvent(WebInputEvent::GestureScrollBegin, args);
1705 void EventSender::GestureScrollEnd(gin::Arguments* args) {
1706 GestureEvent(WebInputEvent::GestureScrollEnd, args);
1709 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
1710 GestureEvent(WebInputEvent::GestureScrollUpdate, args);
1713 void EventSender::GestureScrollUpdateWithoutPropagation(gin::Arguments* args) {
1714 GestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, args);
1717 void EventSender::GestureTap(gin::Arguments* args) {
1718 GestureEvent(WebInputEvent::GestureTap, args);
1721 void EventSender::GestureTapDown(gin::Arguments* args) {
1722 GestureEvent(WebInputEvent::GestureTapDown, args);
1725 void EventSender::GestureShowPress(gin::Arguments* args) {
1726 GestureEvent(WebInputEvent::GestureShowPress, args);
1729 void EventSender::GestureTapCancel(gin::Arguments* args) {
1730 GestureEvent(WebInputEvent::GestureTapCancel, args);
1733 void EventSender::GestureLongPress(gin::Arguments* args) {
1734 GestureEvent(WebInputEvent::GestureLongPress, args);
1737 void EventSender::GestureLongTap(gin::Arguments* args) {
1738 GestureEvent(WebInputEvent::GestureLongTap, args);
1741 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
1742 GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
1745 void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) {
1746 WebMouseWheelEvent event;
1747 InitMouseWheelEvent(args, true, &event);
1748 view_->handleInputEvent(event);
1751 void EventSender::MouseMoveTo(gin::Arguments* args) {
1752 if (force_layout_on_events_)
1759 WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
1762 if (!args->PeekNext().IsEmpty())
1763 modifiers = GetKeyModifiersFromV8(args->PeekNext());
1765 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1766 !replaying_saved_events_) {
1767 SavedEvent saved_event;
1768 saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
1769 saved_event.pos = mouse_pos;
1770 saved_event.modifiers = modifiers;
1771 mouse_event_queue_.push_back(saved_event);
1773 WebMouseEvent event;
1774 InitMouseEvent(WebInputEvent::MouseMove,
1777 GetCurrentEventTimeSec(),
1785 void EventSender::TrackpadScrollBegin() {
1786 WebMouseWheelEvent event;
1787 InitMouseEvent(WebInputEvent::MouseWheel,
1788 WebMouseEvent::ButtonNone,
1790 GetCurrentEventTimeSec(),
1794 event.phase = blink::WebMouseWheelEvent::PhaseBegan;
1795 event.hasPreciseScrollingDeltas = true;
1796 view_->handleInputEvent(event);
1799 void EventSender::TrackpadScroll(gin::Arguments* args) {
1800 WebMouseWheelEvent event;
1801 InitMouseWheelEvent(args, true, &event);
1802 event.phase = blink::WebMouseWheelEvent::PhaseChanged;
1803 event.hasPreciseScrollingDeltas = true;
1804 view_->handleInputEvent(event);
1807 void EventSender::TrackpadScrollEnd() {
1808 WebMouseWheelEvent event;
1809 InitMouseEvent(WebInputEvent::MouseWheel,
1810 WebMouseEvent::ButtonNone,
1812 GetCurrentEventTimeSec(),
1816 event.phase = WebMouseWheelEvent::PhaseEnded;
1817 event.hasPreciseScrollingDeltas = true;
1818 view_->handleInputEvent(event);
1821 void EventSender::MouseScrollBy(gin::Arguments* args) {
1822 WebMouseWheelEvent event;
1823 InitMouseWheelEvent(args, false, &event);
1824 view_->handleInputEvent(event);
1827 void EventSender::MouseMomentumBegin() {
1828 WebMouseWheelEvent event;
1829 InitMouseEvent(WebInputEvent::MouseWheel,
1830 WebMouseEvent::ButtonNone,
1832 GetCurrentEventTimeSec(),
1836 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1837 event.hasPreciseScrollingDeltas = true;
1838 view_->handleInputEvent(event);
1841 void EventSender::MouseMomentumBegin2(gin::Arguments* args) {
1842 WebMouseWheelEvent event;
1843 InitMouseWheelEvent(args, true, &event);
1844 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1845 event.hasPreciseScrollingDeltas = true;
1846 view_->handleInputEvent(event);
1849 void EventSender::MouseMomentumScrollBy(gin::Arguments* args) {
1850 WebMouseWheelEvent event;
1851 InitMouseWheelEvent(args, true, &event);
1852 event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1853 event.hasPreciseScrollingDeltas = true;
1854 view_->handleInputEvent(event);
1857 void EventSender::MouseMomentumEnd() {
1858 WebMouseWheelEvent event;
1859 InitMouseEvent(WebInputEvent::MouseWheel,
1860 WebMouseEvent::ButtonNone,
1862 GetCurrentEventTimeSec(),
1866 event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1867 event.hasPreciseScrollingDeltas = true;
1868 view_->handleInputEvent(event);
1871 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
1872 delegate_->postTask(new MouseDownTask(this, button_number, modifiers));
1873 delegate_->postTask(new MouseUpTask(this, button_number, modifiers));
1876 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
1878 KeyLocationCode location) {
1879 delegate_->postTask(new KeyDownTask(this, code_str, modifiers, location));
1882 double EventSender::GetCurrentEventTimeSec() {
1883 return (delegate_->getCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0;
1886 void EventSender::DoLeapForward(int milliseconds) {
1887 time_offset_ms_ += milliseconds;
1890 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type) {
1891 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap),
1892 touch_points_.size());
1893 if (force_layout_on_events_)
1896 WebTouchEvent touch_event;
1897 touch_event.type = type;
1898 touch_event.modifiers = touch_modifiers_;
1899 touch_event.cancelable = touch_cancelable_;
1900 touch_event.timeStampSeconds = GetCurrentEventTimeSec();
1901 touch_event.touchesLength = touch_points_.size();
1902 for (size_t i = 0; i < touch_points_.size(); ++i)
1903 touch_event.touches[i] = touch_points_[i];
1904 view_->handleInputEvent(touch_event);
1906 for (size_t i = 0; i < touch_points_.size(); ++i) {
1907 WebTouchPoint* touch_point = &touch_points_[i];
1908 if (touch_point->state == WebTouchPoint::StateReleased) {
1909 touch_points_.erase(touch_points_.begin() + i);
1912 touch_point->state = WebTouchPoint::StateStationary;
1916 void EventSender::GestureEvent(WebInputEvent::Type type,
1917 gin::Arguments* args) {
1922 WebPoint point(x, y);
1924 WebGestureEvent event;
1928 case WebInputEvent::GestureScrollUpdate:
1929 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
1930 event.data.scrollUpdate.deltaX = static_cast<float>(x);
1931 event.data.scrollUpdate.deltaY = static_cast<float>(y);
1932 event.x = current_gesture_location_.x;
1933 event.y = current_gesture_location_.y;
1934 current_gesture_location_.x =
1935 current_gesture_location_.x + event.data.scrollUpdate.deltaX;
1936 current_gesture_location_.y =
1937 current_gesture_location_.y + event.data.scrollUpdate.deltaY;
1939 case WebInputEvent::GestureScrollBegin:
1940 current_gesture_location_ = WebPoint(point.x, point.y);
1941 event.x = current_gesture_location_.x;
1942 event.y = current_gesture_location_.y;
1944 case WebInputEvent::GestureScrollEnd:
1945 case WebInputEvent::GestureFlingStart:
1946 event.x = current_gesture_location_.x;
1947 event.y = current_gesture_location_.y;
1949 case WebInputEvent::GestureTap:
1951 float tap_count = 1;
1954 if (!args->PeekNext().IsEmpty()) {
1955 if (!args->GetNext(&tap_count)) {
1960 if (!args->PeekNext().IsEmpty()) {
1961 if (!args->GetNext(&width)) {
1966 if (!args->PeekNext().IsEmpty()) {
1967 if (!args->GetNext(&height)) {
1972 event.data.tap.tapCount = tap_count;
1973 event.data.tap.width = width;
1974 event.data.tap.height = height;
1979 case WebInputEvent::GestureTapUnconfirmed:
1980 if (!args->PeekNext().IsEmpty()) {
1982 if (!args->GetNext(&tap_count)) {
1986 event.data.tap.tapCount = tap_count;
1988 event.data.tap.tapCount = 1;
1993 case WebInputEvent::GestureTapDown:
1997 if (!args->PeekNext().IsEmpty()) {
1998 if (!args->GetNext(&width)) {
2003 if (!args->PeekNext().IsEmpty()) {
2004 if (!args->GetNext(&height)) {
2011 event.data.tapDown.width = width;
2012 event.data.tapDown.height = height;
2015 case WebInputEvent::GestureShowPress:
2019 if (!args->PeekNext().IsEmpty()) {
2020 if (!args->GetNext(&width)) {
2024 if (!args->PeekNext().IsEmpty()) {
2025 if (!args->GetNext(&height)) {
2033 event.data.showPress.width = width;
2034 event.data.showPress.height = height;
2037 case WebInputEvent::GestureTapCancel:
2041 case WebInputEvent::GestureLongPress:
2044 if (!args->PeekNext().IsEmpty()) {
2046 if (!args->GetNext(&width)) {
2050 event.data.longPress.width = width;
2051 if (!args->PeekNext().IsEmpty()) {
2053 if (!args->GetNext(&height)) {
2057 event.data.longPress.height = height;
2061 case WebInputEvent::GestureLongTap:
2064 if (!args->PeekNext().IsEmpty()) {
2066 if (!args->GetNext(&width)) {
2070 event.data.longPress.width = width;
2071 if (!args->PeekNext().IsEmpty()) {
2073 if (!args->GetNext(&height)) {
2077 event.data.longPress.height = height;
2081 case WebInputEvent::GestureTwoFingerTap:
2084 if (!args->PeekNext().IsEmpty()) {
2085 float first_finger_width;
2086 if (!args->GetNext(&first_finger_width)) {
2090 event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2091 if (!args->PeekNext().IsEmpty()) {
2092 float first_finger_height;
2093 if (!args->GetNext(&first_finger_height)) {
2097 event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2105 event.globalX = event.x;
2106 event.globalY = event.y;
2107 event.timeStampSeconds = GetCurrentEventTimeSec();
2109 if (force_layout_on_events_)
2112 bool result = view_->handleInputEvent(event);
2114 // Long press might start a drag drop session. Complete it if so.
2115 if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2116 WebMouseEvent mouse_event;
2117 InitMouseEvent(WebInputEvent::MouseDown,
2120 GetCurrentEventTimeSec(),
2125 FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2127 args->Return(result);
2130 void EventSender::UpdateClickCountForButton(
2131 WebMouseEvent::Button button_type) {
2132 if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2133 kMultipleClickTimeSec) &&
2134 (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) &&
2135 (button_type == last_button_type_)) {
2139 last_button_type_ = button_type;
2143 void EventSender::InitMouseWheelEvent(gin::Arguments* args,
2145 WebMouseWheelEvent* event) {
2146 // Force a layout here just to make sure every position has been
2147 // determined before we send events (as well as all the other methods
2148 // that send an event do).
2149 if (force_layout_on_events_)
2153 if (!args->GetNext(&horizontal)) {
2158 if (!args->GetNext(&vertical)) {
2164 bool has_precise_scrolling_deltas = false;
2166 if (!args->PeekNext().IsEmpty()) {
2167 args->GetNext(&paged);
2168 if (!args->PeekNext().IsEmpty()) {
2169 args->GetNext(&has_precise_scrolling_deltas);
2170 if (!args->PeekNext().IsEmpty())
2171 modifiers = GetKeyModifiersFromV8(args->PeekNext());
2175 InitMouseEvent(WebInputEvent::MouseWheel,
2178 GetCurrentEventTimeSec(),
2182 event->wheelTicksX = static_cast<float>(horizontal);
2183 event->wheelTicksY = static_cast<float>(vertical);
2184 event->deltaX = event->wheelTicksX;
2185 event->deltaY = event->wheelTicksY;
2186 event->scrollByPage = paged;
2187 event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2190 event->wheelTicksX /= kScrollbarPixelsPerTick;
2191 event->wheelTicksY /= kScrollbarPixelsPerTick;
2193 event->deltaX *= kScrollbarPixelsPerTick;
2194 event->deltaY *= kScrollbarPixelsPerTick;
2198 void EventSender::FinishDragAndDrop(const WebMouseEvent& e,
2199 blink::WebDragOperation drag_effect) {
2200 WebPoint client_point(e.x, e.y);
2201 WebPoint screen_point(e.globalX, e.globalY);
2202 current_drag_effect_ = drag_effect;
2203 if (current_drag_effect_) {
2204 // Specifically pass any keyboard modifiers to the drop method. This allows
2205 // tests to control the drop type (i.e. copy or move).
2206 view_->dragTargetDrop(client_point, screen_point, e.modifiers);
2208 view_->dragTargetDragLeave();
2210 view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_);
2211 view_->dragSourceSystemDragEnded();
2213 current_drag_data_.reset();
2216 void EventSender::DoMouseUp(const WebMouseEvent& e) {
2217 view_->handleInputEvent(e);
2219 pressed_button_ = WebMouseEvent::ButtonNone;
2220 last_click_time_sec_ = e.timeStampSeconds;
2221 last_click_pos_ = last_mouse_pos_;
2223 // If we're in a drag operation, complete it.
2224 if (current_drag_data_.isNull())
2227 WebPoint client_point(e.x, e.y);
2228 WebPoint screen_point(e.globalX, e.globalY);
2231 view_->dragTargetDragOver(
2232 client_point, screen_point, current_drag_effects_allowed_, 0));
2235 void EventSender::DoMouseMove(const WebMouseEvent& e) {
2236 last_mouse_pos_ = WebPoint(e.x, e.y);
2238 view_->handleInputEvent(e);
2240 if (pressed_button_ == WebMouseEvent::ButtonNone ||
2241 current_drag_data_.isNull()) {
2245 WebPoint client_point(e.x, e.y);
2246 WebPoint screen_point(e.globalX, e.globalY);
2247 current_drag_effect_ = view_->dragTargetDragOver(
2248 client_point, screen_point, current_drag_effects_allowed_, 0);
2251 void EventSender::ReplaySavedEvents() {
2252 replaying_saved_events_ = true;
2253 while (!mouse_event_queue_.empty()) {
2254 SavedEvent e = mouse_event_queue_.front();
2255 mouse_event_queue_.pop_front();
2258 case SavedEvent::TYPE_MOUSE_MOVE: {
2259 WebMouseEvent event;
2260 InitMouseEvent(WebInputEvent::MouseMove,
2263 GetCurrentEventTimeSec(),
2270 case SavedEvent::TYPE_LEAP_FORWARD:
2271 DoLeapForward(e.milliseconds);
2273 case SavedEvent::TYPE_MOUSE_UP: {
2274 WebMouseEvent event;
2275 InitMouseEvent(WebInputEvent::MouseUp,
2278 GetCurrentEventTimeSec(),
2290 replaying_saved_events_ = false;
2293 } // namespace content