806 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			806 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
   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 <sunshine@sunshineco.com>
 | 
						|
   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 <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#define HACK_MISSING 1
 | 
						|
#define HACK_KEYPAD 1
 | 
						|
 | 
						|
#include <unistd.h>
 | 
						|
#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 "X11Application.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"
 | 
						|
 | 
						|
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)
 | 
						|
 | 
						|
/* 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},
 | 
						|
};
 | 
						|
 | 
						|
/* 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},
 | 
						|
};
 | 
						|
 | 
						|
/* 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 */
 | 
						|
};
 | 
						|
 | 
						|
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;
 | 
						|
                *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
 | 
						|
                *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);
 | 
						|
 | 
						|
    /* Check for system .Xmodmap */
 | 
						|
    if (access(xmodmap, F_OK) == 0) {
 | 
						|
        if (access(sysmodmap, F_OK) == 0) {
 | 
						|
            snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap);
 | 
						|
            X11ApplicationLaunchClient(cmd);
 | 
						|
        }
 | 
						|
    }
 | 
						|
        
 | 
						|
    /* Check for user's local .Xmodmap */
 | 
						|
    if (homedir != NULL) {
 | 
						|
        snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir);
 | 
						|
        if (access(usermodmap, F_OK) == 0) {
 | 
						|
            snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap);
 | 
						|
            X11ApplicationLaunchClient(cmd);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
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 - <rdar://problem/7793566> '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;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Fix up some things that are normally missing.. */
 | 
						|
 | 
						|
    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;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* And some more things. We find the right symbols for the numeric
 | 
						|
       keypad, but not the KP_ keysyms. So try to convert known keycodes. */
 | 
						|
 | 
						|
    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;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    DarwinBuildModifierMaps(info);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 |