OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006-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 "WebInputEventFactory.h" | |
33 | |
34 #include "WebInputEvent.h" | |
35 | |
36 #include <wtf/Assertions.h> | |
37 | |
38 namespace WebKit { | |
39 | |
40 static const unsigned long defaultScrollLinesPerWheelDelta = 3; | |
41 static const unsigned long defaultScrollCharsPerWheelDelta = 1; | |
42 | |
43 // WebKeyboardEvent ----------------------------------------------------------- | |
44 | |
45 static bool isKeyPad(WPARAM wparam, LPARAM lparam) | |
46 { | |
47 bool keypad = false; | |
48 switch (wparam) { | |
49 case VK_RETURN: | |
50 keypad = (lparam >> 16) & KF_EXTENDED; | |
51 break; | |
52 case VK_INSERT: | |
53 case VK_DELETE: | |
54 case VK_HOME: | |
55 case VK_END: | |
56 case VK_PRIOR: | |
57 case VK_NEXT: | |
58 case VK_UP: | |
59 case VK_DOWN: | |
60 case VK_LEFT: | |
61 case VK_RIGHT: | |
62 keypad = !((lparam >> 16) & KF_EXTENDED); | |
63 break; | |
64 case VK_NUMLOCK: | |
65 case VK_NUMPAD0: | |
66 case VK_NUMPAD1: | |
67 case VK_NUMPAD2: | |
68 case VK_NUMPAD3: | |
69 case VK_NUMPAD4: | |
70 case VK_NUMPAD5: | |
71 case VK_NUMPAD6: | |
72 case VK_NUMPAD7: | |
73 case VK_NUMPAD8: | |
74 case VK_NUMPAD9: | |
75 case VK_DIVIDE: | |
76 case VK_MULTIPLY: | |
77 case VK_SUBTRACT: | |
78 case VK_ADD: | |
79 case VK_DECIMAL: | |
80 case VK_CLEAR: | |
81 keypad = true; | |
82 break; | |
83 default: | |
84 keypad = false; | |
85 } | |
86 return keypad; | |
87 } | |
88 | |
89 WebKeyboardEvent WebInputEventFactory::keyboardEvent(HWND hwnd, UINT message, | |
90 WPARAM wparam, LPARAM lparam) | |
91 { | |
92 WebKeyboardEvent result; | |
93 | |
94 // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that | |
95 // GetMessageTime() refers to is the same one that we're passed in? Perhaps | |
96 // one of the construction parameters should be the time passed by the | |
97 // caller, who would know for sure. | |
98 result.timeStampSeconds = GetMessageTime() / 1000.0; | |
99 | |
100 result.windowsKeyCode = result.nativeKeyCode = static_cast<int>(wparam); | |
101 | |
102 switch (message) { | |
103 case WM_SYSKEYDOWN: | |
104 result.isSystemKey = true; | |
105 case WM_KEYDOWN: | |
106 result.type = WebInputEvent::RawKeyDown; | |
107 break; | |
108 case WM_SYSKEYUP: | |
109 result.isSystemKey = true; | |
110 case WM_KEYUP: | |
111 result.type = WebInputEvent::KeyUp; | |
112 break; | |
113 case WM_IME_CHAR: | |
114 result.type = WebInputEvent::Char; | |
115 break; | |
116 case WM_SYSCHAR: | |
117 result.isSystemKey = true; | |
118 result.type = WebInputEvent::Char; | |
119 case WM_CHAR: | |
120 result.type = WebInputEvent::Char; | |
121 break; | |
122 default: | |
123 ASSERT_NOT_REACHED(); | |
124 } | |
125 | |
126 if (result.type == WebInputEvent::Char || result.type == WebInputEvent::RawKeyDown) { | |
127 result.text[0] = result.windowsKeyCode; | |
128 result.unmodifiedText[0] = result.windowsKeyCode; | |
129 } | |
130 if (result.type != WebInputEvent::Char) | |
131 result.setKeyIdentifierFromWindowsKeyCode(); | |
132 | |
133 if (GetKeyState(VK_SHIFT) & 0x8000) | |
134 result.modifiers |= WebInputEvent::ShiftKey; | |
135 if (GetKeyState(VK_CONTROL) & 0x8000) | |
136 result.modifiers |= WebInputEvent::ControlKey; | |
137 if (GetKeyState(VK_MENU) & 0x8000) | |
138 result.modifiers |= WebInputEvent::AltKey; | |
139 // NOTE: There doesn't seem to be a way to query the mouse button state in | |
140 // this case. | |
141 | |
142 if (LOWORD(lparam) > 1) | |
143 result.modifiers |= WebInputEvent::IsAutoRepeat; | |
144 if (isKeyPad(wparam, lparam)) | |
145 result.modifiers |= WebInputEvent::IsKeyPad; | |
146 | |
147 return result; | |
148 } | |
149 | |
150 // WebMouseEvent -------------------------------------------------------------- | |
151 | |
152 static int gLastClickCount; | |
153 static double gLastClickTime; | |
154 | |
155 static LPARAM GetRelativeCursorPos(HWND hwnd) | |
156 { | |
157 POINT pos = {-1, -1}; | |
158 GetCursorPos(&pos); | |
159 ScreenToClient(hwnd, &pos); | |
160 return MAKELPARAM(pos.x, pos.y); | |
161 } | |
162 | |
163 void WebInputEventFactory::resetLastClickState() | |
164 { | |
165 gLastClickTime = gLastClickCount = 0; | |
166 } | |
167 | |
168 WebMouseEvent WebInputEventFactory::mouseEvent(HWND hwnd, UINT message, | |
169 WPARAM wparam, LPARAM lparam) | |
170 { | |
171 WebMouseEvent result; //(WebInputEvent::Uninitialized()); | |
172 | |
173 switch (message) { | |
174 case WM_MOUSEMOVE: | |
175 result.type = WebInputEvent::MouseMove; | |
176 if (wparam & MK_LBUTTON) | |
177 result.button = WebMouseEvent::ButtonLeft; | |
178 else if (wparam & MK_MBUTTON) | |
179 result.button = WebMouseEvent::ButtonMiddle; | |
180 else if (wparam & MK_RBUTTON) | |
181 result.button = WebMouseEvent::ButtonRight; | |
182 else | |
183 result.button = WebMouseEvent::ButtonNone; | |
184 break; | |
185 case WM_MOUSELEAVE: | |
186 result.type = WebInputEvent::MouseLeave; | |
187 result.button = WebMouseEvent::ButtonNone; | |
188 // set the current mouse position (relative to the client area of the | |
189 // current window) since none is specified for this event | |
190 lparam = GetRelativeCursorPos(hwnd); | |
191 break; | |
192 case WM_LBUTTONDOWN: | |
193 case WM_LBUTTONDBLCLK: | |
194 result.type = WebInputEvent::MouseDown; | |
195 result.button = WebMouseEvent::ButtonLeft; | |
196 break; | |
197 case WM_MBUTTONDOWN: | |
198 case WM_MBUTTONDBLCLK: | |
199 result.type = WebInputEvent::MouseDown; | |
200 result.button = WebMouseEvent::ButtonMiddle; | |
201 break; | |
202 case WM_RBUTTONDOWN: | |
203 case WM_RBUTTONDBLCLK: | |
204 result.type = WebInputEvent::MouseDown; | |
205 result.button = WebMouseEvent::ButtonRight; | |
206 break; | |
207 case WM_LBUTTONUP: | |
208 result.type = WebInputEvent::MouseUp; | |
209 result.button = WebMouseEvent::ButtonLeft; | |
210 break; | |
211 case WM_MBUTTONUP: | |
212 result.type = WebInputEvent::MouseUp; | |
213 result.button = WebMouseEvent::ButtonMiddle; | |
214 break; | |
215 case WM_RBUTTONUP: | |
216 result.type = WebInputEvent::MouseUp; | |
217 result.button = WebMouseEvent::ButtonRight; | |
218 break; | |
219 default: | |
220 ASSERT_NOT_REACHED(); | |
221 } | |
222 | |
223 // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that | |
224 // GetMessageTime() refers to is the same one that we're passed in? Perhaps | |
225 // one of the construction parameters should be the time passed by the | |
226 // caller, who would know for sure. | |
227 result.timeStampSeconds = GetMessageTime() / 1000.0; | |
228 | |
229 // set position fields: | |
230 | |
231 result.x = static_cast<short>(LOWORD(lparam)); | |
232 result.y = static_cast<short>(HIWORD(lparam)); | |
233 result.windowX = result.x; | |
234 result.windowY = result.y; | |
235 | |
236 POINT globalPoint = { result.x, result.y }; | |
237 ClientToScreen(hwnd, &globalPoint); | |
238 | |
239 result.globalX = globalPoint.x; | |
240 result.globalY = globalPoint.y; | |
241 | |
242 // calculate number of clicks: | |
243 | |
244 // This differs slightly from the WebKit code in WebKit/win/WebView.cpp | |
245 // where their original code looks buggy. | |
246 static int lastClickPositionX; | |
247 static int lastClickPositionY; | |
248 static WebMouseEvent::Button lastClickButton = WebMouseEvent::ButtonLeft; | |
249 | |
250 double currentTime = result.timeStampSeconds; | |
251 bool cancelPreviousClick = | |
252 (abs(lastClickPositionX - result.x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) | |
253 || (abs(lastClickPositionY - result.y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2)) | |
254 || ((currentTime - gLastClickTime) * 1000.0 > GetDoubleClickTime()); | |
255 | |
256 if (result.type == WebInputEvent::MouseDown) { | |
257 if (!cancelPreviousClick && (result.button == lastClickButton)) | |
258 ++gLastClickCount; | |
259 else { | |
260 gLastClickCount = 1; | |
261 lastClickPositionX = result.x; | |
262 lastClickPositionY = result.y; | |
263 } | |
264 gLastClickTime = currentTime; | |
265 lastClickButton = result.button; | |
266 } else if (result.type == WebInputEvent::MouseMove | |
267 || result.type == WebInputEvent::MouseLeave) { | |
268 if (cancelPreviousClick) { | |
269 gLastClickCount = 0; | |
270 lastClickPositionX = 0; | |
271 lastClickPositionY = 0; | |
272 gLastClickTime = 0; | |
273 } | |
274 } | |
275 result.clickCount = gLastClickCount; | |
276 | |
277 // set modifiers: | |
278 | |
279 if (wparam & MK_CONTROL) | |
280 result.modifiers |= WebInputEvent::ControlKey; | |
281 if (wparam & MK_SHIFT) | |
282 result.modifiers |= WebInputEvent::ShiftKey; | |
283 if (GetKeyState(VK_MENU) & 0x8000) | |
284 result.modifiers |= WebInputEvent::AltKey; | |
285 if (wparam & MK_LBUTTON) | |
286 result.modifiers |= WebInputEvent::LeftButtonDown; | |
287 if (wparam & MK_MBUTTON) | |
288 result.modifiers |= WebInputEvent::MiddleButtonDown; | |
289 if (wparam & MK_RBUTTON) | |
290 result.modifiers |= WebInputEvent::RightButtonDown; | |
291 | |
292 return result; | |
293 } | |
294 | |
295 // WebMouseWheelEvent --------------------------------------------------------- | |
296 | |
297 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(HWND hwnd, UINT message, | |
298 WPARAM wparam, LPARAM lparam) | |
299 { | |
300 WebMouseWheelEvent result; //(WebInputEvent::Uninitialized()); | |
301 | |
302 result.type = WebInputEvent::MouseWheel; | |
303 | |
304 // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that | |
305 // GetMessageTime() refers to is the same one that we're passed in? Perhaps | |
306 // one of the construction parameters should be the time passed by the | |
307 // caller, who would know for sure. | |
308 result.timeStampSeconds = GetMessageTime() / 1000.0; | |
309 | |
310 result.button = WebMouseEvent::ButtonNone; | |
311 | |
312 // Get key state, coordinates, and wheel delta from event. | |
313 typedef SHORT (WINAPI *GetKeyStateFunction)(int key); | |
314 GetKeyStateFunction getKeyState; | |
315 UINT keyState; | |
316 float wheelDelta; | |
317 bool horizontalScroll = false; | |
318 if ((message == WM_VSCROLL) || (message == WM_HSCROLL)) { | |
319 // Synthesize mousewheel event from a scroll event. This is needed to | |
320 // simulate middle mouse scrolling in some laptops. Use GetAsyncKeyState | |
321 // for key state since we are synthesizing the input event. | |
322 getKeyState = GetAsyncKeyState; | |
323 keyState = 0; | |
324 if (getKeyState(VK_SHIFT)) | |
325 keyState |= MK_SHIFT; | |
326 if (getKeyState(VK_CONTROL)) | |
327 keyState |= MK_CONTROL; | |
328 // NOTE: There doesn't seem to be a way to query the mouse button state | |
329 // in this case. | |
330 | |
331 POINT cursorPosition = {0}; | |
332 GetCursorPos(&cursorPosition); | |
333 result.globalX = cursorPosition.x; | |
334 result.globalY = cursorPosition.y; | |
335 | |
336 switch (LOWORD(wparam)) { | |
337 case SB_LINEUP: // == SB_LINELEFT | |
338 wheelDelta = WHEEL_DELTA; | |
339 break; | |
340 case SB_LINEDOWN: // == SB_LINERIGHT | |
341 wheelDelta = -WHEEL_DELTA; | |
342 break; | |
343 case SB_PAGEUP: | |
344 wheelDelta = 1; | |
345 result.scrollByPage = true; | |
346 break; | |
347 case SB_PAGEDOWN: | |
348 wheelDelta = -1; | |
349 result.scrollByPage = true; | |
350 break; | |
351 default: // We don't supoprt SB_THUMBPOSITION or SB_THUMBTRACK here. | |
352 wheelDelta = 0; | |
353 break; | |
354 } | |
355 | |
356 if (message == WM_HSCROLL) | |
357 horizontalScroll = true; | |
358 } else { | |
359 // Non-synthesized event; we can just read data off the event. | |
360 getKeyState = GetKeyState; | |
361 keyState = GET_KEYSTATE_WPARAM(wparam); | |
362 | |
363 result.globalX = static_cast<short>(LOWORD(lparam)); | |
364 result.globalY = static_cast<short>(HIWORD(lparam)); | |
365 | |
366 wheelDelta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam)); | |
367 if (message == WM_MOUSEHWHEEL) { | |
368 horizontalScroll = true; | |
369 wheelDelta = -wheelDelta; // Windows is <- -/+ ->, WebKit <- +/- ->. | |
370 } | |
371 } | |
372 if (keyState & MK_SHIFT) | |
373 horizontalScroll = true; | |
374 | |
375 // Set modifiers based on key state. | |
376 if (keyState & MK_SHIFT) | |
377 result.modifiers |= WebInputEvent::ShiftKey; | |
378 if (keyState & MK_CONTROL) | |
379 result.modifiers |= WebInputEvent::ControlKey; | |
380 if (getKeyState(VK_MENU) & 0x8000) | |
381 result.modifiers |= WebInputEvent::AltKey; | |
382 if (keyState & MK_LBUTTON) | |
383 result.modifiers |= WebInputEvent::LeftButtonDown; | |
384 if (keyState & MK_MBUTTON) | |
385 result.modifiers |= WebInputEvent::MiddleButtonDown; | |
386 if (keyState & MK_RBUTTON) | |
387 result.modifiers |= WebInputEvent::RightButtonDown; | |
388 | |
389 // Set coordinates by translating event coordinates from screen to client. | |
390 POINT clientPoint = { result.globalX, result.globalY }; | |
391 MapWindowPoints(0, hwnd, &clientPoint, 1); | |
392 result.x = clientPoint.x; | |
393 result.y = clientPoint.y; | |
394 result.windowX = result.x; | |
395 result.windowY = result.y; | |
396 | |
397 // Convert wheel delta amount to a number of pixels to scroll. | |
398 // | |
399 // How many pixels should we scroll per line? Gecko uses the height of the | |
400 // current line, which means scroll distance changes as you go through the | |
401 // page or go to different pages. IE 7 is ~50 px/line, although the value | |
402 // seems to vary slightly by page and zoom level. Since IE 7 has a smoothing | |
403 // algorithm on scrolling, it can get away with slightly larger scroll values | |
404 // without feeling jerky. Here we use 100 px per three lines (the default | |
405 // scroll amount is three lines per wheel tick). | |
406 static const float scrollbarPixelsPerLine = 100.0f / 3.0f; | |
407 wheelDelta /= WHEEL_DELTA; | |
408 float scrollDelta = wheelDelta; | |
409 if (horizontalScroll) { | |
410 unsigned long scrollChars = defaultScrollCharsPerWheelDelta; | |
411 SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0); | |
412 // TODO(pkasting): Should probably have a different multiplier | |
413 // scrollbarPixelsPerChar here. | |
414 scrollDelta *= static_cast<float>(scrollChars) * scrollbarPixelsPerLine; | |
415 } else { | |
416 unsigned long scrollLines = defaultScrollLinesPerWheelDelta; | |
417 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0); | |
418 if (scrollLines == WHEEL_PAGESCROLL) | |
419 result.scrollByPage = true; | |
420 if (!result.scrollByPage) | |
421 scrollDelta *= static_cast<float>(scrollLines) * scrollbarPixelsPerLine; | |
422 } | |
423 | |
424 // Set scroll amount based on above calculations. WebKit expects positive | |
425 // deltaY to mean "scroll up" and positive deltaX to mean "scroll left". | |
426 if (horizontalScroll) { | |
427 result.deltaX = scrollDelta; | |
428 result.wheelTicksX = wheelDelta; | |
429 } else { | |
430 result.deltaY = scrollDelta; | |
431 result.wheelTicksY = wheelDelta; | |
432 } | |
433 | |
434 return result; | |
435 } | |
436 | |
437 } // namespace WebKit | |
OLD | NEW |