#include "sanitizedCarbon.h"
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#define HACK_MISSING 1
#define HACK_KEYPAD 1
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <AvailabilityMacros.h>
#include "quartzCommon.h"
#include "darwin.h"
#include "quartzKeyboard.h"
#include "quartzAudio.h"
#include "threadSafety.h"
#ifdef NDEBUG
#undef NDEBUG
#include <assert.h>
#define NDEBUG 1
#else
#include <assert.h>
#endif
#include <pthread.h>
#include "xkbsrv.h"
#include "exevents.h"
#include "X11/keysym.h"
#include "keysym2ucs.h"
enum {
MOD_COMMAND = 256,
MOD_SHIFT = 512,
MOD_OPTION = 2048,
MOD_CONTROL = 4096,
};
#define UKEYSYM(u) ((u) | 0x01000000)
const static struct {
unsigned short keycode;
KeySym keysym;
} known_keys[] = {
{55, XK_Meta_L},
{56, XK_Shift_L},
{57, XK_Caps_Lock},
{58, XK_Alt_L},
{59, XK_Control_L},
{60, XK_Shift_R},
{61, XK_Alt_R},
{62, XK_Control_R},
{63, XK_Meta_R},
{122, XK_F1},
{120, XK_F2},
{99, XK_F3},
{118, XK_F4},
{96, XK_F5},
{97, XK_F6},
{98, XK_F7},
{100, XK_F8},
{101, XK_F9},
{109, XK_F10},
{103, XK_F11},
{111, XK_F12},
{105, XK_F13},
{107, XK_F14},
{113, XK_F15},
};
const static struct {
unsigned short keycode;
KeySym normal, keypad;
} known_numeric_keys[] = {
{65, XK_period, XK_KP_Decimal},
{67, XK_asterisk, XK_KP_Multiply},
{69, XK_plus, XK_KP_Add},
{75, XK_slash, XK_KP_Divide},
{76, 0x01000003, XK_KP_Enter},
{78, XK_minus, XK_KP_Subtract},
{81, XK_equal, XK_KP_Equal},
{82, XK_0, XK_KP_0},
{83, XK_1, XK_KP_1},
{84, XK_2, XK_KP_2},
{85, XK_3, XK_KP_3},
{86, XK_4, XK_KP_4},
{87, XK_5, XK_KP_5},
{88, XK_6, XK_KP_6},
{89, XK_7, XK_KP_7},
{91, XK_8, XK_KP_8},
{92, XK_9, XK_KP_9},
};
const static struct {
KeySym normal, dead;
} dead_keys[] = {
{XK_grave, XK_dead_grave},
{XK_apostrophe, XK_dead_acute},
{XK_acute, XK_dead_acute},
{UKEYSYM (0x384), XK_dead_acute},
{XK_asciicircum, XK_dead_circumflex},
{UKEYSYM (0x2c6), XK_dead_circumflex},
{XK_asciitilde, XK_dead_tilde},
{UKEYSYM (0x2dc), XK_dead_tilde},
{XK_macron, XK_dead_macron},
{XK_breve, XK_dead_breve},
{XK_abovedot, XK_dead_abovedot},
{XK_diaeresis, XK_dead_diaeresis},
{UKEYSYM (0x2da), XK_dead_abovering},
{XK_doubleacute, XK_dead_doubleacute},
{XK_caron, XK_dead_caron},
{XK_cedilla, XK_dead_cedilla},
{XK_ogonek, XK_dead_ogonek},
{UKEYSYM (0x269), XK_dead_iota},
{UKEYSYM (0x2ec), XK_dead_voiced_sound},
{UKEYSYM (0x323), XK_dead_belowdot},
{UKEYSYM (0x309), XK_dead_hook},
{UKEYSYM (0x31b), XK_dead_horn},
};
darwinKeyboardInfo keyInfo;
pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
static void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) {
}
static void DarwinBuildModifierMaps(darwinKeyboardInfo *info) {
int i;
KeySym *k;
memset(info->modMap, NoSymbol, sizeof(info->modMap));
memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes));
for (i = 0; i < NUM_KEYCODES; i++) {
k = info->keyMap + i * GLYPHS_PER_KEY;
switch (*k) {
case XK_Shift_L:
info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
info->modMap[MIN_KEYCODE + i] = ShiftMask;
break;
case XK_Shift_R:
#ifdef NX_MODIFIERKEY_RSHIFT
info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i;
#else
info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
#endif
info->modMap[MIN_KEYCODE + i] = ShiftMask;
break;
case XK_Control_L:
info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
info->modMap[MIN_KEYCODE + i] = ControlMask;
break;
case XK_Control_R:
#ifdef NX_MODIFIERKEY_RCONTROL
info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i;
#else
info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
#endif
info->modMap[MIN_KEYCODE + i] = ControlMask;
break;
case XK_Caps_Lock:
info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
info->modMap[MIN_KEYCODE + i] = LockMask;
break;
case XK_Alt_L:
info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
info->modMap[MIN_KEYCODE + i] = Mod1Mask;
*k = XK_Mode_switch; break;
case XK_Alt_R:
#ifdef NX_MODIFIERKEY_RALTERNATE
info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
#else
info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
#endif
*k = XK_Mode_switch; info->modMap[MIN_KEYCODE + i] = Mod1Mask;
break;
case XK_Mode_switch:
info->modMap[MIN_KEYCODE + i] = Mod1Mask;
break;
case XK_Meta_L:
info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
info->modMap[MIN_KEYCODE + i] = Mod2Mask;
break;
case XK_Meta_R:
#ifdef NX_MODIFIERKEY_RCOMMAND
info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i;
#else
info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
#endif
info->modMap[MIN_KEYCODE + i] = Mod2Mask;
break;
case XK_Num_Lock:
info->modMap[MIN_KEYCODE + i] = Mod3Mask;
break;
}
}
}
static void DarwinLoadKeyboardMapping(KeySymsRec *keySyms) {
pthread_mutex_lock(&keyInfo_mutex);
DarwinBuildModifierMaps(&keyInfo);
keySyms->map = keyInfo.keyMap;
keySyms->mapWidth = GLYPHS_PER_KEY;
keySyms->minKeyCode = MIN_KEYCODE;
keySyms->maxKeyCode = MAX_KEYCODE;
pthread_mutex_unlock(&keyInfo_mutex);
}
static void DarwinKeyboardSetDeviceKeyMap(KeySymsRec *keySyms) {
DeviceIntPtr pDev;
SendMappingNotify(MappingModifier, 0, 0, serverClient);
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if (pDev->key && pDev->coreEvents)
SendDeviceMappingNotify(serverClient, MappingModifier, 0, 0, pDev);
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key)
assert(SetKeySymsMap(&pDev->key->curKeySyms, keySyms));
SendMappingNotify(MappingKeyboard, keySyms->minKeyCode,
keySyms->maxKeyCode - keySyms->minKeyCode + 1, serverClient);
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if (pDev->key && pDev->coreEvents)
SendDeviceMappingNotify(serverClient, MappingKeyboard, keySyms->minKeyCode,
keySyms->maxKeyCode - keySyms->minKeyCode + 1, pDev);
}
void DarwinKeyboardInit(DeviceIntPtr pDev) {
KeySymsRec keySyms;
XkbComponentNamesRec names;
CFIndex value;
BOOL ok;
assert(darwinParamConnect = NXOpenEventStatus());
DarwinLoadKeyboardMapping(&keySyms);
bzero(&names, sizeof(names));
pthread_mutex_lock(&keyInfo_mutex);
assert(XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, keyInfo.modMap,
QuartzBell, DarwinChangeKeyboardControl));
pthread_mutex_unlock(&keyInfo_mutex);
(void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
value = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
if(!ok)
value = 35;
if(value == 300000) { XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff);
} else {
pDev->key->xkbInfo->desc->ctrls->repeat_delay = value * 15;
value = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
if(!ok)
value = 6;
pDev->key->xkbInfo->desc->ctrls->repeat_interval = value * 15;
XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
}
SwitchCoreKeyboard(pDev);
DarwinKeyboardSetDeviceKeyMap(&keySyms);
}
void DarwinKeyboardReloadHandler(int screenNum, xEventPtr xe, DeviceIntPtr pDev, int nevents) {
KeySymsRec keySyms;
DEBUG_LOG("DarwinKeyboardReloadHandler\n");
DarwinLoadKeyboardMapping(&keySyms);
DarwinKeyboardSetDeviceKeyMap(&keySyms);
}
int DarwinModifierNXKeyToNXKeycode(int key, int side) {
int retval;
pthread_mutex_lock(&keyInfo_mutex);
retval = keyInfo.modifierKeycodes[key][side];
pthread_mutex_unlock(&keyInfo_mutex);
return retval;
}
int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) {
int key, side;
pthread_mutex_lock(&keyInfo_mutex);
keycode += MIN_KEYCODE;
for (key = 0; key < NX_NUMMODIFIERS; key++) {
for (side = 0; side <= 1; side++) {
if (keyInfo.modifierKeycodes[key][side] == keycode) break;
}
}
if (key == NX_NUMMODIFIERS) {
pthread_mutex_unlock(&keyInfo_mutex);
return -1;
}
if (outSide) *outSide = side;
pthread_mutex_unlock(&keyInfo_mutex);
return key;
}
int DarwinModifierNXMaskToNXKey(int mask) {
switch (mask) {
case NX_ALPHASHIFTMASK: return NX_MODIFIERKEY_ALPHALOCK;
case NX_SHIFTMASK: return NX_MODIFIERKEY_SHIFT;
#ifdef NX_DEVICELSHIFTKEYMASK
case NX_DEVICELSHIFTKEYMASK: return NX_MODIFIERKEY_SHIFT;
case NX_DEVICERSHIFTKEYMASK: return NX_MODIFIERKEY_RSHIFT;
#endif
case NX_CONTROLMASK: return NX_MODIFIERKEY_CONTROL;
#ifdef NX_DEVICELCTLKEYMASK
case NX_DEVICELCTLKEYMASK: return NX_MODIFIERKEY_CONTROL;
case NX_DEVICERCTLKEYMASK: return NX_MODIFIERKEY_RCONTROL;
#endif
case NX_ALTERNATEMASK: return NX_MODIFIERKEY_ALTERNATE;
#ifdef NX_DEVICELALTKEYMASK
case NX_DEVICELALTKEYMASK: return NX_MODIFIERKEY_ALTERNATE;
case NX_DEVICERALTKEYMASK: return NX_MODIFIERKEY_RALTERNATE;
#endif
case NX_COMMANDMASK: return NX_MODIFIERKEY_COMMAND;
#ifdef NX_DEVICELCMDKEYMASK
case NX_DEVICELCMDKEYMASK: return NX_MODIFIERKEY_COMMAND;
case NX_DEVICERCMDKEYMASK: return NX_MODIFIERKEY_RCOMMAND;
#endif
case NX_NUMERICPADMASK: return NX_MODIFIERKEY_NUMERICPAD;
case NX_HELPMASK: return NX_MODIFIERKEY_HELP;
case NX_SECONDARYFNMASK: return NX_MODIFIERKEY_SECONDARYFN;
}
return -1;
}
int DarwinModifierNXKeyToNXMask(int key) {
switch (key) {
case NX_MODIFIERKEY_ALPHALOCK: return NX_ALPHASHIFTMASK;
#ifdef NX_DEVICELSHIFTKEYMASK
case NX_MODIFIERKEY_SHIFT: return NX_DEVICELSHIFTKEYMASK;
case NX_MODIFIERKEY_RSHIFT: return NX_DEVICERSHIFTKEYMASK;
case NX_MODIFIERKEY_CONTROL: return NX_DEVICELCTLKEYMASK;
case NX_MODIFIERKEY_RCONTROL: return NX_DEVICERCTLKEYMASK;
case NX_MODIFIERKEY_ALTERNATE: return NX_DEVICELALTKEYMASK;
case NX_MODIFIERKEY_RALTERNATE: return NX_DEVICERALTKEYMASK;
case NX_MODIFIERKEY_COMMAND: return NX_DEVICELCMDKEYMASK;
case NX_MODIFIERKEY_RCOMMAND: return NX_DEVICERCMDKEYMASK;
#else
case NX_MODIFIERKEY_SHIFT: return NX_SHIFTMASK;
case NX_MODIFIERKEY_CONTROL: return NX_CONTROLMASK;
case NX_MODIFIERKEY_ALTERNATE: return NX_ALTERNATEMASK;
case NX_MODIFIERKEY_COMMAND: return NX_COMMANDMASK;
#endif
case NX_MODIFIERKEY_NUMERICPAD: return NX_NUMERICPADMASK;
case NX_MODIFIERKEY_HELP: return NX_HELPMASK;
case NX_MODIFIERKEY_SECONDARYFN: return NX_SECONDARYFNMASK;
}
return 0;
}
int DarwinModifierStringToNXMask(const char *str, int separatelr) {
#ifdef NX_DEVICELSHIFTKEYMASK
if(separatelr) {
if (!strcasecmp(str, "shift")) return NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK;
if (!strcasecmp(str, "control")) return NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK;
if (!strcasecmp(str, "option")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
if (!strcasecmp(str, "alt")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
if (!strcasecmp(str, "command")) return NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK;
if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK;
if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK;
if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK;
if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK;
if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK;
if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK;
if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK;
if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK;
if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK;
if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK;
} else {
#endif
if (!strcasecmp(str, "shift")) return NX_SHIFTMASK;
if (!strcasecmp(str, "control")) return NX_CONTROLMASK;
if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "command")) return NX_COMMANDMASK;
if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK;
if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK;
if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK;
if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK;
if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK;
if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK;
if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK;
#ifdef NX_DEVICELSHIFTKEYMASK
}
#endif
if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK;
if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK;
if (!strcasecmp(str, "help")) return NX_HELPMASK;
if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK;
return 0;
}
Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
{
return 1;
}
static inline UniChar macroman2ucs(unsigned char c) {
static const unsigned short table[128] = {
0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
};
if (c < 128) return c;
else return table[c - 128];
}
static KeySym make_dead_key(KeySym in) {
int i;
for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++)
if (dead_keys[i].normal == in) return dead_keys[i].dead;
return in;
}
Bool QuartzReadSystemKeymap(darwinKeyboardInfo *info) {
#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
KeyboardLayoutRef key_layout;
int is_uchr = 1;
#endif
const void *chr_data = NULL;
int num_keycodes = NUM_KEYCODES;
UInt32 keyboard_type = LMGetKbdType();
int i, j;
OSStatus err;
KeySym *k;
CFDataRef currentKeyLayoutDataRef = NULL;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource();
if (currentKeyLayoutRef) {
currentKeyLayoutDataRef = (CFDataRef )TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData);
if (currentKeyLayoutDataRef)
chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
}
#endif
#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
if (chr_data == NULL) {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
ErrorF("X11.app: Error detected in determining keyboard layout. If you are using an Apple-provided keyboard layout, please report this error at http://xquartz.macosforge.org and http://bugreport.apple.com\n");
ErrorF("X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n",
(unsigned)keyboard_type, currentKeyLayoutRef, currentKeyLayoutDataRef, chr_data);
#endif
KLGetCurrentKeyboardLayout (&key_layout);
KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
if(chr_data != NULL) {
ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
}
#endif
}
if (chr_data == NULL) {
ErrorF("X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
ErrorF("If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n");
KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data);
is_uchr = 0;
num_keycodes = 128;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
if(chr_data != NULL) {
ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
}
#endif
}
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
if(currentKeyLayoutRef)
CFRelease(currentKeyLayoutRef);
#endif
if (chr_data == NULL) {
ErrorF ( "Couldn't get uchr or kchr resource\n");
return FALSE;
}
for (i = 0; i < num_keycodes; i++) {
static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION,
MOD_OPTION | MOD_SHIFT};
k = info->keyMap + i * GLYPHS_PER_KEY;
for (j = 0; j < 4; j++) {
#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
if (is_uchr) {
#endif
UniChar s[8];
UniCharCount len;
UInt32 dead_key_state = 0, extra_dead = 0;
err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
mods[j] >> 8, keyboard_type, 0,
&dead_key_state, 8, &len, s);
if (err != noErr) continue;
if (len == 0 && dead_key_state != 0) {
err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
mods[j] >> 8, keyboard_type,
kUCKeyTranslateNoDeadKeysMask,
&extra_dead, 8, &len, s);
if (err != noErr) continue;
}
if (len > 0 && s[0] != 0x0010) {
k[j] = ucs2keysym (s[0]);
if (dead_key_state != 0) k[j] = make_dead_key (k[j]);
}
#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
} else { UInt32 c, state = 0, state2 = 0;
UInt16 code;
code = i | mods[j];
c = KeyTranslate (chr_data, code, &state);
if (state != 0)
c = KeyTranslate (chr_data, code | 128, &state2);
if (c != 0 && c != 0x0010) {
k[j] = ucs2keysym (macroman2ucs (c & 255));
if (state != 0) k[j] = make_dead_key (k[j]);
}
}
#endif
}
if (k[3] == k[2]) k[3] = NoSymbol;
if (k[1] == k[0]) k[1] = NoSymbol;
if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
}
if (HACK_MISSING) {
for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) {
k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
if (k[0] == NoSymbol && k[1] == NoSymbol
&& k[2] == NoSymbol && k[3] == NoSymbol)
k[0] = known_keys[i].keysym;
}
}
if (HACK_KEYPAD) {
for (i = 0; i < sizeof (known_numeric_keys)
/ sizeof (known_numeric_keys[0]); i++) {
k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
if (k[0] == known_numeric_keys[i].normal)
k[0] = known_numeric_keys[i].keypad;
}
}
return TRUE;
}