2 * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "EventSendingController.h"
29 #include "InjectedBundle.h"
30 #include "InjectedBundlePage.h"
31 #include "JSEventSendingController.h"
32 #include "StringFunctions.h"
33 #include <WebKit2/WKBundle.h>
34 #include <WebKit2/WKBundleFrame.h>
35 #include <WebKit2/WKBundlePagePrivate.h>
36 #include <WebKit2/WKBundlePrivate.h>
37 #include <WebKit2/WKMutableDictionary.h>
38 #include <WebKit2/WKNumber.h>
42 static const float ZoomMultiplierRatio = 1.2f;
44 static bool operator==(const WKPoint& a, const WKPoint& b)
46 return a.x == b.x && a.y == b.y;
49 static WKEventModifiers parseModifier(JSStringRef modifier)
51 if (JSStringIsEqualToUTF8CString(modifier, "ctrlKey"))
52 return kWKEventModifiersControlKey;
53 if (JSStringIsEqualToUTF8CString(modifier, "shiftKey") || JSStringIsEqualToUTF8CString(modifier, "rangeSelectionKey"))
54 return kWKEventModifiersShiftKey;
55 if (JSStringIsEqualToUTF8CString(modifier, "altKey"))
56 return kWKEventModifiersAltKey;
57 if (JSStringIsEqualToUTF8CString(modifier, "metaKey") || JSStringIsEqualToUTF8CString(modifier, "addSelectionKey"))
58 return kWKEventModifiersMetaKey;
62 static unsigned arrayLength(JSContextRef context, JSObjectRef array)
64 JSRetainPtr<JSStringRef> lengthString(Adopt, JSStringCreateWithUTF8CString("length"));
65 JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0);
68 return static_cast<unsigned>(JSValueToNumber(context, lengthValue, 0));
71 static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue)
75 if (!JSValueIsObject(context, arrayValue))
77 JSObjectRef array = const_cast<JSObjectRef>(arrayValue);
78 unsigned length = arrayLength(context, array);
79 WKEventModifiers modifiers = 0;
80 for (unsigned i = 0; i < length; i++) {
81 JSValueRef exception = 0;
82 JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
85 JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, &exception));
88 modifiers |= parseModifier(string.get());
93 PassRefPtr<EventSendingController> EventSendingController::create()
95 return adoptRef(new EventSendingController);
98 EventSendingController::EventSendingController()
104 , m_clickButton(kWKEventMouseButtonNoButton)
108 EventSendingController::~EventSendingController()
112 JSClassRef EventSendingController::wrapperClass()
114 return JSEventSendingController::eventSendingControllerClass();
117 void EventSendingController::mouseDown(int button, JSValueRef modifierArray)
119 WKBundlePageRef page = InjectedBundle::shared().page()->page();
120 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
121 JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
122 WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
123 updateClickCount(button);
124 WKBundlePageSimulateMouseDown(page, button, m_position, m_clickCount, modifiers, m_time);
127 void EventSendingController::mouseUp(int button, JSValueRef modifierArray)
129 WKBundlePageRef page = InjectedBundle::shared().page()->page();
130 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
131 JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
132 WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
133 updateClickCount(button);
134 WKBundlePageSimulateMouseUp(page, button, m_position, m_clickCount, modifiers, m_time);
137 void EventSendingController::mouseMoveTo(int x, int y)
141 WKBundlePageSimulateMouseMotion(InjectedBundle::shared().page()->page(), m_position, m_time);
144 void EventSendingController::leapForward(int milliseconds)
146 m_time += milliseconds / 1000.0;
149 void EventSendingController::updateClickCount(WKEventMouseButton button)
151 if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
153 m_clickTime = m_time;
158 m_clickTime = m_time;
159 m_clickPosition = m_position;
160 m_clickButton = button;
163 void EventSendingController::textZoomIn()
165 // Ensure page zoom is reset.
166 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
168 double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
169 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
172 void EventSendingController::textZoomOut()
174 // Ensure page zoom is reset.
175 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
177 double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
178 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
181 void EventSendingController::zoomPageIn()
183 // Ensure text zoom is reset.
184 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
186 double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
187 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
190 void EventSendingController::zoomPageOut()
192 // Ensure text zoom is reset.
193 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
195 double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
196 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
199 void EventSendingController::scalePageBy(double scale, double x, double y)
201 WKPoint origin = { x, y };
202 WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin);
207 void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
209 setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
212 void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, int location)
214 WKBundlePageRef page = InjectedBundle::shared().page()->page();
215 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
216 JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
217 WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
219 WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
220 WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
222 WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
223 WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("KeyDown"));
224 WKDictionaryAddItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
226 WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
227 WKDictionaryAddItem(EventSenderMessageBody.get(), keyKey.get(), toWK(key).get());
229 WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
230 WKRetainPtr<WKUInt64Ref> modifiersRef = WKUInt64Create(modifiers);
231 WKDictionaryAddItem(EventSenderMessageBody.get(), modifiersKey.get(), modifiersRef.get());
233 WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
234 WKRetainPtr<WKUInt64Ref> locationRef = WKUInt64Create(location);
235 WKDictionaryAddItem(EventSenderMessageBody.get(), locationKey.get(), locationRef.get());
237 WKRetainPtr<WKStringRef> timestampKey = adoptWK(WKStringCreateWithUTF8CString("Timestamp"));
238 WKRetainPtr<WKDoubleRef> timeRef = WKDoubleCreate(m_time);
239 WKDictionaryAddItem(EventSenderMessageBody.get(), timestampKey.get(), timeRef.get());
241 WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);