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

Side by Side Diff: content/browser/renderer_host/input/web_input_event_builders_mac.mm

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

Powered by Google App Engine
This is Rietveld 408576698