blob: c9075214bc01d718d511baef2cafddb2be8068a9 [file] [log] [blame]
/*
* Copyright (C) 2021 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.
*/
#import "config.h"
#import "ModifierKeys.h"
#import <WebKit/WebKitLegacy.h>
#import <wtf/Vector.h>
#if PLATFORM(IOS_FAMILY)
#import <WebKit/KeyEventCodesIOS.h>
#import <WebKit/WebEvent.h>
#endif
struct KeyMappingEntry {
int macKeyCode;
int macNumpadKeyCode;
unichar character;
NSString *characterName;
};
@implementation ModifierKeys
- (instancetype)init
{
self = [super init];
if (!self)
return nil;
return self;
}
- (void)dealloc
{
[super dealloc];
}
+ (ModifierKeys *)modifierKeysWithKey:(NSString *)character modifiers:(int)modifiers keyLocation:(unsigned)keyLocation
{
ModifierKeys *modiferKeys = [[[ModifierKeys alloc] init] autorelease];
modiferKeys->eventCharacter = adoptNS([[NSString alloc] initWithString:character]);
modiferKeys->keyCode = 0;
if ([character isEqualToString:@"leftArrow"]) {
const unichar ch = NSLeftArrowFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x7B;
} else if ([character isEqualToString:@"rightArrow"]) {
const unichar ch = NSRightArrowFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x7C;
} else if ([character isEqualToString:@"upArrow"]) {
const unichar ch = NSUpArrowFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x7E;
} else if ([character isEqualToString:@"downArrow"]) {
const unichar ch = NSDownArrowFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x7D;
} else if ([character isEqualToString:@"pageUp"]) {
const unichar ch = NSPageUpFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x74;
} else if ([character isEqualToString:@"pageDown"]) {
const unichar ch = NSPageDownFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x79;
} else if ([character isEqualToString:@"home"]) {
const unichar ch = NSHomeFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x73;
} else if ([character isEqualToString:@"end"]) {
const unichar ch = NSEndFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x77;
} else if ([character isEqualToString:@"insert"]) {
const unichar ch = NSInsertFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x72;
} else if ([character isEqualToString:@"delete"]) {
const unichar ch = NSDeleteFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x75;
} else if ([character isEqualToString:@"printScreen"]) {
const unichar ch = NSPrintScreenFunctionKey;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x0; // There is no known virtual key code for PrintScreen.
} else if ([character isEqualToString:@"cyrillicSmallLetterA"]) {
const unichar ch = 0x0430;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3; // Shares key with "F" on Russian layout.
} else if ([character isEqualToString:@"leftControl"]) {
const unichar ch = 0xFFE3;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3B;
} else if ([character isEqualToString:@"leftShift"]) {
const unichar ch = 0xFFE1;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x38;
} else if ([character isEqualToString:@"leftAlt"]) {
const unichar ch = 0xFFE7;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3A;
} else if ([character isEqualToString:@"rightControl"]) {
const unichar ch = 0xFFE4;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3E;
} else if ([character isEqualToString:@"rightShift"]) {
const unichar ch = 0xFFE2;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3C;
} else if ([character isEqualToString:@"rightAlt"]) {
const unichar ch = 0xFFE8;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x3D;
} else if ([character isEqualToString:@"escape"]) {
const unichar ch = 0x1B;
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
modiferKeys->keyCode = 0x35;
}
// Compare the input string with the function-key names defined by the DOM spec (i.e. "F1",...,"F24").
// If the input string is a function-key name, set its key code.
for (unsigned i = 1; i <= 24; i++) {
if ([character isEqualToString:[NSString stringWithFormat:@"F%u", i]]) {
const unichar ch = NSF1FunctionKey + (i - 1);
modiferKeys->eventCharacter = [NSString stringWithCharacters:&ch length:1];
switch (i) {
case 1: modiferKeys->keyCode = 0x7A; break;
case 2: modiferKeys->keyCode = 0x78; break;
case 3: modiferKeys->keyCode = 0x63; break;
case 4: modiferKeys->keyCode = 0x76; break;
case 5: modiferKeys->keyCode = 0x60; break;
case 6: modiferKeys->keyCode = 0x61; break;
case 7: modiferKeys->keyCode = 0x62; break;
case 8: modiferKeys->keyCode = 0x64; break;
case 9: modiferKeys->keyCode = 0x65; break;
case 10: modiferKeys->keyCode = 0x6D; break;
case 11: modiferKeys->keyCode = 0x67; break;
case 12: modiferKeys->keyCode = 0x6F; break;
case 13: modiferKeys->keyCode = 0x69; break;
case 14: modiferKeys->keyCode = 0x6B; break;
case 15: modiferKeys->keyCode = 0x71; break;
case 16: modiferKeys->keyCode = 0x6A; break;
case 17: modiferKeys->keyCode = 0x40; break;
case 18: modiferKeys->keyCode = 0x4F; break;
case 19: modiferKeys->keyCode = 0x50; break;
case 20: modiferKeys->keyCode = 0x5A; break;
}
}
}
// FIXME: No keyCode is set for most keys.
if ([character isEqualToString:@"\t"])
modiferKeys->keyCode = 0x30;
else if ([character isEqualToString:@" "])
modiferKeys->keyCode = 0x31;
else if ([character isEqualToString:@"\r"])
modiferKeys->keyCode = 0x24;
else if ([character isEqualToString:@"\n"])
modiferKeys->keyCode = 0x4C;
else if ([character isEqualToString:@"\x8"])
modiferKeys->keyCode = 0x33;
else if ([character isEqualToString:@"a"])
modiferKeys->keyCode = 0x00;
else if ([character isEqualToString:@"b"])
modiferKeys->keyCode = 0x0B;
else if ([character isEqualToString:@"d"])
modiferKeys->keyCode = 0x02;
else if ([character isEqualToString:@"e"])
modiferKeys->keyCode = 0x0E;
else if ([character isEqualToString:@"\x1b"])
modiferKeys->keyCode = 0x1B;
else if ([character isEqualToString:@":"])
modiferKeys->keyCode = 0x29;
else if ([character isEqualToString:@";"])
modiferKeys->keyCode = 0x29;
else if ([character isEqualToString:@","])
modiferKeys->keyCode = 0x2B;
KeyMappingEntry table[] = {
{ 0x2F, 0x41, '.', nil },
{ 0, 0x43, '*', nil },
{ 0, 0x45, '+', nil },
{ 0, 0x47, NSClearLineFunctionKey, @"clear" },
{ 0x2C, 0x4B, '/', nil },
{ 0, 0x4C, 3, @"enter" },
{ 0x1B, 0x4E, '-', nil },
{ 0x18, 0x51, '=', nil },
{ 0x1D, 0x52, '0', nil },
{ 0x12, 0x53, '1', nil },
{ 0x13, 0x54, '2', nil },
{ 0x14, 0x55, '3', nil },
{ 0x15, 0x56, '4', nil },
{ 0x17, 0x57, '5', nil },
{ 0x16, 0x58, '6', nil },
{ 0x1A, 0x59, '7', nil },
{ 0x1C, 0x5B, '8', nil },
{ 0x19, 0x5C, '9', nil },
};
for (unsigned i = 0; i < WTF_ARRAY_LENGTH(table); ++i) {
NSString* currentCharacterString = [NSString stringWithCharacters:&table[i].character length:1];
if ([character isEqualToString:currentCharacterString] || [character isEqualToString:table[i].characterName]) {
if (keyLocation == 0x03 /*DOM_KEY_LOCATION_NUMPAD*/)
modiferKeys->keyCode = table[i].macNumpadKeyCode;
else
modiferKeys->keyCode = table[i].macKeyCode;
modiferKeys->eventCharacter = currentCharacterString;
break;
}
}
modiferKeys->charactersIgnoringModifiers = adoptNS([[NSString alloc] initWithString:modiferKeys->eventCharacter.get()]);
modiferKeys->modifierFlags = 0;
if ([character length] == 1 && [character characterAtIndex:0] >= 'A' && [character characterAtIndex:0] <= 'Z') {
#if !PLATFORM(IOS_FAMILY)
modiferKeys->modifierFlags |= NSEventModifierFlagShift;
#else
modiferKeys->modifierFlags |= WebEventFlagMaskLeftShiftKey;
#endif
modiferKeys->charactersIgnoringModifiers = [character lowercaseString];
}
modiferKeys->modifierFlags |= modifiers;
if (keyLocation == 0x03 /*DOM_KEY_LOCATION_NUMPAD*/)
modiferKeys->modifierFlags |= NSEventModifierFlagNumericPad;
return modiferKeys;
}
@end