7565885d88f95dc167da6d14ca8d0282e587af04
[WebKit-https.git] / Source / WebKit / chromium / src / WebInputEventConversion.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
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.
29  */
30
31 #include "config.h"
32 #include "WebInputEventConversion.h"
33
34 #include "EventNames.h"
35 #include "KeyboardCodes.h"
36 #include "KeyboardEvent.h"
37 #include "MouseEvent.h"
38 #include "PlatformKeyboardEvent.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformWheelEvent.h"
41 #include "ScrollView.h"
42 #include "Touch.h"
43 #include "TouchEvent.h"
44 #include "TouchList.h"
45 #include "WebInputEvent.h"
46 #include "WheelEvent.h"
47 #include "Widget.h"
48
49 using namespace WebCore;
50
51 namespace WebKit {
52
53 static const double millisPerSecond = 1000.0;
54
55 // MakePlatformMouseEvent -----------------------------------------------------
56
57 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e)
58 {
59     // FIXME: widget is always toplevel, unless it's a popup.  We may be able
60     // to get rid of this once we abstract popups into a WebKit API.
61     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
62     m_globalPosition = IntPoint(e.globalX, e.globalY);
63     m_button = static_cast<MouseButton>(e.button);
64     m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
65     m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
66     m_altKey = (e.modifiers & WebInputEvent::AltKey);
67     m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
68     m_modifierFlags = e.modifiers;
69     m_timestamp = e.timeStampSeconds;
70     m_clickCount = e.clickCount;
71
72     switch (e.type) {
73     case WebInputEvent::MouseMove:
74     case WebInputEvent::MouseLeave:  // synthesize a move event
75         m_eventType = MouseEventMoved;
76         break;
77
78     case WebInputEvent::MouseDown:
79         m_eventType = MouseEventPressed;
80         break;
81
82     case WebInputEvent::MouseUp:
83         m_eventType = MouseEventReleased;
84         break;
85
86     default:
87         ASSERT_NOT_REACHED();
88     }
89 }
90
91 // PlatformWheelEventBuilder --------------------------------------------------
92
93 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e)
94 {
95     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
96     m_globalPosition = IntPoint(e.globalX, e.globalY);
97     m_deltaX = e.deltaX;
98     m_deltaY = e.deltaY;
99     m_wheelTicksX = e.wheelTicksX;
100     m_wheelTicksY = e.wheelTicksY;
101     m_isAccepted = false;
102     m_granularity = e.scrollByPage ?
103         ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
104     m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
105     m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
106     m_altKey = (e.modifiers & WebInputEvent::AltKey);
107     m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
108 #if OS(DARWIN)
109     m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas;
110     m_phase = static_cast<WebCore::PlatformWheelEventPhase>(e.phase);
111     m_momentumPhase = static_cast<WebCore::PlatformWheelEventPhase>(e.momentumPhase);
112     m_timestamp = e.timeStampSeconds;
113 #endif
114 }
115
116 // PlatformGestureEventBuilder --------------------------------------------------
117
118 #if ENABLE(GESTURE_EVENTS)
119 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e)
120 {
121     switch (e.type) {
122     case WebInputEvent::GestureScrollBegin:
123         m_type = PlatformGestureEvent::ScrollBeginType;
124         break;
125     case WebInputEvent::GestureScrollEnd:
126         m_type = PlatformGestureEvent::ScrollEndType;
127         break;
128     case WebInputEvent::GestureTap:
129         m_type = PlatformGestureEvent::TapType;
130         break;
131     default:
132         ASSERT_NOT_REACHED();
133     }
134     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
135     m_globalPosition = IntPoint(e.globalX, e.globalY);
136     m_timestamp = e.timeStampSeconds;
137     m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
138     m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
139     m_altKey = (e.modifiers & WebInputEvent::AltKey);
140     m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
141 }
142 #endif
143
144 // MakePlatformKeyboardEvent --------------------------------------------------
145
146 static inline PlatformKeyboardEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type)
147 {
148     switch (type) {
149     case WebInputEvent::KeyUp:
150         return PlatformKeyboardEvent::KeyUp;
151     case WebInputEvent::KeyDown:
152         return PlatformKeyboardEvent::KeyDown;
153     case WebInputEvent::RawKeyDown:
154         return PlatformKeyboardEvent::RawKeyDown;
155     case WebInputEvent::Char:
156         return PlatformKeyboardEvent::Char;
157     default:
158         ASSERT_NOT_REACHED();
159     }
160     return PlatformKeyboardEvent::KeyDown;
161 }
162
163 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e)
164 {
165     m_type = toPlatformKeyboardEventType(e.type);
166     m_text = String(e.text);
167     m_unmodifiedText = String(e.unmodifiedText);
168     m_keyIdentifier = String(e.keyIdentifier);
169     m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat);
170     m_windowsVirtualKeyCode = e.windowsKeyCode;
171     m_nativeVirtualKeyCode = e.nativeKeyCode;
172     m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad);
173     m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
174     m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
175     m_altKey = (e.modifiers & WebInputEvent::AltKey);
176     m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
177     m_isSystemKey = e.isSystemKey;
178 }
179
180 void PlatformKeyboardEventBuilder::setKeyType(Type type)
181 {
182     // According to the behavior of Webkit in Windows platform,
183     // we need to convert KeyDown to RawKeydown and Char events
184     // See WebKit/WebKit/Win/WebView.cpp
185     ASSERT(m_type == KeyDown);
186     ASSERT(type == RawKeyDown || type == Char);
187     m_type = type;
188
189     if (type == RawKeyDown) {
190         m_text = String();
191         m_unmodifiedText = String();
192     } else {
193         m_keyIdentifier = String();
194         m_windowsVirtualKeyCode = 0;
195     }
196 }
197
198 // Please refer to bug http://b/issue?id=961192, which talks about Webkit
199 // keyboard event handling changes. It also mentions the list of keys
200 // which don't have associated character events.
201 bool PlatformKeyboardEventBuilder::isCharacterKey() const
202 {
203     switch (windowsVirtualKeyCode()) {
204     case VKEY_BACK:
205     case VKEY_ESCAPE:
206         return false;
207     }
208     return true;
209 }
210
211 #if ENABLE(TOUCH_EVENTS)
212 static inline TouchEventType toPlatformTouchEventType(const WebInputEvent::Type type)
213 {
214     switch (type) {
215     case WebInputEvent::TouchStart:
216         return TouchStart;
217     case WebInputEvent::TouchMove:
218         return TouchMove;
219     case WebInputEvent::TouchEnd:
220         return TouchEnd;
221     case WebInputEvent::TouchCancel:
222         return TouchCancel;
223     default:
224         ASSERT_NOT_REACHED();
225     }
226     return TouchStart;
227 }
228
229 static inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
230 {
231     switch (state) {
232     case WebTouchPoint::StateReleased:
233         return PlatformTouchPoint::TouchReleased;
234     case WebTouchPoint::StatePressed:
235         return PlatformTouchPoint::TouchPressed;
236     case WebTouchPoint::StateMoved:
237         return PlatformTouchPoint::TouchMoved;
238     case WebTouchPoint::StateStationary:
239         return PlatformTouchPoint::TouchStationary;
240     case WebTouchPoint::StateCancelled:
241         return PlatformTouchPoint::TouchCancelled;
242     case WebTouchPoint::StateUndefined:
243         ASSERT_NOT_REACHED();
244     }
245     return PlatformTouchPoint::TouchReleased;
246 }
247
248 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point)
249 {
250     m_id = point.id;
251     m_state = toPlatformTouchPointState(point.state);
252     m_pos = widget->convertFromContainingWindow(point.position);
253     m_screenPos = point.screenPosition;
254     m_radiusY = point.radiusY;
255     m_radiusX = point.radiusX;
256     m_rotationAngle = point.rotationAngle;
257     m_force = point.force;
258 }
259
260 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event)
261 {
262     m_type = toPlatformTouchEventType(event.type);
263     m_ctrlKey = event.modifiers & WebInputEvent::ControlKey;
264     m_altKey = event.modifiers & WebInputEvent::AltKey;
265     m_shiftKey = event.modifiers & WebInputEvent::ShiftKey;
266     m_metaKey = event.modifiers & WebInputEvent::MetaKey;
267     m_timestamp = event.timeStampSeconds;
268
269     for (unsigned i = 0; i < event.touchesLength; ++i)
270         m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touches[i]));
271 }
272 #endif
273
274 static int getWebInputModifiers(const UIEventWithKeyState& event)
275 {
276     int modifiers = 0;
277     if (event.ctrlKey())
278         modifiers |= WebInputEvent::ControlKey;
279     if (event.shiftKey())
280         modifiers |= WebInputEvent::ShiftKey;
281     if (event.altKey())
282         modifiers |= WebInputEvent::AltKey;
283     if (event.metaKey())
284         modifiers |= WebInputEvent::MetaKey;
285     return modifiers;
286 }
287
288 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const MouseEvent& event)
289 {
290     if (event.type() == eventNames().mousemoveEvent)
291         type = WebInputEvent::MouseMove;
292     else if (event.type() == eventNames().mouseoutEvent)
293         type = WebInputEvent::MouseLeave;
294     else if (event.type() == eventNames().mouseoverEvent)
295         type = WebInputEvent::MouseEnter;
296     else if (event.type() == eventNames().mousedownEvent)
297         type = WebInputEvent::MouseDown;
298     else if (event.type() == eventNames().mouseupEvent)
299         type = WebInputEvent::MouseUp;
300     else if (event.type() == eventNames().contextmenuEvent)
301         type = WebInputEvent::ContextMenu;
302     else
303         return; // Skip all other mouse events.
304     timeStampSeconds = event.timeStamp() / millisPerSecond;
305     switch (event.button()) {
306     case LeftButton:
307         button = WebMouseEvent::ButtonLeft;
308         break;
309     case MiddleButton:
310         button = WebMouseEvent::ButtonMiddle;
311         break;
312     case RightButton:
313         button = WebMouseEvent::ButtonRight;
314         break;
315     }
316     modifiers = getWebInputModifiers(event);
317     if (event.buttonDown()) {
318         switch (event.button()) {
319         case LeftButton:
320             modifiers |= WebInputEvent::LeftButtonDown;
321             break;
322         case MiddleButton:
323             modifiers |= WebInputEvent::MiddleButtonDown;
324             break;
325         case RightButton:
326             modifiers |= WebInputEvent::RightButtonDown;
327             break;
328         }
329     }
330     ScrollView* view = widget->parent();
331     IntPoint p = view->contentsToWindow(
332         IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
333     globalX = event.screenX();
334     globalY = event.screenY();
335     windowX = p.x();
336     windowY = p.y();
337     x = event.absoluteLocation().x() - widget->location().x();
338     y = event.absoluteLocation().y() - widget->location().y();
339     clickCount = event.detail();
340 }
341
342 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const WheelEvent& event)
343 {
344     if (event.type() != eventNames().mousewheelEvent)
345         return;
346     type = WebInputEvent::MouseWheel;
347     timeStampSeconds = event.timeStamp() / millisPerSecond;
348     modifiers = getWebInputModifiers(event);
349     ScrollView* view = widget->parent();
350     IntPoint p = view->contentsToWindow(
351         IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
352     globalX = event.screenX();
353     globalY = event.screenY();
354     windowX = p.x();
355     windowY = p.y();
356     x = event.absoluteLocation().x() - widget->location().x();
357     y = event.absoluteLocation().y() - widget->location().y();
358     deltaX = static_cast<float>(event.rawDeltaX());
359     deltaY = static_cast<float>(event.rawDeltaY());
360     // The 120 is from WheelEvent::initWheelEvent().
361     wheelTicksX = static_cast<float>(event.wheelDeltaX()) / 120;
362     wheelTicksY = static_cast<float>(event.wheelDeltaY()) / 120;
363     scrollByPage = event.granularity() == WheelEvent::Page;
364 }
365
366 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
367 {
368     if (event.type() == eventNames().keydownEvent)
369         type = KeyDown;
370     else if (event.type() == eventNames().keyupEvent)
371         type = WebInputEvent::KeyUp;
372     else if (event.type() == eventNames().keypressEvent)
373         type = WebInputEvent::Char;
374     else
375         return; // Skip all other keyboard events.
376     modifiers = getWebInputModifiers(event);
377     timeStampSeconds = event.timeStamp() / millisPerSecond;
378     windowsKeyCode = event.keyCode();
379
380     // The platform keyevent does not exist if the event was created using
381     // initKeyboardEvent.
382     if (!event.keyEvent())
383         return;
384     nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode();
385     unsigned numberOfCharacters = std::min(event.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap));
386     for (unsigned i = 0; i < numberOfCharacters; ++i) {
387         text[i] = event.keyEvent()->text()[i];
388         unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i];
389     }
390 }
391
392 #if ENABLE(TOUCH_EVENTS)
393
394 static void addTouchPoints(TouchList* touches, const IntPoint& offset, WebTouchPoint* touchPoints, unsigned* touchPointsLength)
395 {
396     unsigned numberOfTouches = std::min(touches->length(), static_cast<unsigned>(WebTouchEvent::touchesLengthCap));
397     for (unsigned i = 0; i < numberOfTouches; ++i) {
398         const Touch* touch = touches->item(i);
399
400         WebTouchPoint point;
401         point.id = touch->identifier();
402         point.screenPosition = WebPoint(touch->screenX(), touch->screenY());
403         point.position = WebPoint(touch->pageX() - offset.x(), touch->pageY() - offset.y());
404         point.radiusX = touch->webkitRadiusX();
405         point.radiusY = touch->webkitRadiusY();
406         point.rotationAngle = touch->webkitRotationAngle();
407         point.force = touch->webkitForce();
408
409         touchPoints[i] = point;
410     }
411     *touchPointsLength = numberOfTouches;
412 }
413
414 WebTouchEventBuilder::WebTouchEventBuilder(const Widget* widget, const TouchEvent& event)
415 {
416     if (event.type() == eventNames().touchstartEvent)
417         type = TouchStart;
418     else if (event.type() == eventNames().touchmoveEvent)
419         type = TouchMove;
420     else if (event.type() == eventNames().touchendEvent)
421         type = TouchEnd;
422     else if (event.type() == eventNames().touchcancelEvent)
423         type = TouchCancel;
424     else {
425         ASSERT_NOT_REACHED();
426         type = Undefined;
427         return;
428     }
429
430     modifiers = getWebInputModifiers(event);
431     timeStampSeconds = event.timeStamp() / millisPerSecond;
432
433     addTouchPoints(event.touches(), widget->location(), touches, &touchesLength);
434     addTouchPoints(event.changedTouches(), widget->location(), changedTouches, &changedTouchesLength);
435     addTouchPoints(event.targetTouches(), widget->location(), targetTouches, &targetTouchesLength);
436 }
437
438 #endif // ENABLE(TOUCH_EVENTS)
439
440 } // namespace WebKit