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 "WebInputEvent.h"
43#include "WheelEvent.h"
44#include "Widget.h"
45
46using namespace WebCore;
47
48namespace WebKit {
49
50// MakePlatformMouseEvent -----------------------------------------------------
51
52PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e)
53{
54    // FIXME: widget is always toplevel, unless it's a popup.  We may be able
55    // to get rid of this once we abstract popups into a WebKit API.
56    m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
57    m_globalPosition = IntPoint(e.globalX, e.globalY);
58    m_button = static_cast<MouseButton>(e.button);
59    m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
60    m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
61    m_altKey = (e.modifiers & WebInputEvent::AltKey);
62    m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
63    m_modifierFlags = e.modifiers;
64    m_timestamp = e.timeStampSeconds;
65    m_clickCount = e.clickCount;
66
67    switch (e.type) {
68    case WebInputEvent::MouseMove:
69    case WebInputEvent::MouseLeave:  // synthesize a move event
70        m_eventType = MouseEventMoved;
71        break;
72
73    case WebInputEvent::MouseDown:
74        m_eventType = MouseEventPressed;
75        break;
76
77    case WebInputEvent::MouseUp:
78        m_eventType = MouseEventReleased;
79        break;
80
81    default:
82        ASSERT_NOT_REACHED();
83    }
84}
85
86// PlatformWheelEventBuilder --------------------------------------------------
87
88PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e)
89{
90    m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
91    m_globalPosition = IntPoint(e.globalX, e.globalY);
92    m_deltaX = e.deltaX;
93    m_deltaY = e.deltaY;
94    m_wheelTicksX = e.wheelTicksX;
95    m_wheelTicksY = e.wheelTicksY;
96    m_isAccepted = false;
97    m_granularity = e.scrollByPage ?
98        ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
99    m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
100    m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
101    m_altKey = (e.modifiers & WebInputEvent::AltKey);
102    m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
103}
104
105// MakePlatformKeyboardEvent --------------------------------------------------
106
107static inline PlatformKeyboardEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type)
108{
109    switch (type) {
110    case WebInputEvent::KeyUp:
111        return PlatformKeyboardEvent::KeyUp;
112    case WebInputEvent::KeyDown:
113        return PlatformKeyboardEvent::KeyDown;
114    case WebInputEvent::RawKeyDown:
115        return PlatformKeyboardEvent::RawKeyDown;
116    case WebInputEvent::Char:
117        return PlatformKeyboardEvent::Char;
118    default:
119        ASSERT_NOT_REACHED();
120    }
121    return PlatformKeyboardEvent::KeyDown;
122}
123
124PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e)
125{
126    m_type = toPlatformKeyboardEventType(e.type);
127    m_text = String(e.text);
128    m_unmodifiedText = String(e.unmodifiedText);
129    m_keyIdentifier = String(e.keyIdentifier);
130    m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat);
131    m_windowsVirtualKeyCode = e.windowsKeyCode;
132    m_nativeVirtualKeyCode = e.nativeKeyCode;
133    m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad);
134    m_shiftKey = (e.modifiers & WebInputEvent::ShiftKey);
135    m_ctrlKey = (e.modifiers & WebInputEvent::ControlKey);
136    m_altKey = (e.modifiers & WebInputEvent::AltKey);
137    m_metaKey = (e.modifiers & WebInputEvent::MetaKey);
138    m_isSystemKey = e.isSystemKey;
139}
140
141void PlatformKeyboardEventBuilder::setKeyType(Type type)
142{
143    // According to the behavior of Webkit in Windows platform,
144    // we need to convert KeyDown to RawKeydown and Char events
145    // See WebKit/WebKit/Win/WebView.cpp
146    ASSERT(m_type == KeyDown);
147    ASSERT(type == RawKeyDown || type == Char);
148    m_type = type;
149
150    if (type == RawKeyDown) {
151        m_text = String();
152        m_unmodifiedText = String();
153    } else {
154        m_keyIdentifier = String();
155        m_windowsVirtualKeyCode = 0;
156    }
157}
158
159// Please refer to bug http://b/issue?id=961192, which talks about Webkit
160// keyboard event handling changes. It also mentions the list of keys
161// which don't have associated character events.
162bool PlatformKeyboardEventBuilder::isCharacterKey() const
163{
164    switch (windowsVirtualKeyCode()) {
165    case VKEY_BACK:
166    case VKEY_ESCAPE:
167        return false;
168    }
169    return true;
170}
171
172#if ENABLE(TOUCH_EVENTS)
173static inline TouchEventType toPlatformTouchEventType(const WebInputEvent::Type type)
174{
175    switch (type) {
176    case WebInputEvent::TouchStart:
177        return TouchStart;
178    case WebInputEvent::TouchMove:
179        return TouchMove;
180    case WebInputEvent::TouchEnd:
181        return TouchEnd;
182    case WebInputEvent::TouchCancel:
183        return TouchCancel;
184    default:
185        ASSERT_NOT_REACHED();
186    }
187    return TouchStart;
188}
189
190static inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
191{
192    switch (state) {
193    case WebTouchPoint::StateReleased:
194        return PlatformTouchPoint::TouchReleased;
195    case WebTouchPoint::StatePressed:
196        return PlatformTouchPoint::TouchPressed;
197    case WebTouchPoint::StateMoved:
198        return PlatformTouchPoint::TouchMoved;
199    case WebTouchPoint::StateStationary:
200        return PlatformTouchPoint::TouchStationary;
201    case WebTouchPoint::StateCancelled:
202        return PlatformTouchPoint::TouchCancelled;
203    case WebTouchPoint::StateUndefined:
204        ASSERT_NOT_REACHED();
205    }
206    return PlatformTouchPoint::TouchReleased;
207}
208
209PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point)
210{
211    m_id = point.id;
212    m_state = toPlatformTouchPointState(point.state);
213    m_pos = widget->convertFromContainingWindow(point.position);
214    m_screenPos = point.screenPosition;
215}
216
217PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event)
218{
219    m_type = toPlatformTouchEventType(event.type);
220    m_ctrlKey = event.modifiers & WebInputEvent::ControlKey;
221    m_altKey = event.modifiers & WebInputEvent::AltKey;
222    m_shiftKey = event.modifiers & WebInputEvent::ShiftKey;
223    m_metaKey = event.modifiers & WebInputEvent::MetaKey;
224    m_timestamp = event.timeStampSeconds;
225
226    for (int i = 0; i < event.touchPointsLength; ++i)
227        m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touchPoints[i]));
228}
229#endif
230
231static int getWebInputModifiers(const UIEventWithKeyState& event)
232{
233    int modifiers = 0;
234    if (event.ctrlKey())
235        modifiers |= WebInputEvent::ControlKey;
236    if (event.shiftKey())
237        modifiers |= WebInputEvent::ShiftKey;
238    if (event.altKey())
239        modifiers |= WebInputEvent::AltKey;
240    if (event.metaKey())
241        modifiers |= WebInputEvent::MetaKey;
242    return modifiers;
243}
244
245WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const MouseEvent& event)
246{
247    if (event.type() == eventNames().mousemoveEvent)
248        type = WebInputEvent::MouseMove;
249    else if (event.type() == eventNames().mouseoutEvent)
250        type = WebInputEvent::MouseLeave;
251    else if (event.type() == eventNames().mouseoverEvent)
252        type = WebInputEvent::MouseEnter;
253    else if (event.type() == eventNames().mousedownEvent)
254        type = WebInputEvent::MouseDown;
255    else if (event.type() == eventNames().mouseupEvent)
256        type = WebInputEvent::MouseUp;
257    else if (event.type() == eventNames().contextmenuEvent)
258        type = WebInputEvent::ContextMenu;
259    else
260        return; // Skip all other mouse events.
261    timeStampSeconds = event.timeStamp() * 1.0e-3;
262    switch (event.button()) {
263    case LeftButton:
264        button = WebMouseEvent::ButtonLeft;
265        break;
266    case MiddleButton:
267        button = WebMouseEvent::ButtonMiddle;
268        break;
269    case RightButton:
270        button = WebMouseEvent::ButtonRight;
271        break;
272    }
273    modifiers = getWebInputModifiers(event);
274    if (event.buttonDown()) {
275        switch (event.button()) {
276        case LeftButton:
277            modifiers |= WebInputEvent::LeftButtonDown;
278            break;
279        case MiddleButton:
280            modifiers |= WebInputEvent::MiddleButtonDown;
281            break;
282        case RightButton:
283            modifiers |= WebInputEvent::RightButtonDown;
284            break;
285        }
286    }
287    ScrollView* view = widget->parent();
288    IntPoint p = view->contentsToWindow(
289        IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
290    globalX = event.screenX();
291    globalY = event.screenY();
292    windowX = p.x();
293    windowY = p.y();
294    x = event.absoluteLocation().x() - widget->pos().x();
295    y = event.absoluteLocation().y() - widget->pos().y();
296    clickCount = event.detail();
297}
298
299WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const WheelEvent& event)
300{
301    if (event.type() != eventNames().mousewheelEvent)
302        return;
303    type = WebInputEvent::MouseWheel;
304    timeStampSeconds = event.timeStamp() * 1.0e-3;
305    modifiers = getWebInputModifiers(event);
306    ScrollView* view = widget->parent();
307    IntPoint p = view->contentsToWindow(
308        IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
309    globalX = event.screenX();
310    globalY = event.screenY();
311    windowX = p.x();
312    windowY = p.y();
313    x = event.absoluteLocation().x() - widget->pos().x();
314    y = event.absoluteLocation().y() - widget->pos().y();
315    deltaX = static_cast<float>(event.rawDeltaX());
316    deltaY = static_cast<float>(event.rawDeltaY());
317    // The 120 is from WheelEvent::initWheelEvent().
318    wheelTicksX = static_cast<float>(event.wheelDeltaX()) / 120;
319    wheelTicksY = static_cast<float>(event.wheelDeltaY()) / 120;
320    scrollByPage = event.granularity() == WheelEvent::Page;
321}
322
323WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
324{
325    if (event.type() == eventNames().keydownEvent)
326        type = KeyDown;
327    else if (event.type() == eventNames().keyupEvent)
328        type = WebInputEvent::KeyUp;
329    else if (event.type() == eventNames().keypressEvent)
330        type = WebInputEvent::Char;
331    else
332        return; // Skip all other keyboard events.
333    modifiers = getWebInputModifiers(event);
334    timeStampSeconds = event.timeStamp() * 1.0e-3;
335    windowsKeyCode = event.keyCode();
336
337    // The platform keyevent does not exist if the event was created using
338    // initKeyboardEvent.
339    if (!event.keyEvent())
340        return;
341    nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode();
342    unsigned int numChars = std::min(event.keyEvent()->text().length(),
343        static_cast<unsigned int>(WebKeyboardEvent::textLengthCap));
344    for (unsigned int i = 0; i < numChars; i++) {
345        text[i] = event.keyEvent()->text()[i];
346        unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i];
347    }
348}
349
350} // namespace WebKit
351