A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

511 lines
18 KiB

#include "KeyTransform.h"
#import <Carbon/Carbon.h>
#include <array>
#include <unordered_map>
struct KeyInfo
{
uint16_t scanCode;
AvnPhysicalKey physicalKey;
AvnKey qwertyKey;
uint16_t menuChar;
};
// ScanCode - PhysicalKey - Key mapping (the virtual key is mapped as in a standard QWERTY keyboard)
// https://github.com/chromium/chromium/blob/main/ui/events/keycodes/dom/dom_code_data.inc
// This list has the same order as the PhysicalKey enum.
const KeyInfo keyInfos[] =
{
// Writing System Keys
{ 0x32, AvnPhysicalKeyBackquote, AvnKeyOem3, '`' },
{ 0x2A, AvnPhysicalKeyBackslash, AvnKeyOem5, '\\' },
{ 0x21, AvnPhysicalKeyBracketLeft,AvnKeyOem4, '[' },
{ 0x1E, AvnPhysicalKeyBracketRight, AvnKeyOem6, ']' },
{ 0x2B, AvnPhysicalKeyComma, AvnKeyOemComma, ',' },
{ 0x1D, AvnPhysicalKeyDigit0, AvnKeyD0, '0' },
{ 0x12, AvnPhysicalKeyDigit1, AvnKeyD1, '1' },
{ 0x13, AvnPhysicalKeyDigit2, AvnKeyD2, '2' },
{ 0x14, AvnPhysicalKeyDigit3, AvnKeyD3, '3' },
{ 0x15, AvnPhysicalKeyDigit4, AvnKeyD4, '4' },
{ 0x17, AvnPhysicalKeyDigit5, AvnKeyD5, '5' },
{ 0x16, AvnPhysicalKeyDigit6, AvnKeyD6, '6' },
{ 0x1A, AvnPhysicalKeyDigit7, AvnKeyD7, '7' },
{ 0x1C, AvnPhysicalKeyDigit8, AvnKeyD8, '8' },
{ 0x19, AvnPhysicalKeyDigit9, AvnKeyD9, '9' },
{ 0x18, AvnPhysicalKeyEqual, AvnKeyOemPlus, '=' },
{ 0x0A, AvnPhysicalKeyIntlBackslash, AvnKeyOem102, 0 },
{ 0x5E, AvnPhysicalKeyIntlRo, AvnKeyOem102, 0 },
{ 0x5D, AvnPhysicalKeyIntlYen, AvnKeyOem5, 0 },
{ 0x00, AvnPhysicalKeyA, AvnKeyA, 'a' },
{ 0x0B, AvnPhysicalKeyB, AvnKeyB, 'b' },
{ 0x08, AvnPhysicalKeyC, AvnKeyC, 'c' },
{ 0x02, AvnPhysicalKeyD, AvnKeyD, 'd' },
{ 0x0E, AvnPhysicalKeyE, AvnKeyE, 'e' },
{ 0x03, AvnPhysicalKeyF, AvnKeyF, 'f' },
{ 0x05, AvnPhysicalKeyG, AvnKeyG, 'g' },
{ 0x04, AvnPhysicalKeyH, AvnKeyH, 'h' },
{ 0x22, AvnPhysicalKeyI, AvnKeyI, 'i' },
{ 0x26, AvnPhysicalKeyJ, AvnKeyJ, 'j' },
{ 0x28, AvnPhysicalKeyK, AvnKeyK, 'k' },
{ 0x25, AvnPhysicalKeyL, AvnKeyL, 'l' },
{ 0x2E, AvnPhysicalKeyM, AvnKeyM, 'm' },
{ 0x2D, AvnPhysicalKeyN, AvnKeyN, 'n' },
{ 0x1F, AvnPhysicalKeyO, AvnKeyO, 'o' },
{ 0x23, AvnPhysicalKeyP, AvnKeyP, 'p' },
{ 0x0C, AvnPhysicalKeyQ, AvnKeyQ, 'q' },
{ 0x0F, AvnPhysicalKeyR, AvnKeyR, 'r' },
{ 0x01, AvnPhysicalKeyS, AvnKeyS, 's' },
{ 0x11, AvnPhysicalKeyT, AvnKeyT, 't' },
{ 0x20, AvnPhysicalKeyU, AvnKeyU, 'u' },
{ 0x09, AvnPhysicalKeyV, AvnKeyV, 'v' },
{ 0x0D, AvnPhysicalKeyW, AvnKeyW, 'w' },
{ 0x07, AvnPhysicalKeyX, AvnKeyX, 'x' },
{ 0x10, AvnPhysicalKeyY, AvnKeyY, 'y' },
{ 0x06, AvnPhysicalKeyZ, AvnKeyZ, 'z' },
{ 0x1B, AvnPhysicalKeyMinus, AvnKeyOemMinus, '-' },
{ 0x2F, AvnPhysicalKeyPeriod, AvnKeyOemPeriod, '.' },
{ 0x27, AvnPhysicalKeyQuote, AvnKeyOem7, '\'' },
{ 0x29, AvnPhysicalKeySemicolon, AvnKeyOem1, ';' },
{ 0x2C, AvnPhysicalKeySlash, AvnKeyOem2, '/' },
// Functional Keys
{ 0x3A, AvnPhysicalKeyAltLeft, AvnKeyLeftAlt, 0 },
{ 0x3D, AvnPhysicalKeyAltRight, AvnKeyRightAlt, 0 },
{ 0x33, AvnPhysicalKeyBackspace, AvnKeyBack, kBackspaceCharCode },
{ 0x39, AvnPhysicalKeyCapsLock, AvnKeyCapsLock, 0 },
{ 0x6E, AvnPhysicalKeyContextMenu, AvnKeyApps, 0 },
{ 0x3B, AvnPhysicalKeyControlLeft, AvnKeyLeftCtrl, 0 },
{ 0x3E, AvnPhysicalKeyControlRight, AvnKeyRightCtrl, 0 },
{ 0x24, AvnPhysicalKeyEnter, AvnKeyEnter, kReturnCharCode },
{ 0x37, AvnPhysicalKeyMetaLeft, AvnKeyLWin, 0 },
{ 0x36, AvnPhysicalKeyMetaRight, AvnKeyRWin, 0 },
{ 0x38, AvnPhysicalKeyShiftLeft, AvnKeyLeftShift, 0 },
{ 0x3C, AvnPhysicalKeyShiftRight, AvnKeyRightShift, 0 },
{ 0x31, AvnPhysicalKeySpace, AvnKeySpace, kSpaceCharCode },
{ 0x30, AvnPhysicalKeyTab, AvnKeyTab, kTabCharCode },
//{ , AvnPhysicalKeyConvert, 0 },
//{ , AvnPhysicalKeyKanaMode, 0 },
{ 0x68, AvnPhysicalKeyLang1, AvnKeyKanaMode, 0 },
{ 0x66, AvnPhysicalKeyLang2, AvnKeyHanjaMode, 0 },
//{ , AvnPhysicalKeyLang3, 0 },
//{ , AvnPhysicalKeyLang4, 0 },
//{ , AvnPhysicalKeyLang5, 0 },
//{ , AvnPhysicalKeyNonConvert, 0 },
// Control Pad Section
{ 0x75, AvnPhysicalKeyDelete, AvnKeyDelete, NSDeleteFunctionKey },
{ 0x77, AvnPhysicalKeyEnd, AvnKeyEnd, NSEndFunctionKey },
//{ , AvnPhysicalKeyHelp, 0 },
{ 0x73, AvnPhysicalKeyHome, AvnKeyHome, NSHomeFunctionKey },
{ 0x72, AvnPhysicalKeyInsert, AvnKeyInsert, NSInsertFunctionKey },
{ 0x79, AvnPhysicalKeyPageDown, AvnKeyPageDown, NSPageDownFunctionKey },
{ 0x74, AvnPhysicalKeyPageUp, AvnKeyPageUp, NSPageUpFunctionKey },
// Arrow Pad Section
{ 0x7D, AvnPhysicalKeyArrowDown, AvnKeyDown, NSDownArrowFunctionKey },
{ 0x7B, AvnPhysicalKeyArrowLeft, AvnKeyLeft, NSLeftArrowFunctionKey },
{ 0x7C, AvnPhysicalKeyArrowRight, AvnKeyRight, NSRightArrowFunctionKey },
{ 0x7E, AvnPhysicalKeyArrowUp, AvnKeyUp, NSUpArrowFunctionKey },
// Numpad Section
{ 0x47, AvnPhysicalKeyNumLock, AvnKeyClear, kClearCharCode },
{ 0x52, AvnPhysicalKeyNumPad0, AvnKeyNumPad0, '0' },
{ 0x53, AvnPhysicalKeyNumPad1, AvnKeyNumPad1, '1' },
{ 0x54, AvnPhysicalKeyNumPad2, AvnKeyNumPad2, '2' },
{ 0x55, AvnPhysicalKeyNumPad3, AvnKeyNumPad3, '3' },
{ 0x56, AvnPhysicalKeyNumPad4, AvnKeyNumPad4, '4' },
{ 0x57, AvnPhysicalKeyNumPad5, AvnKeyNumPad5, '5' },
{ 0x58, AvnPhysicalKeyNumPad6, AvnKeyNumPad6, '6' },
{ 0x59, AvnPhysicalKeyNumPad7, AvnKeyNumPad7, '7' },
{ 0x5B, AvnPhysicalKeyNumPad8, AvnKeyNumPad8, '8' },
{ 0x5C, AvnPhysicalKeyNumPad9, AvnKeyNumPad9, '9' },
{ 0x45, AvnPhysicalKeyNumPadAdd, AvnKeyAdd, '+' },
//{ , AvnPhysicalKeyNumPadClear, 0 },
{ 0x5F, AvnPhysicalKeyNumPadComma, AvnKeyAbntC2, 0 },
{ 0x41, AvnPhysicalKeyNumPadDecimal, AvnKeyDecimal, '.' },
{ 0x4B, AvnPhysicalKeyNumPadDivide, AvnKeyDivide, '/' },
{ 0x4C, AvnPhysicalKeyNumPadEnter, AvnKeyEnter, kReturnCharCode },
{ 0x51, AvnPhysicalKeyNumPadEqual, AvnKeyOemPlus, '=' },
{ 0x43, AvnPhysicalKeyNumPadMultiply, AvnKeyMultiply, '*' },
//{ , AvnPhysicalKeyNumPadParenLeft, 0 },
//{ , AvnPhysicalKeyNumPadParenRight, 0 },
{ 0x4E, AvnPhysicalKeyNumPadSubtract, AvnKeySubtract, '-' },
// Function Section
{ 0x35, AvnPhysicalKeyEscape, AvnKeyEscape, kEscapeCharCode },
{ 0x7A, AvnPhysicalKeyF1, AvnKeyF1, NSF1FunctionKey },
{ 0x78, AvnPhysicalKeyF2, AvnKeyF2, NSF2FunctionKey },
{ 0x63, AvnPhysicalKeyF3, AvnKeyF3, NSF3FunctionKey },
{ 0x76, AvnPhysicalKeyF4, AvnKeyF4, NSF4FunctionKey },
{ 0x60, AvnPhysicalKeyF5, AvnKeyF5, NSF5FunctionKey },
{ 0x61, AvnPhysicalKeyF6, AvnKeyF6, NSF6FunctionKey },
{ 0x62, AvnPhysicalKeyF7, AvnKeyF7, NSF7FunctionKey },
{ 0x64, AvnPhysicalKeyF8, AvnKeyF8, NSF8FunctionKey },
{ 0x65, AvnPhysicalKeyF9, AvnKeyF9, NSF9FunctionKey },
{ 0x6D, AvnPhysicalKeyF10, AvnKeyF10, NSF10FunctionKey },
{ 0x67, AvnPhysicalKeyF11, AvnKeyF11, NSF11FunctionKey },
{ 0x6F, AvnPhysicalKeyF12, AvnKeyF12, NSF12FunctionKey },
{ 0x69, AvnPhysicalKeyF13, AvnKeyF13, NSF13FunctionKey },
{ 0x6B, AvnPhysicalKeyF14, AvnKeyF14, NSF14FunctionKey },
{ 0x71, AvnPhysicalKeyF15, AvnKeyF15, NSF15FunctionKey },
{ 0x6A, AvnPhysicalKeyF16, AvnKeyF16, NSF16FunctionKey },
{ 0x40, AvnPhysicalKeyF17, AvnKeyF17, NSF17FunctionKey },
{ 0x4F, AvnPhysicalKeyF18, AvnKeyF18, NSF18FunctionKey },
{ 0x50, AvnPhysicalKeyF19, AvnKeyF19, NSF19FunctionKey },
{ 0x5A, AvnPhysicalKeyF20, AvnKeyF20, NSF20FunctionKey },
//{ , AvnPhysicalKeyF21, 0 },
//{ , AvnPhysicalKeyF22, 0 },
//{ , AvnPhysicalKeyF23, 0 },
//{ , AvnPhysicalKeyF24, 0 },
//{ , AvnPhysicalKeyPrintScreen, 0 },
//{ , AvnPhysicalKeyScrollLock, 0 },
//{ , AvnPhysicalKeyPause, 0 },
// Media Keys
//{ , AvnPhysicalKeyBrowserBack, 0 },
//{ , AvnPhysicalKeyBrowserFavorites, 0 },
//{ , AvnPhysicalKeyBrowserForward, 0 },
//{ , AvnPhysicalKeyBrowserHome, 0 },
//{ , AvnPhysicalKeyBrowserRefresh, 0 },
//{ , AvnPhysicalKeyBrowserSearch, 0 },
//{ , AvnPhysicalKeyBrowserStop, 0 },
//{ , AvnPhysicalKeyEject, 0 },
//{ , AvnPhysicalKeyLaunchApp1, 0 },
//{ , AvnPhysicalKeyLaunchApp2, 0 },
//{ , AvnPhysicalKeyLaunchMail, 0 },
//{ , AvnPhysicalKeyMediaPlayPause, 0 },
//{ , AvnPhysicalKeyMediaSelect, 0 },
//{ , AvnPhysicalKeyMediaStop, 0 },
//{ , AvnPhysicalKeyMediaTrackNext, 0 },
//{ , AvnPhysicalKeyMediaTrackPrevious, 0 },
//{ , AvnPhysicalKeyPower, 0 },
//{ , AvnPhysicalKeySleep, 0 },
{ 0x49, AvnPhysicalKeyAudioVolumeDown, AvnKeyVolumeDown, 0 },
{ 0x4A, AvnPhysicalKeyAudioVolumeMute, AvnKeyVolumeMute, 0 },
{ 0x48, AvnPhysicalKeyAudioVolumeUp, AvnKeyVolumeUp, 0 },
//{ , AvnPhysicalKeyWakeUp, 0 },
// Legacy Keys
//{ , AvnPhysicalKeyAgain, 0 },
//{ , AvnPhysicalKeyCopy, 0 },
//{ , AvnPhysicalKeyCut, 0 },
//{ , AvnPhysicalKeyFind, 0 },
//{ , AvnPhysicalKeyOpen, 0 },
//{ , AvnPhysicalKeyPaste, 0 },
//{ , AvnPhysicalKeyProps, 0 },
//{ , AvnPhysicalKeySelect, 0 },
//{ , AvnPhysicalKeyUndo, 0 }
};
std::unordered_map<uint16_t, AvnKey> virtualKeyFromChar =
{
// Alphabetic keys
{ 'A', AvnKeyA },
{ 'B', AvnKeyB },
{ 'C', AvnKeyC },
{ 'D', AvnKeyD },
{ 'E', AvnKeyE },
{ 'F', AvnKeyF },
{ 'G', AvnKeyG },
{ 'H', AvnKeyH },
{ 'I', AvnKeyI },
{ 'J', AvnKeyJ },
{ 'K', AvnKeyK },
{ 'L', AvnKeyL },
{ 'M', AvnKeyM },
{ 'N', AvnKeyN },
{ 'O', AvnKeyO },
{ 'P', AvnKeyP },
{ 'Q', AvnKeyQ },
{ 'R', AvnKeyR },
{ 'S', AvnKeyS },
{ 'T', AvnKeyT },
{ 'U', AvnKeyU },
{ 'V', AvnKeyV },
{ 'W', AvnKeyW },
{ 'X', AvnKeyX },
{ 'Y', AvnKeyY },
{ 'Z', AvnKeyZ },
{ 'a', AvnKeyA },
{ 'b', AvnKeyB },
{ 'c', AvnKeyC },
{ 'd', AvnKeyD },
{ 'e', AvnKeyE },
{ 'f', AvnKeyF },
{ 'g', AvnKeyG },
{ 'h', AvnKeyH },
{ 'i', AvnKeyI },
{ 'j', AvnKeyJ },
{ 'k', AvnKeyK },
{ 'l', AvnKeyL },
{ 'm', AvnKeyM },
{ 'n', AvnKeyN },
{ 'o', AvnKeyO },
{ 'p', AvnKeyP },
{ 'q', AvnKeyQ },
{ 'r', AvnKeyR },
{ 's', AvnKeyS },
{ 't', AvnKeyT },
{ 'u', AvnKeyU },
{ 'v', AvnKeyV },
{ 'w', AvnKeyW },
{ 'x', AvnKeyX },
{ 'y', AvnKeyY },
{ 'z', AvnKeyZ },
// Punctuation: US specific mappings (same as Chromium)
{ ';', AvnKeyOem1 },
{ ':', AvnKeyOem1 },
{ '=', AvnKeyOemPlus },
{ '+', AvnKeyOemPlus },
{ ',', AvnKeyOemComma },
{ '<', AvnKeyOemComma },
{ '-', AvnKeyOemMinus },
{ '_', AvnKeyOemMinus },
{ '.', AvnKeyOemPeriod },
{ '>', AvnKeyOemPeriod },
{ '/', AvnKeyOem2 },
{ '?', AvnKeyOem2 },
{ '`', AvnKeyOem3 },
{ '~', AvnKeyOem3 },
{ '[', AvnKeyOem4 },
{ '{', AvnKeyOem4 },
{ '\\', AvnKeyOem5 },
{ '|', AvnKeyOem5 },
{ ']', AvnKeyOem6 },
{ '}', AvnKeyOem6 },
{ '\'', AvnKeyOem7 },
{ '"', AvnKeyOem7 },
// Apple function keys
// https://developer.apple.com/documentation/appkit/1535851-function-key_unicode_values
{ NSDeleteFunctionKey, AvnKeyDelete },
{ NSUpArrowFunctionKey, AvnKeyUp },
{ NSLeftArrowFunctionKey, AvnKeyLeft },
{ NSRightArrowFunctionKey, AvnKeyRight },
{ NSPageUpFunctionKey, AvnKeyPageUp },
{ NSPageDownFunctionKey, AvnKeyPageDown },
{ NSHomeFunctionKey, AvnKeyHome },
{ NSEndFunctionKey, AvnKeyEnd },
{ NSClearLineFunctionKey, AvnKeyClear },
{ NSExecuteFunctionKey, AvnKeyExecute },
{ NSHelpFunctionKey, AvnKeyHelp },
{ NSInsertFunctionKey, AvnKeyInsert },
{ NSMenuFunctionKey, AvnKeyApps },
{ NSPauseFunctionKey, AvnKeyPause },
{ NSPrintFunctionKey, AvnKeyPrint },
{ NSPrintScreenFunctionKey, AvnKeyPrintScreen },
{ NSScrollLockFunctionKey, AvnKeyScroll },
{ NSF1FunctionKey, AvnKeyF1 },
{ NSF2FunctionKey, AvnKeyF2 },
{ NSF3FunctionKey, AvnKeyF3 },
{ NSF4FunctionKey, AvnKeyF4 },
{ NSF5FunctionKey, AvnKeyF5 },
{ NSF6FunctionKey, AvnKeyF6 },
{ NSF7FunctionKey, AvnKeyF7 },
{ NSF8FunctionKey, AvnKeyF8 },
{ NSF9FunctionKey, AvnKeyF9 },
{ NSF10FunctionKey, AvnKeyF10 },
{ NSF11FunctionKey, AvnKeyF11 },
{ NSF12FunctionKey, AvnKeyF12 },
{ NSF13FunctionKey, AvnKeyF13 },
{ NSF14FunctionKey, AvnKeyF14 },
{ NSF15FunctionKey, AvnKeyF15 },
{ NSF16FunctionKey, AvnKeyF16 },
{ NSF17FunctionKey, AvnKeyF17 },
{ NSF18FunctionKey, AvnKeyF18 },
{ NSF19FunctionKey, AvnKeyF19 },
{ NSF20FunctionKey, AvnKeyF20 },
{ NSF21FunctionKey, AvnKeyF21 },
{ NSF22FunctionKey, AvnKeyF22 },
{ NSF23FunctionKey, AvnKeyF23 },
{ NSF24FunctionKey, AvnKeyF24 }
};
typedef std::array<AvnPhysicalKey, 0x7F> PhysicalKeyArray;
static PhysicalKeyArray BuildPhysicalKeyFromScanCode()
{
PhysicalKeyArray result {};
for (auto& keyInfo : keyInfos)
{
result[keyInfo.scanCode] = keyInfo.physicalKey;
}
return result;
}
PhysicalKeyArray physicalKeyFromScanCode = BuildPhysicalKeyFromScanCode();
static std::unordered_map<AvnPhysicalKey, AvnKey, std::hash<int>> BuildQwertyVirtualKeyFromPhysicalKey()
{
std::unordered_map<AvnPhysicalKey, AvnKey, std::hash<int>> result;
result.reserve(sizeof(keyInfos) / sizeof(keyInfos[0]));
for (auto& keyInfo : keyInfos)
{
result[keyInfo.physicalKey] = keyInfo.qwertyKey;
}
return result;
}
std::unordered_map<AvnPhysicalKey, AvnKey, std::hash<int>> qwertyVirtualKeyFromPhysicalKey = BuildQwertyVirtualKeyFromPhysicalKey();
static std::unordered_map<AvnKey, uint16_t, std::hash<int>> BuildMenuCharFromVirtualKey()
{
std::unordered_map<AvnKey, uint16_t, std::hash<int>> result;
result.reserve(100);
for (auto& keyInfo : keyInfos)
{
if (keyInfo.menuChar != 0)
result[keyInfo.qwertyKey] = keyInfo.menuChar;
}
return result;
}
std::unordered_map<AvnKey, uint16_t, std::hash<int>> menuCharFromVirtualKey = BuildMenuCharFromVirtualKey();
static bool IsNumpadOrNumericKey(AvnPhysicalKey physicalKey)
{
return (physicalKey >= AvnPhysicalKeyDigit0 && physicalKey <= AvnPhysicalKeyDigit9)
|| (physicalKey >= AvnPhysicalKeyNumLock && physicalKey <= AvnPhysicalKeyNumPadSubtract);
}
AvnPhysicalKey PhysicalKeyFromScanCode(uint16_t scanCode)
{
return scanCode < physicalKeyFromScanCode.size() ? physicalKeyFromScanCode[scanCode] : AvnPhysicalKeyNone;
}
static bool IsAllowedAsciiChar(UniChar c)
{
if (c < 0x20)
{
switch (c)
{
case kBackspaceCharCode:
case kReturnCharCode:
case kTabCharCode:
case kEscapeCharCode:
return true;
default:
return false;
}
}
if (c == kDeleteCharCode)
return false;
return true;
}
static UniCharCount CharsFromScanCode(UInt16 scanCode, NSEventModifierFlags modifierFlags, UInt16 keyAction, UniChar* buffer, UniCharCount bufferSize)
{
auto currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (!currentKeyboard)
return 0;
auto layoutData = static_cast<CFDataRef>(TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData));
if (!layoutData)
return 0;
auto* keyboardLayout = reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layoutData));
UInt32 deadKeyState = 0;
UniCharCount length = 0;
int glyphModifiers = 0;
if (modifierFlags & NSEventModifierFlagShift)
glyphModifiers |= shiftKey;
if (modifierFlags & NSEventModifierFlagCapsLock)
glyphModifiers |= alphaLock;
if (modifierFlags & NSEventModifierFlagOption)
glyphModifiers |= optionKey;
auto result = UCKeyTranslate(
keyboardLayout,
scanCode,
keyAction,
(glyphModifiers >> 8) & 0xFF,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&deadKeyState,
bufferSize,
&length,
buffer);
if (result != noErr)
return 0;
if (deadKeyState)
{
// translate a space with dead key state to get the dead key itself
result = UCKeyTranslate(
keyboardLayout,
kVK_Space,
keyAction,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&deadKeyState,
bufferSize,
&length,
buffer);
if (result != noErr)
return 0;
}
if (length == 1 && buffer[0] <= 0x7F && !IsAllowedAsciiChar(buffer[0]))
return 0;
return length;
}
AvnKey VirtualKeyFromScanCode(uint16_t scanCode, NSEventModifierFlags modifierFlags)
{
auto physicalKey = PhysicalKeyFromScanCode(scanCode);
if (!IsNumpadOrNumericKey(physicalKey))
{
const UniCharCount charCount = 4;
UniChar chars[charCount];
auto length = CharsFromScanCode(scanCode, modifierFlags, kUCKeyActionDown, chars, charCount);
if (length > 0)
{
auto it = virtualKeyFromChar.find(chars[0]);
if (it != virtualKeyFromChar.end())
return it->second;
}
}
auto it = qwertyVirtualKeyFromPhysicalKey.find(physicalKey);
return it == qwertyVirtualKeyFromPhysicalKey.end() ? AvnKeyNone : it->second;
}
NSString* KeySymbolFromScanCode(uint16_t scanCode, NSEventModifierFlags modifierFlags)
{
auto physicalKey = PhysicalKeyFromScanCode(scanCode);
const UniCharCount charCount = 4;
UniChar chars[charCount];
auto length = CharsFromScanCode(scanCode, modifierFlags, kUCKeyActionDisplay, chars, charCount);
if (length > 0)
return [NSString stringWithCharacters:chars length:length];
auto it = qwertyVirtualKeyFromPhysicalKey.find(physicalKey);
if (it == qwertyVirtualKeyFromPhysicalKey.end())
return nullptr;
auto menuChar = MenuCharFromVirtualKey(it->second);
return menuChar == 0 || menuChar > 0x7E ? nullptr : [NSString stringWithCharacters:&menuChar length:1];
}
uint16_t MenuCharFromVirtualKey(AvnKey key)
{
auto it = menuCharFromVirtualKey.find(key);
return it == menuCharFromVirtualKey.end() ? 0 : it->second;
}