2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
4 * Copyright (C) 2009 Holger Hans Peter Freyther
5 * Copyright (C) 2010 Igalia S.L.
6 * Copyright (C) 2011 ProFUSION Embedded Systems
7 * Copyright (C) 2012 Samsung Electronics
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "EventSenderProxy.h"
34 #include "NotImplemented.h"
35 #include "PlatformWebView.h"
36 #include "TestController.h"
39 #include <Ecore_Evas.h>
41 #include <wtf/StdLibExtras.h>
42 #include <wtf/text/CString.h>
43 #include <wtf/text/WTFString.h>
47 static const char* modifierNames[] = { "Shift", "Control", "Alt", "Meta" };
51 WTREventTypeMouseDown,
53 WTREventTypeMouseMove,
54 WTREventTypeMouseScrollBy,
55 WTREventTypeLeapForward
58 enum EvasMouseButton {
59 EvasMouseButtonNone = 0,
61 EvasMouseButtonMiddle,
65 // Key event location code defined in DOM Level 3.
66 enum KeyLocationCode {
67 DOMKeyLocationStandard = 0x00,
68 DOMKeyLocationLeft = 0x01,
69 DOMKeyLocationRight = 0x02,
70 DOMKeyLocationNumpad = 0x03
74 WTREventType eventType;
76 WKEventModifiers modifiers;
82 : eventType(WTREventTypeNone)
91 WTREvent(WTREventType eventType, unsigned delay, WKEventModifiers modifiers, int button)
92 : eventType(eventType)
94 , modifiers(modifiers)
102 struct KeyEventInfo : public RefCounted<KeyEventInfo> {
103 KeyEventInfo(const CString& keyName, const CString& keyString)
105 , keyString(keyString)
109 const CString keyName;
110 const CString keyString;
113 static unsigned evasMouseButton(unsigned button)
115 // The common case involves converting from a WKEventMouseButton (which
116 // starts at -1) to an EvasMouseButton (which a starts at 0). The special
117 // case for button 3 exists because of fast/events/mouse-click-events.html,
118 // which tests whether a 4th mouse button behaves as the middle one.
119 if (button <= kWKEventMouseButtonRightButton)
121 if (button == kWKEventMouseButtonRightButton + 1)
122 return EvasMouseButtonMiddle;
123 return EvasMouseButtonNone;
126 static void setEvasModifiers(Evas* evas, WKEventModifiers wkModifiers)
128 for (unsigned modifier = 0; modifier < (sizeof(modifierNames) / sizeof(char*)); ++modifier) {
129 if (wkModifiers & (1 << modifier))
130 evas_key_modifier_on(evas, modifierNames[modifier]);
132 evas_key_modifier_off(evas, modifierNames[modifier]);
136 static void dispatchMouseDownEvent(Evas* evas, unsigned button, WKEventModifiers wkModifiers, int clickCount)
138 Evas_Button_Flags buttonFlags = EVAS_BUTTON_NONE;
140 buttonFlags = EVAS_BUTTON_TRIPLE_CLICK;
141 else if (clickCount == 2)
142 buttonFlags = EVAS_BUTTON_DOUBLE_CLICK;
144 setEvasModifiers(evas, wkModifiers);
145 evas_event_feed_mouse_down(evas, button, buttonFlags, 0, 0);
146 setEvasModifiers(evas, 0);
149 static void dispatchMouseUpEvent(Evas* evas, unsigned button, WKEventModifiers wkModifiers)
151 setEvasModifiers(evas, wkModifiers);
152 evas_event_feed_mouse_up(evas, button, EVAS_BUTTON_NONE, 0, 0);
153 setEvasModifiers(evas, 0);
156 static void dispatchMouseMoveEvent(Evas* evas, int x, int y)
158 evas_event_feed_mouse_move(evas, x, y, 0, 0);
161 static void dispatchMouseScrollByEvent(Evas* evas, int horizontal, int vertical)
164 evas_event_feed_mouse_wheel(evas, 1, horizontal, 0, 0);
167 evas_event_feed_mouse_wheel(evas, 0, vertical, 0, 0);
170 static const PassRefPtr<KeyEventInfo> keyPadName(WKStringRef keyRef)
172 if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
173 return adoptRef(new KeyEventInfo("KP_Left", ""));
174 if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
175 return adoptRef(new KeyEventInfo("KP_Right", ""));
176 if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
177 return adoptRef(new KeyEventInfo("KP_Up", ""));
178 if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
179 return adoptRef(new KeyEventInfo("KP_Down", ""));
180 if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
181 return adoptRef(new KeyEventInfo("KP_Prior", ""));
182 if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
183 return adoptRef(new KeyEventInfo("KP_Next", ""));
184 if (WKStringIsEqualToUTF8CString(keyRef, "home"))
185 return adoptRef(new KeyEventInfo("KP_Home", ""));
186 if (WKStringIsEqualToUTF8CString(keyRef, "end"))
187 return adoptRef(new KeyEventInfo("KP_End", ""));
188 if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
189 return adoptRef(new KeyEventInfo("KP_Insert", ""));
190 if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
191 return adoptRef(new KeyEventInfo("KP_Delete", ""));
193 size_t bufferSize = WKStringGetMaximumUTF8CStringSize(keyRef);
194 auto buffer = std::make_unique<char[]>(bufferSize);
195 WKStringGetUTF8CString(keyRef, buffer.get(), bufferSize);
196 return adoptRef(new KeyEventInfo(buffer.get(), buffer.get()));
199 static const PassRefPtr<KeyEventInfo> keyName(WKStringRef keyRef)
201 if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
202 return adoptRef(new KeyEventInfo("Left", ""));
203 if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
204 return adoptRef(new KeyEventInfo("Right", ""));
205 if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
206 return adoptRef(new KeyEventInfo("Up", ""));
207 if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
208 return adoptRef(new KeyEventInfo("Down", ""));
209 if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
210 return adoptRef(new KeyEventInfo("Prior", ""));
211 if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
212 return adoptRef(new KeyEventInfo("Next", ""));
213 if (WKStringIsEqualToUTF8CString(keyRef, "home"))
214 return adoptRef(new KeyEventInfo("Home", ""));
215 if (WKStringIsEqualToUTF8CString(keyRef, "end"))
216 return adoptRef(new KeyEventInfo("End", ""));
217 if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
218 return adoptRef(new KeyEventInfo("Insert", ""));
219 if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
220 return adoptRef(new KeyEventInfo("Delete", ""));
221 if (WKStringIsEqualToUTF8CString(keyRef, "printScreen"))
222 return adoptRef(new KeyEventInfo("Print", ""));
223 if (WKStringIsEqualToUTF8CString(keyRef, "menu"))
224 return adoptRef(new KeyEventInfo("Menu", ""));
225 if (WKStringIsEqualToUTF8CString(keyRef, "leftControl"))
226 return adoptRef(new KeyEventInfo("Control_L", ""));
227 if (WKStringIsEqualToUTF8CString(keyRef, "rightControl"))
228 return adoptRef(new KeyEventInfo("Control_R", ""));
229 if (WKStringIsEqualToUTF8CString(keyRef, "leftShift"))
230 return adoptRef(new KeyEventInfo("Shift_L", ""));
231 if (WKStringIsEqualToUTF8CString(keyRef, "rightShift"))
232 return adoptRef(new KeyEventInfo("Shift_R", ""));
233 if (WKStringIsEqualToUTF8CString(keyRef, "leftAlt"))
234 return adoptRef(new KeyEventInfo("Alt_L", ""));
235 if (WKStringIsEqualToUTF8CString(keyRef, "rightAlt"))
236 return adoptRef(new KeyEventInfo("Alt_R", ""));
237 if (WKStringIsEqualToUTF8CString(keyRef, "F1"))
238 return adoptRef(new KeyEventInfo("F1", ""));
239 if (WKStringIsEqualToUTF8CString(keyRef, "F2"))
240 return adoptRef(new KeyEventInfo("F2", ""));
241 if (WKStringIsEqualToUTF8CString(keyRef, "F3"))
242 return adoptRef(new KeyEventInfo("F3", ""));
243 if (WKStringIsEqualToUTF8CString(keyRef, "F4"))
244 return adoptRef(new KeyEventInfo("F4", ""));
245 if (WKStringIsEqualToUTF8CString(keyRef, "F5"))
246 return adoptRef(new KeyEventInfo("F5", ""));
247 if (WKStringIsEqualToUTF8CString(keyRef, "F6"))
248 return adoptRef(new KeyEventInfo("F6", ""));
249 if (WKStringIsEqualToUTF8CString(keyRef, "F7"))
250 return adoptRef(new KeyEventInfo("F7", ""));
251 if (WKStringIsEqualToUTF8CString(keyRef, "F8"))
252 return adoptRef(new KeyEventInfo("F8", ""));
253 if (WKStringIsEqualToUTF8CString(keyRef, "F9"))
254 return adoptRef(new KeyEventInfo("F9", ""));
255 if (WKStringIsEqualToUTF8CString(keyRef, "F10"))
256 return adoptRef(new KeyEventInfo("F10", ""));
257 if (WKStringIsEqualToUTF8CString(keyRef, "F11"))
258 return adoptRef(new KeyEventInfo("F11", ""));
259 if (WKStringIsEqualToUTF8CString(keyRef, "F12"))
260 return adoptRef(new KeyEventInfo("F12", ""));
262 size_t bufferSize = WKStringGetMaximumUTF8CStringSize(keyRef);
263 auto buffer = std::make_unique<char[]>(bufferSize);
264 WKStringGetUTF8CString(keyRef, buffer.get(), bufferSize);
265 char charCode = buffer.get()[0];
267 if (charCode == '\n' || charCode == '\r')
268 return adoptRef(new KeyEventInfo("Return", "\r"));
269 if (charCode == '\t')
270 return adoptRef(new KeyEventInfo("Tab", "\t"));
271 if (charCode == '\x8')
272 return adoptRef(new KeyEventInfo("BackSpace", "\x8"));
274 return adoptRef(new KeyEventInfo("space", " "));
276 return adoptRef(new KeyEventInfo(buffer.get(), buffer.get()));
279 EventSenderProxy::EventSenderProxy(TestController* testController)
280 : m_testController(testController)
282 , m_leftMouseButtonDown(false)
285 , m_clickButton(kWKEventMouseButtonNoButton)
286 , m_mouseButton(kWKEventMouseButtonNoButton)
287 #if ENABLE(TOUCH_EVENTS)
293 EventSenderProxy::~EventSenderProxy()
295 #if ENABLE(TOUCH_EVENTS)
300 void EventSenderProxy::updateClickCountForButton(int button)
302 if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
304 m_clickTime = m_time;
309 m_clickTime = m_time;
310 m_clickPosition = m_position;
311 m_clickButton = button;
314 void EventSenderProxy::dispatchEvent(const WTREvent& event)
316 Evas* evas = evas_object_evas_get(m_testController->mainWebView()->platformView());
318 if (event.eventType == WTREventTypeMouseDown)
319 dispatchMouseDownEvent(evas, event.button, event.modifiers, m_clickCount);
320 else if (event.eventType == WTREventTypeMouseUp)
321 dispatchMouseUpEvent(evas, event.button, event.modifiers);
322 else if (event.eventType == WTREventTypeMouseMove)
323 dispatchMouseMoveEvent(evas, static_cast<int>(m_position.x), static_cast<int>(m_position.y));
324 else if (event.eventType == WTREventTypeMouseScrollBy)
325 dispatchMouseScrollByEvent(evas, event.horizontal, event.vertical);
328 void EventSenderProxy::replaySavedEvents()
330 while (!m_eventQueue.isEmpty()) {
331 WTREvent event = m_eventQueue.takeFirst();
333 usleep(event.delay * 1000);
335 dispatchEvent(event);
339 void EventSenderProxy::sendOrQueueEvent(const WTREvent& event)
341 if (m_eventQueue.isEmpty() || !m_eventQueue.last().delay) {
342 dispatchEvent(event);
346 m_eventQueue.append(event);
350 void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
352 if (m_mouseButton == button)
355 m_mouseButton = button;
356 updateClickCountForButton(button);
358 sendOrQueueEvent(WTREvent(WTREventTypeMouseDown, 0, wkModifiers, evasMouseButton(button)));
361 void EventSenderProxy::mouseUp(unsigned button, WKEventModifiers wkModifiers)
363 sendOrQueueEvent(WTREvent(WTREventTypeMouseUp, 0, wkModifiers, evasMouseButton(button)));
365 if (m_mouseButton == button)
366 m_mouseButton = kWKEventMouseButtonNoButton;
368 m_clickPosition = m_position;
369 m_clickTime = currentEventTime();
372 void EventSenderProxy::mouseMoveTo(double x, double y)
377 sendOrQueueEvent(WTREvent(WTREventTypeMouseMove, 0, 0, kWKEventMouseButtonNoButton));
380 void EventSenderProxy::mouseScrollBy(int horizontal, int vertical)
382 WTREvent event(WTREventTypeMouseScrollBy, 0, 0, kWKEventMouseButtonNoButton);
383 // We need to invert scrolling values since in EFL negative z value means that
384 // canvas is scrolling down
385 event.horizontal = -horizontal;
386 event.vertical = -vertical;
387 sendOrQueueEvent(event);
390 void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, bool paged)
395 void EventSenderProxy::mouseScrollByWithWheelAndMomentumPhases(int x, int y, int /*phase*/, int /*momentum*/)
397 // EFL does not have the concept of wheel gesture phases or momentum. Just relay to
398 // the mouse wheel handler.
402 void EventSenderProxy::leapForward(int milliseconds)
404 if (m_eventQueue.isEmpty())
405 m_eventQueue.append(WTREvent(WTREventTypeLeapForward, milliseconds, 0, kWKEventMouseButtonNoButton));
407 m_time += milliseconds / 1000.0;
410 void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers wkModifiers, unsigned location)
412 const RefPtr<KeyEventInfo> keyEventInfo = (location == DOMKeyLocationNumpad) ? keyPadName(keyRef) : keyName(keyRef);
416 const char* keyName = keyEventInfo->keyName.data();
417 const char* keyString = keyEventInfo->keyString.data();
419 // Enforce 'Shift' modifier for caps.
420 if ((strlen(keyName) == 1) && (keyName[0] >= 'A' && keyName[0] <= 'Z'))
421 wkModifiers |= kWKEventModifiersShiftKey;
423 Evas* evas = evas_object_evas_get(m_testController->mainWebView()->platformView());
426 // Mimic the emacs ctrl-o binding by inserting a paragraph
427 // separator and then putting the cursor back to its original
428 // position. Allows us to pass emacs-ctrl-o.html
429 if ((wkModifiers & kWKEventModifiersControlKey) && !strcmp(keyName, "o")) {
430 setEvasModifiers(evas, 0);
431 evas_event_feed_key_down(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
432 evas_event_feed_key_up(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
438 setEvasModifiers(evas, wkModifiers);
439 evas_event_feed_key_down(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
440 evas_event_feed_key_up(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
441 setEvasModifiers(evas, 0);
444 #if ENABLE(TOUCH_EVENTS)
445 void EventSenderProxy::sendTouchEvent(Ewk_Touch_Event_Type eventType)
447 ASSERT(m_touchPoints);
449 Evas_Object* ewkView = m_testController->mainWebView()->platformView();
450 ewk_view_feed_touch_event(ewkView, eventType, m_touchPoints, evas_key_modifier_get(evas_object_evas_get(ewkView)));
455 EINA_LIST_FOREACH_SAFE(m_touchPoints, list, listNext, data) {
456 Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(data);
459 if ((touchPoint->state == EVAS_TOUCH_POINT_UP) || (touchPoint->state == EVAS_TOUCH_POINT_CANCEL)) {
461 m_touchPoints = eina_list_remove_list(m_touchPoints, list);
463 touchPoint->state = EVAS_TOUCH_POINT_STILL;
467 void EventSenderProxy::addTouchPoint(int x, int y)
471 Eina_List* last = eina_list_last(m_touchPoints);
472 Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_data_get(last));
475 id = touchPoint->id + 1;
478 Ewk_Touch_Point* touchPoint = new Ewk_Touch_Point;
482 touchPoint->state = EVAS_TOUCH_POINT_DOWN;
484 m_touchPoints = eina_list_append(m_touchPoints, touchPoint);
487 void EventSenderProxy::updateTouchPoint(int index, int x, int y)
489 ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
491 Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
496 touchPoint->state = EVAS_TOUCH_POINT_MOVE;
499 void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable)
501 Evas_Object* ewkView = m_testController->mainWebView()->platformView();
503 for (unsigned index = 0; index < (sizeof(modifierNames) / sizeof(char*)); ++index) {
504 if (modifier & (1 << index)) {
506 evas_key_modifier_on(evas_object_evas_get(ewkView), modifierNames[index]);
508 evas_key_modifier_off(evas_object_evas_get(ewkView), modifierNames[index]);
513 void EventSenderProxy::touchStart()
515 sendTouchEvent(EWK_TOUCH_START);
518 void EventSenderProxy::touchMove()
520 sendTouchEvent(EWK_TOUCH_MOVE);
523 void EventSenderProxy::touchEnd()
525 sendTouchEvent(EWK_TOUCH_END);
528 void EventSenderProxy::touchCancel()
530 sendTouchEvent(EWK_TOUCH_CANCEL);
533 void EventSenderProxy::clearTouchPoints()
536 EINA_LIST_FREE(m_touchPoints, data)
537 delete static_cast<Ewk_Touch_Point*>(data);
540 void EventSenderProxy::releaseTouchPoint(int index)
542 ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
544 Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
547 touchPoint->state = EVAS_TOUCH_POINT_UP;
550 void EventSenderProxy::cancelTouchPoint(int index)
552 ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
554 Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
557 touchPoint->state = EVAS_TOUCH_POINT_CANCEL;
560 void EventSenderProxy::setTouchPointRadius(int radiusX, int radiusY)