Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: webkit/tools/test_shell/event_sending_controller.cc

Issue 6296015: Remove eventSender, accessibilityController, plainText and (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/webkit/tools/test_shell
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 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.
4
5 // This file contains the definition for EventSendingController.
6 //
7 // Some notes about drag and drop handling:
8 // Windows drag and drop goes through a system call to DoDragDrop. At that
9 // point, program control is given to Windows which then periodically makes
10 // callbacks into the webview. This won't work for layout tests, so instead,
11 // we queue up all the mouse move and mouse up events. When the test tries to
12 // start a drag (by calling EvenSendingController::DoDragDrop), we take the
13 // events in the queue and replay them.
14 // The behavior of queuing events and replaying them can be disabled by a
15 // layout test by setting eventSender.dragMode to false.
16
17 #include "webkit/tools/test_shell/event_sending_controller.h"
18
19 #include <queue>
20 #include <vector>
21
22 #include "base/compiler_specific.h"
23 #include "base/file_path.h"
24 #include "base/file_util.h"
25 #include "base/logging.h"
26 #include "base/message_loop.h"
27 #include "base/time.h"
28 #include "base/string_number_conversions.h"
29 #include "base/string_util.h"
30 #include "base/utf_string_conversions.h"
31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTouchPoint.h"
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
38 #include "ui/base/keycodes/keyboard_codes.h"
39 #include "webkit/glue/webkit_glue.h"
40 #include "webkit/tools/test_shell/test_shell.h"
41 #include "webkit/tools/test_shell/test_webview_delegate.h"
42
43 #if defined(OS_WIN)
44 #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFact ory.h"
45 using WebKit::WebInputEventFactory;
46 #endif
47
48 // TODO(mpcomplete): layout before each event?
49
50 using base::Time;
51 using base::TimeTicks;
52 using WebKit::WebDragOperation;
53 using WebKit::WebDragOperationsMask;
54 using WebKit::WebDragData;
55 using WebKit::WebInputEvent;
56 using WebKit::WebKeyboardEvent;
57 using WebKit::WebMouseEvent;
58 using WebKit::WebMouseWheelEvent;
59 using WebKit::WebPoint;
60 using WebKit::WebString;
61 using WebKit::WebTouchEvent;
62 using WebKit::WebTouchPoint;
63 using WebKit::WebView;
64
65 gfx::Point EventSendingController::last_mouse_pos_;
66 WebMouseEvent::Button EventSendingController::pressed_button_ =
67 WebMouseEvent::ButtonNone;
68
69 WebMouseEvent::Button EventSendingController::last_button_type_ =
70 WebMouseEvent::ButtonNone;
71
72 namespace {
73
74 struct SavedEvent {
75 enum SavedEventType {
76 Unspecified,
77 MouseUp,
78 MouseMove,
79 LeapForward
80 };
81
82 SavedEventType type;
83 WebMouseEvent::Button button_type; // For MouseUp
84 gfx::Point pos; // For MouseMove.
85 int milliseconds; // For LeapForward.
86
87 SavedEvent()
88 : type(Unspecified),
89 button_type(WebMouseEvent::ButtonNone),
90 milliseconds(0) {
91 }
92 };
93
94 static WebDragData current_drag_data;
95 static WebDragOperation current_drag_effect;
96 static WebDragOperationsMask current_drag_effects_allowed;
97 static bool replaying_saved_events = false;
98 static std::queue<SavedEvent> mouse_event_queue;
99 static int touch_modifiers;
100 static std::vector<WebTouchPoint> touch_points;
101
102 // Time and place of the last mouse up event.
103 static double last_click_time_sec = 0;
104 static gfx::Point last_click_pos;
105 static int click_count = 0;
106
107 // maximum distance (in space and time) for a mouse click
108 // to register as a double or triple click
109 static const double kMultiClickTimeSec = 1;
110 static const int kMultiClickRadiusPixels = 5;
111
112 // How much we should scroll per event - the value here is chosen to
113 // match the WebKit impl and layout test results.
114 static const float kScrollbarPixelsPerTick = 40.0f;
115
116 inline bool outside_multiclick_radius(const gfx::Point &a,
117 const gfx::Point &b) {
118 return ((a.x() - b.x()) * (a.x() - b.x()) +
119 (a.y() - b.y()) * (a.y() - b.y())) >
120 kMultiClickRadiusPixels * kMultiClickRadiusPixels;
121 }
122
123 // Used to offset the time the event hander things an event happened. This is
124 // done so tests can run without a delay, but bypass checks that are time
125 // dependent (e.g., dragging has a timeout vs selection).
126 static uint32 time_offset_ms = 0;
127
128 double GetCurrentEventTimeSec() {
129 return (TimeTicks::Now().ToInternalValue()
130 / Time::kMicrosecondsPerMillisecond +
131 time_offset_ms) / 1000.0;
132 }
133
134 void AdvanceEventTime(int32 delta_ms) {
135 time_offset_ms += delta_ms;
136 }
137
138 void InitMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b,
139 const gfx::Point& pos, WebMouseEvent* e) {
140 e->type = t;
141 e->button = b;
142 e->modifiers = 0;
143 e->x = pos.x();
144 e->y = pos.y();
145 e->globalX = pos.x();
146 e->globalY = pos.y();
147 e->timeStampSeconds = GetCurrentEventTimeSec();
148 e->clickCount = click_count;
149 }
150
151 // Returns true if the specified key is the system key.
152 bool ApplyKeyModifier(const std::string& key, WebInputEvent* event) {
153 bool system_key = false;
154 if (key == "ctrlKey"
155 #if !defined(OS_MACOSX)
156 || key == "addSelectionKey"
157 #endif
158 ) {
159 event->modifiers |= WebInputEvent::ControlKey;
160 } else if (key == "shiftKey" || key == "rangeSelectionKey") {
161 event->modifiers |= WebInputEvent::ShiftKey;
162 } else if (key == "altKey") {
163 event->modifiers |= WebInputEvent::AltKey;
164 #if !defined(OS_MACOSX)
165 // On Windows all keys with Alt modifier will be marked as system key.
166 // We keep the same behavior on Linux and everywhere non-Mac, see:
167 // third_party/WebKit/Source/WebKit/chromium/src/gtk/WebInputEventFactory.cp p
168 // If we want to change this behavior on Linux, this piece of code must be
169 // kept in sync with the related code in above file.
170 system_key = true;
171 #endif
172 #if defined(OS_MACOSX)
173 } else if (key == "metaKey" || key == "addSelectionKey") {
174 event->modifiers |= WebInputEvent::MetaKey;
175 // On Mac only command key presses are marked as system key.
176 // See the related code in:
177 // third_party/WebKit/Source/WebKit/chromium/src/mac/WebInputEventFactory.cp p
178 // It must be kept in sync with the related code in above file.
179 system_key = true;
180 #else
181 } else if (key == "metaKey") {
182 event->modifiers |= WebInputEvent::MetaKey;
183 #endif
184 }
185 return system_key;
186 }
187
188 bool ApplyKeyModifiers(const CppVariant* arg, WebInputEvent* event) {
189 bool system_key = false;
190 if (arg->isObject()) {
191 std::vector<std::string> args = arg->ToStringVector();
192 for (std::vector<std::string>::const_iterator i = args.begin();
193 i != args.end(); ++i) {
194 system_key |= ApplyKeyModifier(*i, event);
195 }
196 } else if (arg->isString()) {
197 system_key = ApplyKeyModifier(arg->ToString(), event);
198 }
199 return system_key;
200 }
201
202 // Get the edit command corresponding to a keyboard event.
203 // Returns true if the specified event corresponds to an edit command, the name
204 // of the edit command will be stored in |*name|.
205 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
206 #if defined(OS_MACOSX)
207 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
208 // modifiers. These key events correspond to some special movement and
209 // selection editor commands, and was supposed to be handled in
210 // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp. But the se keys
211 // will be marked as system key, which prevents them from being handled.
212 // Thus they must be handled specially.
213 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
214 WebKeyboardEvent::MetaKey)
215 return false;
216
217 switch (event.windowsKeyCode) {
218 case ui::VKEY_LEFT:
219 *name = "MoveToBeginningOfLine";
220 break;
221 case ui::VKEY_RIGHT:
222 *name = "MoveToEndOfLine";
223 break;
224 case ui::VKEY_UP:
225 *name = "MoveToBeginningOfDocument";
226 break;
227 case ui::VKEY_DOWN:
228 *name = "MoveToEndOfDocument";
229 break;
230 default:
231 return false;
232 }
233
234 if (event.modifiers & WebKeyboardEvent::ShiftKey)
235 name->append("AndModifySelection");
236
237 return true;
238 #else
239 return false;
240 #endif
241 }
242
243 // Key event location code introduced in DOM Level 3.
244 // See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
245 enum KeyLocationCode {
246 DOM_KEY_LOCATION_STANDARD = 0x00,
247 DOM_KEY_LOCATION_LEFT = 0x01,
248 DOM_KEY_LOCATION_RIGHT = 0x02,
249 DOM_KEY_LOCATION_NUMPAD = 0x03
250 };
251
252 } // anonymous namespace
253
254 EventSendingController::EventSendingController(TestShell* shell)
255 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
256 shell_(shell) {
257 // Initialize the map that associates methods of this class with the names
258 // they will use when called by JavaScript. The actual binding of those
259 // names to their methods will be done by calling BindToJavaScript() (defined
260 // by CppBoundClass, the parent to EventSendingController).
261 BindMethod("mouseDown", &EventSendingController::mouseDown);
262 BindMethod("mouseUp", &EventSendingController::mouseUp);
263 BindMethod("contextClick", &EventSendingController::contextClick);
264 BindMethod("mouseMoveTo", &EventSendingController::mouseMoveTo);
265 BindMethod("leapForward", &EventSendingController::leapForward);
266 BindMethod("keyDown", &EventSendingController::keyDown);
267 BindMethod("dispatchMessage", &EventSendingController::dispatchMessage);
268 BindMethod("enableDOMUIEventLogging",
269 &EventSendingController::enableDOMUIEventLogging);
270 BindMethod("fireKeyboardEventsToElement",
271 &EventSendingController::fireKeyboardEventsToElement);
272 BindMethod("clearKillRing", &EventSendingController::clearKillRing);
273 BindMethod("textZoomIn", &EventSendingController::textZoomIn);
274 BindMethod("textZoomOut", &EventSendingController::textZoomOut);
275 BindMethod("zoomPageIn", &EventSendingController::zoomPageIn);
276 BindMethod("zoomPageOut", &EventSendingController::zoomPageOut);
277 BindMethod("mouseScrollBy", &EventSendingController::mouseScrollBy);
278 BindMethod("continuousMouseScrollBy",
279 &EventSendingController::continuousMouseScrollBy);
280 BindMethod("scheduleAsynchronousClick",
281 &EventSendingController::scheduleAsynchronousClick);
282 BindMethod("beginDragWithFiles",
283 &EventSendingController::beginDragWithFiles);
284 BindMethod("addTouchPoint", &EventSendingController::addTouchPoint);
285 BindMethod("cancelTouchPoint", &EventSendingController::cancelTouchPoint);
286 BindMethod("clearTouchPoints", &EventSendingController::clearTouchPoints);
287 BindMethod("releaseTouchPoint", &EventSendingController::releaseTouchPoint);
288 BindMethod("updateTouchPoint", &EventSendingController::updateTouchPoint);
289 BindMethod("setTouchModifier", &EventSendingController::setTouchModifier);
290 BindMethod("touchCancel", &EventSendingController::touchCancel);
291 BindMethod("touchEnd", &EventSendingController::touchEnd);
292 BindMethod("touchMove", &EventSendingController::touchMove);
293 BindMethod("touchStart", &EventSendingController::touchStart);
294
295 // When set to true (the default value), we batch mouse move and mouse up
296 // events so we can simulate drag & drop.
297 BindProperty("dragMode", &dragMode);
298 #if defined(OS_WIN)
299 BindProperty("WM_KEYDOWN", &wmKeyDown);
300 BindProperty("WM_KEYUP", &wmKeyUp);
301 BindProperty("WM_CHAR", &wmChar);
302 BindProperty("WM_DEADCHAR", &wmDeadChar);
303 BindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
304 BindProperty("WM_SYSKEYUP", &wmSysKeyUp);
305 BindProperty("WM_SYSCHAR", &wmSysChar);
306 BindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
307 #endif
308 }
309
310 EventSendingController::~EventSendingController() {
311 }
312
313 void EventSendingController::Reset() {
314 // The test should have finished a drag and the mouse button state.
315 DCHECK(current_drag_data.isNull());
316 current_drag_data.reset();
317 current_drag_effect = WebKit::WebDragOperationNone;
318 current_drag_effects_allowed = WebKit::WebDragOperationNone;
319 pressed_button_ = WebMouseEvent::ButtonNone;
320 dragMode.Set(true);
321 #if defined(OS_WIN)
322 wmKeyDown.Set(WM_KEYDOWN);
323 wmKeyUp.Set(WM_KEYUP);
324 wmChar.Set(WM_CHAR);
325 wmDeadChar.Set(WM_DEADCHAR);
326 wmSysKeyDown.Set(WM_SYSKEYDOWN);
327 wmSysKeyUp.Set(WM_SYSKEYUP);
328 wmSysChar.Set(WM_SYSCHAR);
329 wmSysDeadChar.Set(WM_SYSDEADCHAR);
330 #endif
331 last_mouse_pos_.SetPoint(0, 0);
332 last_click_time_sec = 0;
333 last_click_pos.SetPoint(0, 0);
334 click_count = 0;
335 last_button_type_ = WebMouseEvent::ButtonNone;
336 time_offset_ms = 0;
337 touch_modifiers = 0;
338 touch_points.clear();
339 }
340
341 WebView* EventSendingController::webview() {
342 return shell_->webView();
343 }
344
345 void EventSendingController::DoDragDrop(const WebDragData& drag_data,
346 WebDragOperationsMask mask) {
347 WebMouseEvent event;
348 InitMouseEvent(WebInputEvent::MouseDown, pressed_button_, last_mouse_pos_,
349 &event);
350 WebPoint client_point(event.x, event.y);
351 WebPoint screen_point(event.globalX, event.globalY);
352 current_drag_data = drag_data;
353 current_drag_effects_allowed = mask;
354 current_drag_effect = webview()->dragTargetDragEnter(
355 drag_data, 0, client_point, screen_point, current_drag_effects_allowed);
356
357 // Finish processing events.
358 ReplaySavedEvents();
359 }
360
361 WebMouseEvent::Button EventSendingController::GetButtonTypeFromButtonNumber(
362 int button_code) {
363 if (button_code == 0)
364 return WebMouseEvent::ButtonLeft;
365 else if (button_code == 2)
366 return WebMouseEvent::ButtonRight;
367
368 return WebMouseEvent::ButtonMiddle;
369 }
370
371 // static
372 int EventSendingController::GetButtonNumberFromSingleArg(
373 const CppArgumentList& args) {
374 int button_code = 0;
375
376 if (args.size() > 0 && args[0].isNumber()) {
377 button_code = args[0].ToInt32();
378 }
379
380 return button_code;
381 }
382
383 void EventSendingController::UpdateClickCountForButton(
384 WebMouseEvent::Button button_type) {
385 if ((GetCurrentEventTimeSec() - last_click_time_sec < kMultiClickTimeSec) &&
386 (!outside_multiclick_radius(last_mouse_pos_, last_click_pos)) &&
387 (button_type == last_button_type_)) {
388 ++click_count;
389 } else {
390 click_count = 1;
391 last_button_type_ = button_type;
392 }
393 }
394
395 //
396 // Implemented javascript methods.
397 //
398
399 void EventSendingController::mouseDown(
400 const CppArgumentList& args, CppVariant* result) {
401 if (result) // Could be NULL if invoked asynchronously.
402 result->SetNull();
403
404 webview()->layout();
405
406 int button_number = GetButtonNumberFromSingleArg(args);
407 DCHECK(button_number != -1);
408
409 WebMouseEvent::Button button_type = GetButtonTypeFromButtonNumber(
410 button_number);
411
412 UpdateClickCountForButton(button_type);
413
414 WebMouseEvent event;
415 pressed_button_ = button_type;
416 InitMouseEvent(WebInputEvent::MouseDown, button_type,
417 last_mouse_pos_, &event);
418 if (args.size() >= 2 && (args[1].isObject() || args[1].isString()))
419 ApplyKeyModifiers(&(args[1]), &event);
420 webview()->handleInputEvent(event);
421 }
422
423 void EventSendingController::mouseUp(
424 const CppArgumentList& args, CppVariant* result) {
425 if (result) // Could be NULL if invoked asynchronously.
426 result->SetNull();
427
428 webview()->layout();
429
430 int button_number = GetButtonNumberFromSingleArg(args);
431 DCHECK(button_number != -1);
432
433 WebMouseEvent::Button button_type = GetButtonTypeFromButtonNumber(
434 button_number);
435
436 if (drag_mode() && !replaying_saved_events) {
437 SavedEvent saved_event;
438 saved_event.type = SavedEvent::MouseUp;
439 saved_event.button_type = button_type;
440 mouse_event_queue.push(saved_event);
441 ReplaySavedEvents();
442 } else {
443 WebMouseEvent event;
444 InitMouseEvent(WebInputEvent::MouseUp, button_type,
445 last_mouse_pos_, &event);
446 if (args.size() >= 2 && (args[1].isObject() || args[1].isString()))
447 ApplyKeyModifiers(&(args[1]), &event);
448 DoMouseUp(event);
449 }
450 }
451
452 void EventSendingController::DoMouseUp(const WebMouseEvent& e) {
453 webview()->handleInputEvent(e);
454
455 pressed_button_ = WebMouseEvent::ButtonNone;
456 last_click_time_sec = e.timeStampSeconds;
457 last_click_pos = last_mouse_pos_;
458
459 // If we're in a drag operation, complete it.
460 if (!current_drag_data.isNull()) {
461 WebPoint client_point(e.x, e.y);
462 WebPoint screen_point(e.globalX, e.globalY);
463
464 current_drag_effect = webview()->dragTargetDragOver(
465 client_point, screen_point, current_drag_effects_allowed);
466 if (current_drag_effect) {
467 webview()->dragTargetDrop(client_point, screen_point);
468 } else {
469 webview()->dragTargetDragLeave();
470 }
471 webview()->dragSourceEndedAt(
472 client_point, screen_point, current_drag_effect);
473 webview()->dragSourceSystemDragEnded();
474
475 current_drag_data.reset();
476 }
477 }
478
479 void EventSendingController::mouseMoveTo(
480 const CppArgumentList& args, CppVariant* result) {
481 result->SetNull();
482
483 if (args.size() >= 2 && args[0].isNumber() && args[1].isNumber()) {
484 webview()->layout();
485
486 gfx::Point mouse_pos;
487 mouse_pos.SetPoint(args[0].ToInt32(), args[1].ToInt32());
488
489 if (drag_mode() && pressed_button_ == WebMouseEvent::ButtonLeft &&
490 !replaying_saved_events) {
491 SavedEvent saved_event;
492 saved_event.type = SavedEvent::MouseMove;
493 saved_event.pos = mouse_pos;
494 mouse_event_queue.push(saved_event);
495 } else {
496 WebMouseEvent event;
497 InitMouseEvent(WebInputEvent::MouseMove, pressed_button_,
498 mouse_pos, &event);
499 DoMouseMove(event);
500 }
501 }
502 }
503
504 void EventSendingController::DoMouseMove(const WebMouseEvent& e) {
505 last_mouse_pos_.SetPoint(e.x, e.y);
506
507 webview()->handleInputEvent(e);
508
509 if (pressed_button_ != WebMouseEvent::ButtonNone &&
510 !current_drag_data.isNull()) {
511 WebPoint client_point(e.x, e.y);
512 WebPoint screen_point(e.globalX, e.globalY);
513
514 current_drag_effect = webview()->dragTargetDragOver(
515 client_point, screen_point, current_drag_effects_allowed);
516 }
517 }
518
519 void EventSendingController::keyDown(
520 const CppArgumentList& args, CppVariant* result) {
521 result->SetNull();
522
523 bool generate_char = false;
524
525 if (args.size() >= 1 && args[0].isString()) {
526 // TODO(mpcomplete): I'm not exactly sure how we should convert the string
527 // to a key event. This seems to work in the cases I tested.
528 // TODO(mpcomplete): Should we also generate a KEY_UP?
529 std::wstring code_str = UTF8ToWide(args[0].ToString());
530
531 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
532 // Windows uses \r for "Enter".
533 int code = 0;
534 int text = 0;
535 bool needs_shift_key_modifier = false;
536 if (L"\n" == code_str) {
537 generate_char = true;
538 text = code = ui::VKEY_RETURN;
539 } else if (L"rightArrow" == code_str) {
540 code = ui::VKEY_RIGHT;
541 } else if (L"downArrow" == code_str) {
542 code = ui::VKEY_DOWN;
543 } else if (L"leftArrow" == code_str) {
544 code = ui::VKEY_LEFT;
545 } else if (L"upArrow" == code_str) {
546 code = ui::VKEY_UP;
547 } else if (L"insert" == code_str) {
548 code = ui::VKEY_INSERT;
549 } else if (L"delete" == code_str) {
550 code = ui::VKEY_DELETE;
551 } else if (L"pageUp" == code_str) {
552 code = ui::VKEY_PRIOR;
553 } else if (L"pageDown" == code_str) {
554 code = ui::VKEY_NEXT;
555 } else if (L"home" == code_str) {
556 code = ui::VKEY_HOME;
557 } else if (L"end" == code_str) {
558 code = ui::VKEY_END;
559 } else if (L"printScreen" == code_str) {
560 code = ui::VKEY_SNAPSHOT;
561 } else {
562 // Compare the input string with the function-key names defined by the
563 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
564 // name, set its key code.
565 for (int i = 1; i <= 24; ++i) {
566 std::wstring function_key_name;
567 function_key_name += L"F";
568 function_key_name += UTF8ToWide(base::IntToString(i));
569 if (function_key_name == code_str) {
570 code = ui::VKEY_F1 + (i - 1);
571 break;
572 }
573 }
574 if (!code) {
575 DCHECK(code_str.length() == 1);
576 text = code = code_str[0];
577 needs_shift_key_modifier = NeedsShiftModifier(code);
578 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
579 code -= 'a' - 'A';
580 generate_char = true;
581 }
582 }
583
584 // For one generated keyboard event, we need to generate a keyDown/keyUp
585 // pair; refer to EventSender.cpp in WebKit/Tools/DumpRenderTree/win.
586 // On Windows, we might also need to generate a char event to mimic the
587 // Windows event flow; on other platforms we create a merged event and test
588 // the event flow that that platform provides.
589 WebKeyboardEvent event_down, event_char, event_up;
590 event_down.type = WebInputEvent::RawKeyDown;
591 event_down.modifiers = 0;
592 event_down.windowsKeyCode = code;
593 if (generate_char) {
594 event_down.text[0] = text;
595 event_down.unmodifiedText[0] = text;
596 }
597 event_down.setKeyIdentifierFromWindowsKeyCode();
598
599 if (args.size() >= 2 && (args[1].isObject() || args[1].isString()))
600 event_down.isSystemKey = ApplyKeyModifiers(&(args[1]), &event_down);
601
602 if (needs_shift_key_modifier)
603 event_down.modifiers |= WebInputEvent::ShiftKey;
604
605 // See if KeyLocation argument is given.
606 if (args.size() >= 3 && args[2].isNumber()) {
607 int location = args[2].ToInt32();
608 if (location == DOM_KEY_LOCATION_NUMPAD) {
609 event_down.modifiers |= WebInputEvent::IsKeyPad;
610 }
611 }
612
613 event_char = event_up = event_down;
614 event_up.type = WebInputEvent::KeyUp;
615 // EventSendingController.m forces a layout here, with at least one
616 // test (fast\forms\focus-control-to-page.html) relying on this.
617 webview()->layout();
618
619 // In the browser, if a keyboard event corresponds to an editor command,
620 // the command will be dispatched to the renderer just before dispatching
621 // the keyboard event, and then it will be executed in the
622 // RenderView::handleCurrentKeyboardEvent() method, which is called from
623 // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp.
624 // We just simulate the same behavior here.
625 std::string edit_command;
626 if (GetEditCommand(event_down, &edit_command))
627 shell_->delegate()->SetEditCommand(edit_command, "");
628
629 webview()->handleInputEvent(event_down);
630
631 shell_->delegate()->ClearEditCommand();
632
633 if (generate_char) {
634 event_char.type = WebInputEvent::Char;
635 event_char.keyIdentifier[0] = '\0';
636 webview()->handleInputEvent(event_char);
637 }
638
639 webview()->handleInputEvent(event_up);
640 }
641 }
642
643 void EventSendingController::dispatchMessage(
644 const CppArgumentList& args, CppVariant* result) {
645 result->SetNull();
646
647 #if defined(OS_WIN)
648 if (args.size() == 3) {
649 // Grab the message id to see if we need to dispatch it.
650 int msg = args[0].ToInt32();
651
652 // WebKit's version of this function stuffs a MSG struct and uses
653 // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
654 // doesn't need to receive the DeadChar and SysDeadChar messages.
655 if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
656 return;
657
658 webview()->layout();
659
660 unsigned long lparam = static_cast<unsigned long>(args[2].ToDouble());
661 webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(
662 NULL, msg, args[1].ToInt32(), lparam));
663 } else {
664 NOTREACHED() << L"Wrong number of arguments";
665 }
666 #endif
667 }
668
669 bool EventSendingController::NeedsShiftModifier(int key_code) {
670 // If code is an uppercase letter, assign a SHIFT key to
671 // event_down.modifier, this logic comes from
672 // WebKit/Tools/DumpRenderTree/Win/EventSender.cpp
673 if ((key_code & 0xFF) >= 'A' && (key_code & 0xFF) <= 'Z')
674 return true;
675 return false;
676 }
677
678 void EventSendingController::leapForward(
679 const CppArgumentList& args, CppVariant* result) {
680 result->SetNull();
681
682 if (args.size() <1 || !args[0].isNumber())
683 return;
684
685 int milliseconds = args[0].ToInt32();
686 if (drag_mode() && pressed_button_ == WebMouseEvent::ButtonLeft &&
687 !replaying_saved_events) {
688 SavedEvent saved_event;
689 saved_event.type = SavedEvent::LeapForward;
690 saved_event.milliseconds = milliseconds;
691 mouse_event_queue.push(saved_event);
692 } else {
693 DoLeapForward(milliseconds);
694 }
695 }
696
697 // static
698 void EventSendingController::DoLeapForward(int milliseconds) {
699 AdvanceEventTime(milliseconds);
700 }
701
702 // Apple's port of WebKit zooms by a factor of 1.2 (see
703 // WebKit/WebView/WebView.mm)
704 void EventSendingController::textZoomIn(
705 const CppArgumentList& args, CppVariant* result) {
706 webview()->setZoomLevel(true, webview()->zoomLevel() + 1);
707 result->SetNull();
708 }
709
710 void EventSendingController::textZoomOut(
711 const CppArgumentList& args, CppVariant* result) {
712 webview()->setZoomLevel(true, webview()->zoomLevel() - 1);
713 result->SetNull();
714 }
715
716 void EventSendingController::zoomPageIn(
717 const CppArgumentList& args, CppVariant* result) {
718 webview()->setZoomLevel(false, webview()->zoomLevel() + 1);
719 result->SetNull();
720 }
721
722 void EventSendingController::zoomPageOut(
723 const CppArgumentList& args, CppVariant* result) {
724 webview()->setZoomLevel(false, webview()->zoomLevel() - 1);
725 result->SetNull();
726 }
727
728 void EventSendingController::mouseScrollBy(const CppArgumentList& args,
729 CppVariant* result) {
730 handleMouseWheel(args, result, false);
731 }
732
733 void EventSendingController::continuousMouseScrollBy(
734 const CppArgumentList& args,
735 CppVariant* result) {
736 handleMouseWheel(args, result, true);
737 }
738
739 void EventSendingController::ReplaySavedEvents() {
740 replaying_saved_events = true;
741 while (!mouse_event_queue.empty()) {
742 SavedEvent e = mouse_event_queue.front();
743 mouse_event_queue.pop();
744
745 switch (e.type) {
746 case SavedEvent::MouseMove: {
747 WebMouseEvent event;
748 InitMouseEvent(WebInputEvent::MouseMove, pressed_button_,
749 e.pos, &event);
750 DoMouseMove(event);
751 break;
752 }
753 case SavedEvent::LeapForward:
754 DoLeapForward(e.milliseconds);
755 break;
756 case SavedEvent::MouseUp: {
757 WebMouseEvent event;
758 InitMouseEvent(WebInputEvent::MouseUp, e.button_type,
759 last_mouse_pos_, &event);
760 DoMouseUp(event);
761 break;
762 }
763 default:
764 NOTREACHED();
765 }
766 }
767
768 replaying_saved_events = false;
769 }
770
771 // Because actual context menu is implemented by the browser side,
772 // this function does only what LayoutTests are expecting:
773 // - Many test checks the count of items. So returning non-zero value
774 // makes sense.
775 // - Some test compares the count before and after some action. So
776 // changing the count based on flags also makes sense. This function
777 // is doing such for some flags.
778 // - Some test even checks actual string content. So providing it
779 // would be also helpful.
780 static std::vector<WebString>
781 MakeMenuItemStringsFor(const WebKit::WebContextMenuData* context_menu,
782 MockSpellCheck* spellcheck) {
783 // These constants are based on Safari's context menu because tests
784 // are made for it.
785 static const char* kNonEditableMenuStrings[] = {
786 "Back", "Reload Page", "Open in Dashbaord", "<separator>",
787 "View Source", "Save Page As", "Print Page", "Inspect Element",
788 0 };
789 static const char* kEditableMenuStrings[] = {
790 "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar",
791 "Substitutions, Transformations", "Font", "Speech",
792 "Paragraph Direction", "<separator>", 0 };
793
794 // This is possible because mouse events are cancelleable.
795 if (!context_menu)
796 return std::vector<WebString>();
797
798 std::vector<WebString> strings;
799
800 if (context_menu->isEditable) {
801 for (const char** item = kEditableMenuStrings; *item; ++item)
802 strings.push_back(WebString::fromUTF8(*item));
803 std::vector<string16> suggestions;
804 spellcheck->FillSuggestions(context_menu->misspelledWord, &suggestions);
805 for (size_t i = 0; i < suggestions.size(); ++i)
806 strings.push_back(WebString(suggestions[i]));
807 } else {
808 for (const char** item = kNonEditableMenuStrings; *item; ++item)
809 strings.push_back(WebString::fromUTF8(*item));
810 }
811
812 return strings;
813 }
814
815 void EventSendingController::contextClick(
816 const CppArgumentList& args, CppVariant* result) {
817 result->SetNull();
818
819 webview()->layout();
820
821 // Clears last context menu data because we need to know if the
822 // context menu be requested after following mouse events.
823 shell_->delegate()->ClearContextMenuData();
824
825 UpdateClickCountForButton(WebMouseEvent::ButtonRight);
826
827 // Generate right mouse down and up.
828
829 WebMouseEvent event;
830 pressed_button_ = WebMouseEvent::ButtonRight;
831 InitMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight,
832 last_mouse_pos_, &event);
833 webview()->handleInputEvent(event);
834
835 InitMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight,
836 last_mouse_pos_, &event);
837 webview()->handleInputEvent(event);
838
839 pressed_button_ = WebMouseEvent::ButtonNone;
840
841 result->Set(WebKit::WebBindings::makeStringArray(
842 MakeMenuItemStringsFor(
843 shell_->delegate()->last_context_menu_data(),
844 shell_->delegate()->mock_spellcheck())));
845
846 }
847
848 void EventSendingController::scheduleAsynchronousClick(
849 const CppArgumentList& args, CppVariant* result) {
850 result->SetNull();
851
852 MessageLoop::current()->PostTask(FROM_HERE,
853 method_factory_.NewRunnableMethod(&EventSendingController::mouseDown,
854 args, static_cast<CppVariant*>(NULL)));
855 MessageLoop::current()->PostTask(FROM_HERE,
856 method_factory_.NewRunnableMethod(&EventSendingController::mouseUp,
857 args, static_cast<CppVariant*>(NULL)));
858 }
859
860 void EventSendingController::beginDragWithFiles(
861 const CppArgumentList& args, CppVariant* result) {
862 current_drag_data.initialize();
863 std::vector<std::string> files = args[0].ToStringVector();
864 for (size_t i = 0; i < files.size(); ++i) {
865 std::wstring file = UTF8ToWide(files[i]);
866 FilePath file_path = FilePath::FromWStringHack(file);
867 file_util::AbsolutePath(&file_path);
868 current_drag_data.appendToFilenames(
869 webkit_glue::FilePathStringToWebString(file_path.value()));
870 }
871 current_drag_effects_allowed = WebKit::WebDragOperationCopy;
872
873 // Provide a drag source.
874 WebPoint client_point(last_mouse_pos_.x(), last_mouse_pos_.y());
875 WebPoint screen_point(last_mouse_pos_.x(), last_mouse_pos_.y());
876 webview()->dragTargetDragEnter(
877 current_drag_data, 0, client_point, screen_point,
878 current_drag_effects_allowed);
879
880 // dragMode saves events and then replays them later. We don't need/want that.
881 dragMode.Set(false);
882
883 // Make the rest of eventSender think a drag is in progress.
884 pressed_button_ = WebMouseEvent::ButtonLeft;
885
886 result->SetNull();
887 }
888
889 void EventSendingController::addTouchPoint(
890 const CppArgumentList& args, CppVariant* result) {
891 result->SetNull();
892
893 WebTouchPoint touch_point;
894 touch_point.state = WebTouchPoint::StatePressed;
895 touch_point.position = WebPoint(args[0].ToInt32(), args[1].ToInt32());
896 touch_point.screenPosition = touch_point.position;
897 touch_point.id = touch_points.size();
898 touch_points.push_back(touch_point);
899 }
900
901 void EventSendingController::clearTouchPoints(
902 const CppArgumentList& args, CppVariant* result) {
903 result->SetNull();
904
905 touch_points.clear();
906 }
907
908 void EventSendingController::releaseTouchPoint(
909 const CppArgumentList& args, CppVariant* result) {
910 result->SetNull();
911
912 const unsigned int index = args[0].ToInt32();
913 if (index >= touch_points.size()) {
914 NOTREACHED() << "Invalid touch point index";
915 }
916
917 WebTouchPoint* touch_point = &touch_points[index];
918 touch_point->state = WebTouchPoint::StateReleased;
919 }
920
921 void EventSendingController::setTouchModifier(
922 const CppArgumentList& args, CppVariant* result) {
923 result->SetNull();
924
925 int mask = 0;
926 const std::string key_name = args[0].ToString();
927 if (key_name == "shift") {
928 mask = WebInputEvent::ShiftKey;
929 } else if (key_name == "alt") {
930 mask = WebInputEvent::AltKey;
931 } else if (key_name == "ctrl") {
932 mask = WebInputEvent::ControlKey;
933 } else if (key_name == "meta") {
934 mask = WebInputEvent::MetaKey;
935 }
936
937 if (args[1].ToBoolean() == true) {
938 touch_modifiers |= mask;
939 } else {
940 touch_modifiers &= ~mask;
941 }
942 }
943
944 void EventSendingController::updateTouchPoint(
945 const CppArgumentList& args, CppVariant* result) {
946 result->SetNull();
947
948 const unsigned int index = args[0].ToInt32();
949 if (index >= touch_points.size()) {
950 NOTREACHED() << "Invalid touch point index";
951 }
952
953 WebPoint position(args[1].ToInt32(), args[2].ToInt32());
954
955 WebTouchPoint* touch_point = &touch_points[index];
956 touch_point->state = WebTouchPoint::StateMoved;
957 touch_point->position = position;
958 touch_point->screenPosition = position;
959 }
960
961 void EventSendingController::cancelTouchPoint(
962 const CppArgumentList& args, CppVariant* result) {
963 result->SetNull();
964
965 const unsigned int index = args[0].ToInt32();
966 if (index >= touch_points.size()) {
967 NOTREACHED() << "Invalid touch point index";
968 }
969
970 WebTouchPoint* touch_point = &touch_points[index];
971 touch_point->state = WebTouchPoint::StateCancelled;
972 }
973
974 void EventSendingController::SendCurrentTouchEvent(
975 const WebInputEvent::Type type) {
976 webview()->layout();
977
978 if (static_cast<unsigned int>(WebTouchEvent::touchPointsLengthCap) <=
979 touch_points.size()) {
980 NOTREACHED() << "Too many touch points for event";
981 }
982
983 WebTouchEvent touch_event;
984 touch_event.type = type;
985 touch_event.modifiers = touch_modifiers;
986 touch_event.timeStampSeconds = GetCurrentEventTimeSec();
987 touch_event.touchPointsLength = touch_points.size();
988 for (unsigned int i = 0; i < touch_points.size(); ++i) {
989 touch_event.touchPoints[i] = touch_points[i];
990 }
991 webview()->handleInputEvent(touch_event);
992
993 std::vector<WebTouchPoint>::iterator i = touch_points.begin();
994 while (i != touch_points.end()) {
995 WebTouchPoint* touch_point = &(*i);
996 if (touch_point->state == WebTouchPoint::StateReleased) {
997 i = touch_points.erase(i);
998 } else {
999 touch_point->state = WebTouchPoint::StateStationary;
1000 ++i;
1001 }
1002 }
1003 }
1004
1005 void EventSendingController::handleMouseWheel(const CppArgumentList& args,
1006 CppVariant* result,
1007 bool continuous) {
1008 result->SetNull();
1009
1010 if (args.size() < 2 || !args[0].isNumber() || !args[1].isNumber())
1011 return;
1012
1013 // Force a layout here just to make sure every position has been
1014 // determined before we send events (as well as all the other methods
1015 // that send an event do).
1016 webview()->layout();
1017
1018 int horizontal = args[0].ToInt32();
1019 int vertical = args[1].ToInt32();
1020
1021 WebMouseWheelEvent event;
1022 InitMouseEvent(WebInputEvent::MouseWheel, pressed_button_, last_mouse_pos_,
1023 &event);
1024 event.wheelTicksX = static_cast<float>(horizontal);
1025 event.wheelTicksY = static_cast<float>(vertical);
1026 event.deltaX = event.wheelTicksX;
1027 event.deltaY = event.wheelTicksY;
1028 if (continuous) {
1029 event.wheelTicksX /= kScrollbarPixelsPerTick;
1030 event.wheelTicksY /= kScrollbarPixelsPerTick;
1031 } else {
1032 event.deltaX *= kScrollbarPixelsPerTick;
1033 event.deltaY *= kScrollbarPixelsPerTick;
1034 }
1035 webview()->handleInputEvent(event);
1036 }
1037
1038 void EventSendingController::touchEnd(
1039 const CppArgumentList& args, CppVariant* result) {
1040 result->SetNull();
1041 SendCurrentTouchEvent(WebInputEvent::TouchEnd);
1042 }
1043
1044 void EventSendingController::touchMove(
1045 const CppArgumentList& args, CppVariant* result) {
1046 result->SetNull();
1047 SendCurrentTouchEvent(WebInputEvent::TouchMove);
1048 }
1049
1050 void EventSendingController::touchStart(
1051 const CppArgumentList& args, CppVariant* result) {
1052 result->SetNull();
1053 SendCurrentTouchEvent(WebInputEvent::TouchStart);
1054 }
1055
1056 void EventSendingController::touchCancel(
1057 const CppArgumentList& args, CppVariant* result) {
1058 result->SetNull();
1059 SendCurrentTouchEvent(WebInputEvent::TouchCancel);
1060 }
1061
1062 //
1063 // Unimplemented stubs
1064 //
1065
1066 void EventSendingController::enableDOMUIEventLogging(
1067 const CppArgumentList& args, CppVariant* result) {
1068 result->SetNull();
1069 }
1070
1071 void EventSendingController::fireKeyboardEventsToElement(
1072 const CppArgumentList& args, CppVariant* result) {
1073 result->SetNull();
1074 }
1075
1076 void EventSendingController::clearKillRing(
1077 const CppArgumentList& args, CppVariant* result) {
1078 result->SetNull();
1079 }
OLDNEW
« no previous file with comments | « webkit/tools/test_shell/event_sending_controller.h ('k') | webkit/tools/test_shell/plain_text_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698