• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2006-2009 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "WebEventFactory.h"
29 
30 #include <windowsx.h>
31 #include <wtf/ASCIICType.h>
32 
33 using namespace WebCore;
34 
35 namespace WebKit {
36 
37 static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
38 static const unsigned short SPI_GETWHEELSCROLLCHARS = 0x006C;
39 
40 static const unsigned WM_VISTA_MOUSEHWHEEL = 0x20E;
41 
relativeCursorPosition(HWND hwnd)42 static inline LPARAM relativeCursorPosition(HWND hwnd)
43 {
44     POINT point = { -1, -1 };
45     ::GetCursorPos(&point);
46     ::ScreenToClient(hwnd, &point);
47     return MAKELPARAM(point.x, point.y);
48 }
49 
point(LPARAM lParam)50 static inline POINT point(LPARAM lParam)
51 {
52     POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
53     return point;
54 }
55 
horizontalScrollChars()56 static int horizontalScrollChars()
57 {
58     static ULONG scrollChars;
59     if (!scrollChars && !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0))
60         scrollChars = 1;
61     return scrollChars;
62 }
63 
verticalScrollLines()64 static int verticalScrollLines()
65 {
66     static ULONG scrollLines;
67     if (!scrollLines && !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0))
68         scrollLines = 3;
69     return scrollLines;
70 }
71 
clickCount(WebEvent::Type type,WebMouseEvent::Button button,const POINT & position,double timeStampSeconds)72 static inline int clickCount(WebEvent::Type type, WebMouseEvent::Button button, const POINT& position, double timeStampSeconds)
73 {
74     static int gLastClickCount;
75     static double gLastClickTime;
76     static POINT lastClickPosition;
77     static WebMouseEvent::Button lastClickButton = WebMouseEvent::LeftButton;
78 
79     bool cancelPreviousClick = (abs(lastClickPosition.x - position.x) > (::GetSystemMetrics(SM_CXDOUBLECLK) / 2))
80                             || (abs(lastClickPosition.y - position.y) > (::GetSystemMetrics(SM_CYDOUBLECLK) / 2))
81                             || ((timeStampSeconds - gLastClickTime) * 1000.0 > ::GetDoubleClickTime());
82 
83     if (type == WebEvent::MouseDown) {
84         if (!cancelPreviousClick && (button == lastClickButton))
85             ++gLastClickCount;
86         else {
87             gLastClickCount = 1;
88             lastClickPosition = position;
89         }
90         gLastClickTime = timeStampSeconds;
91         lastClickButton = button;
92     } else if (type == WebEvent::MouseMove) {
93         if (cancelPreviousClick) {
94             gLastClickCount = 0;
95             lastClickPosition.x = 0;
96             lastClickPosition.y = 0;
97             gLastClickTime = 0;
98         }
99     }
100 
101     return gLastClickCount;
102 }
103 
modifiersForEvent(WPARAM wparam)104 static inline WebEvent::Modifiers modifiersForEvent(WPARAM wparam)
105 {
106     unsigned modifiers = 0;
107     if (wparam & MK_CONTROL)
108         modifiers |= WebEvent::ControlKey;
109     if (wparam & MK_SHIFT)
110         modifiers |= WebEvent::ShiftKey;
111     if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
112         modifiers |= WebEvent::AltKey;
113     return static_cast<WebEvent::Modifiers>(modifiers);
114 }
115 
modifiersForCurrentKeyState()116 static inline WebEvent::Modifiers modifiersForCurrentKeyState()
117 {
118     unsigned modifiers = 0;
119     if (::GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
120         modifiers |= WebEvent::ControlKey;
121     if (::GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
122         modifiers |= WebEvent::ShiftKey;
123     if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
124         modifiers |= WebEvent::AltKey;
125     return static_cast<WebEvent::Modifiers>(modifiers);
126 }
127 
keyboardEventTypeForEvent(UINT message)128 static inline WebEvent::Type keyboardEventTypeForEvent(UINT message)
129 {
130     switch (message) {
131     case WM_SYSKEYDOWN:
132     case WM_KEYDOWN:
133         return WebEvent::RawKeyDown;
134         break;
135     case WM_SYSKEYUP:
136     case WM_KEYUP:
137         return WebEvent::KeyUp;
138         break;
139     case WM_IME_CHAR:
140     case WM_SYSCHAR:
141     case WM_CHAR:
142         return WebEvent::Char;
143         break;
144     default:
145         ASSERT_NOT_REACHED();
146         return WebEvent::Char;
147     }
148 }
149 
isSystemKeyEvent(UINT message)150 static inline bool isSystemKeyEvent(UINT message)
151 {
152     switch (message) {
153     case WM_SYSKEYDOWN:
154     case WM_SYSKEYUP:
155     case WM_SYSCHAR:
156         return true;
157     default:
158         return false;
159     }
160 }
161 
isKeypadEvent(WPARAM wParam,LPARAM lParam,WebEvent::Type type)162 static bool isKeypadEvent(WPARAM wParam, LPARAM lParam, WebEvent::Type type)
163 {
164     if (type != WebEvent::RawKeyDown && type != WebEvent::KeyUp)
165         return false;
166 
167     switch (wParam) {
168     case VK_NUMLOCK:
169     case VK_NUMPAD0:
170     case VK_NUMPAD1:
171     case VK_NUMPAD2:
172     case VK_NUMPAD3:
173     case VK_NUMPAD4:
174     case VK_NUMPAD5:
175     case VK_NUMPAD6:
176     case VK_NUMPAD7:
177     case VK_NUMPAD8:
178     case VK_NUMPAD9:
179     case VK_MULTIPLY:
180     case VK_ADD:
181     case VK_SEPARATOR:
182     case VK_SUBTRACT:
183     case VK_DECIMAL:
184     case VK_DIVIDE:
185         return true;
186     case VK_RETURN:
187         return HIWORD(lParam) & KF_EXTENDED;
188     case VK_INSERT:
189     case VK_DELETE:
190     case VK_PRIOR:
191     case VK_NEXT:
192     case VK_END:
193     case VK_HOME:
194     case VK_LEFT:
195     case VK_UP:
196     case VK_RIGHT:
197     case VK_DOWN:
198         return !(HIWORD(lParam) & KF_EXTENDED);
199     default:
200         return false;
201     }
202 }
203 
textFromEvent(WPARAM wparam,WebEvent::Type type)204 static String textFromEvent(WPARAM wparam, WebEvent::Type type)
205 {
206     if (type != WebEvent::Char)
207         return String();
208 
209     UChar c = static_cast<UChar>(wparam);
210     return String(&c, 1);
211 }
212 
unmodifiedTextFromEvent(WPARAM wparam,WebEvent::Type type)213 static String unmodifiedTextFromEvent(WPARAM wparam, WebEvent::Type type)
214 {
215     if (type != WebEvent::Char)
216         return String();
217 
218     UChar c = static_cast<UChar>(wparam);
219     return String(&c, 1);
220 }
221 
keyIdentifierFromEvent(WPARAM wparam,WebEvent::Type type)222 static String keyIdentifierFromEvent(WPARAM wparam, WebEvent::Type type)
223 {
224     if (type == WebEvent::Char)
225         return String();
226 
227     unsigned short keyCode = static_cast<unsigned short>(wparam);
228     switch (keyCode) {
229     case VK_MENU:
230         return String("Alt");
231     case VK_CONTROL:
232         return String("Control");
233     case VK_SHIFT:
234         return String("Shift");
235     case VK_CAPITAL:
236         return String("CapsLock");
237     case VK_LWIN:
238     case VK_RWIN:
239         return String("Win");
240     case VK_CLEAR:
241         return String("Clear");
242     case VK_DOWN:
243         return String("Down");
244     case VK_END:
245         return String("End");
246     case VK_RETURN:
247         return String("Enter");
248     case VK_EXECUTE:
249         return String("Execute");
250     case VK_F1:
251         return String("F1");
252     case VK_F2:
253         return String("F2");
254     case VK_F3:
255         return String("F3");
256     case VK_F4:
257         return String("F4");
258     case VK_F5:
259         return String("F5");
260     case VK_F6:
261         return String("F6");
262     case VK_F7:
263         return String("F7");
264     case VK_F8:
265         return String("F8");
266     case VK_F9:
267         return String("F9");
268     case VK_F10:
269         return String("F11");
270     case VK_F12:
271         return String("F12");
272     case VK_F13:
273         return String("F13");
274     case VK_F14:
275         return String("F14");
276     case VK_F15:
277         return String("F15");
278     case VK_F16:
279         return String("F16");
280     case VK_F17:
281         return String("F17");
282     case VK_F18:
283         return String("F18");
284     case VK_F19:
285         return String("F19");
286     case VK_F20:
287         return String("F20");
288     case VK_F21:
289         return String("F21");
290     case VK_F22:
291         return String("F22");
292     case VK_F23:
293         return String("F23");
294     case VK_F24:
295         return String("F24");
296     case VK_HELP:
297         return String("Help");
298     case VK_HOME:
299         return String("Home");
300     case VK_INSERT:
301         return String("Insert");
302     case VK_LEFT:
303         return String("Left");
304     case VK_NEXT:
305         return String("PageDown");
306     case VK_PRIOR:
307         return String("PageUp");
308     case VK_PAUSE:
309         return String("Pause");
310     case VK_SNAPSHOT:
311         return String("PrintScreen");
312     case VK_RIGHT:
313         return String("Right");
314     case VK_SCROLL:
315         return String("Scroll");
316     case VK_SELECT:
317         return String("Select");
318     case VK_UP:
319         return String("Up");
320     case VK_DELETE:
321         return String("U+007F"); // Standard says that DEL becomes U+007F.
322     default:
323         return String::format("U+%04X", toASCIIUpper(keyCode));
324     }
325 }
326 
createWebMouseEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool didActivateWebView)327 WebMouseEvent WebEventFactory::createWebMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool didActivateWebView)
328 {
329     WebEvent::Type type;
330     WebMouseEvent::Button button = WebMouseEvent::NoButton;
331     switch (message) {
332     case WM_MOUSEMOVE:
333         type = WebEvent::MouseMove;
334         if (wParam & MK_LBUTTON)
335             button = WebMouseEvent::LeftButton;
336         else if (wParam & MK_MBUTTON)
337             button = WebMouseEvent::MiddleButton;
338         else if (wParam & MK_RBUTTON)
339             button = WebMouseEvent::RightButton;
340         break;
341     case WM_MOUSELEAVE:
342         type = WebEvent::MouseMove;
343         if (wParam & MK_LBUTTON)
344             button = WebMouseEvent::LeftButton;
345         else if (wParam & MK_MBUTTON)
346             button = WebMouseEvent::MiddleButton;
347         else if (wParam & MK_RBUTTON)
348             button = WebMouseEvent::RightButton;
349 
350         // Set the current mouse position (relative to the client area of the
351         // current window) since none is specified for this event.
352         lParam = relativeCursorPosition(hWnd);
353         break;
354     case WM_LBUTTONDOWN:
355     case WM_LBUTTONDBLCLK:
356         type = WebEvent::MouseDown;
357         button = WebMouseEvent::LeftButton;
358         break;
359     case WM_MBUTTONDOWN:
360     case WM_MBUTTONDBLCLK:
361         type = WebEvent::MouseDown;
362         button = WebMouseEvent::MiddleButton;
363         break;
364     case WM_RBUTTONDOWN:
365     case WM_RBUTTONDBLCLK:
366         type = WebEvent::MouseDown;
367         button = WebMouseEvent::RightButton;
368         break;
369     case WM_LBUTTONUP:
370         type = WebEvent::MouseUp;
371         button = WebMouseEvent::LeftButton;
372         break;
373     case WM_MBUTTONUP:
374         type = WebEvent::MouseUp;
375         button = WebMouseEvent::MiddleButton;
376         break;
377     case WM_RBUTTONUP:
378         type = WebEvent::MouseUp;
379         button = WebMouseEvent::RightButton;
380         break;
381     default:
382         ASSERT_NOT_REACHED();
383         type = WebEvent::KeyDown;
384     }
385 
386     POINT position = point(lParam);
387     POINT globalPosition = position;
388     ::ClientToScreen(hWnd, &globalPosition);
389 
390     double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
391 
392     int clickCount = WebKit::clickCount(type, button, position, timestamp);
393     WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
394 
395     return WebMouseEvent(type, button, position, globalPosition, 0, 0, 0, clickCount, modifiers, timestamp, didActivateWebView);
396 }
397 
createWebWheelEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)398 WebWheelEvent WebEventFactory::createWebWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
399 {
400     // Taken from WebCore
401     static const float cScrollbarPixelsPerLine = 100.0f / 3.0f;
402 
403     POINT globalPosition = point(lParam);
404     POINT position = globalPosition;
405     ::ScreenToClient(hWnd, &position);
406 
407     WebWheelEvent::Granularity granularity  = WebWheelEvent::ScrollByPixelWheelEvent;
408 
409     WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
410     double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
411 
412     int deltaX = 0;
413     int deltaY = 0;
414     int wheelTicksX = 0;
415     int wheelTicksY = 0;
416 
417     float delta = GET_WHEEL_DELTA_WPARAM(wParam) / static_cast<float>(WHEEL_DELTA);
418     bool isMouseHWheel = (message == WM_VISTA_MOUSEHWHEEL);
419     if (isMouseHWheel) {
420         wheelTicksX = delta;
421         wheelTicksY = 0;
422         delta = -delta;
423     } else {
424         wheelTicksX = 0;
425         wheelTicksY = delta;
426     }
427     if (isMouseHWheel || (modifiers & WebEvent::ShiftKey)) {
428         deltaX = delta * static_cast<float>(horizontalScrollChars()) * cScrollbarPixelsPerLine;
429         deltaY = 0;
430         granularity = WebWheelEvent::ScrollByPixelWheelEvent;
431     } else {
432         deltaX = 0;
433         deltaY = delta;
434         int verticalMultiplier = verticalScrollLines();
435         if (verticalMultiplier == WHEEL_PAGESCROLL)
436             granularity = WebWheelEvent::ScrollByPageWheelEvent;
437         else {
438             granularity = WebWheelEvent::ScrollByPixelWheelEvent;
439             deltaY *= static_cast<float>(verticalMultiplier) * cScrollbarPixelsPerLine;
440         }
441     }
442 
443     return WebWheelEvent(WebEvent::Wheel, position, globalPosition, FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, modifiers, timestamp);
444 }
445 
createWebKeyboardEvent(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)446 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
447 {
448     WebEvent::Type type             = keyboardEventTypeForEvent(message);
449     String text                     = textFromEvent(wparam, type);
450     String unmodifiedText           = unmodifiedTextFromEvent(wparam, type);
451     String keyIdentifier            = keyIdentifierFromEvent(wparam, type);
452     int windowsVirtualKeyCode       = static_cast<int>(wparam);
453     int nativeVirtualKeyCode        = static_cast<int>(wparam);
454     int macCharCode                 = 0;
455     bool autoRepeat                 = HIWORD(lparam) & KF_REPEAT;
456     bool isKeypad                   = isKeypadEvent(wparam, lparam, type);
457     bool isSystemKey                = isSystemKeyEvent(message);
458     WebEvent::Modifiers modifiers   = modifiersForCurrentKeyState();
459     double timestamp                = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
460 
461     return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
462 }
463 
464 } // namespace WebKit
465