2006-11-26 11:13:41 -07:00
/*
2009-09-06 13:44:18 -06:00
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 .
2006-11-26 11:13:41 -07:00
*/
2009-09-06 13:44:18 -06:00
# include "sanitizedCarbon.h"
2008-11-02 08:26:08 -07:00
# ifdef HAVE_DIX_CONFIG_H
# include <dix-config.h>
2007-11-24 10:55:21 -07:00
# endif
2008-11-02 08:26:08 -07:00
2009-09-06 13:44:18 -06:00
# define HACK_MISSING 1
# define HACK_KEYPAD 1
2010-07-27 13:02:24 -06:00
# define HACK_BLACKLIST 1
2006-11-26 11:13:41 -07:00
2010-07-27 13:02:24 -06:00
# include <unistd.h>
2009-09-06 13:44:18 -06:00
# include <stdio.h>
# include <stdlib.h>
# include <errno.h>
# include <sys/stat.h>
# include <AvailabilityMacros.h>
2010-12-05 08:36:02 -07:00
# include "quartz.h"
2009-09-06 13:44:18 -06:00
# include "darwin.h"
2010-07-27 13:02:24 -06:00
# include "darwinEvents.h"
2006-11-26 11:13:41 -07:00
2008-11-02 08:26:08 -07:00
# include "quartzKeyboard.h"
2009-09-06 13:44:18 -06:00
# include "quartzAudio.h"
2010-07-27 13:02:24 -06:00
# include "X11Application.h"
2009-09-06 13:44:18 -06:00
# 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"
2007-11-24 10:55:21 -07:00
# include "X11/keysym.h"
2006-11-26 11:13:41 -07:00
# include "keysym2ucs.h"
2010-07-27 13:02:24 -06:00
extern void
CopyKeyClass ( DeviceIntPtr device , DeviceIntPtr master ) ;
2006-11-26 11:13:41 -07:00
enum {
MOD_COMMAND = 256 ,
MOD_SHIFT = 512 ,
MOD_OPTION = 2048 ,
MOD_CONTROL = 4096 ,
} ;
# define UKEYSYM(u) ((u) | 0x01000000)
2010-07-27 13:02:24 -06:00
# if HACK_MISSING
2006-11-26 11:13:41 -07:00
/* 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 } ,
} ;
2010-07-27 13:02:24 -06:00
# endif
2006-11-26 11:13:41 -07:00
2010-07-27 13:02:24 -06:00
# if HACK_KEYPAD
2006-11-26 11:13:41 -07:00
/* 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 } ,
} ;
2010-07-27 13:02:24 -06:00
# 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
2006-11-26 11:13:41 -07:00
/* 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 } ,
2009-09-06 13:44:18 -06:00
{ XK_apostrophe , XK_dead_acute } , /* US:"=" on a Czech keyboard */
2006-11-26 11:13:41 -07:00
{ XK_acute , XK_dead_acute } ,
2009-09-06 13:44:18 -06:00
{ UKEYSYM ( 0x384 ) , XK_dead_acute } , /* US:";" on a Greek keyboard */
2010-07-27 13:02:24 -06:00
// {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */
2006-11-26 11:13:41 -07:00
{ 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 */
} ;
2010-07-27 13:02:24 -06:00
typedef struct darwinKeyboardInfo_struct {
CARD8 modMap [ MAP_LENGTH ] ;
KeySym keyMap [ MAP_LENGTH * GLYPHS_PER_KEY ] ;
unsigned char modifierKeycodes [ 32 ] [ 2 ] ;
} darwinKeyboardInfo ;
2009-09-06 13:44:18 -06:00
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 ;
2010-12-05 08:36:02 -07:00
if ( ! XQuartzOptionSendsAlt )
2010-07-27 13:02:24 -06:00
* k = XK_Mode_switch ; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
2009-09-06 13:44:18 -06:00
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
2010-12-05 08:36:02 -07:00
if ( ! XQuartzOptionSendsAlt )
2010-07-27 13:02:24 -06:00
* k = XK_Mode_switch ; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
2009-09-06 13:44:18 -06:00
info - > modMap [ MIN_KEYCODE + i ] = Mod1Mask ;
break ;
case XK_Mode_switch :
2010-07-27 13:02:24 -06:00
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
2009-09-06 13:44:18 -06:00
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 ( ) ) ;
2010-07-27 13:02:24 -06:00
InitKeyboardDeviceStruct ( pDev , NULL , NULL , DarwinChangeKeyboardControl ) ;
2009-09-06 13:44:18 -06:00
2010-07-27 13:02:24 -06:00
DarwinKeyboardReloadHandler ( ) ;
2009-09-06 13:44:18 -06:00
2010-07-27 13:02:24 -06:00
CopyKeyClass ( pDev , inputInfo . keyboard ) ;
}
2009-09-06 13:44:18 -06:00
2010-07-27 13:02:24 -06:00
/* 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 */
2009-09-06 13:44:18 -06:00
XkbSetRepeatKeys ( pDev , - 1 , AutoRepeatModeOff ) ;
} else {
2010-07-27 13:02:24 -06:00
int i ;
XkbControlsPtr ctrl ;
XkbControlsRec old ;
2009-09-06 13:44:18 -06:00
2010-07-27 13:02:24 -06:00
/* Turn on repeats globally */
2009-09-06 13:44:18 -06:00
XkbSetRepeatKeys ( pDev , - 1 , AutoRepeatModeOn ) ;
2010-07-27 13:02:24 -06:00
/* 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 ) ;
}
2009-09-06 13:44:18 -06:00
2010-07-27 13:02:24 -06:00
/* 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 ) ;
}
2009-09-06 13:44:18 -06:00
}
2010-07-27 13:02:24 -06:00
void DarwinKeyboardReloadHandler ( void ) {
2009-09-06 13:44:18 -06:00
KeySymsRec keySyms ;
2010-07-27 13:02:24 -06:00
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 ] ;
2009-09-06 13:44:18 -06:00
DEBUG_LOG ( " DarwinKeyboardReloadHandler \n " ) ;
2010-07-27 13:02:24 -06:00
/* 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 ) ;
2010-12-05 08:36:02 -07:00
/* Modify with xmodmap */
2010-07-27 13:02:24 -06:00
if ( access ( xmodmap , F_OK ) = = 0 ) {
2010-12-05 08:36:02 -07:00
/* Check for system .Xmodmap */
2010-07-27 13:02:24 -06:00
if ( access ( sysmodmap , F_OK ) = = 0 ) {
2010-12-05 08:36:02 -07:00
if ( snprintf ( cmd , sizeof ( cmd ) , " %s %s " , xmodmap , sysmodmap ) < sizeof ( cmd ) ) {
X11ApplicationLaunchClient ( cmd ) ;
} else {
ErrorF ( " X11.app: Unable to create / execute xmodmap command line " ) ;
}
2010-07-27 13:02:24 -06:00
}
2010-12-05 08:36:02 -07:00
/* 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 " ) ;
2010-07-27 13:02:24 -06:00
}
}
2009-09-06 13:44:18 -06:00
}
2006-11-26 11:13:41 -07:00
2009-09-06 13:44:18 -06:00
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
2006-11-26 11:13:41 -07:00
2009-09-06 13:44:18 -06:00
/*
* 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 ;
2010-07-27 13:02:24 -06:00
2009-09-06 13:44:18 -06:00
// search modifierKeycodes for this keycode+side
2010-07-27 13:02:24 -06:00
pthread_mutex_lock ( & keyInfo_mutex ) ;
2009-09-06 13:44:18 -06:00
for ( key = 0 ; key < NX_NUMMODIFIERS ; key + + ) {
for ( side = 0 ; side < = 1 ; side + + ) {
if ( keyInfo . modifierKeycodes [ key ] [ side ] = = keycode ) break ;
}
}
2010-07-27 13:02:24 -06:00
pthread_mutex_unlock ( & keyInfo_mutex ) ;
2009-09-06 13:44:18 -06:00
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 ;
2006-11-26 11:13:41 -07:00
}
2008-11-02 08:26:08 -07:00
static inline UniChar macroman2ucs ( unsigned char c ) {
2006-11-26 11:13:41 -07:00
/* 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 ,
} ;
2008-11-02 08:26:08 -07:00
if ( c < 128 ) return c ;
else return table [ c - 128 ] ;
2006-11-26 11:13:41 -07:00
}
2008-11-02 08:26:08 -07:00
static KeySym make_dead_key ( KeySym in ) {
2006-11-26 11:13:41 -07:00
int i ;
for ( i = 0 ; i < sizeof ( dead_keys ) / sizeof ( dead_keys [ 0 ] ) ; i + + )
2008-11-02 08:26:08 -07:00
if ( dead_keys [ i ] . normal = = in ) return dead_keys [ i ] . dead ;
2006-11-26 11:13:41 -07:00
return in ;
}
2010-07-27 13:02:24 -06:00
static Bool QuartzReadSystemKeymap ( darwinKeyboardInfo * info ) {
2009-09-06 13:44:18 -06:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2006-11-26 11:13:41 -07:00
KeyboardLayoutRef key_layout ;
2009-09-06 13:44:18 -06:00
int is_uchr = 1 ;
# endif
2008-11-02 08:26:08 -07:00
const void * chr_data = NULL ;
2006-11-26 11:13:41 -07:00
int num_keycodes = NUM_KEYCODES ;
2009-09-06 13:44:18 -06:00
UInt32 keyboard_type = LMGetKbdType ( ) ;
int i , j ;
2006-11-26 11:13:41 -07:00
OSStatus err ;
KeySym * k ;
2009-09-06 13:44:18 -06:00
CFDataRef currentKeyLayoutDataRef = NULL ;
2006-11-26 11:13:41 -07:00
2009-09-06 13:44:18 -06:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
2008-11-02 08:26:08 -07:00
TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource ( ) ;
2009-09-06 13:44:18 -06:00
2008-11-02 08:26:08 -07:00
if ( currentKeyLayoutRef ) {
2009-09-06 13:44:18 -06:00
currentKeyLayoutDataRef = ( CFDataRef ) TISGetInputSourceProperty ( currentKeyLayoutRef , kTISPropertyUnicodeKeyLayoutData ) ;
if ( currentKeyLayoutDataRef )
chr_data = CFDataGetBytePtr ( currentKeyLayoutDataRef ) ;
2008-11-02 08:26:08 -07:00
}
2009-09-06 13:44:18 -06:00
# endif
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2008-11-02 08:26:08 -07:00
if ( chr_data = = NULL ) {
2009-09-06 13:44:18 -06:00
# 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
2008-11-02 08:26:08 -07:00
}
2009-09-06 13:44:18 -06:00
2008-11-02 08:26:08 -07:00
if ( chr_data = = NULL ) {
2009-09-06 13:44:18 -06:00
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
2008-11-02 08:26:08 -07:00
}
2009-09-06 13:44:18 -06:00
# endif
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
if ( currentKeyLayoutRef )
CFRelease ( currentKeyLayoutRef ) ;
# endif
2008-11-02 08:26:08 -07:00
if ( chr_data = = NULL ) {
ErrorF ( " Couldn't get uchr or kchr resource \n " ) ;
return FALSE ;
2006-11-26 11:13:41 -07:00
}
2009-09-06 13:44:18 -06:00
2006-11-26 11:13:41 -07:00
/* 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.) */
2009-09-06 13:44:18 -06:00
/* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
must be used instead . */
2006-11-26 11:13:41 -07:00
2008-11-02 08:26:08 -07:00
for ( i = 0 ; i < num_keycodes ; i + + ) {
2006-11-26 11:13:41 -07:00
static const int mods [ 4 ] = { 0 , MOD_SHIFT , MOD_OPTION ,
MOD_OPTION | MOD_SHIFT } ;
k = info - > keyMap + i * GLYPHS_PER_KEY ;
2008-11-02 08:26:08 -07:00
for ( j = 0 ; j < 4 ; j + + ) {
2009-09-06 13:44:18 -06:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2008-11-02 08:26:08 -07:00
if ( is_uchr ) {
2009-09-06 13:44:18 -06:00
# endif
2006-11-26 11:13:41 -07:00
UniChar s [ 8 ] ;
UniCharCount len ;
2008-11-02 08:26:08 -07:00
UInt32 dead_key_state = 0 , extra_dead = 0 ;
2006-11-26 11:13:41 -07:00
err = UCKeyTranslate ( chr_data , i , kUCKeyActionDown ,
mods [ j ] > > 8 , keyboard_type , 0 ,
& dead_key_state , 8 , & len , s ) ;
2008-11-02 08:26:08 -07:00
if ( err ! = noErr ) continue ;
2006-11-26 11:13:41 -07:00
2008-11-02 08:26:08 -07:00
if ( len = = 0 & & dead_key_state ! = 0 ) {
2006-11-26 11:13:41 -07:00
/* 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 ) ;
2008-11-02 08:26:08 -07:00
if ( err ! = noErr ) continue ;
2006-11-26 11:13:41 -07:00
}
2010-07-27 13:02:24 -06:00
/* Not sure why 0x0010 is there.
* 0x0000 - < rdar : //problem/7793566> 'Unicode Hex Input' ...
*/
if ( len > 0 & & s [ 0 ] ! = 0x0010 & & s [ 0 ] ! = 0x0000 ) {
2006-11-26 11:13:41 -07:00
k [ j ] = ucs2keysym ( s [ 0 ] ) ;
2008-11-02 08:26:08 -07:00
if ( dead_key_state ! = 0 ) k [ j ] = make_dead_key ( k [ j ] ) ;
2006-11-26 11:13:41 -07:00
}
2009-09-06 13:44:18 -06:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2008-11-02 08:26:08 -07:00
} else { // kchr
UInt32 c , state = 0 , state2 = 0 ;
2006-11-26 11:13:41 -07:00
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. */
2008-11-02 08:26:08 -07:00
if ( c ! = 0 & & c ! = 0x0010 ) {
2006-11-26 11:13:41 -07:00
k [ j ] = ucs2keysym ( macroman2ucs ( c & 255 ) ) ;
2008-11-02 08:26:08 -07:00
if ( state ! = 0 ) k [ j ] = make_dead_key ( k [ j ] ) ;
2006-11-26 11:13:41 -07:00
}
}
2009-09-06 13:44:18 -06:00
# endif
2006-11-26 11:13:41 -07:00
}
2010-07-27 13:02:24 -06:00
2008-11-02 08:26:08 -07:00
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 ;
2010-07-27 13:02:24 -06:00
if ( k [ 3 ] = = k [ 0 ] & & k [ 2 ] = = k [ 1 ] & & k [ 2 ] = = NoSymbol ) k [ 3 ] = NoSymbol ;
2006-11-26 11:13:41 -07:00
}
2010-07-27 13:02:24 -06:00
# if HACK_MISSING
2006-11-26 11:13:41 -07:00
/* Fix up some things that are normally missing.. */
2010-07-27 13:02:24 -06:00
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 ;
2006-11-26 11:13:41 -07:00
}
2010-07-27 13:02:24 -06:00
# endif
# if HACK_KEYPAD
2006-11-26 11:13:41 -07:00
/* And some more things. We find the right symbols for the numeric
2010-07-27 13:02:24 -06:00
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 ;
2006-11-26 11:13:41 -07:00
}
2010-07-27 13:02:24 -06:00
# 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 ) ;
2009-09-06 13:44:18 -06:00
2006-11-26 11:13:41 -07:00
return TRUE ;
}
2010-07-27 13:02:24 -06:00
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 ;
}