gohook/hook/darwin/input_c.h
2018-09-17 14:09:59 -04:00

550 lines
22 KiB
C

/* Copyright (C) 2006-2017 Alexander Barker.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef USE_COREFOUNDATION
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifndef USE_WEAK_IMPORT
#include <dlfcn.h>
#endif
#include <stdbool.h>
#include "input.h"
#include "../iohook.h"
#include "../logger_c.h"
// Current dead key state.
#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION)
static UInt32 deadkey_state;
#endif
// Input source data for the keyboard.
#if defined(USE_CARBON_LEGACY)
static KeyboardLayoutRef prev_keyboard_layout = NULL;
#elif defined(USE_COREFOUNDATION)
static TISInputSourceRef prev_keyboard_layout = NULL;
#endif
#ifdef USE_WEAK_IMPORT
// Required to dynamically check for AXIsProcessTrustedWithOptions availability.
extern Boolean AXIsProcessTrustedWithOptions(CFDictionaryRef options) __attribute__((weak_import));
extern CFStringRef kAXTrustedCheckOptionPrompt __attribute__((weak_import));
#else
static Boolean (*AXIsProcessTrustedWithOptions_t)(CFDictionaryRef);
#endif
bool is_accessibility_enabled() {
bool is_enabled = false;
#ifdef USE_WEAK_IMPORT
// Check and make sure assistive devices is enabled.
if (AXIsProcessTrustedWithOptions != NULL) {
// New accessibility API 10.9 and later.
const void * keys[] = { kAXTrustedCheckOptionPrompt };
const void * values[] = { kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(
kCFAllocatorDefault,
keys,
values,
sizeof(keys) / sizeof(*keys),
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
is_enabled = AXIsProcessTrustedWithOptions(options);
}
#else
// Dynamically load the application services framework for examination.
*(void **) (&AXIsProcessTrustedWithOptions_t) = dlsym(RTLD_DEFAULT, "AXIsProcessTrustedWithOptions");
const char *dlError = dlerror();
if (AXIsProcessTrustedWithOptions_t != NULL && dlError == NULL) {
// Check for property CFStringRef kAXTrustedCheckOptionPrompt
void ** kAXTrustedCheckOptionPrompt_t = dlsym(RTLD_DEFAULT, "kAXTrustedCheckOptionPrompt");
dlError = dlerror();
if (kAXTrustedCheckOptionPrompt_t != NULL && dlError == NULL) {
// New accessibility API 10.9 and later.
const void * keys[] = { *kAXTrustedCheckOptionPrompt_t };
const void * values[] = { kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(
kCFAllocatorDefault,
keys,
values,
sizeof(keys) / sizeof(*keys),
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
is_enabled = (*AXIsProcessTrustedWithOptions_t)(options);
}
}
#endif
else {
#ifndef USE_WEAK_IMPORT
if (dlError != NULL) {
// Could not load the AXIsProcessTrustedWithOptions function!
logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n",
__FUNCTION__, __LINE__, dlError);
}
#endif
logger(LOG_LEVEL_DEBUG, "%s [%u]: Weak import AXIsProcessTrustedWithOptions not found.\n",
__FUNCTION__, __LINE__, dlError);
logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to AXAPIEnabled().\n",
__FUNCTION__, __LINE__, dlError);
// Old accessibility check 10.8 and older.
is_enabled = AXAPIEnabled();
}
return is_enabled;
}
UniCharCount keycode_to_unicode(CGEventRef event_ref, UniChar *buffer, UniCharCount size) {
UniCharCount count = 0;
#if defined(USE_CARBON_LEGACY)
KeyboardLayoutRef curr_keyboard_layout;
void *inputData = NULL;
if (KLGetCurrentKeyboardLayout(&curr_keyboard_layout) == noErr) {
if (KLGetKeyboardLayoutProperty(curr_keyboard_layout, kKLuchrData, (const void **) &inputData) != noErr) {
inputData = NULL;
}
}
#elif defined(USE_COREFOUNDATION)
CFDataRef inputData = NULL;
if (CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain())) {
// NOTE The following block must execute on the main runloop,
// Ex: CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain()) to avoid
// Exception detected while handling key input and TSMProcessRawKeyCode failed
// (-192) errors.
TISInputSourceRef curr_keyboard_layout = TISCopyCurrentKeyboardLayoutInputSource();
if (curr_keyboard_layout != NULL && CFGetTypeID(curr_keyboard_layout) == TISInputSourceGetTypeID()) {
CFDataRef data = (CFDataRef) TISGetInputSourceProperty(curr_keyboard_layout, kTISPropertyUnicodeKeyLayoutData);
if (data != NULL && CFGetTypeID(data) == CFDataGetTypeID() && CFDataGetLength(data) > 0) {
inputData = (CFDataRef) data;
}
}
// Check if the keyboard layout has changed to see if the dead key state needs to be discarded.
if (prev_keyboard_layout != NULL && curr_keyboard_layout != NULL && CFEqual(curr_keyboard_layout, prev_keyboard_layout) == false) {
deadkey_state = 0x00;
}
// Release the previous keyboard layout.
if (prev_keyboard_layout != NULL) {
CFRelease(prev_keyboard_layout);
prev_keyboard_layout = NULL;
}
// Set the previous keyboard layout to the current layout.
if (curr_keyboard_layout != NULL) {
prev_keyboard_layout = curr_keyboard_layout;
}
}
#endif
#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION)
if (inputData != NULL) {
#ifdef USE_CARBON_LEGACY
const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *) inputData;
#else
const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout*) CFDataGetBytePtr(inputData);
#endif
if (keyboard_layout != NULL) {
//Extract keycode and modifier information.
CGKeyCode keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode);
CGEventFlags modifiers = CGEventGetFlags(event_ref);
// Disable all command modifiers for translation. This is required
// so UCKeyTranslate will provide a keysym for the separate event.
static const CGEventFlags cmd_modifiers = kCGEventFlagMaskCommand |
kCGEventFlagMaskControl | kCGEventFlagMaskAlternate;
modifiers &= ~cmd_modifiers;
// I don't know why but UCKeyTranslate does not process the
// kCGEventFlagMaskAlphaShift (A.K.A. Caps Lock Mask) correctly.
// We need to basically turn off the mask and process the capital
// letters after UCKeyTranslate().
bool is_caps_lock = modifiers & kCGEventFlagMaskAlphaShift;
modifiers &= ~kCGEventFlagMaskAlphaShift;
// Run the translation with the saved deadkey_state.
OSStatus status = UCKeyTranslate(
keyboard_layout,
keycode,
kUCKeyActionDown, //kUCKeyActionDisplay,
(modifiers >> 16) & 0xFF, //(modifiers >> 16) & 0xFF, || (modifiers >> 8) & 0xFF,
LMGetKbdType(),
kNilOptions, //kNilOptions, //kUCKeyTranslateNoDeadKeysMask
&deadkey_state,
size,
&count,
buffer);
if (status == noErr && count > 0) {
if (is_caps_lock) {
// We *had* a caps lock mask so we need to convert to uppercase.
CFMutableStringRef keytxt = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, buffer, count, size, kCFAllocatorNull);
if (keytxt != NULL) {
CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringUppercase(keytxt, locale);
CFRelease(locale);
CFRelease(keytxt);
}
else {
// There was an problem creating the CFMutableStringRef.
count = 0;
}
}
}
else {
// Make sure the buffer count is zero if an error occurred.
count = 0;
}
}
}
#else
CGEventKeyboardGetUnicodeString(event_ref, size, &count, buffer);
#endif
// The following codes should not be processed because they are invalid.
if (count == 1) {
switch (buffer[0]) {
case 0x01: // Home
case 0x04: // End
case 0x05: // Help Key
case 0x10: // Function Keys
case 0x0B: // Page Up
case 0x0C: // Page Down
case 0x1F: // Volume Up
count = 0;
}
}
return count;
}
static const uint16_t keycode_scancode_table[][2] = {
/* idx { keycode, scancode }, */
/* 0 */ { VC_A, kVK_Undefined }, // 0x00
/* 1 */ { VC_S, kVK_Escape }, // 0x01
/* 2 */ { VC_D, kVK_ANSI_1 }, // 0x02
/* 3 */ { VC_F, kVK_ANSI_2 }, // 0x03
/* 4 */ { VC_H, kVK_ANSI_3 }, // 0x04
/* 5 */ { VC_G, kVK_ANSI_4 }, // 0x05
/* 6 */ { VC_Z, kVK_ANSI_5 }, // 0x07
/* 7 */ { VC_X, kVK_ANSI_6 }, // 0x08
/* 8 */ { VC_C, kVK_ANSI_7 }, // 0x09
/* 9 */ { VC_V, kVK_ANSI_8 }, // 0x0A
/* 10 */ { VC_UNDEFINED, kVK_ANSI_9 }, // 0x0B
/* 11 */ { VC_B, kVK_ANSI_0 }, // 0x0C
/* 12 */ { VC_Q, kVK_ANSI_Minus }, // 0x0D
/* 13 */ { VC_W, kVK_ANSI_Equal }, // 0x0E
/* 14 */ { VC_E, kVK_Delete }, // 0x0F
/* 15 */ { VC_R, kVK_Tab }, // 0x10
/* 16 */ { VC_Y, kVK_ANSI_Q }, // 0x11
/* 17 */ { VC_T, kVK_ANSI_W }, // 0x12
/* 18 */ { VC_1, kVK_ANSI_E }, // 0x13
/* 19 */ { VC_2, kVK_ANSI_R }, // 0x14
/* 20 */ { VC_3, kVK_ANSI_T }, // 0x15
/* 21 */ { VC_4, kVK_ANSI_Y }, // 0x16
/* 22 */ { VC_6, kVK_ANSI_U }, // 0x17
/* 23 */ { VC_5, kVK_ANSI_I }, // 0x18
/* 24 */ { VC_EQUALS, kVK_ANSI_O }, // 0x19
/* 25 */ { VC_9, kVK_ANSI_P }, // 0x19
/* 26 */ { VC_7, kVK_ANSI_LeftBracket }, // 0x1A
/* 27 */ { VC_MINUS, kVK_ANSI_RightBracket }, // 0x1B
/* 28 */ { VC_8, kVK_Return }, // 0x1C
/* 29 */ { VC_0, kVK_Control }, // 0x1D
/* 30 */ { VC_CLOSE_BRACKET, kVK_ANSI_A }, // 0x1E
/* 31 */ { VC_O, kVK_ANSI_S }, // 0x1F
/* 32 */ { VC_U, kVK_ANSI_D }, // 0x20
/* 33 */ { VC_OPEN_BRACKET, kVK_ANSI_F }, // 0x21
/* 34 */ { VC_I, kVK_ANSI_G }, // 0x22
/* 35 */ { VC_P, kVK_ANSI_H }, // 0x23
/* 36 */ { VC_ENTER, kVK_ANSI_J }, // 0x24
/* 37 */ { VC_L, kVK_ANSI_K }, // 0x25
/* 38 */ { VC_J, kVK_ANSI_L }, // 0x26
/* 39 */ { VC_QUOTE, kVK_ANSI_Semicolon }, // 0x27
/* 40 */ { VC_K, kVK_ANSI_Quote }, // 0x28
/* 41 */ { VC_SEMICOLON, kVK_ANSI_Grave }, // 0x29
/* 42 */ { VC_BACK_SLASH, kVK_Shift }, // 0x2A
/* 43 */ { VC_COMMA, kVK_ANSI_Backslash }, // 0x2B
/* 44 */ { VC_SLASH, kVK_ANSI_Z }, // 0x2C
/* 45 */ { VC_N, kVK_ANSI_X }, // 0x2D
/* 46 */ { VC_M, kVK_ANSI_C }, // 0x2E
/* 47 */ { VC_PERIOD, kVK_ANSI_V }, // 0x2F
/* 48 */ { VC_TAB, kVK_ANSI_B }, // 0x30
/* 49 */ { VC_SPACE, kVK_ANSI_N }, // 0x31
/* 50 */ { VC_BACKQUOTE, kVK_ANSI_M }, // 0x32
/* 51 */ { VC_BACKSPACE, kVK_ANSI_Comma }, // 0x33
/* 52 */ { VC_UNDEFINED, kVK_ANSI_Period }, // 0x34
/* 53 */ { VC_ESCAPE, kVK_ANSI_Slash }, // 0x35
/* 54 */ { VC_META_R, kVK_RightShift }, // 0x36
/* 55 */ { VC_META_L, kVK_ANSI_KeypadMultiply }, // 0x37
/* 56 */ { VC_SHIFT_L, kVK_Option }, // 0x38
/* 57 */ { VC_CAPS_LOCK, kVK_Space }, // 0x39
/* 58 */ { VC_ALT_L, kVK_CapsLock }, // 0x3A
/* 59 */ { VC_CONTROL_L, kVK_F1 }, // 0x3B
/* 60 */ { VC_SHIFT_R, kVK_F2 }, // 0x3C
/* 61 */ { VC_ALT_R, kVK_F3 }, // 0x3D
/* 62 */ { VC_CONTROL_R, kVK_F4 }, // 0x3E
/* 63 */ { VC_UNDEFINED, kVK_F5 }, // 0x3F
/* 64 */ { VC_F17, kVK_F6 }, // 0x40
/* 65 */ { VC_KP_SEPARATOR, kVK_F7 }, // 0x41
/* 66 */ { VC_UNDEFINED, kVK_F8 }, // 0x42
/* 67 */ { VC_KP_MULTIPLY, kVK_F9 }, // 0x43
/* 68 */ { VC_UNDEFINED, kVK_F10 }, // 0x44
/* 69 */ { VC_KP_ADD, kVK_ANSI_KeypadClear }, // 0x45
/* 70 */ { VC_UNDEFINED, kVK_Undefined }, // 0x46
/* 71 */ { VC_NUM_LOCK, kVK_ANSI_Keypad7 }, // 0x47
/* 72 */ { VC_VOLUME_UP, kVK_ANSI_Keypad8 }, // 0x48
/* 73 */ { VC_VOLUME_DOWN, kVK_ANSI_Keypad9 }, // 0x49
/* 74 */ { VC_VOLUME_MUTE, kVK_ANSI_KeypadMinus }, // 0x4A
/* 75 */ { VC_KP_DIVIDE, kVK_ANSI_Keypad4 }, // 0x4B
/* 76 */ { VC_KP_ENTER, kVK_ANSI_Keypad5 }, // 0x4C
/* 77 */ { VC_UNDEFINED, kVK_ANSI_Keypad6 }, // 0x4D
/* 78 */ { VC_KP_SUBTRACT, kVK_ANSI_KeypadPlus }, // 0x4E
/* 79 */ { VC_F18, kVK_ANSI_Keypad1 }, // 0x4F
/* 80 */ { VC_F19, kVK_ANSI_Keypad2 }, // 0x50
/* 81 */ { VC_KP_EQUALS, kVK_ANSI_Keypad3 }, // 0x51
/* 82 */ { VC_KP_0, kVK_ANSI_Keypad0 }, // 0x52
/* 83 */ { VC_KP_1, kVK_ANSI_KeypadDecimal }, // 0x53
/* 84 */ { VC_KP_2, kVK_Undefined }, // 0x54
/* 85 */ { VC_KP_3, kVK_Undefined }, // 0x55
/* 86 */ { VC_KP_4, kVK_Undefined }, // 0x56
/* 87 */ { VC_KP_5, kVK_F11 }, // 0x57
/* 88 */ { VC_KP_6, kVK_F12 }, // 0x58
/* 89 */ { VC_KP_7, kVK_Undefined }, // 0x59
/* 90 */ { VC_F20, kVK_Undefined }, // 0x5A
/* 91 */ { VC_KP_8, kVK_F13 }, // 0x5B
/* 92 */ { VC_KP_9, kVK_F14 }, // 0x5C
/* 93 */ { VC_YEN, kVK_F15 }, // 0x5D
/* 94 */ { VC_UNDERSCORE, kVK_Undefined }, // 0x5E
/* 95 */ { VC_KP_COMMA, kVK_Undefined }, // 0x5F
/* 96 */ { VC_F5, kVK_Undefined }, // 0x60
/* 97 */ { VC_F6, kVK_Undefined }, // 0x61
/* 98 */ { VC_F7, kVK_Undefined }, // 0x62
/* 99 */ { VC_F3, kVK_F16 }, // 0x63
/* 100 */ { VC_F8, kVK_F17 }, // 0x64
/* 101 */ { VC_F9, kVK_F18 }, // 0x65
/* 102 */ { VC_UNDEFINED, kVK_F19 }, // 0x66
/* 103 */ { VC_F11, kVK_F20 }, // 0x67
/* 104 */ { VC_KATAKANA, kVK_Undefined }, // 0x68
/* 105 */ { VC_F13, kVK_Undefined }, // 0x69
/* 106 */ { VC_F16, kVK_Undefined }, // 0x6A
/* 107 */ { VC_F14, kVK_Undefined }, // 0x6B
/* 108 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6C FIXME kVK_JIS_Eisu same as Caps Lock ?
/* 109 */ { VC_F10, kVK_Undefined }, // 0x6D
/* 110 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6E
/* 111 */ { VC_F12, kVK_Undefined }, // 0x6F
/* 112 */ { VC_UNDEFINED, kVK_JIS_Kana }, // 0x70
/* 113 */ { VC_F15, kVK_Undefined }, // 0x71
/* 114 */ { VC_INSERT, kVK_Undefined }, // 0x72
/* 115 */ { VC_HOME, kVK_JIS_Underscore }, // 0x73
/* 116 */ { VC_PAGE_UP, kVK_Undefined }, // 0x74
/* 117 */ { VC_DELETE, kVK_Undefined }, // 0x75
/* 118 */ { VC_F4, kVK_Undefined }, // 0x76
/* 119 */ { VC_END, kVK_Undefined }, // 0x77
/* 120 */ { VC_F2, kVK_Undefined }, // 0x78
/* 121 */ { VC_PAGE_DOWN, kVK_Undefined }, // 0x79
/* 122 */ { VC_F1, kVK_Undefined }, // 0x7A
/* 123 */ { VC_LEFT, kVK_Undefined }, // 0x7B
/* 124 */ { VC_RIGHT, kVK_Undefined }, // 0x7C
/* 125 */ { VC_DOWN, kVK_JIS_Yen }, // 0x7D
/* 126 */ { VC_UP, kVK_JIS_KeypadComma }, // 0x7E
/* 127 */ { VC_UNDEFINED, kVK_Undefined }, // 0x7F
// No Offset Offset (i & 0x007F) + 128
/* 128 */ { VC_UNDEFINED, kVK_Undefined }, // 0x80
/* 129 */ { VC_UNDEFINED, kVK_Undefined }, // 0x81
/* 130 */ { VC_UNDEFINED, kVK_Undefined }, // 0x82
/* 131 */ { VC_UNDEFINED, kVK_Undefined }, // 0x83
/* 132 */ { VC_UNDEFINED, kVK_Undefined }, // 0x84
/* 133 */ { VC_UNDEFINED, kVK_Undefined }, // 0x85
/* 134 */ { VC_UNDEFINED, kVK_Undefined }, // 0x86
/* 135 */ { VC_UNDEFINED, kVK_Undefined }, // 0x87
/* 136 */ { VC_UNDEFINED, kVK_Undefined }, // 0x88
/* 137 */ { VC_UNDEFINED, kVK_Undefined }, // 0x89
/* 138 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8A
/* 139 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8B
/* 140 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8C
/* 141 */ { VC_UNDEFINED, kVK_ANSI_KeypadEquals }, // 0x8D
/* 142 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8E
/* 143 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8F
/* 144 */ { VC_UNDEFINED, kVK_MEDIA_Previous }, // 0x90
/* 145 */ { VC_UNDEFINED, kVK_Undefined }, // 0x91
/* 146 */ { VC_UNDEFINED, kVK_Undefined }, // 0x92
/* 147 */ { VC_UNDEFINED, kVK_Undefined }, // 0x93
/* 148 */ { VC_UNDEFINED, kVK_Undefined }, // 0x94
/* 149 */ { VC_UNDEFINED, kVK_Undefined }, // 0x95
/* 150 */ { VC_UNDEFINED, kVK_Undefined }, // 0x96
/* 151 */ { VC_UNDEFINED, kVK_Undefined }, // 0x97
/* 152 */ { VC_UNDEFINED, kVK_Undefined }, // 0x98
/* 153 */ { VC_UNDEFINED, kVK_MEDIA_Next }, // 0x99
/* 154 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9A
/* 155 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9B
/* 156 */ { VC_UNDEFINED, kVK_ANSI_KeypadEnter }, // 0x9C
/* 157 */ { VC_UNDEFINED, kVK_RightControl }, // 0x9D
/* 158 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9E
/* 159 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9F
/* 160 */ { VC_UNDEFINED, kVK_Mute }, // 0xA0
/* 161 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA1
/* 162 */ { VC_UNDEFINED, kVK_MEDIA_Play }, // 0xA2
/* 163 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA3
/* 164 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA4
/* 165 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA5
/* 166 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA6
/* 167 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA7
/* 168 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA8
/* 169 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA9
/* 170 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAA
/* 171 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAB
/* 172 */ { VC_UNDEFINED, kVK_NX_Eject }, // 0xAC
/* 173 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAD
/* 174 */ { VC_UNDEFINED, kVK_VolumeDown }, // 0xAE
/* 175 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAF
/* 176 */ { VC_UNDEFINED, kVK_VolumeUp }, // 0xB0
/* 177 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB1
/* 178 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB2
/* 179 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB3
/* 180 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB4
/* 181 */ { VC_UNDEFINED, kVK_ANSI_KeypadDivide }, // 0xB5
/* 182 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB6
/* 183 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB7
/* 184 */ { VC_UNDEFINED, kVK_RightOption }, // 0xB8
/* 185 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB9
/* 186 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBA
/* 187 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBB
/* 188 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBC
/* 189 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBD
/* 190 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBE
/* 191 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBF
/* 192 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC0
/* 193 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC1
/* 194 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC2
/* 195 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC3
/* 196 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC4
/* 197 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC5
/* 198 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC6
/* 199 */ { VC_UNDEFINED, kVK_Home }, // 0xC7
/* 200 */ { VC_UNDEFINED, kVK_UpArrow }, // 0xC8
/* 201 */ { VC_UNDEFINED, kVK_PageUp }, // 0xC9
/* 202 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCA
/* 203 */ { VC_UNDEFINED, kVK_LeftArrow }, // 0xCB
/* 204 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCC
/* 205 */ { VC_UNDEFINED, kVK_RightArrow }, // 0xCD
/* 206 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCE
/* 207 */ { VC_UNDEFINED, kVK_End }, // 0xCF
/* 208 */ { VC_UNDEFINED, kVK_DownArrow }, // 0xD0
/* 209 */ { VC_UNDEFINED, kVK_PageDown }, // 0xD1
/* 210 */ { VC_UNDEFINED, kVK_Help }, // 0xD2
/* 211 */ { VC_UNDEFINED, kVK_ForwardDelete }, // 0xD3
/* 212 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD4
/* 213 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD5
/* 214 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD6
/* 215 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD7
/* 216 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD8
/* 217 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD9
/* 218 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDA
/* 219 */ { VC_UNDEFINED, kVK_Command }, // 0xDB
/* 220 */ { VC_UNDEFINED, kVK_RightCommand }, // 0xDC
/* 221 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDD
/* 222 */ { VC_UNDEFINED, kVK_NX_Power }, // 0xDE
/* 223 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDF
/* 224 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE0
/* 225 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE1
/* 226 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE2
/* 227 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE3
/* 228 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE4
/* 229 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE5
/* 230 */ { VC_POWER, kVK_Undefined }, // 0xE6
/* 231 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE7
/* 232 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE8
/* 233 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE9
/* 234 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEA
/* 235 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEB
/* 236 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEC
/* 237 */ { VC_UNDEFINED, kVK_Undefined }, // 0xED
/* 238 */ { VC_MEDIA_EJECT, kVK_Undefined }, // 0xEE
/* 239 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEF
/* 240 */ { VC_MEDIA_PLAY, kVK_Undefined }, // 0xF0
/* 241 */ { VC_MEDIA_NEXT, kVK_Undefined }, // 0xF1
/* 242 */ { VC_MEDIA_PREVIOUS, kVK_Undefined }, // 0xF2
/* 243 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF3
/* 244 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF4
/* 245 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF5
/* 246 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF6
/* 247 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF7
/* 248 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF8
/* 249 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF9
/* 250 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFA
/* 251 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFB
/* 252 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFC
/* 253 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFD
/* 254 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFE
/* 255 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFF
};
uint16_t keycode_to_scancode(UInt64 keycode) {
uint16_t scancode = VC_UNDEFINED;
// Bound check 0 <= keycode < 256
if (keycode < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[0])) {
scancode = keycode_scancode_table[keycode][0];
}
return scancode;
}
UInt64 scancode_to_keycode(uint16_t scancode) {
UInt64 keycode = kVK_Undefined;
// Bound check 0 <= keycode < 128
if (scancode < 128) {
keycode = keycode_scancode_table[scancode][1];
}
else {
// Calculate the upper offset.
unsigned short i = (scancode & 0x007F) | 0x80;
if (i < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[1])) {
keycode = keycode_scancode_table[i][1];
}
}
return keycode;
}
void load_input_helper() {
#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION)
// Start with a fresh dead key state.
//curr_deadkey_state = 0;
#endif
}
void unload_input_helper() {
#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION)
if (prev_keyboard_layout != NULL) {
// Cleanup tracking of the previous layout.
CFRelease(prev_keyboard_layout);
prev_keyboard_layout = NULL;
}
#endif
}