Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(471)

Side by Side Diff: content/browser/renderer_host/web_input_event_factory_mac.mm

Issue 19776016: Add files. Does not compile yet! (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: gtk links, may not work correctly Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2006-2009 Google Inc.
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 COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "WebInputEventFactory.h"
29
30 #include <ApplicationServices/ApplicationServices.h>
31 #import <Cocoa/Cocoa.h>
32
33 #include "WebInputEvent.h"
34 #import "core/platform/cocoa/KeyEventCocoa.h"
35 #include <wtf/ASCIICType.h>
36
37 #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1070
38
39 // Additional Lion APIs.
40 enum {
41 NSEventPhaseNone = 0,
42 NSEventPhaseBegan = 0x1 << 0,
43 NSEventPhaseStationary = 0x1 << 1,
44 NSEventPhaseChanged = 0x1 << 2,
45 NSEventPhaseEnded = 0x1 << 3,
46 NSEventPhaseCancelled = 0x1 << 4
47 };
48 typedef NSUInteger NSEventPhase;
49
50 @interface NSEvent (LionSDKDeclarations)
51 - (NSEventPhase)phase;
52 - (NSEventPhase)momentumPhase;
53 @end
54
55 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED < 1070
56
57 #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
58
59 // Additional Mountain Lion APIs.
60 enum {
61 NSEventPhaseMayBegin = 0x1 << 5
62 };
63
64 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
65
66 // Do not __MAC_OS_X_VERSION_MAX_ALLOWED here because of a bug in the 10.5 SDK,
67 // see <http://lists.webkit.org/pipermail/webkit-dev/2012-July/021442.html>.
68 #if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
69
70 // These are not defined in the 10.5 SDK but are defined in later SDKs inside
71 // a MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 #ifdef.
72 enum {
73 NSEventTypeBeginGesture = 19,
74 NSEventTypeEndGesture = 20
75 };
76
77 #endif // MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
78
79 namespace WebKit {
80
81 // WebKeyboardEvent -----------------------------------------------------------
82
83 // ----------------------------------------------------------------------------
84 // Begin Apple code, copied from KeyEventMac.mm
85 //
86 // We can share some of this code if we factored it out of KeyEventMac, but
87 // the main problem is that it relies on the NSString ctor on String for
88 // conversions, and since we're building without PLATFORM(MAC), we don't have
89 // that. As a result we have to use NSString here exclusively and thus tweak
90 // the code so it's not re-usable as-is. One possiblity would be to make the
91 // upstream code only use NSString, but I'm not certain how far that change
92 // would propagate.
93
94 static inline bool isKeyUpEvent(NSEvent* event) {
95 if ([event type] != NSFlagsChanged)
96 return [event type] == NSKeyUp;
97 // FIXME: This logic fails if the user presses both Shift keys at once, for
98 // example:
99 // we treat releasing one of them as keyDown.
100 switch ([event keyCode]) {
101 case 54: // Right Command
102 case 55: // Left Command
103 return ([event modifierFlags] & NSCommandKeyMask) == 0;
104
105 case 57: // Capslock
106 return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
107
108 case 56: // Left Shift
109 case 60: // Right Shift
110 return ([event modifierFlags] & NSShiftKeyMask) == 0;
111
112 case 58: // Left Alt
113 case 61: // Right Alt
114 return ([event modifierFlags] & NSAlternateKeyMask) == 0;
115
116 case 59: // Left Ctrl
117 case 62: // Right Ctrl
118 return ([event modifierFlags] & NSControlKeyMask) == 0;
119
120 case 63: // Function
121 return ([event modifierFlags] & NSFunctionKeyMask) == 0;
122 }
123 return false;
124 }
125
126 static bool isKeypadEvent(NSEvent* event) {
127 // Check that this is the type of event that has a keyCode.
128 switch ([event type]) {
129 case NSKeyDown:
130 case NSKeyUp:
131 case NSFlagsChanged:
132 break;
133 default:
134 return false;
135 }
136
137 switch ([event keyCode]) {
138 case 71: // Clear
139 case 81: // =
140 case 75: // /
141 case 67: // *
142 case 78: // -
143 case 69: // +
144 case 76: // Enter
145 case 65: // .
146 case 82: // 0
147 case 83: // 1
148 case 84: // 2
149 case 85: // 3
150 case 86: // 4
151 case 87: // 5
152 case 88: // 6
153 case 89: // 7
154 case 91: // 8
155 case 92: // 9
156 return true;
157 }
158
159 return false;
160 }
161
162 static int windowsKeyCodeForKeyEvent(NSEvent* event) {
163 int code = 0;
164 // There are several kinds of characters for which we produce key code from
165 // char code:
166 // 1. Roman letters. Windows keyboard layouts affect both virtual key codes
167 // and character codes for these,
168 // so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts.
169 // 2. Keys for which there is no known Mac virtual key codes, like
170 // PrintScreen.
171 // 3. Certain punctuation keys. On Windows, these are also remapped depending
172 // on current keyboard layout,
173 // but see comment in windowsKeyCodeForCharCode().
174 if (!isKeypadEvent(event) &&
175 ([event type] == NSKeyDown || [event type] == NSKeyUp)) {
176 // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified
177 // characters first.
178 NSString* s = [event characters];
179 code = [s length] > 0
180 ? WebCore::windowsKeyCodeForCharCode([s characterAtIndex:0])
181 : 0;
182 if (code)
183 return code;
184
185 // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on
186 // -[NSEvent keyCode] below.
187 s = [event charactersIgnoringModifiers];
188 code = [s length] > 0
189 ? WebCore::windowsKeyCodeForCharCode([s characterAtIndex:0])
190 : 0;
191 if (code)
192 return code;
193 }
194
195 // Map Mac virtual key code directly to Windows one for any keys not handled
196 // above.
197 // E.g. the key next to Caps Lock has the same Event.keyCode on U.S. keyboard
198 // ('A') and on Russian keyboard (CYRILLIC LETTER EF).
199 return WebCore::windowsKeyCodeForKeyCode([event keyCode]);
200 }
201
202 static WebInputEvent::Type gestureEventTypeForEvent(NSEvent* event) {
203 switch ([event type]) {
204 case NSEventTypeBeginGesture:
205 return WebInputEvent::GestureScrollBegin;
206 case NSEventTypeEndGesture:
207 return WebInputEvent::GestureScrollEnd;
208 default:
209 ASSERT_NOT_REACHED();
210 return WebInputEvent::GestureScrollEnd;
211 }
212 }
213
214 static inline NSString* textFromEvent(NSEvent* event) {
215 if ([event type] == NSFlagsChanged)
216 return @"";
217 return [event characters];
218 }
219
220 static inline NSString* unmodifiedTextFromEvent(NSEvent* event) {
221 if ([event type] == NSFlagsChanged)
222 return @"";
223 return [event charactersIgnoringModifiers];
224 }
225
226 static NSString* keyIdentifierForKeyEvent(NSEvent* event) {
227 if ([event type] == NSFlagsChanged) {
228 switch ([event keyCode]) {
229 case 54: // Right Command
230 case 55: // Left Command
231 return @"Meta";
232
233 case 57: // Capslock
234 return @"CapsLock";
235
236 case 56: // Left Shift
237 case 60: // Right Shift
238 return @"Shift";
239
240 case 58: // Left Alt
241 case 61: // Right Alt
242 return @"Alt";
243
244 case 59: // Left Ctrl
245 case 62: // Right Ctrl
246 return @"Control";
247
248 // Begin non-Apple addition/modification
249 // --------------------------------------
250 case 63: // Function
251 return @"Function";
252
253 default: // Unknown, but this may be a strange/new keyboard.
254 return @"Unidentified";
255 // End non-Apple addition/modification
256 // ----------------------------------------
257 }
258 }
259
260 NSString* s = [event charactersIgnoringModifiers];
261 if ([s length] != 1)
262 return @"Unidentified";
263
264 unichar c = [s characterAtIndex:0];
265 switch (c) {
266 // Each identifier listed in the DOM spec is listed here.
267 // Many are simply commented out since they do not appear on standard
268 // Macintosh keyboards
269 // or are on a key that doesn't have a corresponding character.
270
271 // "Accept"
272 // "AllCandidates"
273
274 // "Alt"
275 case NSMenuFunctionKey:
276 return @"Alt";
277
278 // "Apps"
279 // "BrowserBack"
280 // "BrowserForward"
281 // "BrowserHome"
282 // "BrowserRefresh"
283 // "BrowserSearch"
284 // "BrowserStop"
285 // "CapsLock"
286
287 // "Clear"
288 case NSClearLineFunctionKey:
289 return @"Clear";
290
291 // "CodeInput"
292 // "Compose"
293 // "Control"
294 // "Crsel"
295 // "Convert"
296 // "Copy"
297 // "Cut"
298
299 // "Down"
300 case NSDownArrowFunctionKey:
301 return @"Down";
302 // "End"
303 case NSEndFunctionKey:
304 return @"End";
305 // "Enter"
306 case 0x3:
307 case 0xA:
308 case 0xD: // Macintosh calls the one on the main keyboard Return, but
309 // Windows calls it Enter, so we'll do the same for the DOM
310 return @"Enter";
311
312 // "EraseEof"
313
314 // "Execute"
315 case NSExecuteFunctionKey:
316 return @"Execute";
317
318 // "Exsel"
319
320 // "F1"
321 case NSF1FunctionKey:
322 return @"F1";
323 // "F2"
324 case NSF2FunctionKey:
325 return @"F2";
326 // "F3"
327 case NSF3FunctionKey:
328 return @"F3";
329 // "F4"
330 case NSF4FunctionKey:
331 return @"F4";
332 // "F5"
333 case NSF5FunctionKey:
334 return @"F5";
335 // "F6"
336 case NSF6FunctionKey:
337 return @"F6";
338 // "F7"
339 case NSF7FunctionKey:
340 return @"F7";
341 // "F8"
342 case NSF8FunctionKey:
343 return @"F8";
344 // "F9"
345 case NSF9FunctionKey:
346 return @"F9";
347 // "F10"
348 case NSF10FunctionKey:
349 return @"F10";
350 // "F11"
351 case NSF11FunctionKey:
352 return @"F11";
353 // "F12"
354 case NSF12FunctionKey:
355 return @"F12";
356 // "F13"
357 case NSF13FunctionKey:
358 return @"F13";
359 // "F14"
360 case NSF14FunctionKey:
361 return @"F14";
362 // "F15"
363 case NSF15FunctionKey:
364 return @"F15";
365 // "F16"
366 case NSF16FunctionKey:
367 return @"F16";
368 // "F17"
369 case NSF17FunctionKey:
370 return @"F17";
371 // "F18"
372 case NSF18FunctionKey:
373 return @"F18";
374 // "F19"
375 case NSF19FunctionKey:
376 return @"F19";
377 // "F20"
378 case NSF20FunctionKey:
379 return @"F20";
380 // "F21"
381 case NSF21FunctionKey:
382 return @"F21";
383 // "F22"
384 case NSF22FunctionKey:
385 return @"F22";
386 // "F23"
387 case NSF23FunctionKey:
388 return @"F23";
389 // "F24"
390 case NSF24FunctionKey:
391 return @"F24";
392
393 // "FinalMode"
394
395 // "Find"
396 case NSFindFunctionKey:
397 return @"Find";
398
399 // "FullWidth"
400 // "HalfWidth"
401 // "HangulMode"
402 // "HanjaMode"
403
404 // "Help"
405 case NSHelpFunctionKey:
406 return @"Help";
407
408 // "Hiragana"
409
410 // "Home"
411 case NSHomeFunctionKey:
412 return @"Home";
413 // "Insert"
414 case NSInsertFunctionKey:
415 return @"Insert";
416
417 // "JapaneseHiragana"
418 // "JapaneseKatakana"
419 // "JapaneseRomaji"
420 // "JunjaMode"
421 // "KanaMode"
422 // "KanjiMode"
423 // "Katakana"
424 // "LaunchApplication1"
425 // "LaunchApplication2"
426 // "LaunchMail"
427
428 // "Left"
429 case NSLeftArrowFunctionKey:
430 return @"Left";
431
432 // "Meta"
433 // "MediaNextTrack"
434 // "MediaPlayPause"
435 // "MediaPreviousTrack"
436 // "MediaStop"
437
438 // "ModeChange"
439 case NSModeSwitchFunctionKey:
440 return @"ModeChange";
441
442 // "Nonconvert"
443 // "NumLock"
444
445 // "PageDown"
446 case NSPageDownFunctionKey:
447 return @"PageDown";
448 // "PageUp"
449 case NSPageUpFunctionKey:
450 return @"PageUp";
451
452 // "Paste"
453
454 // "Pause"
455 case NSPauseFunctionKey:
456 return @"Pause";
457
458 // "Play"
459 // "PreviousCandidate"
460
461 // "PrintScreen"
462 case NSPrintScreenFunctionKey:
463 return @"PrintScreen";
464
465 // "Process"
466 // "Props"
467
468 // "Right"
469 case NSRightArrowFunctionKey:
470 return @"Right";
471
472 // "RomanCharacters"
473
474 // "Scroll"
475 case NSScrollLockFunctionKey:
476 return @"Scroll";
477 // "Select"
478 case NSSelectFunctionKey:
479 return @"Select";
480
481 // "SelectMedia"
482 // "Shift"
483
484 // "Stop"
485 case NSStopFunctionKey:
486 return @"Stop";
487 // "Up"
488 case NSUpArrowFunctionKey:
489 return @"Up";
490 // "Undo"
491 case NSUndoFunctionKey:
492 return @"Undo";
493
494 // "VolumeDown"
495 // "VolumeMute"
496 // "VolumeUp"
497 // "Win"
498 // "Zoom"
499
500 // More function keys, not in the key identifier specification.
501 case NSF25FunctionKey:
502 return @"F25";
503 case NSF26FunctionKey:
504 return @"F26";
505 case NSF27FunctionKey:
506 return @"F27";
507 case NSF28FunctionKey:
508 return @"F28";
509 case NSF29FunctionKey:
510 return @"F29";
511 case NSF30FunctionKey:
512 return @"F30";
513 case NSF31FunctionKey:
514 return @"F31";
515 case NSF32FunctionKey:
516 return @"F32";
517 case NSF33FunctionKey:
518 return @"F33";
519 case NSF34FunctionKey:
520 return @"F34";
521 case NSF35FunctionKey:
522 return @"F35";
523
524 // Turn 0x7F into 0x08, because backspace needs to always be 0x08.
525 case 0x7F:
526 return @"U+0008";
527 // Standard says that DEL becomes U+007F.
528 case NSDeleteFunctionKey:
529 return @"U+007F";
530
531 // Always use 0x09 for tab instead of AppKit's backtab character.
532 case NSBackTabCharacter:
533 return @"U+0009";
534
535 case NSBeginFunctionKey:
536 case NSBreakFunctionKey:
537 case NSClearDisplayFunctionKey:
538 case NSDeleteCharFunctionKey:
539 case NSDeleteLineFunctionKey:
540 case NSInsertCharFunctionKey:
541 case NSInsertLineFunctionKey:
542 case NSNextFunctionKey:
543 case NSPrevFunctionKey:
544 case NSPrintFunctionKey:
545 case NSRedoFunctionKey:
546 case NSResetFunctionKey:
547 case NSSysReqFunctionKey:
548 case NSSystemFunctionKey:
549 case NSUserFunctionKey:
550 // FIXME: We should use something other than the vendor-area Unicode values
551 // for the above keys.
552 // For now, just fall through to the default.
553 default:
554 return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)];
555 }
556 }
557
558 // End Apple code.
559 // ----------------------------------------------------------------------------
560
561 static inline int modifiersFromEvent(NSEvent* event) {
562 int modifiers = 0;
563
564 if ([event modifierFlags] & NSControlKeyMask)
565 modifiers |= WebInputEvent::ControlKey;
566 if ([event modifierFlags] & NSShiftKeyMask)
567 modifiers |= WebInputEvent::ShiftKey;
568 if ([event modifierFlags] & NSAlternateKeyMask)
569 modifiers |= WebInputEvent::AltKey;
570 if ([event modifierFlags] & NSCommandKeyMask)
571 modifiers |= WebInputEvent::MetaKey;
572 if ([event modifierFlags] & NSAlphaShiftKeyMask)
573 modifiers |= WebInputEvent::CapsLockOn;
574 // TODO(port): Set mouse button states
575
576 return modifiers;
577 }
578
579 static inline void setWebEventLocationFromEventInView(WebMouseEvent* result,
580 NSEvent* event,
581 NSView* view) {
582 NSPoint windowLocal = [event locationInWindow];
583
584 NSPoint screenLocal = [[view window] convertBaseToScreen:windowLocal];
585 result->globalX = screenLocal.x;
586 // Flip y.
587 NSScreen* primaryScreen =
588 ([[NSScreen screens] count] > 0) ? [[NSScreen screens] objectAtIndex:0]
589 : nil;
590 if (primaryScreen)
591 result->globalY = [primaryScreen frame].size.height - screenLocal.y;
592 else
593 result->globalY = screenLocal.y;
594
595 NSPoint contentLocal = [view convertPoint:windowLocal fromView:nil];
596 result->x = contentLocal.x;
597 result->y = [view frame].size.height - contentLocal.y; // Flip y.
598
599 result->windowX = result->x;
600 result->windowY = result->y;
601
602 result->movementX = [event deltaX];
603 result->movementY = [event deltaY];
604 }
605
606 WebKeyboardEvent WebInputEventFactory::keyboardEvent(NSEvent* event) {
607 WebKeyboardEvent result;
608
609 result.type =
610 isKeyUpEvent(event) ? WebInputEvent::KeyUp : WebInputEvent::RawKeyDown;
611
612 result.modifiers = modifiersFromEvent(event);
613
614 if (isKeypadEvent(event))
615 result.modifiers |= WebInputEvent::IsKeyPad;
616
617 if (([event type] != NSFlagsChanged) && [event isARepeat])
618 result.modifiers |= WebInputEvent::IsAutoRepeat;
619
620 int windowsKeyCode = windowsKeyCodeForKeyEvent(event);
621 result.windowsKeyCode =
622 WebKeyboardEvent::windowsKeyCodeWithoutLocation(windowsKeyCode);
623 result.modifiers |=
624 WebKeyboardEvent::locationModifiersFromWindowsKeyCode(windowsKeyCode);
625 result.nativeKeyCode = [event keyCode];
626
627 NSString* textStr = textFromEvent(event);
628 NSString* unmodifiedStr = unmodifiedTextFromEvent(event);
629 NSString* identifierStr = keyIdentifierForKeyEvent(event);
630
631 // Begin Apple code, copied from KeyEventMac.mm
632
633 // Always use 13 for Enter/Return -- we don't want to use AppKit's
634 // different character for Enter.
635 if (result.windowsKeyCode == '\r') {
636 textStr = @"\r";
637 unmodifiedStr = @"\r";
638 }
639
640 // The adjustments below are only needed in backward compatibility mode,
641 // but we cannot tell what mode we are in from here.
642
643 // Turn 0x7F into 8, because backspace needs to always be 8.
644 if ([textStr isEqualToString:@"\x7F"])
645 textStr = @"\x8";
646 if ([unmodifiedStr isEqualToString:@"\x7F"])
647 unmodifiedStr = @"\x8";
648 // Always use 9 for tab -- we don't want to use AppKit's different character
649 // for shift-tab.
650 if (result.windowsKeyCode == 9) {
651 textStr = @"\x9";
652 unmodifiedStr = @"\x9";
653 }
654
655 // End Apple code.
656
657 if ([textStr length] < WebKeyboardEvent::textLengthCap &&
658 [unmodifiedStr length] < WebKeyboardEvent::textLengthCap) {
659 [textStr getCharacters:&result.text[0]];
660 [unmodifiedStr getCharacters:&result.unmodifiedText[0]];
661 } else
662 ASSERT_NOT_REACHED();
663
664 [identifierStr getCString:&result.keyIdentifier[0]
665 maxLength:sizeof(result.keyIdentifier)
666 encoding:NSASCIIStringEncoding];
667
668 result.timeStampSeconds = [event timestamp];
669
670 // Windows and Linux set |isSystemKey| if alt is down. WebKit looks at this
671 // flag to decide if it should handle a key or not. E.g. alt-left/right
672 // shouldn't be used by WebKit to scroll the current page, because we want
673 // to get that key back for it to do history navigation. Hence, the
674 // corresponding situation on OS X is to set this for cmd key presses.
675 if (result.modifiers & WebInputEvent::MetaKey)
676 result.isSystemKey = true;
677
678 return result;
679 }
680
681 WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character,
682 int modifiers,
683 double timeStampSeconds) {
684 // keyboardEvent(NSEvent*) depends on the NSEvent object and
685 // it is hard to use it from methods of the NSTextInput protocol. For
686 // such methods, this function creates a WebInputEvent::Char event without
687 // using a NSEvent object.
688 WebKeyboardEvent result;
689 result.type = WebKit::WebInputEvent::Char;
690 result.timeStampSeconds = timeStampSeconds;
691 result.modifiers = modifiers;
692 result.windowsKeyCode = character;
693 result.nativeKeyCode = character;
694 result.text[0] = character;
695 result.unmodifiedText[0] = character;
696
697 // Windows and Linux set |isSystemKey| if alt is down. WebKit looks at this
698 // flag to decide if it should handle a key or not. E.g. alt-left/right
699 // shouldn't be used by WebKit to scroll the current page, because we want
700 // to get that key back for it to do history navigation. Hence, the
701 // corresponding situation on OS X is to set this for cmd key presses.
702 if (result.modifiers & WebInputEvent::MetaKey)
703 result.isSystemKey = true;
704
705 return result;
706 }
707
708 // WebMouseEvent --------------------------------------------------------------
709
710 WebMouseEvent WebInputEventFactory::mouseEvent(NSEvent* event, NSView* view) {
711 WebMouseEvent result;
712
713 result.clickCount = 0;
714
715 switch ([event type]) {
716 case NSMouseExited:
717 result.type = WebInputEvent::MouseLeave;
718 result.button = WebMouseEvent::ButtonNone;
719 break;
720 case NSLeftMouseDown:
721 result.type = WebInputEvent::MouseDown;
722 result.clickCount = [event clickCount];
723 result.button = WebMouseEvent::ButtonLeft;
724 break;
725 case NSOtherMouseDown:
726 result.type = WebInputEvent::MouseDown;
727 result.clickCount = [event clickCount];
728 result.button = WebMouseEvent::ButtonMiddle;
729 break;
730 case NSRightMouseDown:
731 result.type = WebInputEvent::MouseDown;
732 result.clickCount = [event clickCount];
733 result.button = WebMouseEvent::ButtonRight;
734 break;
735 case NSLeftMouseUp:
736 result.type = WebInputEvent::MouseUp;
737 result.clickCount = [event clickCount];
738 result.button = WebMouseEvent::ButtonLeft;
739 break;
740 case NSOtherMouseUp:
741 result.type = WebInputEvent::MouseUp;
742 result.clickCount = [event clickCount];
743 result.button = WebMouseEvent::ButtonMiddle;
744 break;
745 case NSRightMouseUp:
746 result.type = WebInputEvent::MouseUp;
747 result.clickCount = [event clickCount];
748 result.button = WebMouseEvent::ButtonRight;
749 break;
750 case NSMouseMoved:
751 case NSMouseEntered:
752 result.type = WebInputEvent::MouseMove;
753 break;
754 case NSLeftMouseDragged:
755 result.type = WebInputEvent::MouseMove;
756 result.button = WebMouseEvent::ButtonLeft;
757 break;
758 case NSOtherMouseDragged:
759 result.type = WebInputEvent::MouseMove;
760 result.button = WebMouseEvent::ButtonMiddle;
761 break;
762 case NSRightMouseDragged:
763 result.type = WebInputEvent::MouseMove;
764 result.button = WebMouseEvent::ButtonRight;
765 break;
766 default:
767 ASSERT_NOT_REACHED();
768 }
769
770 setWebEventLocationFromEventInView(&result, event, view);
771
772 result.modifiers = modifiersFromEvent(event);
773
774 result.timeStampSeconds = [event timestamp];
775
776 return result;
777 }
778
779 // WebMouseWheelEvent ---------------------------------------------------------
780
781 static WebMouseWheelEvent::Phase phaseForNSEventPhase(NSEventPhase eventPhase) {
782 uint32_t phase = WebMouseWheelEvent::PhaseNone;
783 if (eventPhase & NSEventPhaseBegan)
784 phase |= WebMouseWheelEvent::PhaseBegan;
785 if (eventPhase & NSEventPhaseStationary)
786 phase |= WebMouseWheelEvent::PhaseStationary;
787 if (eventPhase & NSEventPhaseChanged)
788 phase |= WebMouseWheelEvent::PhaseChanged;
789 if (eventPhase & NSEventPhaseEnded)
790 phase |= WebMouseWheelEvent::PhaseEnded;
791 if (eventPhase & NSEventPhaseCancelled)
792 phase |= WebMouseWheelEvent::PhaseCancelled;
793 if (eventPhase & NSEventPhaseMayBegin)
794 phase |= WebMouseWheelEvent::PhaseMayBegin;
795 return static_cast<WebMouseWheelEvent::Phase>(phase);
796 }
797
798 static WebMouseWheelEvent::Phase phaseForEvent(NSEvent* event) {
799 if (![event respondsToSelector:@selector(phase)])
800 return WebMouseWheelEvent::PhaseNone;
801
802 NSEventPhase eventPhase = [event phase];
803 return phaseForNSEventPhase(eventPhase);
804 }
805
806 static WebMouseWheelEvent::Phase momentumPhaseForEvent(NSEvent* event) {
807 if (![event respondsToSelector:@selector(momentumPhase)])
808 return WebMouseWheelEvent::PhaseNone;
809
810 NSEventPhase eventMomentumPhase = [event momentumPhase];
811 return phaseForNSEventPhase(eventMomentumPhase);
812 }
813
814 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(NSEvent* event,
815 NSView* view) {
816 WebMouseWheelEvent result;
817
818 result.type = WebInputEvent::MouseWheel;
819 result.button = WebMouseEvent::ButtonNone;
820
821 result.modifiers = modifiersFromEvent(event);
822
823 setWebEventLocationFromEventInView(&result, event, view);
824
825 // Of Mice and Men
826 // ---------------
827 //
828 // There are three types of scroll data available on a scroll wheel CGEvent.
829 // Apple's documentation ([1]) is rather vague in their differences, and not
830 // terribly helpful in deciding which to use. This is what's really going on.
831 //
832 // First, these events behave very differently depending on whether a standard
833 // wheel mouse is used (one that scrolls in discrete units) or a
834 // trackpad/Mighty Mouse is used (which both provide continuous scrolling).
835 // You must check to see which was used for the event by testing the
836 // kCGScrollWheelEventIsContinuous field.
837 //
838 // Second, these events refer to "axes". Axis 1 is the y-axis, and axis 2 is
839 // the x-axis.
840 //
841 // Third, there is a concept of mouse acceleration. Scrolling the same amount
842 // of physical distance will give you different results logically depending on
843 // whether you scrolled a little at a time or in one continuous motion. Some
844 // fields account for this while others do not.
845 //
846 // Fourth, for trackpads there is a concept of chunkiness. When scrolling
847 // continuously, events can be delivered in chunks. That is to say, lots of
848 // scroll events with delta 0 will be delivered, and every so often an event
849 // with a non-zero delta will be delivered, containing the accumulated deltas
850 // from all the intermediate moves. [2]
851 //
852 // For notchy wheel mice (kCGScrollWheelEventIsContinuous == 0)
853 // ------------------------------------------------------------
854 //
855 // kCGScrollWheelEventDeltaAxis*
856 // This is the rawest of raw events. For each mouse notch you get a value of
857 // +1/-1. This does not take acceleration into account and thus is less
858 // useful for building UIs.
859 //
860 // kCGScrollWheelEventPointDeltaAxis*
861 // This is smarter. In general, for each mouse notch you get a value of
862 // +1/-1, but this _does_ take acceleration into account, so you will get
863 // larger values on longer scrolls. This field would be ideal for building
864 // UIs except for one nasty bug: when the shift key is pressed, this set of
865 // fields fails to move the value into the axis2 field (the other two types
866 // of data do). This wouldn't be so bad except for the fact that while the
867 // number of axes is used in the creation of a CGScrollWheelEvent, there is
868 // no way to get that information out of the event once created.
869 //
870 // kCGScrollWheelEventFixedPtDeltaAxis*
871 // This is a fixed value, and for each mouse notch you get a value of
872 // +0.1/-0.1 (but, like above, scaled appropriately for acceleration). This
873 // value takes acceleration into account, and in fact is identical to the
874 // results you get from -[NSEvent delta*]. (That is, if you linked on Tiger
875 // or greater; see [2] for details.)
876 //
877 // A note about continuous devices
878 // -------------------------------
879 //
880 // There are two devices that provide continuous scrolling events (trackpads
881 // and Mighty Mouses) and they behave rather differently. The Mighty Mouse
882 // behaves a lot like a regular mouse. There is no chunking, and the
883 // FixedPtDelta values are the PointDelta values multiplied by 0.1. With the
884 // trackpad, though, there is chunking. While the FixedPtDelta values are
885 // reasonable (they occur about every fifth event but have values five times
886 // larger than usual) the Delta values are unreasonable. They don't appear to
887 // accumulate properly.
888 //
889 // For continuous devices (kCGScrollWheelEventIsContinuous != 0)
890 // -------------------------------------------------------------
891 //
892 // kCGScrollWheelEventDeltaAxis*
893 // This provides values with no acceleration. With a trackpad, these values
894 // are chunked but each non-zero value does not appear to be cumulative.
895 // This seems to be a bug.
896 //
897 // kCGScrollWheelEventPointDeltaAxis*
898 // This provides values with acceleration. With a trackpad, these values are
899 // not chunked and are highly accurate.
900 //
901 // kCGScrollWheelEventFixedPtDeltaAxis*
902 // This provides values with acceleration. With a trackpad, these values are
903 // chunked but unlike Delta events are properly cumulative.
904 //
905 // Summary
906 // -------
907 //
908 // In general the best approach to take is: determine if the event is
909 // continuous. If it is not, then use the FixedPtDelta events (or just stick
910 // with Cocoa events). They provide both acceleration and proper horizontal
911 // scrolling. If the event is continuous, then doing pixel scrolling with the
912 // PointDelta is the way to go. In general, avoid the Delta events. They're
913 // the oldest (dating back to 10.4, before CGEvents were public) but they lack
914 // acceleration and precision, making them useful only in specific edge cases.
915 //
916 // References
917 // ----------
918 //
919 // [1]
920 // <http://developer.apple.com/documentation/Carbon/Reference/QuartzEventServi cesRef/Reference/reference.html>
921 // [2] <http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html>
922 // Scroll to the section headed "NSScrollWheel events".
923 //
924 // P.S. The "smooth scrolling" option in the system preferences is utterly
925 // unrelated to any of this.
926
927 CGEventRef cgEvent = [event CGEvent];
928 ASSERT(cgEvent);
929
930 // Wheel ticks are supposed to be raw, unaccelerated values, one per physical
931 // mouse wheel notch. The delta event is perfect for this (being a good
932 // "specific edge case" as mentioned above). Trackpads, unfortunately, do
933 // event chunking, and sending mousewheel events with 0 ticks causes some
934 // websites to malfunction. Therefore, for all continuous input devices we use
935 // the point delta data instead, since we cannot distinguish trackpad data
936 // from data from any other continuous device.
937
938 // Conversion between wheel delta amounts and number of pixels to scroll.
939 static const double scrollbarPixelsPerCocoaTick = 40.0;
940
941 if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) {
942 result.deltaX = CGEventGetIntegerValueField(
943 cgEvent, kCGScrollWheelEventPointDeltaAxis2);
944 result.deltaY = CGEventGetIntegerValueField(
945 cgEvent, kCGScrollWheelEventPointDeltaAxis1);
946 result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick;
947 result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick;
948 result.hasPreciseScrollingDeltas = true;
949 } else {
950 result.deltaX = [event deltaX] * scrollbarPixelsPerCocoaTick;
951 result.deltaY = [event deltaY] * scrollbarPixelsPerCocoaTick;
952 result.wheelTicksY =
953 CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis1);
954 result.wheelTicksX =
955 CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis2);
956 }
957
958 result.timeStampSeconds = [event timestamp];
959
960 result.phase = phaseForEvent(event);
961 result.momentumPhase = momentumPhaseForEvent(event);
962
963 return result;
964 }
965
966 WebGestureEvent WebInputEventFactory::gestureEvent(NSEvent* event,
967 NSView* view) {
968 WebGestureEvent result;
969
970 // Use a temporary WebMouseEvent to get the location.
971 WebMouseEvent temp;
972
973 setWebEventLocationFromEventInView(&temp, event, view);
974 result.x = temp.x;
975 result.y = temp.y;
976 result.globalX = temp.globalX;
977 result.globalY = temp.globalY;
978
979 result.type = gestureEventTypeForEvent(event);
980 result.modifiers = modifiersFromEvent(event);
981 result.timeStampSeconds = [event timestamp];
982
983 return result;
984 }
985
986 } // namespace WebKit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698