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