1022 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1022 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
   quartzKeyboard.c: Keyboard support for Xquartz
 | 
						|
 | 
						|
   Copyright (c) 2003-2012 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
 | 
						|
#define HACK_BLACKLIST 1
 | 
						|
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <AvailabilityMacros.h>
 | 
						|
 | 
						|
#include "quartz.h"
 | 
						|
#include "darwin.h"
 | 
						|
#include "darwinEvents.h"
 | 
						|
 | 
						|
#include "quartzKeyboard.h"
 | 
						|
 | 
						|
#include "X11Application.h"
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#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)
 | 
						|
 | 
						|
#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        },
 | 
						|
 | 
						|
    { 110, XK_Menu          },
 | 
						|
 | 
						|
    { 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           },
 | 
						|
    { 106, XK_F16           },
 | 
						|
    { 64,  XK_F17           },
 | 
						|
    { 79,  XK_F18           },
 | 
						|
    { 80,  XK_F19           },
 | 
						|
    { 90,  XK_F20           },
 | 
						|
};
 | 
						|
#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
 | 
						|
/* <rdar://problem/7824370> 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);
 | 
						|
 | 
						|
        //ErrorF("per_key_repeat =\n");
 | 
						|
        //for(i=0; i < XkbPerKeyBitArraySize; i++)
 | 
						|
        //    ErrorF("%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;
 | 
						|
}
 | 
						|
 | 
						|
#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | 
						|
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];
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static KeySym
 | 
						|
make_dead_key(KeySym in)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(dead_keys); 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
 | 
						|
 | 
						|
#ifdef __clang__
 | 
						|
#pragma clang diagnostic push
 | 
						|
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty
 | 
						|
#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
 | 
						|
 | 
						|
#ifdef __clang__
 | 
						|
#pragma clang diagnostic pop
 | 
						|
#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];
 | 
						|
 | 
						|
#ifdef __clang__
 | 
						|
#pragma clang diagnostic push
 | 
						|
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate
 | 
						|
#endif
 | 
						|
 | 
						|
            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);
 | 
						|
 | 
						|
#ifdef __clang__
 | 
						|
#pragma clang diagnostic pop
 | 
						|
#endif
 | 
						|
 | 
						|
            /* 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 < ARRAY_SIZE(known_keys); 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 < ARRAY_SIZE(known_numeric_keys); 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 < ARRAY_SIZE(keycode_blacklist); 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;
 | 
						|
}
 |