[iOS] Key code is 0 for many hardware keyboard keys
[WebKit-https.git] / Source / WebCore / platform / ios / WebEvent.mm
1 /*
2  * Copyright (C) 2009, 2010 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 // FIXME: Rename this file to WebEventIOS.mm after we upstream the iOS port and remove the PLATFORM(IOS)-guard.
27
28 #import "config.h"
29 #import "WebEvent.h"
30
31 #import "KeyEventCocoa.h"
32 #import <wtf/Assertions.h>
33
34 #if PLATFORM(IOS)
35
36 #import "WAKAppKitStubs.h"
37
38 using WebCore::windowsKeyCodeForKeyCode;
39 using WebCore::windowsKeyCodeForCharCode;
40 @implementation WebEvent
41
42 @synthesize type = _type;
43 @synthesize timestamp = _timestamp;
44 @synthesize wasHandled = _wasHandled;
45
46 - (WebEvent *)initWithMouseEventType:(WebEventType)type
47                            timeStamp:(CFTimeInterval)timeStamp
48                             location:(CGPoint)point
49 {
50     self = [super init];
51     if (!self)
52         return nil;
53     
54     _type = type;
55     _timestamp = timeStamp;
56
57     _locationInWindow = point;
58     
59     return self;
60 }
61
62 - (WebEvent *)initWithScrollWheelEventWithTimeStamp:(CFTimeInterval)timeStamp
63                                            location:(CGPoint)point
64                                               deltaX:(float)deltaX
65                                               deltaY:(float)deltaY
66 {
67     self = [super init];
68     if (!self)
69         return nil;
70     
71     _type = WebEventScrollWheel;
72     _timestamp = timeStamp;
73
74     _locationInWindow = point;
75     _deltaX = deltaX;
76     _deltaY = deltaY;
77     
78     return self;
79 }
80
81 - (WebEvent *)initWithTouchEventType:(WebEventType)type
82                            timeStamp:(CFTimeInterval)timeStamp
83                             location:(CGPoint)point
84                            modifiers:(WebEventFlags)modifiers
85                           touchCount:(unsigned)touchCount
86                       touchLocations:(NSArray *)touchLocations
87                     touchIdentifiers:(NSArray *)touchIdentifiers
88                          touchPhases:(NSArray *)touchPhases isGesture:(BOOL)isGesture
89                         gestureScale:(float)gestureScale
90                      gestureRotation:(float)gestureRotation
91 {
92     self = [super init];
93     if (!self)
94         return nil;
95
96     _type = type;
97     _timestamp = timeStamp;
98     _modifierFlags = modifiers;
99
100     // FIXME: <rdar://problem/7185284> TouchEvents may be in more than one window some day.
101     _locationInWindow = point;
102     _touchCount = touchCount;
103     _touchLocations = [touchLocations copy];
104     _touchIdentifiers = [touchIdentifiers copy];
105     _touchPhases = [touchPhases copy];
106     _isGesture = isGesture;
107     _gestureScale = gestureScale;
108     _gestureRotation = gestureRotation;
109
110     return self;
111 }
112
113 static int windowsKeyCodeForCharCodeIOS(unichar charCode)
114 {
115     // iPhone Specific Cases
116     // <rdar://7709408>: We get 10 ('\n') from UIKit when using the software keyboard
117     if (charCode == 10)
118         return 0x0D;
119
120     // General Case
121     return windowsKeyCodeForCharCode(charCode);
122 }
123
124 // FIXME: to be removed when the adoption of the new initializer is complete.
125 - (WebEvent *)initWithKeyEventType:(WebEventType)type
126                          timeStamp:(CFTimeInterval)timeStamp
127                         characters:(NSString *)characters
128        charactersIgnoringModifiers:(NSString *)charactersIgnoringModifiers
129                          modifiers:(WebEventFlags)modifiers
130                        isRepeating:(BOOL)repeating
131                          withFlags:(NSUInteger)flags
132                            keyCode:(uint16_t)keyCode
133                           isTabKey:(BOOL)tabKey
134                       characterSet:(WebEventCharacterSet)characterSet
135 {
136     UNUSED_PARAM(characterSet);
137     self = [super init];
138     if (!self)
139         return nil;
140     
141     _type = type;
142     _timestamp = timeStamp;
143
144     _characters = [characters retain];
145     _charactersIgnoringModifiers = [charactersIgnoringModifiers retain];
146     _modifierFlags = modifiers;
147     _keyRepeating = repeating;
148     _keyboardFlags = flags;
149     _tabKey = tabKey;
150     
151     if (keyCode)
152         _keyCode = windowsKeyCodeForKeyCode(keyCode);
153     else if ([charactersIgnoringModifiers length] == 1) {
154         // This event is likely for a software keyboard-generated event.
155         _keyCode = windowsKeyCodeForCharCodeIOS([charactersIgnoringModifiers characterAtIndex:0]);
156     }
157
158     return self;
159 }
160
161 - (WebEvent *)initWithKeyEventType:(WebEventType)type
162                          timeStamp:(CFTimeInterval)timeStamp
163                         characters:(NSString *)characters
164        charactersIgnoringModifiers:(NSString *)charactersIgnoringModifiers
165                          modifiers:(WebEventFlags)modifiers
166                        isRepeating:(BOOL)repeating
167                          withFlags:(NSUInteger)flags
168               withInputManagerHint:(NSString *)hint
169                            keyCode:(uint16_t)keyCode
170                           isTabKey:(BOOL)tabKey
171 {
172     self = [super init];
173     if (!self)
174         return nil;
175     
176     _type = type;
177     _timestamp = timeStamp;
178     
179     _characters = [characters retain];
180     _charactersIgnoringModifiers = [charactersIgnoringModifiers retain];
181     _modifierFlags = modifiers;
182     _keyRepeating = repeating;
183     _keyboardFlags = flags;
184     _inputManagerHint = [hint retain];
185     _tabKey = tabKey;
186     
187     if (keyCode)
188         _keyCode = windowsKeyCodeForKeyCode(keyCode);
189     else if ([charactersIgnoringModifiers length] == 1) {
190         // This event is likely for a software keyboard-generated event.
191         _keyCode = windowsKeyCodeForCharCodeIOS([charactersIgnoringModifiers characterAtIndex:0]);
192     }
193
194     return self;
195 }
196
197 - (void)dealloc
198 {
199     [_characters release];
200     [_charactersIgnoringModifiers release];
201     [_inputManagerHint release];
202
203     [_touchLocations release];
204     [_touchIdentifiers release];
205     [_touchPhases release];
206     
207     [super dealloc];
208 }
209
210 - (NSString *)_typeDescription
211 {
212     switch (_type) {
213         case WebEventMouseDown:
214             return @"WebEventMouseDown";
215         case WebEventMouseUp:
216             return @"WebEventMouseUp";
217         case WebEventMouseMoved:
218             return @"WebEventMouseMoved";
219         case WebEventScrollWheel:
220             return @"WebEventScrollWheel";
221         case WebEventKeyDown:
222             return @"WebEventKeyDown";
223         case WebEventKeyUp:
224             return @"WebEventKeyUp";
225         case WebEventTouchBegin:
226             return @"WebEventTouchBegin";
227         case WebEventTouchChange:
228             return @"WebEventTouchChange";
229         case WebEventTouchEnd:
230             return @"WebEventTouchEnd";
231         case WebEventTouchCancel:
232             return @"WebEventTouchCancel";
233         default:
234             ASSERT_NOT_REACHED();
235     }
236     return @"Unknown";
237 }
238
239 - (NSString *)_modiferFlagsDescription
240 {
241     switch (_modifierFlags) {
242         case WebEventMouseDown:
243             return @"WebEventMouseDown";
244         case WebEventMouseUp:
245             return @"WebEventMouseUp";
246         case WebEventMouseMoved:
247             return @"WebEventMouseMoved";
248         case WebEventScrollWheel:
249             return @"WebEventScrollWheel";
250         case WebEventKeyDown:
251             return @"WebEventKeyDown";
252         case WebEventKeyUp:
253             return @"WebEventKeyUp";
254         case WebEventTouchBegin:
255             return @"WebEventTouchBegin";
256         case WebEventTouchChange:
257             return @"WebEventTouchChange";
258         case WebEventTouchEnd:
259             return @"WebEventTouchEnd";
260         case WebEventTouchCancel:
261             return @"WebEventTouchCancel";
262         default:
263             ASSERT_NOT_REACHED();
264     }
265     return @"Unknown";
266 }
267
268 - (NSString *)_touchLocationsDescription:(NSArray *)locations
269 {
270     BOOL shouldAddComma = NO;
271     NSMutableString *description = [NSMutableString string];
272     for (NSValue *value in locations) {
273         CGPoint point = [value pointValue];
274         [description appendFormat:@"%@(%f, %f)", (shouldAddComma ? @", " : @""), point.x, point.y];
275         shouldAddComma = YES;
276     }
277     return description;
278 }
279
280 - (NSString *)_touchIdentifiersDescription
281 {
282     BOOL shouldAddComma = NO;
283     NSMutableString *description = [NSMutableString string];
284     for (NSNumber *identifier in _touchIdentifiers) {
285         [description appendFormat:@"%@%u", (shouldAddComma ? @", " : @""), [identifier unsignedIntValue]];
286         shouldAddComma = YES;
287     }
288     return description;
289 }
290
291 - (NSString *)_touchPhaseDescription:(WebEventTouchPhaseType)phase
292 {
293     switch (phase) {
294         case WebEventTouchPhaseBegan:
295             return @"WebEventTouchPhaseBegan";
296         case WebEventTouchPhaseMoved:
297             return @"WebEventTouchPhaseMoved";
298         case WebEventTouchPhaseStationary:
299             return @"WebEventTouchPhaseStationary";
300         case WebEventTouchPhaseEnded:
301             return @"WebEventTouchPhaseEnded";
302         case WebEventTouchPhaseCancelled:
303             return @"WebEventTouchPhaseCancelled";
304         default:
305             ASSERT_NOT_REACHED();
306     }
307     return @"Unknown";
308 }
309
310 - (NSString *)_touchPhasesDescription
311 {
312     BOOL shouldAddComma = NO;
313     NSMutableString *description = [NSMutableString string];
314     for (NSNumber *phase in _touchPhases) {
315         [description appendFormat:@"%@%@", (shouldAddComma ? @", " : @""), [self _touchPhaseDescription:static_cast<WebEventTouchPhaseType>([phase unsignedIntValue])]];
316         shouldAddComma = YES;
317     }
318     return description;
319 }
320
321 - (NSString *)_eventDescription
322 {
323     switch (_type) {
324         case WebEventMouseDown:
325         case WebEventMouseUp:
326         case WebEventMouseMoved:
327             return [NSString stringWithFormat:@"location: (%f, %f)", _locationInWindow.x, _locationInWindow.y];
328         case WebEventScrollWheel:
329             return [NSString stringWithFormat:@"location: (%f, %f) deltaX: %f deltaY: %f", _locationInWindow.x, _locationInWindow.y, _deltaX, _deltaY];
330         case WebEventKeyDown:
331         case WebEventKeyUp:
332             return [NSString stringWithFormat:@"chars: %@ charsNoModifiers: %@ flags: %d repeating: %d keyboardFlags: %lu keyCode %d, isTab: %d", _characters, _charactersIgnoringModifiers, _modifierFlags, _keyRepeating, static_cast<unsigned long>(_keyboardFlags), _keyCode, _tabKey];
333         case WebEventTouchBegin:
334         case WebEventTouchChange:
335         case WebEventTouchEnd:
336         case WebEventTouchCancel:
337             return [NSString stringWithFormat:@"location: (%f, %f) count: %d locations: %@ identifiers: %@ phases: %@ isGesture: %d scale: %f rotation: %f", _locationInWindow.x, _locationInWindow.y, _touchCount, [self _touchLocationsDescription:_touchLocations], [self _touchIdentifiersDescription], [self _touchPhasesDescription], (_isGesture ? 1 : 0), _gestureScale, _gestureRotation];
338         default:
339             ASSERT_NOT_REACHED();
340     }
341     return @"Unknown";
342 }
343
344 - (NSString *)description
345 {
346     return [NSString stringWithFormat:@"%@ type: %@ - %@", [super description], [self _typeDescription], [self _eventDescription]];
347 }
348
349 - (CGPoint)locationInWindow
350 {
351     ASSERT_WITH_MESSAGE(_type == WebEventMouseDown || _type == WebEventMouseUp || _type == WebEventMouseMoved || _type == WebEventScrollWheel
352                         // FIXME: <rdar://problem/7185284> TouchEvents may be in more than one window some day.
353                         || _type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel
354                         , "WebEventType: %d", _type);
355     return _locationInWindow;
356 }
357
358 - (NSString *)characters
359 {
360     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
361     return [[_characters retain] autorelease];
362 }
363
364 - (NSString *)charactersIgnoringModifiers
365 {
366     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
367     return [[_charactersIgnoringModifiers retain] autorelease];
368 }
369
370 - (NSString *)inputManagerHint
371 {
372     return [[_inputManagerHint retain] autorelease];
373 }
374
375 - (WebEventFlags)modifierFlags
376 {
377     return _modifierFlags;
378 }
379
380 - (BOOL)isKeyRepeating
381 {
382     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
383     return _keyRepeating;
384 }
385
386 - (NSUInteger)keyboardFlags
387 {
388     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
389     return _keyboardFlags;
390 }
391
392 - (uint16_t)keyCode
393 {
394     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
395     return _keyCode;
396 }
397
398 - (BOOL)isTabKey
399 {
400     ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
401     return _tabKey;
402 }
403
404 - (float)deltaX
405 {
406     ASSERT(_type == WebEventScrollWheel);
407     return _deltaX;
408 }
409
410 - (float)deltaY
411 {
412     ASSERT(_type == WebEventScrollWheel);
413     return _deltaY;
414 }
415
416 // Touch
417 - (unsigned)touchCount
418 {
419     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
420     return _touchCount;
421 }
422
423 - (NSArray *)touchLocations
424 {
425     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
426     return _touchLocations;
427 }
428
429 - (NSArray *)touchIdentifiers
430 {
431     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
432     return _touchIdentifiers;
433 }
434
435 - (NSArray *)touchPhases
436 {
437     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
438     return _touchPhases;
439 }
440
441 // Gesture
442 - (BOOL)isGesture
443 {
444     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
445     return _isGesture;
446 }
447
448 - (float)gestureScale
449 {
450     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
451     return _gestureScale;
452 }
453
454 - (float)gestureRotation
455 {
456     ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
457     return _gestureRotation;
458 }
459
460 @end
461
462 #endif // PLATFORM(IOS)