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