WebEvent.mm   [plain text]


/*
 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

// FIXME: Rename this file to WebEventIOS.mm after we upstream the iOS port and remove the PLATFORM(IOS)-guard.

#import "config.h"
#import "WebEvent.h"

#import "KeyEventCocoa.h"
#import <wtf/Assertions.h>

using namespace WebCore;

#if PLATFORM(IOS)

#import "WAKAppKitStubs.h"

@implementation WebEvent

@synthesize type = _type;
@synthesize timestamp = _timestamp;
@synthesize wasHandled = _wasHandled;

- (WebEvent *)initWithMouseEventType:(WebEventType)type
                           timeStamp:(CFTimeInterval)timeStamp
                            location:(CGPoint)point
{
    self = [super init];
    if (!self)
        return nil;
    
    _type = type;
    _timestamp = timeStamp;

    _locationInWindow = point;
    
    return self;
}

- (WebEvent *)initWithScrollWheelEventWithTimeStamp:(CFTimeInterval)timeStamp
                                           location:(CGPoint)point
                                              deltaX:(float)deltaX
                                              deltaY:(float)deltaY
{
    self = [super init];
    if (!self)
        return nil;
    
    _type = WebEventScrollWheel;
    _timestamp = timeStamp;

    _locationInWindow = point;
    _deltaX = deltaX;
    _deltaY = deltaY;
    
    return self;
}

- (WebEvent *)initWithTouchEventType:(WebEventType)type
                           timeStamp:(CFTimeInterval)timeStamp
                            location:(CGPoint)point
                           modifiers:(WebEventFlags)modifiers
                          touchCount:(unsigned)touchCount
                      touchLocations:(NSArray *)touchLocations
                    touchIdentifiers:(NSArray *)touchIdentifiers
                         touchPhases:(NSArray *)touchPhases isGesture:(BOOL)isGesture
                        gestureScale:(float)gestureScale
                     gestureRotation:(float)gestureRotation
{
    self = [super init];
    if (!self)
        return nil;

    _type = type;
    _timestamp = timeStamp;
    _modifierFlags = modifiers;

    // FIXME: <rdar://problem/7185284> TouchEvents may be in more than one window some day.
    _locationInWindow = point;
    _touchCount = touchCount;
    _touchLocations = [touchLocations copy];
    _touchIdentifiers = [touchIdentifiers copy];
    _touchPhases = [touchPhases copy];
    _isGesture = isGesture;
    _gestureScale = gestureScale;
    _gestureRotation = gestureRotation;

    return self;
}

static int windowsKeyCodeForCharCodeIOS(unichar charCode)
{
    // iPhone Specific Cases
    // <rdar://7709408>: We get 10 ('\n') from UIKit when using the software keyboard
    if (charCode == 10)
        return 0x0D;

    // General Case
    return windowsKeyCodeForCharCode(charCode);
}

// FIXME: to be removed when the adoption of the new initializer is complete.
- (WebEvent *)initWithKeyEventType:(WebEventType)type
                         timeStamp:(CFTimeInterval)timeStamp
                        characters:(NSString *)characters
       charactersIgnoringModifiers:(NSString *)charactersIgnoringModifiers
                         modifiers:(WebEventFlags)modifiers
                       isRepeating:(BOOL)repeating
                         withFlags:(NSUInteger)flags
                           keyCode:(uint16_t)keyCode
                          isTabKey:(BOOL)tabKey
                      characterSet:(WebEventCharacterSet)characterSet
{
    UNUSED_PARAM(characterSet);
    self = [super init];
    if (!self)
        return nil;
    
    _type = type;
    _timestamp = timeStamp;

    _characters = [characters retain];
    _charactersIgnoringModifiers = [charactersIgnoringModifiers retain];
    _modifierFlags = modifiers;
    _keyRepeating = repeating;
    _keyboardFlags = flags;
    _tabKey = tabKey;
    
    if (keyCode)
        _keyCode = windowsKeyCodeForKeyCode(keyCode);

    // NOTE: this preserves the original semantics which used the 
    // characters string for the keyCode. This should be changed in iOS 4.0 to
    // allow the client to explicitly specify a keyCode, otherwise default to 
    // mapping the characters string to a keyCode.
    // e.g. add an 'else' before this 'if'.
    if ([charactersIgnoringModifiers length] == 1) {
        unichar ch = [charactersIgnoringModifiers characterAtIndex:0];
        _keyCode = windowsKeyCodeForCharCodeIOS(ch);
    }

    return self;
}

- (WebEvent *)initWithKeyEventType:(WebEventType)type
                         timeStamp:(CFTimeInterval)timeStamp
                        characters:(NSString *)characters
       charactersIgnoringModifiers:(NSString *)charactersIgnoringModifiers
                         modifiers:(WebEventFlags)modifiers
                       isRepeating:(BOOL)repeating
                         withFlags:(NSUInteger)flags
              withInputManagerHint:(NSString *)hint
                           keyCode:(uint16_t)keyCode
                          isTabKey:(BOOL)tabKey
{
    self = [super init];
    if (!self)
        return nil;
    
    _type = type;
    _timestamp = timeStamp;
    
    _characters = [characters retain];
    _charactersIgnoringModifiers = [charactersIgnoringModifiers retain];
    _modifierFlags = modifiers;
    _keyRepeating = repeating;
    _keyboardFlags = flags;
    _inputManagerHint = [hint retain];
    _tabKey = tabKey;
    
    if (keyCode)
        _keyCode = windowsKeyCodeForKeyCode(keyCode);
    
    // NOTE: this preserves the original semantics which used the
    // characters string for the keyCode. This should be changed in iOS 4.0 to
    // allow the client to explicitly specify a keyCode, otherwise default to
    // mapping the characters string to a keyCode.
    // e.g. add an 'else' before this 'if'.
    if ([charactersIgnoringModifiers length] == 1) {
        unichar ch = [charactersIgnoringModifiers characterAtIndex:0];
        _keyCode = windowsKeyCodeForCharCodeIOS(ch);
    }
    
    return self;
}

- (void)dealloc
{
    [_characters release];
    [_charactersIgnoringModifiers release];
    [_inputManagerHint release];

    [_touchLocations release];
    [_touchIdentifiers release];
    [_touchPhases release];
    
    [super dealloc];
}

- (NSString *)_typeDescription
{
    switch (_type) {
        case WebEventMouseDown:
            return @"WebEventMouseDown";
        case WebEventMouseUp:
            return @"WebEventMouseUp";
        case WebEventMouseMoved:
            return @"WebEventMouseMoved";
        case WebEventScrollWheel:
            return @"WebEventScrollWheel";
        case WebEventKeyDown:
            return @"WebEventKeyDown";
        case WebEventKeyUp:
            return @"WebEventKeyUp";
        case WebEventTouchBegin:
            return @"WebEventTouchBegin";
        case WebEventTouchChange:
            return @"WebEventTouchChange";
        case WebEventTouchEnd:
            return @"WebEventTouchEnd";
        case WebEventTouchCancel:
            return @"WebEventTouchCancel";
        default:
            ASSERT_NOT_REACHED();
    }
    return @"Unknown";
}

- (NSString *)_modiferFlagsDescription
{
    switch (_modifierFlags) {
        case WebEventMouseDown:
            return @"WebEventMouseDown";
        case WebEventMouseUp:
            return @"WebEventMouseUp";
        case WebEventMouseMoved:
            return @"WebEventMouseMoved";
        case WebEventScrollWheel:
            return @"WebEventScrollWheel";
        case WebEventKeyDown:
            return @"WebEventKeyDown";
        case WebEventKeyUp:
            return @"WebEventKeyUp";
        case WebEventTouchBegin:
            return @"WebEventTouchBegin";
        case WebEventTouchChange:
            return @"WebEventTouchChange";
        case WebEventTouchEnd:
            return @"WebEventTouchEnd";
        case WebEventTouchCancel:
            return @"WebEventTouchCancel";
        default:
            ASSERT_NOT_REACHED();
    }
    return @"Unknown";
}

- (NSString *)_touchLocationsDescription:(NSArray *)locations
{
    BOOL shouldAddComma = NO;
    NSMutableString *description = [NSMutableString string];
    for (NSValue *value in locations) {
        CGPoint point = [value pointValue];
        [description appendFormat:@"%@(%f, %f)", (shouldAddComma ? @", " : @""), point.x, point.y];
        shouldAddComma = YES;
    }
    return description;
}

- (NSString *)_touchIdentifiersDescription
{
    BOOL shouldAddComma = NO;
    NSMutableString *description = [NSMutableString string];
    for (NSNumber *identifier in _touchIdentifiers) {
        [description appendFormat:@"%@%u", (shouldAddComma ? @", " : @""), [identifier unsignedIntValue]];
        shouldAddComma = YES;
    }
    return description;
}

- (NSString *)_touchPhaseDescription:(WebEventTouchPhaseType)phase
{
    switch (phase) {
        case WebEventTouchPhaseBegan:
            return @"WebEventTouchPhaseBegan";
        case WebEventTouchPhaseMoved:
            return @"WebEventTouchPhaseMoved";
        case WebEventTouchPhaseStationary:
            return @"WebEventTouchPhaseStationary";
        case WebEventTouchPhaseEnded:
            return @"WebEventTouchPhaseEnded";
        case WebEventTouchPhaseCancelled:
            return @"WebEventTouchPhaseCancelled";
        default:
            ASSERT_NOT_REACHED();
    }
    return @"Unknown";
}

- (NSString *)_touchPhasesDescription
{
    BOOL shouldAddComma = NO;
    NSMutableString *description = [NSMutableString string];
    for (NSNumber *phase in _touchPhases) {
        [description appendFormat:@"%@%@", (shouldAddComma ? @", " : @""), [self _touchPhaseDescription:static_cast<WebEventTouchPhaseType>([phase unsignedIntValue])]];
        shouldAddComma = YES;
    }
    return description;
}

- (NSString *)_eventDescription
{
    switch (_type) {
        case WebEventMouseDown:
        case WebEventMouseUp:
        case WebEventMouseMoved:
            return [NSString stringWithFormat:@"location: (%f, %f)", _locationInWindow.x, _locationInWindow.y];
        case WebEventScrollWheel:
            return [NSString stringWithFormat:@"location: (%f, %f) deltaX: %f deltaY: %f", _locationInWindow.x, _locationInWindow.y, _deltaX, _deltaY];
        case WebEventKeyDown:
        case WebEventKeyUp:
            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];
        case WebEventTouchBegin:
        case WebEventTouchChange:
        case WebEventTouchEnd:
        case WebEventTouchCancel:
            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];
        default:
            ASSERT_NOT_REACHED();
    }
    return @"Unknown";
}

- (NSString *)description
{
    return [NSString stringWithFormat:@"%@ type: %@ - %@", [super description], [self _typeDescription], [self _eventDescription]];
}

- (CGPoint)locationInWindow
{
    ASSERT_WITH_MESSAGE(_type == WebEventMouseDown || _type == WebEventMouseUp || _type == WebEventMouseMoved || _type == WebEventScrollWheel
                        // FIXME: <rdar://problem/7185284> TouchEvents may be in more than one window some day.
                        || _type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel
                        , "WebEventType: %d", _type);
    return _locationInWindow;
}

- (NSString *)characters
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return [[_characters retain] autorelease];
}

- (NSString *)charactersIgnoringModifiers
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return [[_charactersIgnoringModifiers retain] autorelease];
}

- (NSString *)inputManagerHint
{
    return [[_inputManagerHint retain] autorelease];
}

- (WebEventFlags)modifierFlags
{
    return _modifierFlags;
}

- (BOOL)isKeyRepeating
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return _keyRepeating;
}

- (NSUInteger)keyboardFlags
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return _keyboardFlags;
}

- (uint16_t)keyCode
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return _keyCode;
}

- (BOOL)isTabKey
{
    ASSERT(_type == WebEventKeyDown || _type == WebEventKeyUp);
    return _tabKey;
}

- (float)deltaX
{
    ASSERT(_type == WebEventScrollWheel);
    return _deltaX;
}

- (float)deltaY
{
    ASSERT(_type == WebEventScrollWheel);
    return _deltaY;
}

// Touch
- (unsigned)touchCount
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _touchCount;
}

- (NSArray *)touchLocations
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _touchLocations;
}

- (NSArray *)touchIdentifiers
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _touchIdentifiers;
}

- (NSArray *)touchPhases
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _touchPhases;
}

// Gesture
- (BOOL)isGesture
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _isGesture;
}

- (float)gestureScale
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _gestureScale;
}

- (float)gestureRotation
{
    ASSERT(_type == WebEventTouchBegin || _type == WebEventTouchChange || _type == WebEventTouchEnd || _type == WebEventTouchCancel);
    return _gestureRotation;
}

@end

#endif // PLATFORM(IOS)