| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2006-2009 Google Inc. | 3 * Copyright (C) 2006-2009 Google Inc. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| 11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
| 13 * | 13 * |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include <ApplicationServices/ApplicationServices.h> |
| 27 #import <Cocoa/Cocoa.h> | 28 #import <Cocoa/Cocoa.h> |
| 28 | 29 |
| 29 #include "config.h" | 30 #include "config.h" |
| 30 | 31 |
| 31 #include "wtf/ASCIICType.h" | 32 #include "wtf/ASCIICType.h" |
| 32 #include "webkit/glue/webinputevent.h" | 33 #include "webkit/glue/webinputevent.h" |
| 33 #include "webkit/glue/event_conversion.h" | 34 #include "webkit/glue/event_conversion.h" |
| 34 | 35 |
| 35 #undef LOG | 36 #undef LOG |
| 36 #include "base/logging.h" | 37 #include "base/logging.h" |
| 37 | 38 |
| 38 // WebMouseEvent -------------------------------------------------------------- | 39 // WebMouseEvent -------------------------------------------------------------- |
| 39 | 40 |
| 40 WebMouseEvent::WebMouseEvent(NSEvent *event, NSView* view) { | 41 WebMouseEvent::WebMouseEvent(NSEvent* event, NSView* view) { |
| 41 switch ([event type]) { | 42 switch ([event type]) { |
| 42 case NSMouseExited: | 43 case NSMouseExited: |
| 43 type = MOUSE_LEAVE; | 44 type = MOUSE_LEAVE; |
| 44 button = BUTTON_NONE; | 45 button = BUTTON_NONE; |
| 45 break; | 46 break; |
| 46 case NSLeftMouseDown: | 47 case NSLeftMouseDown: |
| 47 type = [event clickCount] == 2 ? MOUSE_DOUBLE_CLICK : MOUSE_DOWN; | 48 type = [event clickCount] == 2 ? MOUSE_DOUBLE_CLICK : MOUSE_DOWN; |
| 48 button = BUTTON_LEFT; | 49 button = BUTTON_LEFT; |
| 49 break; | 50 break; |
| 50 case NSOtherMouseDown: | 51 case NSOtherMouseDown: |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 if ([event modifierFlags] & NSAlternateKeyMask) | 107 if ([event modifierFlags] & NSAlternateKeyMask) |
| 107 modifiers |= (ALT_KEY | META_KEY); // TODO(darin): set META properly | 108 modifiers |= (ALT_KEY | META_KEY); // TODO(darin): set META properly |
| 108 | 109 |
| 109 timestamp_sec = [event timestamp]; | 110 timestamp_sec = [event timestamp]; |
| 110 | 111 |
| 111 layout_test_click_count = 0; | 112 layout_test_click_count = 0; |
| 112 } | 113 } |
| 113 | 114 |
| 114 // WebMouseWheelEvent --------------------------------------------------------- | 115 // WebMouseWheelEvent --------------------------------------------------------- |
| 115 | 116 |
| 116 WebMouseWheelEvent::WebMouseWheelEvent(NSEvent *event, NSView* view) { | 117 WebMouseWheelEvent::WebMouseWheelEvent(NSEvent* event, NSView* view) { |
| 117 type = MOUSE_WHEEL; | 118 type = MOUSE_WHEEL; |
| 118 button = BUTTON_NONE; | 119 button = BUTTON_NONE; |
| 119 | 120 |
| 120 // Set modifiers based on key state. | 121 // Set modifiers based on key state. |
| 121 if ([event modifierFlags] & NSControlKeyMask) | 122 if ([event modifierFlags] & NSControlKeyMask) |
| 122 modifiers |= CTRL_KEY; | 123 modifiers |= CTRL_KEY; |
| 123 if ([event modifierFlags] & NSShiftKeyMask) | 124 if ([event modifierFlags] & NSShiftKeyMask) |
| 124 modifiers |= SHIFT_KEY; | 125 modifiers |= SHIFT_KEY; |
| 125 if ([event modifierFlags] & NSAlternateKeyMask) | 126 if ([event modifierFlags] & NSAlternateKeyMask) |
| 126 modifiers |= ALT_KEY; | 127 modifiers |= ALT_KEY; |
| 127 | 128 |
| 128 // Set coordinates by translating event coordinates from screen to client. | 129 // Set coordinates by translating event coordinates from screen to client. |
| 129 NSPoint location = [NSEvent mouseLocation]; // global coordinates | 130 NSPoint location = [NSEvent mouseLocation]; // global coordinates |
| 130 global_x = location.x; | 131 global_x = location.x; |
| 131 global_y = location.y; | 132 global_y = location.y; |
| 132 NSPoint windowLocal = [event locationInWindow]; | 133 NSPoint windowLocal = [event locationInWindow]; |
| 133 location = [view convertPoint:windowLocal fromView:nil]; | 134 location = [view convertPoint:windowLocal fromView:nil]; |
| 134 x = location.x; | 135 x = location.x; |
| 135 y = [view frame].size.height - location.y; // flip y | 136 y = [view frame].size.height - location.y; // flip y |
| 136 | 137 |
| 137 // Convert wheel delta amount to a number of pixels to scroll. | 138 // Of Mice and Men |
| 138 // Cocoa sets deltaX instead of deltaY if shift is pressed when scrolling | 139 // --------------- |
| 139 // with a scroll wheel, no need to do that ourselves. | 140 // |
| 140 static const float kScrollbarPixelsPerTick = 40.0f; | 141 // There are three types of scroll data available on a scroll wheel CGEvent. |
| 142 // Apple's documentation ([1]) is rather vague in their differences, and not |
| 143 // terribly helpful in deciding which to use. This is what's really going on. |
| 144 // |
| 145 // First, these events behave very differently depending on whether a standard |
| 146 // wheel mouse is used (one that scrolls in discrete units) or a |
| 147 // trackpad/Mighty Mouse is used (which both provide continuous scrolling). |
| 148 // You must check to see which was used for the event by testing the |
| 149 // kCGScrollWheelEventIsContinuous field. |
| 150 // |
| 151 // Second, these events refer to "axes". Axis 1 is the y-axis, and axis 2 is |
| 152 // the x-axis. |
| 153 // |
| 154 // Third, there is a concept of mouse acceleration. Scrolling the same amount |
| 155 // of physical distance will give you different results logically depending on |
| 156 // whether you scrolled a little at a time or in one continuous motion. Some |
| 157 // fields account for this while others do not. |
| 158 // |
| 159 // Fourth, for trackpads there is a concept of chunkiness. When scrolling |
| 160 // continuously, events can be delivered in chunks. That is to say, lots of |
| 161 // scroll events with delta 0 will be delivered, and every so often an event |
| 162 // with a non-zero delta will be delivered, containing the accumulated deltas |
| 163 // from all the intermediate moves. [2] |
| 164 // |
| 165 // For notchy wheel mice (kCGScrollWheelEventIsContinuous == 0) |
| 166 // ------------------------------------------------------------ |
| 167 // |
| 168 // kCGScrollWheelEventDeltaAxis* |
| 169 // This is the rawest of raw events. For each mouse notch you get a value of |
| 170 // +1/-1. This does not take acceleration into account and thus is less |
| 171 // useful for building UIs. |
| 172 // |
| 173 // kCGScrollWheelEventPointDeltaAxis* |
| 174 // This is smarter. In general, for each mouse notch you get a value of |
| 175 // +1/-1, but this _does_ take acceleration into account, so you will get |
| 176 // larger values on longer scrolls. This field would be ideal for building |
| 177 // UIs except for one nasty bug: when the shift key is pressed, this set of |
| 178 // fields fails to move the value into the axis2 field (the other two types |
| 179 // of data do). This wouldn't be so bad except for the fact that while the |
| 180 // number of axes is used in the creation of a CGScrollWheelEvent, there is |
| 181 // no way to get that information out of the event once created. |
| 182 // |
| 183 // kCGScrollWheelEventFixedPtDeltaAxis* |
| 184 // This is a fixed value, and for each mouse notch you get a value of |
| 185 // +0.1/-0.1 (but, like above, scaled appropriately for acceleration). This |
| 186 // value takes acceleration into account, and in fact is identical to the |
| 187 // results you get from -[NSEvent delta*]. (That is, if you linked on Tiger |
| 188 // or greater; see [2] for details.) |
| 189 // |
| 190 // A note about continuous devices |
| 191 // ------------------------------- |
| 192 // |
| 193 // There are two devices that provide continuous scrolling events (trackpads |
| 194 // and Mighty Mouses) and they behave rather differently. The Mighty Mouse |
| 195 // behaves a lot like a regular mouse. There is no chunking, and the |
| 196 // FixedPtDelta values are the PointDelta values multiplied by 0.1. With the |
| 197 // trackpad, though, there is chunking. While the FixedPtDelta values are |
| 198 // reasonable (they occur about every fifth event but have values five times |
| 199 // larger than usual) the Delta values are unreasonable. They don't appear to |
| 200 // accumulate properly. |
| 201 // |
| 202 // For continuous devices (kCGScrollWheelEventIsContinuous != 0) |
| 203 // ------------------------------------------------------------- |
| 204 // |
| 205 // kCGScrollWheelEventDeltaAxis* |
| 206 // This provides values with no acceleration. With a trackpad, these values |
| 207 // are chunked but each non-zero value does not appear to be cumulative. |
| 208 // This seems to be a bug. |
| 209 // |
| 210 // kCGScrollWheelEventPointDeltaAxis* |
| 211 // This provides values with acceleration. With a trackpad, these values are |
| 212 // not chunked and are highly accurate. |
| 213 // |
| 214 // kCGScrollWheelEventFixedPtDeltaAxis* |
| 215 // This provides values with acceleration. With a trackpad, these values are |
| 216 // chunked but unlike Delta events are properly cumulative. |
| 217 // |
| 218 // Summary |
| 219 // ------- |
| 220 // |
| 221 // In general the best approach to take is: determine if the event is |
| 222 // continuous. If it is not, then use the FixedPtDelta events (or just stick |
| 223 // with Cocoa events). They provide both acceleration and proper horizontal |
| 224 // scrolling. If the event is continuous, then doing pixel scrolling with the |
| 225 // PointDelta is the way to go. In general, avoid the Delta events. They're |
| 226 // the oldest (dating back to 10.4, before CGEvents were public) but they lack |
| 227 // acceleration and precision, making them useful only in specific edge cases. |
| 228 // |
| 229 // References |
| 230 // ---------- |
| 231 // |
| 232 // [1] <http://developer.apple.com/documentation/Carbon/Reference/QuartzEventS
ervicesRef/Reference/reference.html> |
| 233 // [2] <http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html> |
| 234 // Scroll to the section headed "NSScrollWheel events". |
| 235 // |
| 236 // P.S. The "smooth scrolling" option in the system preferences is utterly |
| 237 // unrelated to any of this. |
| 141 | 238 |
| 142 wheel_ticks_x = [event deltaX]; | 239 CGEventRef cg_event = [event CGEvent]; |
| 143 delta_x = wheel_ticks_x * kScrollbarPixelsPerTick; | 240 DCHECK(cg_event); |
| 144 | 241 |
| 145 wheel_ticks_y = [event deltaY]; | 242 // Wheel Ticks are supposed to be raw, unaccelerated values, one per physical |
| 146 delta_y = wheel_ticks_y * kScrollbarPixelsPerTick; | 243 // mouse wheel notch. The delta event is perfect for this (being a good |
| 244 // "specific edge case" as mentioned above). For trackpads, unfortunately, we |
| 245 // don't have anything better. |
| 246 |
| 247 wheel_ticks_y = CGEventGetIntegerValueField(cg_event, |
| 248 kCGScrollWheelEventDeltaAxis1); |
| 249 wheel_ticks_x = CGEventGetIntegerValueField(cg_event, |
| 250 kCGScrollWheelEventDeltaAxis2); |
| 251 |
| 252 if (CGEventGetIntegerValueField(cg_event, kCGScrollWheelEventIsContinuous)) { |
| 253 delta_y = CGEventGetIntegerValueField(cg_event, |
| 254 kCGScrollWheelEventPointDeltaAxis1); |
| 255 delta_x = CGEventGetIntegerValueField(cg_event, |
| 256 kCGScrollWheelEventPointDeltaAxis2); |
| 257 } else { |
| 258 // Convert wheel delta amount to a number of pixels to scroll. |
| 259 static const double kScrollbarPixelsPerCocoaTick = 40.0; |
| 260 |
| 261 delta_x = [event deltaX] * kScrollbarPixelsPerCocoaTick; |
| 262 delta_y = [event deltaY] * kScrollbarPixelsPerCocoaTick; |
| 263 } |
| 147 | 264 |
| 148 scroll_by_page = false; | 265 scroll_by_page = false; |
| 149 } | 266 } |
| 150 | 267 |
| 151 // WebKeyboardEvent ----------------------------------------------------------- | 268 // WebKeyboardEvent ----------------------------------------------------------- |
| 152 | 269 |
| 153 // ---------------------------------------------------------------------- | 270 // ---------------------------------------------------------------------- |
| 154 // Begin Apple code, copied from KeyEventMac.mm | 271 // Begin Apple code, copied from KeyEventMac.mm |
| 155 // | 272 // |
| 156 // We can share some of this code if we factored it out of KeyEventMac, but | 273 // We can share some of this code if we factored it out of KeyEventMac, but |
| 157 // the main problem is that it relies on the NSString ctor on String for | 274 // the main problem is that it relies on the NSString ctor on String for |
| 158 // conversions, and since we're building without PLATFORM(MAC), we don't have | 275 // conversions, and since we're building without PLATFORM(MAC), we don't have |
| 159 // that. As a result we have to use NSString here exclusively and thus tweak | 276 // that. As a result we have to use NSString here exclusively and thus tweak |
| 160 // the code so it's not re-usable as-is. One possiblity would be to make the | 277 // the code so it's not re-usable as-is. One possiblity would be to make the |
| 161 // upstream code only use NSString, but I'm not certain how far that change | 278 // upstream code only use NSString, but I'm not certain how far that change |
| 162 // would propagate. | 279 // would propagate. |
| 163 | 280 |
| 164 namespace WebCore { | 281 namespace WebCore { |
| 165 | 282 |
| 166 static inline bool isKeyUpEvent(NSEvent *event) | 283 static inline bool isKeyUpEvent(NSEvent* event) |
| 167 { | 284 { |
| 168 if ([event type] != NSFlagsChanged) | 285 if ([event type] != NSFlagsChanged) |
| 169 return [event type] == NSKeyUp; | 286 return [event type] == NSKeyUp; |
| 170 // FIXME: This logic fails if the user presses both Shift keys at once, for
example: | 287 // FIXME: This logic fails if the user presses both Shift keys at once, for
example: |
| 171 // we treat releasing one of them as keyDown. | 288 // we treat releasing one of them as keyDown. |
| 172 switch ([event keyCode]) { | 289 switch ([event keyCode]) { |
| 173 case 54: // Right Command | 290 case 54: // Right Command |
| 174 case 55: // Left Command | 291 case 55: // Left Command |
| 175 return ([event modifierFlags] & NSCommandKeyMask) == 0; | 292 return ([event modifierFlags] & NSCommandKeyMask) == 0; |
| 176 | 293 |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 | 753 |
| 637 case 59: // Left Ctrl | 754 case 59: // Left Ctrl |
| 638 case 62: // Right Ctrl | 755 case 62: // Right Ctrl |
| 639 return @"Control"; | 756 return @"Control"; |
| 640 | 757 |
| 641 default: | 758 default: |
| 642 ASSERT_NOT_REACHED(); | 759 ASSERT_NOT_REACHED(); |
| 643 return @""; | 760 return @""; |
| 644 } | 761 } |
| 645 | 762 |
| 646 NSString *s = [event charactersIgnoringModifiers]; | 763 NSString* s = [event charactersIgnoringModifiers]; |
| 647 if ([s length] != 1) { | 764 if ([s length] != 1) { |
| 648 return @"Unidentified"; | 765 return @"Unidentified"; |
| 649 } | 766 } |
| 650 unichar c = [s characterAtIndex:0]; | 767 unichar c = [s characterAtIndex:0]; |
| 651 switch (c) { | 768 switch (c) { |
| 652 // Each identifier listed in the DOM spec is listed here. | 769 // Each identifier listed in the DOM spec is listed here. |
| 653 // Many are simply commented out since they do not appear on standard Ma
cintosh keyboards | 770 // Many are simply commented out since they do not appear on standard Ma
cintosh keyboards |
| 654 // or are on a key that doesn't have a corresponding character. | 771 // or are on a key that doesn't have a corresponding character. |
| 655 | 772 |
| 656 // "Accept" | 773 // "Accept" |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 default: | 1051 default: |
| 935 return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)]; | 1052 return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)]; |
| 936 } | 1053 } |
| 937 } | 1054 } |
| 938 | 1055 |
| 939 } // namespace WebCore | 1056 } // namespace WebCore |
| 940 | 1057 |
| 941 // End Apple code. | 1058 // End Apple code. |
| 942 // --------------------------------------------------------------------- | 1059 // --------------------------------------------------------------------- |
| 943 | 1060 |
| 944 WebKeyboardEvent::WebKeyboardEvent(NSEvent *event) { | 1061 WebKeyboardEvent::WebKeyboardEvent(NSEvent* event) { |
| 945 system_key = false; | 1062 system_key = false; |
| 946 type = WebCore::isKeyUpEvent(event) ? KEY_UP : KEY_DOWN; | 1063 type = WebCore::isKeyUpEvent(event) ? KEY_UP : KEY_DOWN; |
| 947 | 1064 |
| 948 if ([event modifierFlags] & NSControlKeyMask) | 1065 if ([event modifierFlags] & NSControlKeyMask) |
| 949 modifiers |= CTRL_KEY; | 1066 modifiers |= CTRL_KEY; |
| 950 if ([event modifierFlags] & NSShiftKeyMask) | 1067 if ([event modifierFlags] & NSShiftKeyMask) |
| 951 modifiers |= SHIFT_KEY; | 1068 modifiers |= SHIFT_KEY; |
| 952 if ([event modifierFlags] & NSAlternateKeyMask) | 1069 if ([event modifierFlags] & NSAlternateKeyMask) |
| 953 modifiers |= ALT_KEY; | 1070 modifiers |= ALT_KEY; |
| 954 if ([event modifierFlags] & NSCommandKeyMask) | 1071 if ([event modifierFlags] & NSCommandKeyMask) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 [unmodified_str length] < kTextLengthCap) { | 1118 [unmodified_str length] < kTextLengthCap) { |
| 1002 [text_str getCharacters:&text[0]]; | 1119 [text_str getCharacters:&text[0]]; |
| 1003 [unmodified_str getCharacters:&unmodified_text[0]]; | 1120 [unmodified_str getCharacters:&unmodified_text[0]]; |
| 1004 } else { | 1121 } else { |
| 1005 LOG(ERROR) << "Event had text too long; dropped"; | 1122 LOG(ERROR) << "Event had text too long; dropped"; |
| 1006 } | 1123 } |
| 1007 [identifier_str getCString:&key_identifier[0] | 1124 [identifier_str getCString:&key_identifier[0] |
| 1008 maxLength:kIdentifierLengthCap | 1125 maxLength:kIdentifierLengthCap |
| 1009 encoding:NSASCIIStringEncoding]; | 1126 encoding:NSASCIIStringEncoding]; |
| 1010 } | 1127 } |
| OLD | NEW |