From f851244b9298d88c29331ab285c2839d8bee6925 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 16 Dec 2010 16:13:08 +0000 Subject: xserver libXdmcp git update 16-12-2010 --- xorg-server/hw/xquartz/quartzKeyboard.c | 1715 +++++++++++++++---------------- 1 file changed, 857 insertions(+), 858 deletions(-) (limited to 'xorg-server/hw/xquartz/quartzKeyboard.c') diff --git a/xorg-server/hw/xquartz/quartzKeyboard.c b/xorg-server/hw/xquartz/quartzKeyboard.c index cd73ec5bd..54f709a8b 100644 --- a/xorg-server/hw/xquartz/quartzKeyboard.c +++ b/xorg-server/hw/xquartz/quartzKeyboard.c @@ -1,858 +1,857 @@ -/* - quartzKeyboard.c: Keyboard support for Xquartz - - Copyright (c) 2003-2008 Apple Inc. - Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved. - Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. - - Copyright (C) 1999,2000 by Eric Sunshine - 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. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -*/ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#define HACK_MISSING 1 -#define HACK_KEYPAD 1 -#define HACK_BLACKLIST 1 - -#include -#include -#include -#include -#include -#include - -#include "quartz.h" -#include "darwin.h" -#include "darwinEvents.h" - -#include "quartzKeyboard.h" -#include "quartzAudio.h" - -#include "X11Application.h" - -#include "threadSafety.h" - -#ifdef NDEBUG -#undef NDEBUG -#include -#define NDEBUG 1 -#else -#include -#endif -#include - -#include "xkbsrv.h" -#include "exevents.h" -#include "X11/keysym.h" -#include "keysym2ucs.h" - -extern void -CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); - -enum { - MOD_COMMAND = 256, - MOD_SHIFT = 512, - MOD_OPTION = 2048, - MOD_CONTROL = 4096, -}; - -#define UKEYSYM(u) ((u) | 0x01000000) - -#if HACK_MISSING -/* Table of keycode->keysym mappings we use to fallback on for important - keys that are often not in the Unicode mapping. */ - -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}, -}; -#endif - -#if HACK_KEYPAD -/* Table of keycode->old,new-keysym mappings we use to fixup the numeric - keypad entries. */ - -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}, -}; -#endif - -#if HACK_BLACKLIST -/* wine notepad produces wrong characters on shift+arrow - * http://xquartz.macosforge.org/trac/ticket/295 - * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html - * - * legacy Mac keycodes for arrow keys that shift-modify to math symbols - */ -const static unsigned short keycode_blacklist[] = {66, 70, 72, 77}; -#endif - -/* Table mapping normal keysyms to their dead equivalents. - FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ - -const static struct { - KeySym normal, dead; -} dead_keys[] = { - {XK_grave, XK_dead_grave}, - {XK_apostrophe, XK_dead_acute}, /* US:"=" on a Czech keyboard */ - {XK_acute, XK_dead_acute}, - {UKEYSYM (0x384), XK_dead_acute}, /* US:";" on a Greek keyboard */ -// {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */ - {XK_asciicircum, XK_dead_circumflex}, - {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ - {XK_asciitilde, XK_dead_tilde}, - {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL 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}, /* DOT ABOVE */ - {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}, /* LATIN SMALL LETTER IOTA */ - {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */ -/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ - {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */ - {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */ - {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */ -}; - -typedef struct darwinKeyboardInfo_struct { - CARD8 modMap[MAP_LENGTH]; - KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; - unsigned char modifierKeycodes[32][2]; -} darwinKeyboardInfo; - -darwinKeyboardInfo keyInfo; -pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) { - // FIXME: to be implemented - // keyclick, bell volume / pitch, autorepead, LED's -} - -//----------------------------------------------------------------------------- -// Utility functions to help parse Darwin keymap -//----------------------------------------------------------------------------- - -/* - * DarwinBuildModifierMaps - * Use the keyMap field of keyboard info structure to populate - * the modMap and modifierKeycodes fields. - */ -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; - if(!XQuartzOptionSendsAlt) - *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. - 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 - if(!XQuartzOptionSendsAlt) - *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. - info->modMap[MIN_KEYCODE + i] = Mod1Mask; - break; - - case XK_Mode_switch: - ErrorF("DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n"); - info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; -#ifdef NX_MODIFIERKEY_RALTERNATE - info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; -#endif - 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; - } - } -} - -/* - * DarwinKeyboardInit - * Get the Darwin keyboard map and compute an equivalent - * X keyboard map and modifier map. Set the new keyboard - * device structure. - */ -void DarwinKeyboardInit(DeviceIntPtr pDev) { - // Open a shared connection to the HID System. - // Note that the Event Status Driver is really just a wrapper - // for a kIOHIDParamConnectType connection. - assert(darwinParamConnect = NXOpenEventStatus()); - - InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl); - - DarwinKeyboardReloadHandler(); - - CopyKeyClass(pDev, inputInfo.keyboard); -} - -/* Set the repeat rates based on global preferences and keycodes for modifiers. - * Precondition: Has the keyInfo_mutex lock. - */ -static void DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, int keyRepeatValue) { - if(initialKeyRepeatValue == 300000) { // off - /* Turn off repeats globally */ - XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff); - } else { - int i; - XkbControlsPtr ctrl; - XkbControlsRec old; - - /* Turn on repeats globally */ - XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); - - /* Setup the bit mask for individual key repeats */ - ctrl = pDev->key->xkbInfo->desc->ctrls; - old= *ctrl; - - ctrl->repeat_delay = initialKeyRepeatValue * 15; - ctrl->repeat_interval = keyRepeatValue * 15; - - /* Turn off key-repeat for modifier keys, on for others */ - /* First set them all on */ - for(i=0; i < XkbPerKeyBitArraySize; i++) - ctrl->per_key_repeat[i] = -1; - - /* Now turn off the modifiers */ - for(i=0; i < 32; i++) { - unsigned char keycode; - - keycode = keyInfo.modifierKeycodes[i][0]; - if(keycode) - ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); - - keycode = keyInfo.modifierKeycodes[i][1]; - if(keycode) - ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); - } - - /* Hurray for data duplication */ - if (pDev->kbdfeed) - memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, XkbPerKeyBitArraySize); - - //fprintf(stderr, "per_key_repeat =\n"); - //for(i=0; i < XkbPerKeyBitArraySize; i++) - // fprintf(stderr, "%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n"); - - /* And now we notify the puppies about the changes */ - XkbDDXChangeControls(pDev, &old, ctrl); - } -} - -void DarwinKeyboardReloadHandler(void) { - KeySymsRec keySyms; - CFIndex initialKeyRepeatValue, keyRepeatValue; - BOOL ok; - DeviceIntPtr pDev; - const char *xmodmap = PROJECTROOT "/bin/xmodmap"; - const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap"; - const char *homedir = getenv("HOME"); - char usermodmap[PATH_MAX], cmd[PATH_MAX]; - - DEBUG_LOG("DarwinKeyboardReloadHandler\n"); - - /* Get our key repeat settings from GlobalPreferences */ - (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); - - initialKeyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok); - if(!ok) - initialKeyRepeatValue = 35; - - keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok); - if(!ok) - keyRepeatValue = 6; - - pthread_mutex_lock(&keyInfo_mutex); { - /* Initialize our keySyms */ - keySyms.map = keyInfo.keyMap; - keySyms.mapWidth = GLYPHS_PER_KEY; - keySyms.minKeyCode = MIN_KEYCODE; - keySyms.maxKeyCode = MAX_KEYCODE; - - // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap - /* Apply the mappings to darwinKeyboard */ - XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode, - keySyms.maxKeyCode - keySyms.minKeyCode + 1, - keyInfo.modMap, serverClient); - DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, keyRepeatValue); - - /* Apply the mappings to the core keyboard */ - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { - XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode, - keySyms.maxKeyCode - keySyms.minKeyCode + 1, - keyInfo.modMap, serverClient); - DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, keyRepeatValue); - } - } - } pthread_mutex_unlock(&keyInfo_mutex); - - /* Modify with xmodmap */ - if (access(xmodmap, F_OK) == 0) { - /* Check for system .Xmodmap */ - if (access(sysmodmap, F_OK) == 0) { - if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap) < sizeof(cmd)) { - X11ApplicationLaunchClient(cmd); - } else { - ErrorF("X11.app: Unable to create / execute xmodmap command line"); - } - } - - /* Check for user's local .Xmodmap */ - if ((homedir != NULL) && (snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir) < sizeof(usermodmap))) { - if (access(usermodmap, F_OK) == 0) { - if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap) < sizeof(cmd)) { - X11ApplicationLaunchClient(cmd); - } else { - ErrorF("X11.app: Unable to create / execute xmodmap command line"); - } - } - } else { - ErrorF("X11.app: Unable to determine path to user's .Xmodmap"); - } - } -} - -//----------------------------------------------------------------------------- -// Modifier translation functions -// -// There are three different ways to specify a Mac modifier key: -// keycode - specifies hardware key, read from keymapping -// key - NX_MODIFIERKEY_*, really an index -// mask - NX_*MASK, mask for modifier flags in event record -// Left and right side have different keycodes but the same key and mask. -//----------------------------------------------------------------------------- - -/* - * DarwinModifierNXKeyToNXKeycode - * Return the keycode for an NX_MODIFIERKEY_* modifier. - * side = 0 for left or 1 for right. - * Returns 0 if key+side is not a known modifier. - */ -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; -} - -/* - * DarwinModifierNXKeycodeToNXKey - * Returns -1 if keycode+side is not a modifier key - * outSide may be NULL, else it gets 0 for left and 1 for right. - */ -int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) { - int key, side; - - keycode += MIN_KEYCODE; - - // search modifierKeycodes for this keycode+side - pthread_mutex_lock(&keyInfo_mutex); - for (key = 0; key < NX_NUMMODIFIERS; key++) { - for (side = 0; side <= 1; side++) { - if (keyInfo.modifierKeycodes[key][side] == keycode) break; - } - } - pthread_mutex_unlock(&keyInfo_mutex); - - if (key == NX_NUMMODIFIERS) { - return -1; - } - if (outSide) *outSide = side; - - return key; -} - -/* - * DarwinModifierNXMaskToNXKey - * Returns -1 if mask is not a known modifier mask. - */ -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; -} - -/* - * DarwinModifierNXKeyToNXMask - * Returns 0 if key is not a known modifier key. - */ -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; -} - -/* - * DarwinModifierStringToNXMask - * Returns 0 if string is not a known modifier. - */ -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; -} - -/* - * LegalModifier - * This allows the ddx layer to prevent some keys from being remapped - * as modifier keys. - */ -Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) -{ - return 1; -} - -static inline UniChar macroman2ucs(unsigned char c) { - /* Precalculated table mapping MacRoman-128 to Unicode. Generated - by creating single element CFStringRefs then extracting the - first character. */ - - 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; -} - -static 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; - } - - /* Scan the keycode range for the Unicode character that each - key produces in the four shift states. Then convert that to - an X11 keysym (which may just the bit that says "this is - Unicode" if it can't find the real symbol.) */ - - /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate - must be used instead. */ - - 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) { - /* Found a dead key. Work out which one it is, but - remembering that it's dead. */ - err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, - mods[j] >> 8, keyboard_type, - kUCKeyTranslateNoDeadKeysMask, - &extra_dead, 8, &len, s); - if (err != noErr) continue; - } - - /* Not sure why 0x0010 is there. - * 0x0000 - 'Unicode Hex Input' ... - */ - if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { - 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 { // kchr - UInt32 c, state = 0, state2 = 0; - UInt16 code; - - code = i | mods[j]; - c = KeyTranslate (chr_data, code, &state); - - /* Dead keys are only processed on key-down, so ask - to translate those events. When we find a dead key, - translating the matching key up event will give - us the actual dead character. */ - - if (state != 0) - c = KeyTranslate (chr_data, code | 128, &state2); - - /* Characters seem to be in MacRoman encoding. */ - - 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 (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; - } - -#if HACK_MISSING - /* Fix up some things that are normally 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; - } -#endif - -#if HACK_KEYPAD - /* And some more things. We find the right symbols for the numeric - keypad, but not the KP_ keysyms. So try to convert known keycodes. */ - 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; - } -#endif - -#if HACK_BLACKLIST - for (i = 0; i < sizeof (keycode_blacklist) / sizeof (keycode_blacklist[0]); i++) { - k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; - k[0] = k[1] = k[2] = k[3] = NoSymbol; - } -#endif - - DarwinBuildModifierMaps(info); - - return TRUE; -} - -Bool QuartsResyncKeymap(Bool sendDDXEvent) { - Bool retval; - /* Update keyInfo */ - pthread_mutex_lock(&keyInfo_mutex); - memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); - retval = QuartzReadSystemKeymap(&keyInfo); - pthread_mutex_unlock(&keyInfo_mutex); - - /* Tell server thread to deal with new keyInfo */ - if(sendDDXEvent) - DarwinSendDDXEvent(kXquartzReloadKeymap, 0); - - return retval; -} +/* + quartzKeyboard.c: Keyboard support for Xquartz + + Copyright (c) 2003-2008 Apple Inc. + Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved. + Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. + + Copyright (C) 1999,2000 by Eric Sunshine + 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. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. +*/ + +#include "sanitizedCarbon.h" + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#define HACK_MISSING 1 +#define HACK_KEYPAD 1 +#define HACK_BLACKLIST 1 + +#include +#include +#include +#include +#include +#include + +#include "quartz.h" +#include "darwin.h" +#include "darwinEvents.h" + +#include "quartzKeyboard.h" + +#include "X11Application.h" + +#include "threadSafety.h" + +#ifdef NDEBUG +#undef NDEBUG +#include +#define NDEBUG 1 +#else +#include +#endif +#include + +#include "xkbsrv.h" +#include "exevents.h" +#include "X11/keysym.h" +#include "keysym2ucs.h" + +extern void +CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); + +enum { + MOD_COMMAND = 256, + MOD_SHIFT = 512, + MOD_OPTION = 2048, + MOD_CONTROL = 4096, +}; + +#define UKEYSYM(u) ((u) | 0x01000000) + +#if HACK_MISSING +/* Table of keycode->keysym mappings we use to fallback on for important + keys that are often not in the Unicode mapping. */ + +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}, +}; +#endif + +#if HACK_KEYPAD +/* Table of keycode->old,new-keysym mappings we use to fixup the numeric + keypad entries. */ + +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}, +}; +#endif + +#if HACK_BLACKLIST +/* wine notepad produces wrong characters on shift+arrow + * http://xquartz.macosforge.org/trac/ticket/295 + * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html + * + * legacy Mac keycodes for arrow keys that shift-modify to math symbols + */ +const static unsigned short keycode_blacklist[] = {66, 70, 72, 77}; +#endif + +/* Table mapping normal keysyms to their dead equivalents. + FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ + +const static struct { + KeySym normal, dead; +} dead_keys[] = { + {XK_grave, XK_dead_grave}, + {XK_apostrophe, XK_dead_acute}, /* US:"=" on a Czech keyboard */ + {XK_acute, XK_dead_acute}, + {UKEYSYM (0x384), XK_dead_acute}, /* US:";" on a Greek keyboard */ +// {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */ + {XK_asciicircum, XK_dead_circumflex}, + {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ + {XK_asciitilde, XK_dead_tilde}, + {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL 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}, /* DOT ABOVE */ + {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}, /* LATIN SMALL LETTER IOTA */ + {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */ +/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ + {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */ + {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */ + {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */ +}; + +typedef struct darwinKeyboardInfo_struct { + CARD8 modMap[MAP_LENGTH]; + KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; + unsigned char modifierKeycodes[32][2]; +} darwinKeyboardInfo; + +darwinKeyboardInfo keyInfo; +pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) { + // FIXME: to be implemented + // keyclick, bell volume / pitch, autorepead, LED's +} + +//----------------------------------------------------------------------------- +// Utility functions to help parse Darwin keymap +//----------------------------------------------------------------------------- + +/* + * DarwinBuildModifierMaps + * Use the keyMap field of keyboard info structure to populate + * the modMap and modifierKeycodes fields. + */ +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; + if(!XQuartzOptionSendsAlt) + *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. + 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 + if(!XQuartzOptionSendsAlt) + *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. + info->modMap[MIN_KEYCODE + i] = Mod1Mask; + break; + + case XK_Mode_switch: + ErrorF("DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n"); + info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; +#ifdef NX_MODIFIERKEY_RALTERNATE + info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; +#endif + 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; + } + } +} + +/* + * DarwinKeyboardInit + * Get the Darwin keyboard map and compute an equivalent + * X keyboard map and modifier map. Set the new keyboard + * device structure. + */ +void DarwinKeyboardInit(DeviceIntPtr pDev) { + // Open a shared connection to the HID System. + // Note that the Event Status Driver is really just a wrapper + // for a kIOHIDParamConnectType connection. + assert(darwinParamConnect = NXOpenEventStatus()); + + InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl); + + DarwinKeyboardReloadHandler(); + + CopyKeyClass(pDev, inputInfo.keyboard); +} + +/* Set the repeat rates based on global preferences and keycodes for modifiers. + * Precondition: Has the keyInfo_mutex lock. + */ +static void DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, int keyRepeatValue) { + if(initialKeyRepeatValue == 300000) { // off + /* Turn off repeats globally */ + XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff); + } else { + int i; + XkbControlsPtr ctrl; + XkbControlsRec old; + + /* Turn on repeats globally */ + XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); + + /* Setup the bit mask for individual key repeats */ + ctrl = pDev->key->xkbInfo->desc->ctrls; + old= *ctrl; + + ctrl->repeat_delay = initialKeyRepeatValue * 15; + ctrl->repeat_interval = keyRepeatValue * 15; + + /* Turn off key-repeat for modifier keys, on for others */ + /* First set them all on */ + for(i=0; i < XkbPerKeyBitArraySize; i++) + ctrl->per_key_repeat[i] = -1; + + /* Now turn off the modifiers */ + for(i=0; i < 32; i++) { + unsigned char keycode; + + keycode = keyInfo.modifierKeycodes[i][0]; + if(keycode) + ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); + + keycode = keyInfo.modifierKeycodes[i][1]; + if(keycode) + ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); + } + + /* Hurray for data duplication */ + if (pDev->kbdfeed) + memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, XkbPerKeyBitArraySize); + + //fprintf(stderr, "per_key_repeat =\n"); + //for(i=0; i < XkbPerKeyBitArraySize; i++) + // fprintf(stderr, "%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n"); + + /* And now we notify the puppies about the changes */ + XkbDDXChangeControls(pDev, &old, ctrl); + } +} + +void DarwinKeyboardReloadHandler(void) { + KeySymsRec keySyms; + CFIndex initialKeyRepeatValue, keyRepeatValue; + BOOL ok; + DeviceIntPtr pDev; + const char *xmodmap = PROJECTROOT "/bin/xmodmap"; + const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap"; + const char *homedir = getenv("HOME"); + char usermodmap[PATH_MAX], cmd[PATH_MAX]; + + DEBUG_LOG("DarwinKeyboardReloadHandler\n"); + + /* Get our key repeat settings from GlobalPreferences */ + (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); + + initialKeyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok); + if(!ok) + initialKeyRepeatValue = 35; + + keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok); + if(!ok) + keyRepeatValue = 6; + + pthread_mutex_lock(&keyInfo_mutex); { + /* Initialize our keySyms */ + keySyms.map = keyInfo.keyMap; + keySyms.mapWidth = GLYPHS_PER_KEY; + keySyms.minKeyCode = MIN_KEYCODE; + keySyms.maxKeyCode = MAX_KEYCODE; + + // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap + /* Apply the mappings to darwinKeyboard */ + XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode, + keySyms.maxKeyCode - keySyms.minKeyCode + 1, + keyInfo.modMap, serverClient); + DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, keyRepeatValue); + + /* Apply the mappings to the core keyboard */ + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { + XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode, + keySyms.maxKeyCode - keySyms.minKeyCode + 1, + keyInfo.modMap, serverClient); + DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, keyRepeatValue); + } + } + } pthread_mutex_unlock(&keyInfo_mutex); + + /* Modify with xmodmap */ + if (access(xmodmap, F_OK) == 0) { + /* Check for system .Xmodmap */ + if (access(sysmodmap, F_OK) == 0) { + if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap) < sizeof(cmd)) { + X11ApplicationLaunchClient(cmd); + } else { + ErrorF("X11.app: Unable to create / execute xmodmap command line"); + } + } + + /* Check for user's local .Xmodmap */ + if ((homedir != NULL) && (snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir) < sizeof(usermodmap))) { + if (access(usermodmap, F_OK) == 0) { + if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap) < sizeof(cmd)) { + X11ApplicationLaunchClient(cmd); + } else { + ErrorF("X11.app: Unable to create / execute xmodmap command line"); + } + } + } else { + ErrorF("X11.app: Unable to determine path to user's .Xmodmap"); + } + } +} + +//----------------------------------------------------------------------------- +// Modifier translation functions +// +// There are three different ways to specify a Mac modifier key: +// keycode - specifies hardware key, read from keymapping +// key - NX_MODIFIERKEY_*, really an index +// mask - NX_*MASK, mask for modifier flags in event record +// Left and right side have different keycodes but the same key and mask. +//----------------------------------------------------------------------------- + +/* + * DarwinModifierNXKeyToNXKeycode + * Return the keycode for an NX_MODIFIERKEY_* modifier. + * side = 0 for left or 1 for right. + * Returns 0 if key+side is not a known modifier. + */ +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; +} + +/* + * DarwinModifierNXKeycodeToNXKey + * Returns -1 if keycode+side is not a modifier key + * outSide may be NULL, else it gets 0 for left and 1 for right. + */ +int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) { + int key, side; + + keycode += MIN_KEYCODE; + + // search modifierKeycodes for this keycode+side + pthread_mutex_lock(&keyInfo_mutex); + for (key = 0; key < NX_NUMMODIFIERS; key++) { + for (side = 0; side <= 1; side++) { + if (keyInfo.modifierKeycodes[key][side] == keycode) break; + } + } + pthread_mutex_unlock(&keyInfo_mutex); + + if (key == NX_NUMMODIFIERS) { + return -1; + } + if (outSide) *outSide = side; + + return key; +} + +/* + * DarwinModifierNXMaskToNXKey + * Returns -1 if mask is not a known modifier mask. + */ +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; +} + +/* + * DarwinModifierNXKeyToNXMask + * Returns 0 if key is not a known modifier key. + */ +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; +} + +/* + * DarwinModifierStringToNXMask + * Returns 0 if string is not a known modifier. + */ +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; +} + +/* + * LegalModifier + * This allows the ddx layer to prevent some keys from being remapped + * as modifier keys. + */ +Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return 1; +} + +static inline UniChar macroman2ucs(unsigned char c) { + /* Precalculated table mapping MacRoman-128 to Unicode. Generated + by creating single element CFStringRefs then extracting the + first character. */ + + 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; +} + +static 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; + } + + /* Scan the keycode range for the Unicode character that each + key produces in the four shift states. Then convert that to + an X11 keysym (which may just the bit that says "this is + Unicode" if it can't find the real symbol.) */ + + /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate + must be used instead. */ + + 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) { + /* Found a dead key. Work out which one it is, but + remembering that it's dead. */ + err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, + mods[j] >> 8, keyboard_type, + kUCKeyTranslateNoDeadKeysMask, + &extra_dead, 8, &len, s); + if (err != noErr) continue; + } + + /* Not sure why 0x0010 is there. + * 0x0000 - 'Unicode Hex Input' ... + */ + if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { + 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 { // kchr + UInt32 c, state = 0, state2 = 0; + UInt16 code; + + code = i | mods[j]; + c = KeyTranslate (chr_data, code, &state); + + /* Dead keys are only processed on key-down, so ask + to translate those events. When we find a dead key, + translating the matching key up event will give + us the actual dead character. */ + + if (state != 0) + c = KeyTranslate (chr_data, code | 128, &state2); + + /* Characters seem to be in MacRoman encoding. */ + + 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 (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; + } + +#if HACK_MISSING + /* Fix up some things that are normally 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; + } +#endif + +#if HACK_KEYPAD + /* And some more things. We find the right symbols for the numeric + keypad, but not the KP_ keysyms. So try to convert known keycodes. */ + 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; + } +#endif + +#if HACK_BLACKLIST + for (i = 0; i < sizeof (keycode_blacklist) / sizeof (keycode_blacklist[0]); i++) { + k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; + k[0] = k[1] = k[2] = k[3] = NoSymbol; + } +#endif + + DarwinBuildModifierMaps(info); + + return TRUE; +} + +Bool QuartsResyncKeymap(Bool sendDDXEvent) { + Bool retval; + /* Update keyInfo */ + pthread_mutex_lock(&keyInfo_mutex); + memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); + retval = QuartzReadSystemKeymap(&keyInfo); + pthread_mutex_unlock(&keyInfo_mutex); + + /* Tell server thread to deal with new keyInfo */ + if(sendDDXEvent) + DarwinSendDDXEvent(kXquartzReloadKeymap, 0); + + return retval; +} -- cgit v1.2.3