EventSender.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. /*
  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) 2011, 2012 Samsung Electronics
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  19. * its contributors may be used to endorse or promote products derived
  20. * from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  23. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  26. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  27. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #include "config.h"
  34. #include "EventSender.h"
  35. #include "DumpRenderTree.h"
  36. #include "DumpRenderTreeChrome.h"
  37. #include "IntPoint.h"
  38. #include "JSStringUtils.h"
  39. #include "NotImplemented.h"
  40. #include "PlatformEvent.h"
  41. #include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
  42. #include "ewk_private.h"
  43. #include <EWebKit.h>
  44. #include <Ecore_Input.h>
  45. #include <JavaScriptCore/JSObjectRef.h>
  46. #include <JavaScriptCore/JSRetainPtr.h>
  47. #include <JavaScriptCore/JSStringRef.h>
  48. #include <JavaScriptCore/OpaqueJSString.h>
  49. #include <wtf/ASCIICType.h>
  50. #include <wtf/Platform.h>
  51. #include <wtf/text/CString.h>
  52. static bool gDragMode;
  53. static int gTimeOffset = 0;
  54. static int gLastMousePositionX;
  55. static int gLastMousePositionY;
  56. static int gLastClickPositionX;
  57. static int gLastClickPositionY;
  58. static int gLastClickTimeOffset;
  59. static int gLastClickButton;
  60. static int gButtonCurrentlyDown;
  61. static int gClickCount;
  62. static const float zoomMultiplierRatio = 1.2f;
  63. // Key event location code defined in DOM Level 3.
  64. enum KeyLocationCode {
  65. DomKeyLocationStandard,
  66. DomKeyLocationLeft,
  67. DomKeyLocationRight,
  68. DomKeyLocationNumpad
  69. };
  70. enum EvasKeyModifier {
  71. EvasKeyModifierNone = 0,
  72. EvasKeyModifierControl = 1 << 0,
  73. EvasKeyModifierShift = 1 << 1,
  74. EvasKeyModifierAlt = 1 << 2,
  75. EvasKeyModifierMeta = 1 << 3
  76. };
  77. enum EvasMouseButton {
  78. EvasMouseButtonNone,
  79. EvasMouseButtonLeft,
  80. EvasMouseButtonMiddle,
  81. EvasMouseButtonRight
  82. };
  83. enum EvasMouseEvent {
  84. EvasMouseEventNone = 0,
  85. EvasMouseEventDown = 1 << 0,
  86. EvasMouseEventUp = 1 << 1,
  87. EvasMouseEventMove = 1 << 2,
  88. EvasMouseEventScrollUp = 1 << 3,
  89. EvasMouseEventScrollDown = 1 << 4,
  90. EvasMouseEventScrollLeft = 1 << 5,
  91. EvasMouseEventScrollRight = 1 << 6,
  92. EvasMouseEventClick = EvasMouseEventMove | EvasMouseEventDown | EvasMouseEventUp,
  93. };
  94. enum ZoomEvent {
  95. ZoomIn,
  96. ZoomOut
  97. };
  98. enum EventQueueStrategy {
  99. FeedQueuedEvents,
  100. DoNotFeedQueuedEvents
  101. };
  102. struct KeyEventInfo {
  103. KeyEventInfo(const CString& keyName, unsigned modifiers, const CString& keyString = CString())
  104. : keyName(keyName)
  105. , keyString(keyString)
  106. , modifiers(modifiers)
  107. {
  108. }
  109. const CString keyName;
  110. const CString keyString;
  111. unsigned modifiers;
  112. };
  113. struct MouseEventInfo {
  114. MouseEventInfo(EvasMouseEvent event, unsigned modifiers = EvasKeyModifierNone, EvasMouseButton button = EvasMouseButtonNone, int horizontalDelta = 0, int verticalDelta = 0)
  115. : event(event)
  116. , modifiers(modifiers)
  117. , button(button)
  118. , horizontalDelta(horizontalDelta)
  119. , verticalDelta(verticalDelta)
  120. {
  121. }
  122. EvasMouseEvent event;
  123. unsigned modifiers;
  124. EvasMouseButton button;
  125. int horizontalDelta;
  126. int verticalDelta;
  127. };
  128. struct DelayedEvent {
  129. DelayedEvent(MouseEventInfo* eventInfo, unsigned long delay = 0)
  130. : eventInfo(eventInfo)
  131. , delay(delay)
  132. {
  133. }
  134. MouseEventInfo* eventInfo;
  135. unsigned long delay;
  136. };
  137. struct TouchEventInfo {
  138. TouchEventInfo(unsigned id, Ewk_Touch_Point_Type state, const WebCore::IntPoint& point)
  139. : state(state)
  140. , point(point)
  141. , id(id)
  142. {
  143. }
  144. unsigned id;
  145. Ewk_Touch_Point_Type state;
  146. WebCore::IntPoint point;
  147. };
  148. static unsigned touchModifiers;
  149. WTF::Vector<TouchEventInfo>& touchPointList()
  150. {
  151. DEFINE_STATIC_LOCAL(WTF::Vector<TouchEventInfo>, staticTouchPointList, ());
  152. return staticTouchPointList;
  153. }
  154. WTF::Vector<DelayedEvent>& delayedEventQueue()
  155. {
  156. DEFINE_STATIC_LOCAL(WTF::Vector<DelayedEvent>, staticDelayedEventQueue, ());
  157. return staticDelayedEventQueue;
  158. }
  159. static void feedOrQueueMouseEvent(MouseEventInfo*, EventQueueStrategy);
  160. static void feedMouseEvent(MouseEventInfo*);
  161. static void feedQueuedMouseEvents();
  162. static void setEvasModifiers(Evas* evas, unsigned modifiers)
  163. {
  164. static const char* modifierNames[] = { "Control", "Shift", "Alt", "Super" };
  165. for (unsigned modifier = 0; modifier < 4; ++modifier) {
  166. if (modifiers & (1 << modifier))
  167. evas_key_modifier_on(evas, modifierNames[modifier]);
  168. else
  169. evas_key_modifier_off(evas, modifierNames[modifier]);
  170. }
  171. }
  172. static EvasMouseButton translateMouseButtonNumber(int eventSenderButtonNumber)
  173. {
  174. static const EvasMouseButton translationTable[] = {
  175. EvasMouseButtonLeft,
  176. EvasMouseButtonMiddle,
  177. EvasMouseButtonRight,
  178. EvasMouseButtonMiddle // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
  179. };
  180. static const unsigned translationTableSize = sizeof(translationTable) / sizeof(translationTable[0]);
  181. if (eventSenderButtonNumber < translationTableSize)
  182. return translationTable[eventSenderButtonNumber];
  183. return EvasMouseButtonLeft;
  184. }
  185. static Eina_Bool sendClick(void*)
  186. {
  187. MouseEventInfo* eventInfo = new MouseEventInfo(EvasMouseEventClick, EvasKeyModifierNone, EvasMouseButtonLeft);
  188. feedOrQueueMouseEvent(eventInfo, FeedQueuedEvents);
  189. return ECORE_CALLBACK_CANCEL;
  190. }
  191. static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  192. {
  193. ecore_idler_add(sendClick, 0);
  194. return JSValueMakeUndefined(context);
  195. }
  196. static void updateClickCount(int button)
  197. {
  198. if (gLastClickPositionX != gLastMousePositionX
  199. || gLastClickPositionY != gLastMousePositionY
  200. || gLastClickButton != button
  201. || gTimeOffset - gLastClickTimeOffset >= 1)
  202. gClickCount = 1;
  203. else
  204. gClickCount++;
  205. }
  206. static EvasKeyModifier modifierFromJSValue(JSContextRef context, const JSValueRef value)
  207. {
  208. JSRetainPtr<JSStringRef> jsKeyValue(Adopt, JSValueToStringCopy(context, value, 0));
  209. if (equals(jsKeyValue, "ctrlKey") || equals(jsKeyValue, "addSelectionKey"))
  210. return EvasKeyModifierControl;
  211. if (equals(jsKeyValue, "shiftKey") || equals(jsKeyValue, "rangeSelectionKey"))
  212. return EvasKeyModifierShift;
  213. if (equals(jsKeyValue, "altKey"))
  214. return EvasKeyModifierAlt;
  215. if (equals(jsKeyValue, "metaKey"))
  216. return EvasKeyModifierMeta;
  217. return EvasKeyModifierNone;
  218. }
  219. static unsigned modifiersFromJSValue(JSContextRef context, const JSValueRef modifiers)
  220. {
  221. // The value may either be a string with a single modifier or an array of modifiers.
  222. if (JSValueIsString(context, modifiers))
  223. return modifierFromJSValue(context, modifiers);
  224. JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
  225. if (!modifiersArray)
  226. return EvasKeyModifierNone;
  227. unsigned modifier = EvasKeyModifierNone;
  228. JSRetainPtr<JSStringRef> lengthProperty(Adopt, JSStringCreateWithUTF8CString("length"));
  229. int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty.get(), 0), 0);
  230. for (int i = 0; i < modifiersCount; ++i)
  231. modifier |= modifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0));
  232. return modifier;
  233. }
  234. static JSValueRef getMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
  235. {
  236. Ewk_Context_Menu_Item* item = static_cast<Ewk_Context_Menu_Item*>(JSObjectGetPrivate(object));
  237. CString label;
  238. if (ewk_context_menu_item_type_get(item) == EWK_SEPARATOR_TYPE)
  239. label = "<separator>";
  240. else
  241. label = ewk_context_menu_item_title_get(item);
  242. return JSValueMakeString(context, JSStringCreateWithUTF8CString(label.data()));
  243. }
  244. static bool setMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
  245. {
  246. return true;
  247. }
  248. static JSValueRef menuItemClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  249. {
  250. Ewk_Context_Menu_Item* item = static_cast<Ewk_Context_Menu_Item*>(JSObjectGetPrivate(thisObject));
  251. ewk_context_menu_item_select(ewk_context_menu_item_parent_get(item), item);
  252. return JSValueMakeUndefined(context);
  253. }
  254. static JSStaticFunction staticMenuItemFunctions[] = {
  255. { "click", menuItemClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  256. { 0, 0, 0 }
  257. };
  258. static JSStaticValue staticMenuItemValues[] = {
  259. { "title", getMenuItemTitleCallback, setMenuItemTitleCallback, kJSPropertyAttributeNone },
  260. { 0, 0, 0, 0 }
  261. };
  262. static JSClassRef getMenuItemClass()
  263. {
  264. static JSClassRef menuItemClass = 0;
  265. if (!menuItemClass) {
  266. JSClassDefinition classDefinition = {
  267. 0, 0, 0, 0, 0, 0,
  268. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  269. classDefinition.staticFunctions = staticMenuItemFunctions;
  270. classDefinition.staticValues = staticMenuItemValues;
  271. menuItemClass = JSClassCreate(&classDefinition);
  272. }
  273. return menuItemClass;
  274. }
  275. static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  276. {
  277. Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
  278. if (!view)
  279. return JSValueMakeUndefined(context);
  280. Evas* evas = evas_object_evas_get(view);
  281. if (!evas)
  282. return JSValueMakeUndefined(context);
  283. Evas_Event_Mouse_Down mouseDown;
  284. mouseDown.button = 3;
  285. mouseDown.output.x = gLastMousePositionX;
  286. mouseDown.output.y = gLastMousePositionY;
  287. mouseDown.canvas.x = gLastMousePositionX;
  288. mouseDown.canvas.y = gLastMousePositionY;
  289. mouseDown.data = 0;
  290. mouseDown.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
  291. mouseDown.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
  292. mouseDown.flags = EVAS_BUTTON_NONE;
  293. mouseDown.timestamp = ecore_loop_time_get();
  294. mouseDown.event_flags = EVAS_EVENT_FLAG_NONE;
  295. mouseDown.dev = 0;
  296. ewk_view_context_menu_forward_event(view, &mouseDown);
  297. Ewk_Context_Menu* ewkMenu = ewk_view_context_menu_get(view);
  298. JSValueRef valueRef = JSObjectMakeArray(context, 0, 0, 0);
  299. if (ewkMenu) {
  300. const Eina_List* ewkMenuItems = ewk_context_menu_item_list_get(ewkMenu);
  301. JSValueRef arrayValues[eina_list_count(ewkMenuItems)];
  302. const Eina_List* listIterator;
  303. void* data;
  304. int index = 0;
  305. EINA_LIST_FOREACH(ewkMenuItems, listIterator, data)
  306. arrayValues[index++] = JSObjectMake(context, getMenuItemClass(), data);
  307. if (index)
  308. valueRef = JSObjectMakeArray(context, index - 1, arrayValues, 0);
  309. }
  310. return valueRef;
  311. }
  312. static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  313. {
  314. int button = 0;
  315. if (argumentCount == 1) {
  316. button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  317. if (exception && *exception)
  318. return JSValueMakeUndefined(context);
  319. }
  320. button = translateMouseButtonNumber(button);
  321. // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb.
  322. if (gButtonCurrentlyDown == button)
  323. return JSValueMakeUndefined(context);
  324. updateClickCount(button);
  325. unsigned modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
  326. MouseEventInfo* eventInfo = new MouseEventInfo(EvasMouseEventDown, modifiers, static_cast<EvasMouseButton>(button));
  327. feedOrQueueMouseEvent(eventInfo, FeedQueuedEvents);
  328. gButtonCurrentlyDown = button;
  329. return JSValueMakeUndefined(context);
  330. }
  331. static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  332. {
  333. int button = 0;
  334. if (argumentCount == 1) {
  335. button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  336. if (exception && *exception)
  337. return JSValueMakeUndefined(context);
  338. }
  339. gLastClickPositionX = gLastMousePositionX;
  340. gLastClickPositionY = gLastMousePositionY;
  341. gLastClickButton = gButtonCurrentlyDown;
  342. gLastClickTimeOffset = gTimeOffset;
  343. gButtonCurrentlyDown = 0;
  344. unsigned modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
  345. MouseEventInfo* eventInfo = new MouseEventInfo(EvasMouseEventUp, modifiers, translateMouseButtonNumber(button));
  346. feedOrQueueMouseEvent(eventInfo, FeedQueuedEvents);
  347. return JSValueMakeUndefined(context);
  348. }
  349. static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  350. {
  351. if (argumentCount < 2)
  352. return JSValueMakeUndefined(context);
  353. gLastMousePositionX = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  354. if (exception && *exception)
  355. return JSValueMakeUndefined(context);
  356. gLastMousePositionY = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
  357. if (exception && *exception)
  358. return JSValueMakeUndefined(context);
  359. MouseEventInfo* eventInfo = new MouseEventInfo(EvasMouseEventMove);
  360. feedOrQueueMouseEvent(eventInfo, DoNotFeedQueuedEvents);
  361. return JSValueMakeUndefined(context);
  362. }
  363. static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  364. {
  365. if (argumentCount > 0) {
  366. const unsigned long leapForwardDelay = JSValueToNumber(context, arguments[0], exception);
  367. if (delayedEventQueue().isEmpty())
  368. delayedEventQueue().append(DelayedEvent(0, leapForwardDelay));
  369. else
  370. delayedEventQueue().last().delay = leapForwardDelay;
  371. gTimeOffset += leapForwardDelay;
  372. }
  373. return JSValueMakeUndefined(context);
  374. }
  375. static EvasMouseEvent evasMouseEventFromHorizontalAndVerticalOffsets(int horizontalOffset, int verticalOffset)
  376. {
  377. unsigned mouseEvent = 0;
  378. if (verticalOffset > 0)
  379. mouseEvent |= EvasMouseEventScrollUp;
  380. else if (verticalOffset < 0)
  381. mouseEvent |= EvasMouseEventScrollDown;
  382. if (horizontalOffset > 0)
  383. mouseEvent |= EvasMouseEventScrollRight;
  384. else if (horizontalOffset < 0)
  385. mouseEvent |= EvasMouseEventScrollLeft;
  386. return static_cast<EvasMouseEvent>(mouseEvent);
  387. }
  388. static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  389. {
  390. if (argumentCount < 2)
  391. return JSValueMakeUndefined(context);
  392. // We need to invert scrolling values since in EFL negative z value means that
  393. // canvas is scrolling down
  394. const int horizontal = -(static_cast<int>(JSValueToNumber(context, arguments[0], exception)));
  395. if (exception && *exception)
  396. return JSValueMakeUndefined(context);
  397. const int vertical = -(static_cast<int>(JSValueToNumber(context, arguments[1], exception)));
  398. if (exception && *exception)
  399. return JSValueMakeUndefined(context);
  400. MouseEventInfo* eventInfo = new MouseEventInfo(evasMouseEventFromHorizontalAndVerticalOffsets(horizontal, vertical), EvasKeyModifierNone, EvasMouseButtonNone, horizontal, vertical);
  401. feedOrQueueMouseEvent(eventInfo, FeedQueuedEvents);
  402. return JSValueMakeUndefined(context);
  403. }
  404. static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  405. {
  406. return JSValueMakeUndefined(context);
  407. }
  408. static KeyEventInfo* keyPadNameFromJSValue(JSStringRef character, unsigned modifiers)
  409. {
  410. if (equals(character, "leftArrow"))
  411. return new KeyEventInfo("KP_Left", modifiers);
  412. if (equals(character, "rightArrow"))
  413. return new KeyEventInfo("KP_Right", modifiers);
  414. if (equals(character, "upArrow"))
  415. return new KeyEventInfo("KP_Up", modifiers);
  416. if (equals(character, "downArrow"))
  417. return new KeyEventInfo("KP_Down", modifiers);
  418. if (equals(character, "pageUp"))
  419. return new KeyEventInfo("KP_Prior", modifiers);
  420. if (equals(character, "pageDown"))
  421. return new KeyEventInfo("KP_Next", modifiers);
  422. if (equals(character, "home"))
  423. return new KeyEventInfo("KP_Home", modifiers);
  424. if (equals(character, "end"))
  425. return new KeyEventInfo("KP_End", modifiers);
  426. if (equals(character, "insert"))
  427. return new KeyEventInfo("KP_Insert", modifiers);
  428. if (equals(character, "delete"))
  429. return new KeyEventInfo("KP_Delete", modifiers);
  430. return new KeyEventInfo(character->string().utf8(), modifiers, character->string().utf8());
  431. }
  432. static KeyEventInfo* keyNameFromJSValue(JSStringRef character, unsigned modifiers)
  433. {
  434. if (equals(character, "leftArrow"))
  435. return new KeyEventInfo("Left", modifiers);
  436. if (equals(character, "rightArrow"))
  437. return new KeyEventInfo("Right", modifiers);
  438. if (equals(character, "upArrow"))
  439. return new KeyEventInfo("Up", modifiers);
  440. if (equals(character, "downArrow"))
  441. return new KeyEventInfo("Down", modifiers);
  442. if (equals(character, "pageUp"))
  443. return new KeyEventInfo("Prior", modifiers);
  444. if (equals(character, "pageDown"))
  445. return new KeyEventInfo("Next", modifiers);
  446. if (equals(character, "home"))
  447. return new KeyEventInfo("Home", modifiers);
  448. if (equals(character, "end"))
  449. return new KeyEventInfo("End", modifiers);
  450. if (equals(character, "insert"))
  451. return new KeyEventInfo("Insert", modifiers);
  452. if (equals(character, "delete"))
  453. return new KeyEventInfo("Delete", modifiers);
  454. if (equals(character, "printScreen"))
  455. return new KeyEventInfo("Print", modifiers);
  456. if (equals(character, "menu"))
  457. return new KeyEventInfo("Menu", modifiers);
  458. if (equals(character, "leftControl"))
  459. return new KeyEventInfo("Control_L", modifiers);
  460. if (equals(character, "rightControl"))
  461. return new KeyEventInfo("Control_R", modifiers);
  462. if (equals(character, "leftShift"))
  463. return new KeyEventInfo("Shift_L", modifiers);
  464. if (equals(character, "rightShift"))
  465. return new KeyEventInfo("Shift_R", modifiers);
  466. if (equals(character, "leftAlt"))
  467. return new KeyEventInfo("Alt_L", modifiers);
  468. if (equals(character, "rightAlt"))
  469. return new KeyEventInfo("Alt_R", modifiers);
  470. if (equals(character, "F1"))
  471. return new KeyEventInfo("F1", modifiers);
  472. if (equals(character, "F2"))
  473. return new KeyEventInfo("F2", modifiers);
  474. if (equals(character, "F3"))
  475. return new KeyEventInfo("F3", modifiers);
  476. if (equals(character, "F4"))
  477. return new KeyEventInfo("F4", modifiers);
  478. if (equals(character, "F5"))
  479. return new KeyEventInfo("F5", modifiers);
  480. if (equals(character, "F6"))
  481. return new KeyEventInfo("F6", modifiers);
  482. if (equals(character, "F7"))
  483. return new KeyEventInfo("F7", modifiers);
  484. if (equals(character, "F8"))
  485. return new KeyEventInfo("F8", modifiers);
  486. if (equals(character, "F9"))
  487. return new KeyEventInfo("F9", modifiers);
  488. if (equals(character, "F10"))
  489. return new KeyEventInfo("F10", modifiers);
  490. if (equals(character, "F11"))
  491. return new KeyEventInfo("F11", modifiers);
  492. if (equals(character, "F12"))
  493. return new KeyEventInfo("F12", modifiers);
  494. int charCode = JSStringGetCharactersPtr(character)[0];
  495. if (charCode == '\n' || charCode == '\r')
  496. return new KeyEventInfo("Return", modifiers, "\r");
  497. if (charCode == '\t')
  498. return new KeyEventInfo("Tab", modifiers, "\t");
  499. if (charCode == '\x8')
  500. return new KeyEventInfo("BackSpace", modifiers, "\x8");
  501. if (charCode == ' ')
  502. return new KeyEventInfo("space", modifiers, " ");
  503. if (charCode == '\x1B')
  504. return new KeyEventInfo("Escape", modifiers, "\x1B");
  505. if ((character->length() == 1) && (charCode >= 'A' && charCode <= 'Z'))
  506. modifiers |= EvasKeyModifierShift;
  507. return new KeyEventInfo(character->string().utf8(), modifiers, character->string().utf8());
  508. }
  509. static KeyEventInfo* createKeyEventInfo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  510. {
  511. if (!ewk_frame_view_get(browser->mainFrame()))
  512. return 0;
  513. if (argumentCount < 1)
  514. return 0;
  515. // handle location argument.
  516. int location = DomKeyLocationStandard;
  517. if (argumentCount > 2)
  518. location = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
  519. JSRetainPtr<JSStringRef> character(Adopt, JSValueToStringCopy(context, arguments[0], exception));
  520. if (exception && *exception)
  521. return 0;
  522. unsigned modifiers = EvasKeyModifierNone;
  523. if (argumentCount >= 2)
  524. modifiers = modifiersFromJSValue(context, arguments[1]);
  525. return (location == DomKeyLocationNumpad) ? keyPadNameFromJSValue(character.get(), modifiers) : keyNameFromJSValue(character.get(), modifiers);
  526. }
  527. static void sendKeyDown(Evas* evas, KeyEventInfo* keyEventInfo)
  528. {
  529. if (!keyEventInfo)
  530. return;
  531. const char* keyName = keyEventInfo->keyName.data();
  532. const char* keyString = keyEventInfo->keyString.data();
  533. unsigned modifiers = keyEventInfo->modifiers;
  534. DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame());
  535. ASSERT(evas);
  536. int eventIndex = 0;
  537. // Mimic the emacs ctrl-o binding by inserting a paragraph
  538. // separator and then putting the cursor back to its original
  539. // position. Allows us to pass emacs-ctrl-o.html
  540. if ((modifiers & EvasKeyModifierControl) && !strcmp(keyName, "o")) {
  541. setEvasModifiers(evas, EvasKeyModifierNone);
  542. evas_event_feed_key_down(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
  543. evas_event_feed_key_up(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
  544. modifiers = EvasKeyModifierNone;
  545. keyName = "Left";
  546. keyString = 0;
  547. }
  548. setEvasModifiers(evas, modifiers);
  549. evas_event_feed_key_down(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
  550. evas_event_feed_key_up(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
  551. setEvasModifiers(evas, EvasKeyModifierNone);
  552. DumpRenderTreeSupportEfl::deliverAllMutationsIfNecessary();
  553. }
  554. static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  555. {
  556. OwnPtr<KeyEventInfo> keyEventInfo = adoptPtr(createKeyEventInfo(context, argumentCount, arguments, exception));
  557. sendKeyDown(evas_object_evas_get(browser->mainFrame()), keyEventInfo.get());
  558. return JSValueMakeUndefined(context);
  559. }
  560. static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  561. {
  562. if (argumentCount < 3)
  563. return JSValueMakeUndefined(context);
  564. Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
  565. if (!view)
  566. return JSValueMakeUndefined(context);
  567. float scaleFactor = JSValueToNumber(context, arguments[0], exception);
  568. float x = JSValueToNumber(context, arguments[1], exception);
  569. float y = JSValueToNumber(context, arguments[2], exception);
  570. ewk_view_scale_set(view, scaleFactor, x, y);
  571. return JSValueMakeUndefined(context);
  572. }
  573. static void textZoom(ZoomEvent zoomEvent)
  574. {
  575. Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
  576. if (!view)
  577. return;
  578. float zoomFactor = ewk_view_text_zoom_get(view);
  579. if (zoomEvent == ZoomIn)
  580. zoomFactor *= zoomMultiplierRatio;
  581. else
  582. zoomFactor /= zoomMultiplierRatio;
  583. ewk_view_text_zoom_set(view, zoomFactor);
  584. }
  585. static void pageZoom(ZoomEvent zoomEvent)
  586. {
  587. Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
  588. if (!view)
  589. return;
  590. float zoomFactor = ewk_view_page_zoom_get(view);
  591. if (zoomEvent == ZoomIn)
  592. zoomFactor *= zoomMultiplierRatio;
  593. else
  594. zoomFactor /= zoomMultiplierRatio;
  595. ewk_view_page_zoom_set(view, zoomFactor);
  596. }
  597. static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  598. {
  599. textZoom(ZoomIn);
  600. return JSValueMakeUndefined(context);
  601. }
  602. static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  603. {
  604. textZoom(ZoomOut);
  605. return JSValueMakeUndefined(context);
  606. }
  607. static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  608. {
  609. pageZoom(ZoomIn);
  610. return JSValueMakeUndefined(context);
  611. }
  612. static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  613. {
  614. pageZoom(ZoomOut);
  615. return JSValueMakeUndefined(context);
  616. }
  617. static Eina_Bool sendAsynchronousKeyDown(void* userData)
  618. {
  619. OwnPtr<KeyEventInfo> keyEventInfo = adoptPtr(static_cast<KeyEventInfo*>(userData));
  620. sendKeyDown(evas_object_evas_get(browser->mainFrame()), keyEventInfo.get());
  621. return ECORE_CALLBACK_CANCEL;
  622. }
  623. static JSValueRef scheduleAsynchronousKeyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  624. {
  625. KeyEventInfo* keyEventInfo = createKeyEventInfo(context, argumentCount, arguments, exception);
  626. ecore_idler_add(sendAsynchronousKeyDown, static_cast<void*>(keyEventInfo));
  627. return JSValueMakeUndefined(context);
  628. }
  629. static void sendTouchEvent(Ewk_Touch_Event_Type type)
  630. {
  631. Eina_List* eventList = 0;
  632. for (unsigned i = 0; i < touchPointList().size(); ++i) {
  633. Ewk_Touch_Point* event = new Ewk_Touch_Point;
  634. WebCore::IntPoint point = touchPointList().at(i).point;
  635. event->id = touchPointList().at(i).id;
  636. event->x = point.x();
  637. event->y = point.y();
  638. event->state = touchPointList().at(i).state;
  639. eventList = eina_list_append(eventList, event);
  640. }
  641. ewk_frame_feed_touch_event(browser->mainFrame(), type, eventList, touchModifiers);
  642. void* listData;
  643. EINA_LIST_FREE(eventList, listData) {
  644. Ewk_Touch_Point* event = static_cast<Ewk_Touch_Point*>(listData);
  645. delete event;
  646. }
  647. for (unsigned i = 0; i < touchPointList().size(); ) {
  648. if (touchPointList().at(i).state == EWK_TOUCH_POINT_RELEASED)
  649. touchPointList().remove(i);
  650. else {
  651. touchPointList().at(i).state = EWK_TOUCH_POINT_STATIONARY;
  652. ++i;
  653. }
  654. }
  655. }
  656. static JSValueRef addTouchPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  657. {
  658. if (argumentCount != 2)
  659. return JSValueMakeUndefined(context);
  660. int x = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  661. ASSERT(!exception || !*exception);
  662. int y = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
  663. ASSERT(!exception || !*exception);
  664. const WebCore::IntPoint point(x, y);
  665. const unsigned id = touchPointList().isEmpty() ? 0 : touchPointList().last().id + 1;
  666. TouchEventInfo eventInfo(id, EWK_TOUCH_POINT_PRESSED, point);
  667. touchPointList().append(eventInfo);
  668. return JSValueMakeUndefined(context);
  669. }
  670. static JSValueRef touchStartCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  671. {
  672. sendTouchEvent(EWK_TOUCH_START);
  673. return JSValueMakeUndefined(context);
  674. }
  675. static JSValueRef updateTouchPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  676. {
  677. if (argumentCount != 3)
  678. return JSValueMakeUndefined(context);
  679. int index = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  680. ASSERT(!exception || !*exception);
  681. int x = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
  682. ASSERT(!exception || !*exception);
  683. int y = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
  684. ASSERT(!exception || !*exception);
  685. if (index < 0 || index >= touchPointList().size())
  686. return JSValueMakeUndefined(context);
  687. WebCore::IntPoint& point = touchPointList().at(index).point;
  688. point.setX(x);
  689. point.setY(y);
  690. touchPointList().at(index).state = EWK_TOUCH_POINT_MOVED;
  691. return JSValueMakeUndefined(context);
  692. }
  693. static JSValueRef touchMoveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  694. {
  695. sendTouchEvent(EWK_TOUCH_MOVE);
  696. return JSValueMakeUndefined(context);
  697. }
  698. static JSValueRef cancelTouchPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  699. {
  700. if (argumentCount != 1)
  701. return JSValueMakeUndefined(context);
  702. int index = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  703. ASSERT(!exception || !*exception);
  704. if (index < 0 || index >= touchPointList().size())
  705. return JSValueMakeUndefined(context);
  706. touchPointList().at(index).state = EWK_TOUCH_POINT_CANCELLED;
  707. return JSValueMakeUndefined(context);
  708. }
  709. static JSValueRef touchCancelCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  710. {
  711. sendTouchEvent(EWK_TOUCH_CANCEL);
  712. return JSValueMakeUndefined(context);
  713. }
  714. static JSValueRef releaseTouchPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  715. {
  716. if (argumentCount != 1)
  717. return JSValueMakeUndefined(context);
  718. int index = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
  719. ASSERT(!exception || !*exception);
  720. if (index < 0 || index >= touchPointList().size())
  721. return JSValueMakeUndefined(context);
  722. touchPointList().at(index).state = EWK_TOUCH_POINT_RELEASED;
  723. return JSValueMakeUndefined(context);
  724. }
  725. static JSValueRef touchEndCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  726. {
  727. sendTouchEvent(EWK_TOUCH_END);
  728. touchModifiers = 0;
  729. return JSValueMakeUndefined(context);
  730. }
  731. static JSValueRef clearTouchPointsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  732. {
  733. touchPointList().clear();
  734. return JSValueMakeUndefined(context);
  735. }
  736. static JSValueRef setTouchModifierCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
  737. {
  738. if (argumentCount != 2)
  739. return JSValueMakeUndefined(context);
  740. JSRetainPtr<JSStringRef> jsModifier(Adopt, JSValueToStringCopy(context, arguments[0], exception));
  741. unsigned mask = 0;
  742. if (equals(jsModifier, "alt"))
  743. mask |= ECORE_EVENT_MODIFIER_ALT;
  744. else if (equals(jsModifier, "ctrl"))
  745. mask |= ECORE_EVENT_MODIFIER_CTRL;
  746. else if (equals(jsModifier, "meta"))
  747. mask |= ECORE_EVENT_MODIFIER_WIN;
  748. else if (equals(jsModifier, "shift"))
  749. mask |= ECORE_EVENT_MODIFIER_SHIFT;
  750. if (JSValueToBoolean(context, arguments[1]))
  751. touchModifiers |= mask;
  752. else
  753. touchModifiers &= ~mask;
  754. return JSValueMakeUndefined(context);
  755. }
  756. static JSStaticFunction staticFunctions[] = {
  757. { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  758. { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  759. { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  760. { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  761. { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  762. { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  763. { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  764. { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  765. { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  766. { "scheduleAsynchronousKeyDown", scheduleAsynchronousKeyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  767. { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  768. { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  769. { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  770. { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  771. { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  772. { "addTouchPoint", addTouchPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  773. { "touchStart", touchStartCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  774. { "updateTouchPoint", updateTouchPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  775. { "touchMove", touchMoveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  776. { "releaseTouchPoint", releaseTouchPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  777. { "touchEnd", touchEndCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  778. { "cancelTouchPoint", cancelTouchPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  779. { "touchCancel", touchCancelCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  780. { "clearTouchPoints", clearTouchPointsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  781. { "setTouchModifier", setTouchModifierCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  782. { 0, 0, 0 }
  783. };
  784. static JSStaticValue staticValues[] = {
  785. { 0, 0, 0, 0 }
  786. };
  787. static JSClassRef getClass(JSContextRef context)
  788. {
  789. static JSClassRef eventSenderClass = 0;
  790. if (!eventSenderClass) {
  791. JSClassDefinition classDefinition = {
  792. 0, 0, 0, 0, 0, 0,
  793. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  794. classDefinition.staticFunctions = staticFunctions;
  795. classDefinition.staticValues = staticValues;
  796. eventSenderClass = JSClassCreate(&classDefinition);
  797. }
  798. return eventSenderClass;
  799. }
  800. JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
  801. {
  802. if (isTopFrame) {
  803. gDragMode = true;
  804. // Fly forward in time one second when the main frame loads. This will
  805. // ensure that when a test begins clicking in the same location as
  806. // a previous test, those clicks won't be interpreted as continuations
  807. // of the previous test's click sequences.
  808. gTimeOffset += 1000;
  809. gLastMousePositionX = gLastMousePositionY = 0;
  810. gLastClickPositionX = gLastClickPositionY = 0;
  811. gLastClickTimeOffset = 0;
  812. gLastClickButton = 0;
  813. gButtonCurrentlyDown = 0;
  814. gClickCount = 0;
  815. }
  816. return JSObjectMake(context, getClass(context), 0);
  817. }
  818. static void feedOrQueueMouseEvent(MouseEventInfo* eventInfo, EventQueueStrategy strategy)
  819. {
  820. if (!delayedEventQueue().isEmpty()) {
  821. if (delayedEventQueue().last().eventInfo)
  822. delayedEventQueue().append(DelayedEvent(eventInfo));
  823. else
  824. delayedEventQueue().last().eventInfo = eventInfo;
  825. if (strategy == FeedQueuedEvents)
  826. feedQueuedMouseEvents();
  827. } else
  828. feedMouseEvent(eventInfo);
  829. }
  830. static void feedMouseEvent(MouseEventInfo* eventInfo)
  831. {
  832. if (!eventInfo)
  833. return;
  834. unsigned timeStamp = 0;
  835. Evas_Object* mainFrame = browser->mainFrame();
  836. Evas* evas = evas_object_evas_get(mainFrame);
  837. EvasMouseEvent event = eventInfo->event;
  838. setEvasModifiers(evas, eventInfo->modifiers);
  839. Evas_Button_Flags flags = EVAS_BUTTON_NONE;
  840. // FIXME: We need to pass additional information with our events, so that
  841. // we could construct correct PlatformWheelEvent. At the moment, max number
  842. // of clicks is 3
  843. if (gClickCount == 3)
  844. flags = EVAS_BUTTON_TRIPLE_CLICK;
  845. else if (gClickCount == 2)
  846. flags = EVAS_BUTTON_DOUBLE_CLICK;
  847. if (event & EvasMouseEventMove)
  848. evas_event_feed_mouse_move(evas, gLastMousePositionX, gLastMousePositionY, timeStamp++, 0);
  849. if (event & EvasMouseEventDown)
  850. evas_event_feed_mouse_down(evas, eventInfo->button, flags, timeStamp++, 0);
  851. if (event & EvasMouseEventUp)
  852. evas_event_feed_mouse_up(evas, eventInfo->button, flags, timeStamp++, 0);
  853. if (event & EvasMouseEventScrollLeft | event & EvasMouseEventScrollRight)
  854. evas_event_feed_mouse_wheel(evas, 1, eventInfo->horizontalDelta, timeStamp, 0);
  855. if (event & EvasMouseEventScrollUp | event & EvasMouseEventScrollDown)
  856. evas_event_feed_mouse_wheel(evas, 0, eventInfo->verticalDelta, timeStamp, 0);
  857. setEvasModifiers(evas, EvasKeyModifierNone);
  858. delete eventInfo;
  859. }
  860. static void feedQueuedMouseEvents()
  861. {
  862. WTF::Vector<DelayedEvent>::const_iterator it = delayedEventQueue().begin();
  863. for (; it != delayedEventQueue().end(); it++) {
  864. DelayedEvent delayedEvent = *it;
  865. if (delayedEvent.delay)
  866. usleep(delayedEvent.delay * 1000);
  867. feedMouseEvent(delayedEvent.eventInfo);
  868. }
  869. delayedEventQueue().clear();
  870. }