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/MockSpellCheck.h"
12 #include "content/shell/renderer/test_runner/TestInterfaces.h"
13 #include "content/shell/renderer/test_runner/WebTestDelegate.h"
14 #include "content/shell/renderer/test_runner/WebTestProxy.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::WebMouseEvent
;
36 using blink::WebMouseWheelEvent
;
37 using blink::WebPoint
;
38 using blink::WebString
;
39 using blink::WebTouchEvent
;
40 using blink::WebTouchPoint
;
41 using blink::WebVector
;
48 void InitMouseEvent(WebInputEvent::Type t
,
49 WebMouseEvent::Button b
,
57 e
->modifiers
= modifiers
;
62 e
->timeStampSeconds
= time_stamp
;
63 e
->clickCount
= click_count
;
66 int GetKeyModifier(const std::string
& modifier_name
) {
67 const char* characters
= modifier_name
.c_str();
68 if (!strcmp(characters
, "ctrlKey")
70 || !strcmp(characters
, "addSelectionKey")
73 return WebInputEvent::ControlKey
;
74 } else if (!strcmp(characters
, "shiftKey") ||
75 !strcmp(characters
, "rangeSelectionKey")) {
76 return WebInputEvent::ShiftKey
;
77 } else if (!strcmp(characters
, "altKey")) {
78 return WebInputEvent::AltKey
;
80 } else if (!strcmp(characters
, "metaKey") ||
81 !strcmp(characters
, "addSelectionKey")) {
82 return WebInputEvent::MetaKey
;
84 } else if (!strcmp(characters
, "metaKey")) {
85 return WebInputEvent::MetaKey
;
87 } else if (!strcmp(characters
, "autoRepeat")) {
88 return WebInputEvent::IsAutoRepeat
;
89 } else if (!strcmp(characters
, "copyKey")) {
91 return WebInputEvent::AltKey
;
93 return WebInputEvent::ControlKey
;
100 int GetKeyModifiers(const std::vector
<std::string
>& modifier_names
) {
102 for (std::vector
<std::string
>::const_iterator it
= modifier_names
.begin();
103 it
!= modifier_names
.end(); ++it
) {
104 modifiers
|= GetKeyModifier(*it
);
109 int GetKeyModifiersFromV8(v8::Handle
<v8::Value
> value
) {
110 std::vector
<std::string
> modifier_names
;
111 if (value
->IsString()) {
112 modifier_names
.push_back(gin::V8ToString(value
));
113 } else if (value
->IsArray()) {
114 gin::Converter
<std::vector
<std::string
> >::FromV8(
115 NULL
, value
, &modifier_names
);
117 return GetKeyModifiers(modifier_names
);
120 // Maximum distance (in space and time) for a mouse click to register as a
121 // double or triple click.
122 const double kMultipleClickTimeSec
= 1;
123 const int kMultipleClickRadiusPixels
= 5;
125 bool OutsideMultiClickRadius(const WebPoint
& a
, const WebPoint
& b
) {
126 return ((a
.x
- b
.x
) * (a
.x
- b
.x
) + (a
.y
- b
.y
) * (a
.y
- b
.y
)) >
127 kMultipleClickRadiusPixels
* kMultipleClickRadiusPixels
;
130 // Because actual context menu is implemented by the browser side,
131 // this function does only what LayoutTests are expecting:
132 // - Many test checks the count of items. So returning non-zero value makes
134 // - Some test compares the count before and after some action. So changing the
135 // count based on flags also makes sense. This function is doing such for some
137 // - Some test even checks actual string content. So providing it would be also
139 std::vector
<std::string
> MakeMenuItemStringsFor(
140 WebContextMenuData
* context_menu
,
141 WebTestRunner::WebTestDelegate
* delegate
) {
142 // These constants are based on Safari's context menu because tests are made
144 static const char* kNonEditableMenuStrings
[] = {
155 static const char* kEditableMenuStrings
[] = {
160 "Spelling and Grammar",
161 "Substitutions, Transformations",
164 "Paragraph Direction",
169 // This is possible because mouse events are cancelleable.
171 return std::vector
<std::string
>();
173 std::vector
<std::string
> strings
;
175 if (context_menu
->isEditable
) {
176 for (const char** item
= kEditableMenuStrings
; *item
; ++item
) {
177 strings
.push_back(*item
);
179 WebVector
<WebString
> suggestions
;
180 WebTestRunner::MockSpellCheck::fillSuggestionList(
181 context_menu
->misspelledWord
, &suggestions
);
182 for (size_t i
= 0; i
< suggestions
.size(); ++i
) {
183 strings
.push_back(suggestions
[i
].utf8());
186 for (const char** item
= kNonEditableMenuStrings
; *item
; ++item
) {
187 strings
.push_back(*item
);
194 // How much we should scroll per event - the value here is chosen to match the
195 // WebKit impl and layout test results.
196 const float kScrollbarPixelsPerTick
= 40.0f
;
198 WebMouseEvent::Button
GetButtonTypeFromButtonNumber(int button_code
) {
200 return WebMouseEvent::ButtonLeft
;
201 if (button_code
== 2)
202 return WebMouseEvent::ButtonRight
;
203 return WebMouseEvent::ButtonMiddle
;
206 class MouseDownTask
: public WebTestRunner::WebMethodTask
<EventSender
> {
208 MouseDownTask(EventSender
* obj
, int button_number
, int modifiers
)
209 : WebMethodTask
<EventSender
>(obj
),
210 button_number_(button_number
),
211 modifiers_(modifiers
) {}
213 virtual void runIfValid() OVERRIDE
{
214 m_object
->MouseDown(button_number_
, modifiers_
);
222 class MouseUpTask
: public WebTestRunner::WebMethodTask
<EventSender
> {
224 MouseUpTask(EventSender
* obj
, int button_number
, int modifiers
)
225 : WebMethodTask
<EventSender
>(obj
),
226 button_number_(button_number
),
227 modifiers_(modifiers
) {}
229 virtual void runIfValid() OVERRIDE
{
230 m_object
->MouseUp(button_number_
, modifiers_
);
238 class KeyDownTask
: public WebTestRunner::WebMethodTask
<EventSender
> {
240 KeyDownTask(EventSender
* obj
,
241 const std::string code_str
,
243 KeyLocationCode location
)
244 : WebMethodTask
<EventSender
>(obj
),
246 modifiers_(modifiers
),
247 location_(location
) {}
249 virtual void runIfValid() OVERRIDE
{
250 m_object
->KeyDown(code_str_
, modifiers_
, location_
);
254 std::string code_str_
;
256 KeyLocationCode location_
;
259 bool NeedsShiftModifier(int keyCode
) {
260 // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
261 return (keyCode
& 0xFF) >= 'A' && (keyCode
& 0xFF) <= 'Z';
264 // Get the edit command corresponding to a keyboard event.
265 // Returns true if the specified event corresponds to an edit command, the name
266 // of the edit command will be stored in |*name|.
267 bool GetEditCommand(const WebKeyboardEvent
& event
, std::string
* name
) {
268 #if defined(OS_MACOSX)
269 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
270 // modifiers. These key events correspond to some special movement and
271 // selection editor commands. These keys will be marked as system key, which
272 // prevents them from being handled. Thus they must be handled specially.
273 if ((event
.modifiers
& ~WebKeyboardEvent::ShiftKey
) !=
274 WebKeyboardEvent::MetaKey
)
277 switch (event
.windowsKeyCode
) {
279 *name
= "MoveToBeginningOfLine";
282 *name
= "MoveToEndOfLine";
285 *name
= "MoveToBeginningOfDocument";
288 *name
= "MoveToEndOfDocument";
294 if (event
.modifiers
& WebKeyboardEvent::ShiftKey
)
295 name
->append("AndModifySelection");
303 bool IsSystemKeyEvent(const WebKeyboardEvent
& event
) {
304 #if defined(OS_MACOSX)
305 return event
.modifiers
& WebInputEvent::MetaKey
&&
306 event
.windowsKeyCode
!= ui::VKEY_B
&&
307 event
.windowsKeyCode
!= ui::VKEY_I
;
309 return !!(event
.modifiers
& WebInputEvent::AltKey
);
315 class EventSenderBindings
: public gin::Wrappable
<EventSenderBindings
> {
317 static gin::WrapperInfo kWrapperInfo
;
319 static void Install(base::WeakPtr
<EventSender
> sender
,
320 blink::WebFrame
* frame
);
323 explicit EventSenderBindings(base::WeakPtr
<EventSender
> sender
);
324 virtual ~EventSenderBindings();
327 virtual gin::ObjectTemplateBuilder
GetObjectTemplateBuilder(
328 v8::Isolate
* isolate
) OVERRIDE
;
331 void EnableDOMUIEventLogging();
332 void FireKeyboardEventsToElement();
333 void ClearKillRing();
334 std::vector
<std::string
> ContextClick();
339 void SetPageZoomFactor(gin::Arguments
* args
);
340 void SetPageScaleFactor(gin::Arguments
* args
);
341 void ClearTouchPoints();
342 void ReleaseTouchPoint(unsigned index
);
343 void UpdateTouchPoint(unsigned index
, double x
, double y
);
344 void CancelTouchPoint(unsigned index
);
345 void SetTouchModifier(const std::string
& key_name
, bool set_mask
);
346 void SetTouchCancelable(bool cancelable
);
347 void DumpFilenameBeingDragged();
348 void GestureFlingCancel();
349 void GestureFlingStart(float x
, float y
, float velocity_x
, float velocity_y
);
350 void GestureScrollFirstPoint(int x
, int y
);
355 void LeapForward(int milliseconds
);
356 void BeginDragWithFiles(const std::vector
<std::string
>& files
);
357 void AddTouchPoint(gin::Arguments
* args
);
358 void MouseDragBegin();
360 void MouseMomentumBegin();
361 void GestureScrollBegin(gin::Arguments
* args
);
362 void GestureScrollEnd(gin::Arguments
* args
);
363 void GestureScrollUpdate(gin::Arguments
* args
);
364 void GestureScrollUpdateWithoutPropagation(gin::Arguments
* args
);
365 void GestureTap(gin::Arguments
* args
);
366 void GestureTapDown(gin::Arguments
* args
);
367 void GestureShowPress(gin::Arguments
* args
);
368 void GestureTapCancel(gin::Arguments
* args
);
369 void GestureLongPress(gin::Arguments
* args
);
370 void GestureLongTap(gin::Arguments
* args
);
371 void GestureTwoFingerTap(gin::Arguments
* args
);
372 void ContinuousMouseScrollBy(gin::Arguments
* args
);
373 void MouseMoveTo(gin::Arguments
* args
);
374 void MouseScrollBy(gin::Arguments
* args
);
375 void MouseMomentumScrollBy(gin::Arguments
* args
);
376 void MouseMomentumEnd();
377 void ScheduleAsynchronousClick(gin::Arguments
* args
);
378 void ScheduleAsynchronousKeyDown(gin::Arguments
* args
);
379 void MouseDown(gin::Arguments
* args
);
380 void MouseUp(gin::Arguments
* args
);
381 void KeyDown(gin::Arguments
* args
);
383 // Binding properties:
384 bool ForceLayoutOnEvents() const;
385 void SetForceLayoutOnEvents(bool force
);
386 bool IsDragMode() const;
387 void SetIsDragMode(bool drag_mode
);
390 int WmKeyDown() const;
391 void SetWmKeyDown(int key_down
);
394 void SetWmKeyUp(int key_up
);
397 void SetWmChar(int wm_char
);
399 int WmDeadChar() const;
400 void SetWmDeadChar(int dead_char
);
402 int WmSysKeyDown() const;
403 void SetWmSysKeyDown(int key_down
);
405 int WmSysKeyUp() const;
406 void SetWmSysKeyUp(int key_up
);
408 int WmSysChar() const;
409 void SetWmSysChar(int sys_char
);
411 int WmSysDeadChar() const;
412 void SetWmSysDeadChar(int sys_dead_char
);
415 base::WeakPtr
<EventSender
> sender_
;
417 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings
);
420 gin::WrapperInfo
EventSenderBindings::kWrapperInfo
= {gin::kEmbedderNativeGin
};
422 EventSenderBindings::EventSenderBindings(base::WeakPtr
<EventSender
> sender
)
426 EventSenderBindings::~EventSenderBindings() {}
429 void EventSenderBindings::Install(base::WeakPtr
<EventSender
> sender
,
431 v8::Isolate
* isolate
= blink::mainThreadIsolate();
432 v8::HandleScope
handle_scope(isolate
);
433 v8::Handle
<v8::Context
> context
= frame
->mainWorldScriptContext();
434 if (context
.IsEmpty())
437 v8::Context::Scope
context_scope(context
);
439 gin::Handle
<EventSenderBindings
> bindings
=
440 gin::CreateHandle(isolate
, new EventSenderBindings(sender
));
441 if (bindings
.IsEmpty())
443 v8::Handle
<v8::Object
> global
= context
->Global();
444 global
->Set(gin::StringToV8(isolate
, "eventSender"), bindings
.ToV8());
447 gin::ObjectTemplateBuilder
448 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate
* isolate
) {
449 return gin::Wrappable
<EventSenderBindings
>::GetObjectTemplateBuilder(isolate
)
450 .SetMethod("enableDOMUIEventLogging",
451 &EventSenderBindings::EnableDOMUIEventLogging
)
452 .SetMethod("fireKeyboardEventsToElement",
453 &EventSenderBindings::FireKeyboardEventsToElement
)
454 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing
)
455 .SetMethod("contextClick", &EventSenderBindings::ContextClick
)
456 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn
)
457 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut
)
458 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn
)
459 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut
)
460 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor
)
461 .SetMethod("setPageScaleFactor", &EventSenderBindings::SetPageScaleFactor
)
462 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints
)
463 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint
)
464 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint
)
465 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint
)
466 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier
)
467 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable
)
468 .SetMethod("dumpFilenameBeingDragged",
469 &EventSenderBindings::DumpFilenameBeingDragged
)
470 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel
)
471 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart
)
472 .SetMethod("gestureScrollFirstPoint",
473 &EventSenderBindings::GestureScrollFirstPoint
)
474 .SetMethod("touchStart", &EventSenderBindings::TouchStart
)
475 .SetMethod("touchMove", &EventSenderBindings::TouchMove
)
476 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel
)
477 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd
)
478 .SetMethod("leapForward", &EventSenderBindings::LeapForward
)
479 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles
)
480 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint
)
481 .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin
)
482 .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd
)
483 .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin
)
484 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin
)
485 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd
)
486 .SetMethod("gestureScrollUpdate",
487 &EventSenderBindings::GestureScrollUpdate
)
488 .SetMethod("gestureScrollUpdateWithoutPropagation",
489 &EventSenderBindings::GestureScrollUpdateWithoutPropagation
)
490 .SetMethod("gestureTap", &EventSenderBindings::GestureTap
)
491 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown
)
492 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress
)
493 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel
)
494 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress
)
495 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap
)
496 .SetMethod("gestureTwoFingerTap",
497 &EventSenderBindings::GestureTwoFingerTap
)
498 .SetMethod("continuousMouseScrollBy",
499 &EventSenderBindings::ContinuousMouseScrollBy
)
500 .SetMethod("keyDown", &EventSenderBindings::KeyDown
)
501 .SetMethod("mouseDown", &EventSenderBindings::MouseDown
)
502 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo
)
503 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy
)
504 .SetMethod("mouseUp", &EventSenderBindings::MouseUp
)
505 .SetMethod("mouseMomentumScrollBy",
506 &EventSenderBindings::MouseMomentumScrollBy
)
507 .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd
)
508 .SetMethod("scheduleAsynchronousClick",
509 &EventSenderBindings::ScheduleAsynchronousClick
)
510 .SetMethod("scheduleAsynchronousKeyDown",
511 &EventSenderBindings::ScheduleAsynchronousKeyDown
)
512 .SetProperty("forceLayoutOnEvents",
513 &EventSenderBindings::ForceLayoutOnEvents
,
514 &EventSenderBindings::SetForceLayoutOnEvents
)
515 .SetProperty("dragMode",
516 &EventSenderBindings::IsDragMode
,
517 &EventSenderBindings::SetIsDragMode
)
519 .SetProperty("WM_KEYDOWN",
520 &EventSenderBindings::WmKeyDown
,
521 &EventSenderBindings::SetWmKeyDown
)
522 .SetProperty("WM_KEYUP",
523 &EventSenderBindings::WmKeyUp
,
524 &EventSenderBindings::SetWmKeyUp
)
525 .SetProperty("WM_CHAR",
526 &EventSenderBindings::WmChar
,
527 &EventSenderBindings::SetWmChar
)
528 .SetProperty("WM_DEADCHAR",
529 &EventSenderBindings::WmDeadChar
,
530 &EventSenderBindings::SetWmDeadChar
)
531 .SetProperty("WM_SYSKEYDOWN",
532 &EventSenderBindings::WmSysKeyDown
,
533 &EventSenderBindings::SetWmSysKeyDown
)
534 .SetProperty("WM_SYSKEYUP",
535 &EventSenderBindings::WmSysKeyUp
,
536 &EventSenderBindings::SetWmSysKeyUp
)
537 .SetProperty("WM_SYSCHAR",
538 &EventSenderBindings::WmSysChar
,
539 &EventSenderBindings::SetWmSysChar
)
540 .SetProperty("WM_SYSDEADCHAR",
541 &EventSenderBindings::WmSysDeadChar
,
542 &EventSenderBindings::SetWmSysDeadChar
);
548 void EventSenderBindings::EnableDOMUIEventLogging() {
550 sender_
->EnableDOMUIEventLogging();
553 void EventSenderBindings::FireKeyboardEventsToElement() {
555 sender_
->FireKeyboardEventsToElement();
558 void EventSenderBindings::ClearKillRing() {
560 sender_
->ClearKillRing();
563 std::vector
<std::string
> EventSenderBindings::ContextClick() {
565 return sender_
->ContextClick();
566 return std::vector
<std::string
>();
569 void EventSenderBindings::TextZoomIn() {
571 sender_
->TextZoomIn();
574 void EventSenderBindings::TextZoomOut() {
576 sender_
->TextZoomOut();
579 void EventSenderBindings::ZoomPageIn() {
581 sender_
->ZoomPageIn();
584 void EventSenderBindings::ZoomPageOut() {
586 sender_
->ZoomPageOut();
589 void EventSenderBindings::SetPageZoomFactor(gin::Arguments
* args
) {
593 if (args
->PeekNext().IsEmpty())
595 args
->GetNext(&zoom_factor
);
596 sender_
->SetPageZoomFactor(zoom_factor
);
599 void EventSenderBindings::SetPageScaleFactor(gin::Arguments
* args
) {
605 if (args
->PeekNext().IsEmpty())
607 args
->GetNext(&scale_factor
);
608 if (args
->PeekNext().IsEmpty())
611 if (args
->PeekNext().IsEmpty())
614 sender_
->SetPageScaleFactor(scale_factor
,
615 static_cast<int>(x
), static_cast<int>(y
));
618 void EventSenderBindings::ClearTouchPoints() {
620 sender_
->ClearTouchPoints();
623 void EventSenderBindings::ReleaseTouchPoint(unsigned index
) {
625 sender_
->ReleaseTouchPoint(index
);
628 void EventSenderBindings::UpdateTouchPoint(unsigned index
, double x
, double y
) {
630 sender_
->UpdateTouchPoint(index
, static_cast<int>(x
), static_cast<int>(y
));
633 void EventSenderBindings::CancelTouchPoint(unsigned index
) {
635 sender_
->CancelTouchPoint(index
);
638 void EventSenderBindings::SetTouchModifier(const std::string
& key_name
,
641 sender_
->SetTouchModifier(key_name
, set_mask
);
644 void EventSenderBindings::SetTouchCancelable(bool cancelable
) {
646 sender_
->SetTouchCancelable(cancelable
);
649 void EventSenderBindings::DumpFilenameBeingDragged() {
651 sender_
->DumpFilenameBeingDragged();
654 void EventSenderBindings::GestureFlingCancel() {
656 sender_
->GestureFlingCancel();
659 void EventSenderBindings::GestureFlingStart(float x
,
664 sender_
->GestureFlingStart(x
, y
, velocity_x
, velocity_y
);
667 void EventSenderBindings::GestureScrollFirstPoint(int x
, int y
) {
669 sender_
->GestureScrollFirstPoint(x
, y
);
672 void EventSenderBindings::TouchStart() {
674 sender_
->TouchStart();
677 void EventSenderBindings::TouchMove() {
679 sender_
->TouchMove();
682 void EventSenderBindings::TouchCancel() {
684 sender_
->TouchCancel();
687 void EventSenderBindings::TouchEnd() {
692 void EventSenderBindings::LeapForward(int milliseconds
) {
694 sender_
->LeapForward(milliseconds
);
697 void EventSenderBindings::BeginDragWithFiles(
698 const std::vector
<std::string
>& files
) {
700 sender_
->BeginDragWithFiles(files
);
703 void EventSenderBindings::AddTouchPoint(gin::Arguments
* args
) {
705 sender_
->AddTouchPoint(args
);
708 void EventSenderBindings::MouseDragBegin() {
710 sender_
->MouseDragBegin();
713 void EventSenderBindings::MouseDragEnd() {
715 sender_
->MouseDragEnd();
718 void EventSenderBindings::MouseMomentumBegin() {
720 sender_
->MouseMomentumBegin();
723 void EventSenderBindings::GestureScrollBegin(gin::Arguments
* args
) {
725 sender_
->GestureScrollBegin(args
);
728 void EventSenderBindings::GestureScrollEnd(gin::Arguments
* args
) {
730 sender_
->GestureScrollEnd(args
);
733 void EventSenderBindings::GestureScrollUpdate(gin::Arguments
* args
) {
735 sender_
->GestureScrollUpdate(args
);
738 void EventSenderBindings::GestureScrollUpdateWithoutPropagation(
739 gin::Arguments
* args
) {
741 sender_
->GestureScrollUpdateWithoutPropagation(args
);
744 void EventSenderBindings::GestureTap(gin::Arguments
* args
) {
746 sender_
->GestureTap(args
);
749 void EventSenderBindings::GestureTapDown(gin::Arguments
* args
) {
751 sender_
->GestureTapDown(args
);
754 void EventSenderBindings::GestureShowPress(gin::Arguments
* args
) {
756 sender_
->GestureShowPress(args
);
759 void EventSenderBindings::GestureTapCancel(gin::Arguments
* args
) {
761 sender_
->GestureTapCancel(args
);
764 void EventSenderBindings::GestureLongPress(gin::Arguments
* args
) {
766 sender_
->GestureLongPress(args
);
769 void EventSenderBindings::GestureLongTap(gin::Arguments
* args
) {
771 sender_
->GestureLongTap(args
);
774 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments
* args
) {
776 sender_
->GestureTwoFingerTap(args
);
779 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments
* args
) {
781 sender_
->ContinuousMouseScrollBy(args
);
784 void EventSenderBindings::MouseMoveTo(gin::Arguments
* args
) {
786 sender_
->MouseMoveTo(args
);
789 void EventSenderBindings::MouseScrollBy(gin::Arguments
* args
) {
791 sender_
->MouseScrollBy(args
);
794 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments
* args
) {
796 sender_
->MouseMomentumScrollBy(args
);
799 void EventSenderBindings::MouseMomentumEnd() {
801 sender_
->MouseMomentumEnd();
804 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments
* args
) {
808 int button_number
= 0;
810 if (!args
->PeekNext().IsEmpty()) {
811 args
->GetNext(&button_number
);
812 if (!args
->PeekNext().IsEmpty())
813 modifiers
= GetKeyModifiersFromV8(args
->PeekNext());
815 sender_
->ScheduleAsynchronousClick(button_number
, modifiers
);
818 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments
* args
) {
822 std::string code_str
;
824 int location
= DOMKeyLocationStandard
;
825 args
->GetNext(&code_str
);
826 if (!args
->PeekNext().IsEmpty()) {
827 v8::Handle
<v8::Value
> value
;
828 args
->GetNext(&value
);
829 modifiers
= GetKeyModifiersFromV8(value
);
830 if (!args
->PeekNext().IsEmpty())
831 args
->GetNext(&location
);
833 sender_
->ScheduleAsynchronousKeyDown(code_str
, modifiers
,
834 static_cast<KeyLocationCode
>(location
));
837 void EventSenderBindings::MouseDown(gin::Arguments
* args
) {
841 int button_number
= 0;
843 if (!args
->PeekNext().IsEmpty()) {
844 args
->GetNext(&button_number
);
845 if (!args
->PeekNext().IsEmpty())
846 modifiers
= GetKeyModifiersFromV8(args
->PeekNext());
848 sender_
->MouseDown(button_number
, modifiers
);
851 void EventSenderBindings::MouseUp(gin::Arguments
* args
) {
855 int button_number
= 0;
857 if (!args
->PeekNext().IsEmpty()) {
858 args
->GetNext(&button_number
);
859 if (!args
->PeekNext().IsEmpty())
860 modifiers
= GetKeyModifiersFromV8(args
->PeekNext());
862 sender_
->MouseUp(button_number
, modifiers
);
865 void EventSenderBindings::KeyDown(gin::Arguments
* args
) {
869 std::string code_str
;
871 int location
= DOMKeyLocationStandard
;
872 args
->GetNext(&code_str
);
873 if (!args
->PeekNext().IsEmpty()) {
874 v8::Handle
<v8::Value
> value
;
875 args
->GetNext(&value
);
876 modifiers
= GetKeyModifiersFromV8(value
);
877 if (!args
->PeekNext().IsEmpty())
878 args
->GetNext(&location
);
880 sender_
->KeyDown(code_str
, modifiers
, static_cast<KeyLocationCode
>(location
));
883 bool EventSenderBindings::ForceLayoutOnEvents() const {
885 return sender_
->force_layout_on_events();
889 void EventSenderBindings::SetForceLayoutOnEvents(bool force
) {
891 sender_
->set_force_layout_on_events(force
);
894 bool EventSenderBindings::IsDragMode() const {
896 return sender_
->is_drag_mode();
900 void EventSenderBindings::SetIsDragMode(bool drag_mode
) {
902 sender_
->set_is_drag_mode(drag_mode
);
906 int EventSenderBindings::WmKeyDown() const {
908 return sender_
->wm_key_down();
912 void EventSenderBindings::SetWmKeyDown(int key_down
) {
914 sender_
->set_wm_key_down(key_down
);
917 int EventSenderBindings::WmKeyUp() const {
919 return sender_
->wm_key_up();
923 void EventSenderBindings::SetWmKeyUp(int key_up
) {
925 sender_
->set_wm_key_up(key_up
);
928 int EventSenderBindings::WmChar() const {
930 return sender_
->wm_char();
934 void EventSenderBindings::SetWmChar(int wm_char
) {
936 sender_
->set_wm_char(wm_char
);
939 int EventSenderBindings::WmDeadChar() const {
941 return sender_
->wm_dead_char();
945 void EventSenderBindings::SetWmDeadChar(int dead_char
) {
947 sender_
->set_wm_dead_char(dead_char
);
950 int EventSenderBindings::WmSysKeyDown() const {
952 return sender_
->wm_sys_key_down();
956 void EventSenderBindings::SetWmSysKeyDown(int key_down
) {
958 sender_
->set_wm_sys_key_down(key_down
);
961 int EventSenderBindings::WmSysKeyUp() const {
963 return sender_
->wm_sys_key_up();
967 void EventSenderBindings::SetWmSysKeyUp(int key_up
) {
969 sender_
->set_wm_sys_key_up(key_up
);
972 int EventSenderBindings::WmSysChar() const {
974 return sender_
->wm_sys_char();
978 void EventSenderBindings::SetWmSysChar(int sys_char
) {
980 sender_
->set_wm_sys_char(sys_char
);
983 int EventSenderBindings::WmSysDeadChar() const {
985 return sender_
->wm_sys_dead_char();
989 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char
) {
991 sender_
->set_wm_sys_dead_char(sys_dead_char
);
995 // EventSender -----------------------------------------------------------------
997 WebMouseEvent::Button
EventSender::pressed_button_
= WebMouseEvent::ButtonNone
;
999 WebPoint
EventSender::last_mouse_pos_
;
1001 WebMouseEvent::Button
EventSender::last_button_type_
=
1002 WebMouseEvent::ButtonNone
;
1004 EventSender::SavedEvent::SavedEvent()
1005 : type(TYPE_UNSPECIFIED
),
1006 button_type(WebMouseEvent::ButtonNone
),
1010 EventSender::EventSender(WebTestRunner::TestInterfaces
* interfaces
)
1011 : interfaces_(interfaces
),
1014 force_layout_on_events_(false),
1015 is_drag_mode_(true),
1016 touch_modifiers_(0),
1017 touch_cancelable_(true),
1018 replaying_saved_events_(false),
1019 current_drag_effects_allowed_(blink::WebDragOperationNone
),
1020 last_click_time_sec_(0),
1021 current_drag_effect_(blink::WebDragOperationNone
),
1029 wm_sys_key_down_(0),
1032 wm_sys_dead_char_(0),
1034 weak_factory_(this) {}
1036 EventSender::~EventSender() {}
1038 void EventSender::Reset() {
1039 DCHECK(current_drag_data_
.isNull());
1040 current_drag_data_
.reset();
1041 current_drag_effect_
= blink::WebDragOperationNone
;
1042 current_drag_effects_allowed_
= blink::WebDragOperationNone
;
1043 if (view_
&& pressed_button_
!= WebMouseEvent::ButtonNone
)
1044 view_
->mouseCaptureLost();
1045 pressed_button_
= WebMouseEvent::ButtonNone
;
1046 is_drag_mode_
= true;
1047 force_layout_on_events_
= true;
1050 wm_key_down_
= WM_KEYDOWN
;
1051 wm_key_up_
= WM_KEYUP
;
1053 wm_dead_char_
= WM_DEADCHAR
;
1054 wm_sys_key_down_
= WM_SYSKEYDOWN
;
1055 wm_sys_key_up_
= WM_SYSKEYUP
;
1056 wm_sys_char_
= WM_SYSCHAR
;
1057 wm_sys_dead_char_
= WM_SYSDEADCHAR
;
1060 last_mouse_pos_
= WebPoint(0, 0);
1061 last_click_time_sec_
= 0;
1062 last_click_pos_
= WebPoint(0, 0);
1063 last_button_type_
= WebMouseEvent::ButtonNone
;
1064 touch_points_
.clear();
1065 last_context_menu_data_
.reset();
1066 task_list_
.revokeAll();
1067 current_gesture_location_
= WebPoint(0, 0);
1068 mouse_event_queue_
.clear();
1070 time_offset_ms_
= 0;
1073 touch_modifiers_
= 0;
1074 touch_cancelable_
= true;
1075 touch_points_
.clear();
1078 void EventSender::Install(WebFrame
* frame
) {
1079 EventSenderBindings::Install(weak_factory_
.GetWeakPtr(), frame
);
1082 void EventSender::SetDelegate(WebTestRunner::WebTestDelegate
* delegate
) {
1083 delegate_
= delegate
;
1086 void EventSender::SetWebView(WebView
* view
) {
1090 void EventSender::SetContextMenuData(const WebContextMenuData
& data
) {
1091 last_context_menu_data_
.reset(new WebContextMenuData(data
));
1094 void EventSender::DoDragDrop(const WebDragData
& drag_data
,
1095 WebDragOperationsMask mask
) {
1096 WebMouseEvent event
;
1097 InitMouseEvent(WebInputEvent::MouseDown
,
1100 GetCurrentEventTimeSec(),
1104 WebPoint
client_point(event
.x
, event
.y
);
1105 WebPoint
screen_point(event
.globalX
, event
.globalY
);
1106 current_drag_data_
= drag_data
;
1107 current_drag_effects_allowed_
= mask
;
1108 current_drag_effect_
= view_
->dragTargetDragEnter(
1109 drag_data
, client_point
, screen_point
, current_drag_effects_allowed_
, 0);
1111 // Finish processing events.
1112 ReplaySavedEvents();
1115 void EventSender::MouseDown(int button_number
, int modifiers
) {
1116 if (force_layout_on_events_
)
1119 DCHECK_NE(-1, button_number
);
1121 WebMouseEvent::Button button_type
=
1122 GetButtonTypeFromButtonNumber(button_number
);
1124 UpdateClickCountForButton(button_type
);
1126 pressed_button_
= button_type
;
1128 WebMouseEvent event
;
1129 InitMouseEvent(WebInputEvent::MouseDown
,
1132 GetCurrentEventTimeSec(),
1136 view_
->handleInputEvent(event
);
1139 void EventSender::MouseUp(int button_number
, int modifiers
) {
1140 if (force_layout_on_events_
)
1143 DCHECK_NE(-1, button_number
);
1145 WebMouseEvent::Button button_type
=
1146 GetButtonTypeFromButtonNumber(button_number
);
1148 if (is_drag_mode_
&& !replaying_saved_events_
) {
1149 SavedEvent saved_event
;
1150 saved_event
.type
= SavedEvent::TYPE_MOUSE_UP
;
1151 saved_event
.button_type
= button_type
;
1152 saved_event
.modifiers
= modifiers
;
1153 mouse_event_queue_
.push_back(saved_event
);
1154 ReplaySavedEvents();
1156 WebMouseEvent event
;
1157 InitMouseEvent(WebInputEvent::MouseUp
,
1160 GetCurrentEventTimeSec(),
1168 void EventSender::KeyDown(const std::string
& code_str
,
1170 KeyLocationCode location
) {
1171 // FIXME: I'm not exactly sure how we should convert the string to a key
1172 // event. This seems to work in the cases I tested.
1173 // FIXME: Should we also generate a KEY_UP?
1175 bool generate_char
= false;
1177 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1178 // Windows uses \r for "Enter".
1181 bool needs_shift_key_modifier
= false;
1183 if ("\n" == code_str
) {
1184 generate_char
= true;
1185 text
= code
= ui::VKEY_RETURN
;
1186 } else if ("rightArrow" == code_str
) {
1187 code
= ui::VKEY_RIGHT
;
1188 } else if ("downArrow" == code_str
) {
1189 code
= ui::VKEY_DOWN
;
1190 } else if ("leftArrow" == code_str
) {
1191 code
= ui::VKEY_LEFT
;
1192 } else if ("upArrow" == code_str
) {
1194 } else if ("insert" == code_str
) {
1195 code
= ui::VKEY_INSERT
;
1196 } else if ("delete" == code_str
) {
1197 code
= ui::VKEY_DELETE
;
1198 } else if ("pageUp" == code_str
) {
1199 code
= ui::VKEY_PRIOR
;
1200 } else if ("pageDown" == code_str
) {
1201 code
= ui::VKEY_NEXT
;
1202 } else if ("home" == code_str
) {
1203 code
= ui::VKEY_HOME
;
1204 } else if ("end" == code_str
) {
1205 code
= ui::VKEY_END
;
1206 } else if ("printScreen" == code_str
) {
1207 code
= ui::VKEY_SNAPSHOT
;
1208 } else if ("menu" == code_str
) {
1209 code
= ui::VKEY_APPS
;
1210 } else if ("leftControl" == code_str
) {
1211 code
= ui::VKEY_LCONTROL
;
1212 } else if ("rightControl" == code_str
) {
1213 code
= ui::VKEY_RCONTROL
;
1214 } else if ("leftShift" == code_str
) {
1215 code
= ui::VKEY_LSHIFT
;
1216 } else if ("rightShift" == code_str
) {
1217 code
= ui::VKEY_RSHIFT
;
1218 } else if ("leftAlt" == code_str
) {
1219 code
= ui::VKEY_LMENU
;
1220 } else if ("rightAlt" == code_str
) {
1221 code
= ui::VKEY_RMENU
;
1222 } else if ("numLock" == code_str
) {
1223 code
= ui::VKEY_NUMLOCK
;
1225 // Compare the input string with the function-key names defined by the
1226 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1227 // name, set its key code.
1228 for (int i
= 1; i
<= 24; ++i
) {
1229 std::string function_key_name
= base::StringPrintf("F%d", i
);
1230 if (function_key_name
== code_str
) {
1231 code
= ui::VKEY_F1
+ (i
- 1);
1236 WebString web_code_str
=
1237 WebString::fromUTF8(code_str
.data(), code_str
.size());
1238 DCHECK_EQ(1u, web_code_str
.length());
1239 text
= code
= web_code_str
.at(0);
1240 needs_shift_key_modifier
= NeedsShiftModifier(code
);
1241 if ((code
& 0xFF) >= 'a' && (code
& 0xFF) <= 'z')
1243 generate_char
= true;
1246 if ("(" == code_str
) {
1248 needs_shift_key_modifier
= true;
1252 // For one generated keyboard event, we need to generate a keyDown/keyUp
1254 // On Windows, we might also need to generate a char event to mimic the
1255 // Windows event flow; on other platforms we create a merged event and test
1256 // the event flow that that platform provides.
1257 WebKeyboardEvent event_down
;
1258 event_down
.type
= WebInputEvent::RawKeyDown
;
1259 event_down
.modifiers
= modifiers
;
1260 event_down
.windowsKeyCode
= code
;
1262 if (generate_char
) {
1263 event_down
.text
[0] = text
;
1264 event_down
.unmodifiedText
[0] = text
;
1267 event_down
.setKeyIdentifierFromWindowsKeyCode();
1269 if (event_down
.modifiers
!= 0)
1270 event_down
.isSystemKey
= IsSystemKeyEvent(event_down
);
1272 if (needs_shift_key_modifier
)
1273 event_down
.modifiers
|= WebInputEvent::ShiftKey
;
1275 // See if KeyLocation argument is given.
1276 if (location
== DOMKeyLocationNumpad
)
1277 event_down
.modifiers
|= WebInputEvent::IsKeyPad
;
1279 WebKeyboardEvent event_up
;
1280 event_up
= event_down
;
1281 event_up
.type
= WebInputEvent::KeyUp
;
1282 // EventSender.m forces a layout here, with at least one
1283 // test (fast/forms/focus-control-to-page.html) relying on this.
1284 if (force_layout_on_events_
)
1287 // In the browser, if a keyboard event corresponds to an editor command,
1288 // the command will be dispatched to the renderer just before dispatching
1289 // the keyboard event, and then it will be executed in the
1290 // RenderView::handleCurrentKeyboardEvent() method.
1291 // We just simulate the same behavior here.
1292 std::string edit_command
;
1293 if (GetEditCommand(event_down
, &edit_command
))
1294 delegate_
->setEditCommand(edit_command
, "");
1296 view_
->handleInputEvent(event_down
);
1298 if (code
== ui::VKEY_ESCAPE
&& !current_drag_data_
.isNull()) {
1299 WebMouseEvent event
;
1300 InitMouseEvent(WebInputEvent::MouseDown
,
1303 GetCurrentEventTimeSec(),
1307 FinishDragAndDrop(event
, blink::WebDragOperationNone
);
1310 delegate_
->clearEditCommand();
1312 if (generate_char
) {
1313 WebKeyboardEvent event_char
= event_up
;
1314 event_char
.type
= WebInputEvent::Char
;
1315 event_char
.keyIdentifier
[0] = '\0';
1316 view_
->handleInputEvent(event_char
);
1319 view_
->handleInputEvent(event_up
);
1322 void EventSender::EnableDOMUIEventLogging() {}
1324 void EventSender::FireKeyboardEventsToElement() {}
1326 void EventSender::ClearKillRing() {}
1328 std::vector
<std::string
> EventSender::ContextClick() {
1329 if (force_layout_on_events_
) {
1333 UpdateClickCountForButton(WebMouseEvent::ButtonRight
);
1335 // Clears last context menu data because we need to know if the context menu
1336 // be requested after following mouse events.
1337 last_context_menu_data_
.reset();
1339 // Generate right mouse down and up.
1340 WebMouseEvent event
;
1341 // This is a hack to work around only allowing a single pressed button since
1342 // we want to test the case where both the left and right mouse buttons are
1344 if (pressed_button_
== WebMouseEvent::ButtonNone
) {
1345 pressed_button_
= WebMouseEvent::ButtonRight
;
1347 InitMouseEvent(WebInputEvent::MouseDown
,
1348 WebMouseEvent::ButtonRight
,
1350 GetCurrentEventTimeSec(),
1354 view_
->handleInputEvent(event
);
1357 InitMouseEvent(WebInputEvent::MouseUp
,
1358 WebMouseEvent::ButtonRight
,
1360 GetCurrentEventTimeSec(),
1364 view_
->handleInputEvent(event
);
1366 pressed_button_
= WebMouseEvent::ButtonNone
;
1369 std::vector
<std::string
> menu_items
= MakeMenuItemStringsFor(last_context_menu_data_
.get(), delegate_
);
1370 last_context_menu_data_
.reset();
1374 void EventSender::TextZoomIn() {
1375 view_
->setTextZoomFactor(view_
->textZoomFactor() * 1.2f
);
1378 void EventSender::TextZoomOut() {
1379 view_
->setTextZoomFactor(view_
->textZoomFactor() / 1.2f
);
1382 void EventSender::ZoomPageIn() {
1383 const std::vector
<WebTestProxyBase
*>& window_list
= interfaces_
->windowList();
1385 for (size_t i
= 0; i
< window_list
.size(); ++i
) {
1386 window_list
.at(i
)->webView()->setZoomLevel(
1387 window_list
.at(i
)->webView()->zoomLevel() + 1);
1391 void EventSender::ZoomPageOut() {
1392 const std::vector
<WebTestProxyBase
*>& window_list
= interfaces_
->windowList();
1394 for (size_t i
= 0; i
< window_list
.size(); ++i
) {
1395 window_list
.at(i
)->webView()->setZoomLevel(
1396 window_list
.at(i
)->webView()->zoomLevel() - 1);
1400 void EventSender::SetPageZoomFactor(double zoom_factor
) {
1401 const std::vector
<WebTestProxyBase
*>& window_list
= interfaces_
->windowList();
1403 for (size_t i
= 0; i
< window_list
.size(); ++i
) {
1404 window_list
.at(i
)->webView()->setZoomLevel(
1405 content::ZoomFactorToZoomLevel(zoom_factor
));
1409 void EventSender::SetPageScaleFactor(float scale_factor
, int x
, int y
) {
1410 view_
->setPageScaleFactorLimits(scale_factor
, scale_factor
);
1411 view_
->setPageScaleFactor(scale_factor
, WebPoint(x
, y
));
1414 void EventSender::ClearTouchPoints() {
1415 touch_points_
.clear();
1418 void EventSender::ThrowTouchPointError() {
1419 v8::Isolate
* isolate
= blink::mainThreadIsolate();
1420 isolate
->ThrowException(v8::Exception::TypeError(
1421 gin::StringToV8(isolate
, "Invalid touch point.")));
1424 void EventSender::ReleaseTouchPoint(unsigned index
) {
1425 if (index
>= touch_points_
.size()) {
1426 ThrowTouchPointError();
1430 WebTouchPoint
* touch_point
= &touch_points_
[index
];
1431 touch_point
->state
= WebTouchPoint::StateReleased
;
1434 void EventSender::UpdateTouchPoint(unsigned index
, int x
, int y
) {
1435 if (index
>= touch_points_
.size()) {
1436 ThrowTouchPointError();
1440 WebTouchPoint
* touch_point
= &touch_points_
[index
];
1441 touch_point
->state
= WebTouchPoint::StateMoved
;
1442 touch_point
->position
= WebFloatPoint(x
, y
);
1443 touch_point
->screenPosition
= touch_point
->position
;
1446 void EventSender::CancelTouchPoint(unsigned index
) {
1447 if (index
>= touch_points_
.size()) {
1448 ThrowTouchPointError();
1452 WebTouchPoint
* touch_point
= &touch_points_
[index
];
1453 touch_point
->state
= WebTouchPoint::StateCancelled
;
1456 void EventSender::SetTouchModifier(const std::string
& key_name
,
1459 if (key_name
== "shift")
1460 mask
= WebInputEvent::ShiftKey
;
1461 else if (key_name
== "alt")
1462 mask
= WebInputEvent::AltKey
;
1463 else if (key_name
== "ctrl")
1464 mask
= WebInputEvent::ControlKey
;
1465 else if (key_name
== "meta")
1466 mask
= WebInputEvent::MetaKey
;
1469 touch_modifiers_
|= mask
;
1471 touch_modifiers_
&= ~mask
;
1474 void EventSender::SetTouchCancelable(bool cancelable
) {
1475 touch_cancelable_
= cancelable
;
1478 void EventSender::DumpFilenameBeingDragged() {
1480 WebVector
<WebDragData::Item
> items
= current_drag_data_
.items();
1481 for (size_t i
= 0; i
< items
.size(); ++i
) {
1482 if (items
[i
].storageType
== WebDragData::Item::StorageTypeBinaryData
) {
1483 filename
= items
[i
].title
;
1487 delegate_
->printMessage(std::string("Filename being dragged: ") +
1488 filename
.utf8().data() + "\n");
1491 void EventSender::GestureFlingCancel() {
1492 WebGestureEvent event
;
1493 event
.type
= WebInputEvent::GestureFlingCancel
;
1494 event
.timeStampSeconds
= GetCurrentEventTimeSec();
1496 if (force_layout_on_events_
)
1499 view_
->handleInputEvent(event
);
1502 void EventSender::GestureFlingStart(float x
,
1506 WebGestureEvent event
;
1507 event
.type
= WebInputEvent::GestureFlingStart
;
1511 event
.globalX
= event
.x
;
1512 event
.globalY
= event
.y
;
1514 event
.data
.flingStart
.velocityX
= velocity_x
;
1515 event
.data
.flingStart
.velocityY
= velocity_y
;
1516 event
.timeStampSeconds
= GetCurrentEventTimeSec();
1518 if (force_layout_on_events_
)
1521 view_
->handleInputEvent(event
);
1524 void EventSender::GestureScrollFirstPoint(int x
, int y
) {
1525 current_gesture_location_
= WebPoint(x
, y
);
1528 void EventSender::TouchStart() {
1529 SendCurrentTouchEvent(WebInputEvent::TouchStart
);
1532 void EventSender::TouchMove() {
1533 SendCurrentTouchEvent(WebInputEvent::TouchMove
);
1536 void EventSender::TouchCancel() {
1537 SendCurrentTouchEvent(WebInputEvent::TouchCancel
);
1540 void EventSender::TouchEnd() {
1541 SendCurrentTouchEvent(WebInputEvent::TouchEnd
);
1544 void EventSender::LeapForward(int milliseconds
) {
1545 if (is_drag_mode_
&& pressed_button_
== WebMouseEvent::ButtonLeft
&&
1546 !replaying_saved_events_
) {
1547 SavedEvent saved_event
;
1548 saved_event
.type
= SavedEvent::TYPE_LEAP_FORWARD
;
1549 saved_event
.milliseconds
= milliseconds
;
1550 mouse_event_queue_
.push_back(saved_event
);
1552 DoLeapForward(milliseconds
);
1556 void EventSender::BeginDragWithFiles(const std::vector
<std::string
>& files
) {
1557 current_drag_data_
.initialize();
1558 WebVector
<WebString
> absolute_filenames(files
.size());
1559 for (size_t i
= 0; i
< files
.size(); ++i
) {
1560 WebDragData::Item item
;
1561 item
.storageType
= WebDragData::Item::StorageTypeFilename
;
1562 item
.filenameData
= delegate_
->getAbsoluteWebStringFromUTF8Path(files
[i
]);
1563 current_drag_data_
.addItem(item
);
1564 absolute_filenames
[i
] = item
.filenameData
;
1566 current_drag_data_
.setFilesystemId(
1567 delegate_
->registerIsolatedFileSystem(absolute_filenames
));
1568 current_drag_effects_allowed_
= blink::WebDragOperationCopy
;
1570 // Provide a drag source.
1571 view_
->dragTargetDragEnter(current_drag_data_
,
1574 current_drag_effects_allowed_
,
1576 // |is_drag_mode_| saves events and then replays them later. We don't
1578 is_drag_mode_
= false;
1580 // Make the rest of eventSender think a drag is in progress.
1581 pressed_button_
= WebMouseEvent::ButtonLeft
;
1584 void EventSender::AddTouchPoint(gin::Arguments
* args
) {
1590 WebTouchPoint touch_point
;
1591 touch_point
.state
= WebTouchPoint::StatePressed
;
1592 touch_point
.position
= WebFloatPoint(static_cast<int>(x
),
1593 static_cast<int>(y
));
1594 touch_point
.screenPosition
= touch_point
.position
;
1596 if (!args
->PeekNext().IsEmpty()) {
1598 if (!args
->GetNext(&radius_x
)) {
1603 double radius_y
= radius_x
;
1604 if (!args
->PeekNext().IsEmpty()) {
1605 if (!args
->GetNext(&radius_y
)) {
1611 touch_point
.radiusX
= static_cast<int>(radius_x
);
1612 touch_point
.radiusY
= static_cast<int>(radius_y
);
1616 for (size_t i
= 0; i
< touch_points_
.size(); i
++) {
1617 if (touch_points_
[i
].id
== lowest_id
)
1620 touch_point
.id
= lowest_id
;
1621 touch_points_
.push_back(touch_point
);
1624 void EventSender::MouseDragBegin() {
1625 WebMouseWheelEvent event
;
1626 InitMouseEvent(WebInputEvent::MouseWheel
,
1627 WebMouseEvent::ButtonNone
,
1629 GetCurrentEventTimeSec(),
1633 event
.phase
= WebMouseWheelEvent::PhaseBegan
;
1634 event
.hasPreciseScrollingDeltas
= true;
1635 view_
->handleInputEvent(event
);
1638 void EventSender::MouseDragEnd() {
1639 WebMouseWheelEvent event
;
1640 InitMouseEvent(WebInputEvent::MouseWheel
,
1641 WebMouseEvent::ButtonNone
,
1643 GetCurrentEventTimeSec(),
1647 event
.phase
= WebMouseWheelEvent::PhaseEnded
;
1648 event
.hasPreciseScrollingDeltas
= true;
1649 view_
->handleInputEvent(event
);
1652 void EventSender::MouseMomentumBegin() {
1653 WebMouseWheelEvent event
;
1654 InitMouseEvent(WebInputEvent::MouseWheel
,
1655 WebMouseEvent::ButtonNone
,
1657 GetCurrentEventTimeSec(),
1661 event
.momentumPhase
= WebMouseWheelEvent::PhaseBegan
;
1662 event
.hasPreciseScrollingDeltas
= true;
1663 view_
->handleInputEvent(event
);
1666 void EventSender::GestureScrollBegin(gin::Arguments
* args
) {
1667 GestureEvent(WebInputEvent::GestureScrollBegin
, args
);
1670 void EventSender::GestureScrollEnd(gin::Arguments
* args
) {
1671 GestureEvent(WebInputEvent::GestureScrollEnd
, args
);
1674 void EventSender::GestureScrollUpdate(gin::Arguments
* args
) {
1675 GestureEvent(WebInputEvent::GestureScrollUpdate
, args
);
1678 void EventSender::GestureScrollUpdateWithoutPropagation(gin::Arguments
* args
) {
1679 GestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation
, args
);
1682 void EventSender::GestureTap(gin::Arguments
* args
) {
1683 GestureEvent(WebInputEvent::GestureTap
, args
);
1686 void EventSender::GestureTapDown(gin::Arguments
* args
) {
1687 GestureEvent(WebInputEvent::GestureTapDown
, args
);
1690 void EventSender::GestureShowPress(gin::Arguments
* args
) {
1691 GestureEvent(WebInputEvent::GestureShowPress
, args
);
1694 void EventSender::GestureTapCancel(gin::Arguments
* args
) {
1695 GestureEvent(WebInputEvent::GestureTapCancel
, args
);
1698 void EventSender::GestureLongPress(gin::Arguments
* args
) {
1699 GestureEvent(WebInputEvent::GestureLongPress
, args
);
1702 void EventSender::GestureLongTap(gin::Arguments
* args
) {
1703 GestureEvent(WebInputEvent::GestureLongTap
, args
);
1706 void EventSender::GestureTwoFingerTap(gin::Arguments
* args
) {
1707 GestureEvent(WebInputEvent::GestureTwoFingerTap
, args
);
1710 void EventSender::ContinuousMouseScrollBy(gin::Arguments
* args
) {
1711 WebMouseWheelEvent event
;
1712 InitMouseWheelEvent(args
, true, &event
);
1713 view_
->handleInputEvent(event
);
1716 void EventSender::MouseMoveTo(gin::Arguments
* args
) {
1717 if (force_layout_on_events_
)
1724 WebPoint
mouse_pos(static_cast<int>(x
), static_cast<int>(y
));
1727 if (!args
->PeekNext().IsEmpty())
1728 modifiers
= GetKeyModifiersFromV8(args
->PeekNext());
1730 if (is_drag_mode_
&& pressed_button_
== WebMouseEvent::ButtonLeft
&&
1731 !replaying_saved_events_
) {
1732 SavedEvent saved_event
;
1733 saved_event
.type
= SavedEvent::TYPE_MOUSE_MOVE
;
1734 saved_event
.pos
= mouse_pos
;
1735 saved_event
.modifiers
= modifiers
;
1736 mouse_event_queue_
.push_back(saved_event
);
1738 WebMouseEvent event
;
1739 InitMouseEvent(WebInputEvent::MouseMove
,
1742 GetCurrentEventTimeSec(),
1750 void EventSender::MouseScrollBy(gin::Arguments
* args
) {
1751 WebMouseWheelEvent event
;
1752 InitMouseWheelEvent(args
, false, &event
);
1753 view_
->handleInputEvent(event
);
1756 void EventSender::MouseMomentumScrollBy(gin::Arguments
* args
) {
1757 WebMouseWheelEvent event
;
1758 InitMouseWheelEvent(args
, true, &event
);
1759 event
.momentumPhase
= WebMouseWheelEvent::PhaseChanged
;
1760 event
.hasPreciseScrollingDeltas
= true;
1761 view_
->handleInputEvent(event
);
1764 void EventSender::MouseMomentumEnd() {
1765 WebMouseWheelEvent event
;
1766 InitMouseEvent(WebInputEvent::MouseWheel
,
1767 WebMouseEvent::ButtonNone
,
1769 GetCurrentEventTimeSec(),
1773 event
.momentumPhase
= WebMouseWheelEvent::PhaseEnded
;
1774 event
.hasPreciseScrollingDeltas
= true;
1775 view_
->handleInputEvent(event
);
1778 void EventSender::ScheduleAsynchronousClick(int button_number
, int modifiers
) {
1779 delegate_
->postTask(new MouseDownTask(this, button_number
, modifiers
));
1780 delegate_
->postTask(new MouseUpTask(this, button_number
, modifiers
));
1783 void EventSender::ScheduleAsynchronousKeyDown(const std::string
& code_str
,
1785 KeyLocationCode location
) {
1786 delegate_
->postTask(new KeyDownTask(this, code_str
, modifiers
, location
));
1789 double EventSender::GetCurrentEventTimeSec() {
1790 return (delegate_
->getCurrentTimeInMillisecond() + time_offset_ms_
) / 1000.0;
1793 void EventSender::DoLeapForward(int milliseconds
) {
1794 time_offset_ms_
+= milliseconds
;
1797 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type
) {
1798 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap
),
1799 touch_points_
.size());
1800 if (force_layout_on_events_
)
1803 WebTouchEvent touch_event
;
1804 touch_event
.type
= type
;
1805 touch_event
.modifiers
= touch_modifiers_
;
1806 touch_event
.cancelable
= touch_cancelable_
;
1807 touch_event
.timeStampSeconds
= GetCurrentEventTimeSec();
1808 touch_event
.touchesLength
= touch_points_
.size();
1809 for (size_t i
= 0; i
< touch_points_
.size(); ++i
)
1810 touch_event
.touches
[i
] = touch_points_
[i
];
1811 view_
->handleInputEvent(touch_event
);
1813 for (size_t i
= 0; i
< touch_points_
.size(); ++i
) {
1814 WebTouchPoint
* touch_point
= &touch_points_
[i
];
1815 if (touch_point
->state
== WebTouchPoint::StateReleased
) {
1816 touch_points_
.erase(touch_points_
.begin() + i
);
1819 touch_point
->state
= WebTouchPoint::StateStationary
;
1823 void EventSender::GestureEvent(WebInputEvent::Type type
,
1824 gin::Arguments
* args
) {
1829 WebPoint
point(x
, y
);
1831 WebGestureEvent event
;
1835 case WebInputEvent::GestureScrollUpdate
:
1836 case WebInputEvent::GestureScrollUpdateWithoutPropagation
:
1837 event
.data
.scrollUpdate
.deltaX
= static_cast<float>(x
);
1838 event
.data
.scrollUpdate
.deltaY
= static_cast<float>(y
);
1839 event
.x
= current_gesture_location_
.x
;
1840 event
.y
= current_gesture_location_
.y
;
1841 current_gesture_location_
.x
=
1842 current_gesture_location_
.x
+ event
.data
.scrollUpdate
.deltaX
;
1843 current_gesture_location_
.y
=
1844 current_gesture_location_
.y
+ event
.data
.scrollUpdate
.deltaY
;
1846 case WebInputEvent::GestureScrollBegin
:
1847 current_gesture_location_
= WebPoint(point
.x
, point
.y
);
1848 event
.x
= current_gesture_location_
.x
;
1849 event
.y
= current_gesture_location_
.y
;
1851 case WebInputEvent::GestureScrollEnd
:
1852 case WebInputEvent::GestureFlingStart
:
1853 event
.x
= current_gesture_location_
.x
;
1854 event
.y
= current_gesture_location_
.y
;
1856 case WebInputEvent::GestureTap
:
1857 if (!args
->PeekNext().IsEmpty()) {
1859 if (!args
->GetNext(&tap_count
)) {
1863 event
.data
.tap
.tapCount
= tap_count
;
1865 event
.data
.tap
.tapCount
= 1;
1871 case WebInputEvent::GestureTapUnconfirmed
:
1872 if (!args
->PeekNext().IsEmpty()) {
1874 if (!args
->GetNext(&tap_count
)) {
1878 event
.data
.tap
.tapCount
= tap_count
;
1880 event
.data
.tap
.tapCount
= 1;
1885 case WebInputEvent::GestureTapDown
:
1888 if (!args
->PeekNext().IsEmpty()) {
1890 if (!args
->GetNext(&width
)) {
1894 event
.data
.tapDown
.width
= width
;
1896 if (!args
->PeekNext().IsEmpty()) {
1898 if (!args
->GetNext(&height
)) {
1902 event
.data
.tapDown
.height
= height
;
1905 case WebInputEvent::GestureShowPress
:
1908 if (!args
->PeekNext().IsEmpty()) {
1910 if (!args
->GetNext(&width
)) {
1914 event
.data
.showPress
.width
= width
;
1915 if (!args
->PeekNext().IsEmpty()) {
1917 if (!args
->GetNext(&height
)) {
1921 event
.data
.showPress
.height
= height
;
1925 case WebInputEvent::GestureTapCancel
:
1929 case WebInputEvent::GestureLongPress
:
1932 if (!args
->PeekNext().IsEmpty()) {
1934 if (!args
->GetNext(&width
)) {
1938 event
.data
.longPress
.width
= width
;
1939 if (!args
->PeekNext().IsEmpty()) {
1941 if (!args
->GetNext(&height
)) {
1945 event
.data
.longPress
.height
= height
;
1949 case WebInputEvent::GestureLongTap
:
1952 if (!args
->PeekNext().IsEmpty()) {
1954 if (!args
->GetNext(&width
)) {
1958 event
.data
.longPress
.width
= width
;
1959 if (!args
->PeekNext().IsEmpty()) {
1961 if (!args
->GetNext(&height
)) {
1965 event
.data
.longPress
.height
= height
;
1969 case WebInputEvent::GestureTwoFingerTap
:
1972 if (!args
->PeekNext().IsEmpty()) {
1973 float first_finger_width
;
1974 if (!args
->GetNext(&first_finger_width
)) {
1978 event
.data
.twoFingerTap
.firstFingerWidth
= first_finger_width
;
1979 if (!args
->PeekNext().IsEmpty()) {
1980 float first_finger_height
;
1981 if (!args
->GetNext(&first_finger_height
)) {
1985 event
.data
.twoFingerTap
.firstFingerHeight
= first_finger_height
;
1993 event
.globalX
= event
.x
;
1994 event
.globalY
= event
.y
;
1995 event
.timeStampSeconds
= GetCurrentEventTimeSec();
1997 if (force_layout_on_events_
)
2000 view_
->handleInputEvent(event
);
2002 // Long press might start a drag drop session. Complete it if so.
2003 if (type
== WebInputEvent::GestureLongPress
&& !current_drag_data_
.isNull()) {
2004 WebMouseEvent mouse_event
;
2005 InitMouseEvent(WebInputEvent::MouseDown
,
2008 GetCurrentEventTimeSec(),
2013 FinishDragAndDrop(mouse_event
, blink::WebDragOperationNone
);
2017 void EventSender::UpdateClickCountForButton(
2018 WebMouseEvent::Button button_type
) {
2019 if ((GetCurrentEventTimeSec() - last_click_time_sec_
<
2020 kMultipleClickTimeSec
) &&
2021 (!OutsideMultiClickRadius(last_mouse_pos_
, last_click_pos_
)) &&
2022 (button_type
== last_button_type_
)) {
2026 last_button_type_
= button_type
;
2030 void EventSender::InitMouseWheelEvent(gin::Arguments
* args
,
2032 WebMouseWheelEvent
* event
) {
2033 // Force a layout here just to make sure every position has been
2034 // determined before we send events (as well as all the other methods
2035 // that send an event do).
2036 if (force_layout_on_events_
)
2040 if (!args
->GetNext(&horizontal
)) {
2045 if (!args
->GetNext(&vertical
)) {
2051 bool has_precise_scrolling_deltas
= false;
2053 if (!args
->PeekNext().IsEmpty()) {
2054 args
->GetNext(&paged
);
2055 if (!args
->PeekNext().IsEmpty()) {
2056 args
->GetNext(&has_precise_scrolling_deltas
);
2057 if (!args
->PeekNext().IsEmpty())
2058 modifiers
= GetKeyModifiersFromV8(args
->PeekNext());
2062 InitMouseEvent(WebInputEvent::MouseWheel
,
2065 GetCurrentEventTimeSec(),
2069 event
->wheelTicksX
= static_cast<float>(horizontal
);
2070 event
->wheelTicksY
= static_cast<float>(vertical
);
2071 event
->deltaX
= event
->wheelTicksX
;
2072 event
->deltaY
= event
->wheelTicksY
;
2073 event
->scrollByPage
= paged
;
2074 event
->hasPreciseScrollingDeltas
= has_precise_scrolling_deltas
;
2077 event
->wheelTicksX
/= kScrollbarPixelsPerTick
;
2078 event
->wheelTicksY
/= kScrollbarPixelsPerTick
;
2080 event
->deltaX
*= kScrollbarPixelsPerTick
;
2081 event
->deltaY
*= kScrollbarPixelsPerTick
;
2085 void EventSender::FinishDragAndDrop(const WebMouseEvent
& e
,
2086 blink::WebDragOperation drag_effect
) {
2087 WebPoint
client_point(e
.x
, e
.y
);
2088 WebPoint
screen_point(e
.globalX
, e
.globalY
);
2089 current_drag_effect_
= drag_effect
;
2090 if (current_drag_effect_
) {
2091 // Specifically pass any keyboard modifiers to the drop method. This allows
2092 // tests to control the drop type (i.e. copy or move).
2093 view_
->dragTargetDrop(client_point
, screen_point
, e
.modifiers
);
2095 view_
->dragTargetDragLeave();
2097 view_
->dragSourceEndedAt(client_point
, screen_point
, current_drag_effect_
);
2098 view_
->dragSourceSystemDragEnded();
2100 current_drag_data_
.reset();
2103 void EventSender::DoMouseUp(const WebMouseEvent
& e
) {
2104 view_
->handleInputEvent(e
);
2106 pressed_button_
= WebMouseEvent::ButtonNone
;
2107 last_click_time_sec_
= e
.timeStampSeconds
;
2108 last_click_pos_
= last_mouse_pos_
;
2110 // If we're in a drag operation, complete it.
2111 if (current_drag_data_
.isNull())
2114 WebPoint
client_point(e
.x
, e
.y
);
2115 WebPoint
screen_point(e
.globalX
, e
.globalY
);
2118 view_
->dragTargetDragOver(
2119 client_point
, screen_point
, current_drag_effects_allowed_
, 0));
2122 void EventSender::DoMouseMove(const WebMouseEvent
& e
) {
2123 last_mouse_pos_
= WebPoint(e
.x
, e
.y
);
2125 view_
->handleInputEvent(e
);
2127 if (pressed_button_
== WebMouseEvent::ButtonNone
||
2128 current_drag_data_
.isNull()) {
2132 WebPoint
client_point(e
.x
, e
.y
);
2133 WebPoint
screen_point(e
.globalX
, e
.globalY
);
2134 current_drag_effect_
= view_
->dragTargetDragOver(
2135 client_point
, screen_point
, current_drag_effects_allowed_
, 0);
2138 void EventSender::ReplaySavedEvents() {
2139 replaying_saved_events_
= true;
2140 while (!mouse_event_queue_
.empty()) {
2141 SavedEvent e
= mouse_event_queue_
.front();
2142 mouse_event_queue_
.pop_front();
2145 case SavedEvent::TYPE_MOUSE_MOVE
: {
2146 WebMouseEvent event
;
2147 InitMouseEvent(WebInputEvent::MouseMove
,
2150 GetCurrentEventTimeSec(),
2157 case SavedEvent::TYPE_LEAP_FORWARD
:
2158 DoLeapForward(e
.milliseconds
);
2160 case SavedEvent::TYPE_MOUSE_UP
: {
2161 WebMouseEvent event
;
2162 InitMouseEvent(WebInputEvent::MouseUp
,
2165 GetCurrentEventTimeSec(),
2177 replaying_saved_events_
= false;
2180 } // namespace content