/* * 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 #import #if PLATFORM(IOS_FAMILY) #import #import #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