2003-11-25 20:29:01 +01:00
/*
2008-04-17 20:03:31 +02: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 .
2003-11-25 20:29:01 +01:00
*/
2008-04-19 05:06:17 +02:00
# include "sanitizedCarbon.h"
2007-11-29 11:19:22 +01:00
# ifdef HAVE_DIX_CONFIG_H
2007-09-19 14:58:22 +02:00
# include <dix-config.h>
2007-11-29 11:19:22 +01:00
# endif
2003-11-25 20:29:01 +01:00
2008-04-17 20:03:31 +02:00
# define HACK_MISSING 1
# define HACK_KEYPAD 1
# include <stdio.h>
# include <stdlib.h>
# include <errno.h>
# include <sys/stat.h>
2008-11-16 04:45:49 +01:00
# include <available.h>
2008-04-17 20:03:31 +02:00
2007-09-19 14:58:22 +02:00
# include "quartzCommon.h"
2008-04-17 20:03:31 +02:00
# include "darwin.h"
2003-11-25 20:29:01 +01:00
2007-12-06 04:43:49 +01:00
# include "quartzKeyboard.h"
2008-04-17 20:03:31 +02:00
# include "quartzAudio.h"
2008-09-25 07:51:03 +02:00
# include "threadSafety.h"
2008-04-17 20:03:31 +02:00
# ifdef NDEBUG
# undef NDEBUG
# include <assert.h>
# define NDEBUG 1
# else
# include <assert.h>
# endif
2008-09-25 07:51:03 +02:00
# include <pthread.h>
2008-04-17 20:03:31 +02:00
2008-04-18 02:04:08 +02:00
# include "xkbsrv.h"
# include "exevents.h"
2007-02-17 09:22:39 +01:00
# include "X11/keysym.h"
2003-11-25 20:29:01 +01:00
# include "keysym2ucs.h"
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 } ,
2007-12-11 05:47:48 +01:00
{ 58 , XK_Alt_L } ,
2003-11-25 20:29:01 +01:00
{ 59 , XK_Control_L } ,
2004-04-23 21:54:30 +02:00
2003-11-25 20:29:01 +01:00
{ 60 , XK_Shift_R } ,
2007-12-11 05:47:48 +01:00
{ 61 , XK_Alt_R } ,
2003-11-25 20:29:01 +01:00
{ 62 , XK_Control_R } ,
2004-04-23 21:54:30 +02:00
{ 63 , XK_Meta_R } ,
2003-11-25 20:29:01 +01:00
{ 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_acute , XK_dead_acute } ,
{ 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 */
} ;
2008-04-17 20:03:31 +02:00
darwinKeyboardInfo keyInfo ;
2008-09-25 07:51:03 +02:00
pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER ;
2008-04-17 20:03:31 +02:00
2008-10-20 21:23:04 +02:00
static void DarwinChangeKeyboardControl ( DeviceIntPtr device , KeybdCtrl * ctrl ) {
// FIXME: to be implemented
2008-04-17 20:03:31 +02:00
// 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 :
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 ;
}
}
}
/*
* DarwinLoadKeyboardMapping
* Load the keyboard map from a file or system and convert
* it to an equivalent X keyboard map and modifier map .
*/
static void DarwinLoadKeyboardMapping ( KeySymsRec * keySyms ) {
2008-09-25 07:51:03 +02:00
pthread_mutex_lock ( & keyInfo_mutex ) ;
2008-04-17 20:03:31 +02:00
DarwinBuildModifierMaps ( & keyInfo ) ;
keySyms - > map = keyInfo . keyMap ;
keySyms - > mapWidth = GLYPHS_PER_KEY ;
keySyms - > minKeyCode = MIN_KEYCODE ;
keySyms - > maxKeyCode = MAX_KEYCODE ;
2008-09-25 07:51:03 +02:00
pthread_mutex_unlock ( & keyInfo_mutex ) ;
2008-04-17 20:03:31 +02:00
}
2008-10-20 21:23:04 +02:00
/*
* DarwinKeyboardSetDeviceKeyMap
* Load a keymap into the keyboard device
*/
static void DarwinKeyboardSetDeviceKeyMap ( KeySymsRec * keySyms ) {
DeviceIntPtr pDev ;
/* From ProcSetModifierMapping */
2008-11-22 22:57:45 +01:00
SendMappingNotify ( darwinKeyboard , MappingModifier , 0 , 0 , serverClient ) ;
2008-10-20 21:23:04 +02:00
for ( pDev = inputInfo . devices ; pDev ; pDev = pDev - > next )
if ( pDev - > key & & pDev - > coreEvents )
SendDeviceMappingNotify ( serverClient , MappingModifier , 0 , 0 , pDev ) ;
/* From ProcChangeKeyboardMapping */
for ( pDev = inputInfo . devices ; pDev ; pDev = pDev - > next )
if ( ( pDev - > coreEvents | | pDev = = inputInfo . keyboard ) & & pDev - > key )
assert ( SetKeySymsMap ( & pDev - > key - > curKeySyms , keySyms ) ) ;
2008-11-22 22:57:45 +01:00
SendMappingNotify ( darwinKeyboard , MappingKeyboard , keySyms - > minKeyCode ,
2008-10-20 21:23:04 +02:00
keySyms - > maxKeyCode - keySyms - > minKeyCode + 1 , serverClient ) ;
for ( pDev = inputInfo . devices ; pDev ; pDev = pDev - > next )
if ( pDev - > key & & pDev - > coreEvents )
SendDeviceMappingNotify ( serverClient , MappingKeyboard , keySyms - > minKeyCode ,
keySyms - > maxKeyCode - keySyms - > minKeyCode + 1 , pDev ) ;
}
2008-04-17 20:03:31 +02:00
/*
* 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 ) {
2008-10-20 21:23:04 +02:00
KeySymsRec keySyms ;
XkbComponentNamesRec names ;
2008-04-17 20:03:31 +02:00
// Open a shared connection to the HID System.
// Note that the Event Status Driver is really just a wrapper
// for a kIOHIDParamConnectType connection.
2008-10-20 21:23:04 +02:00
assert ( darwinParamConnect = NXOpenEventStatus ( ) ) ;
2008-04-17 20:03:31 +02:00
DarwinLoadKeyboardMapping ( & keySyms ) ;
2008-10-20 21:23:04 +02:00
2008-04-18 02:04:08 +02:00
bzero ( & names , sizeof ( names ) ) ;
2008-10-20 21:23:04 +02:00
2008-07-05 04:23:21 +02:00
/* We need to really have rules... or something... */
2008-10-20 21:23:04 +02:00
//XkbSetRulesDflts("base", "pc105", "us", NULL, NULL);
2008-09-25 07:51:03 +02:00
pthread_mutex_lock ( & keyInfo_mutex ) ;
2008-04-18 02:04:08 +02:00
assert ( XkbInitKeyboardDeviceStruct ( pDev , & names , & keySyms , keyInfo . modMap ,
2008-10-20 21:23:04 +02:00
QuartzBell , DarwinChangeKeyboardControl ) ) ;
2008-09-25 07:51:03 +02:00
pthread_mutex_unlock ( & keyInfo_mutex ) ;
2008-10-20 21:23:04 +02:00
2008-11-22 22:57:45 +01:00
// TODO: What do we do now in 1.6?
//SwitchCoreKeyboard(pDev);
2008-04-17 20:03:31 +02:00
2008-10-20 21:23:04 +02:00
DarwinKeyboardSetDeviceKeyMap ( & keySyms ) ;
}
2008-04-17 20:03:31 +02:00
2008-04-18 02:04:08 +02:00
void DarwinKeyboardReloadHandler ( int screenNum , xEventPtr xe , DeviceIntPtr pDev , int nevents ) {
KeySymsRec keySyms ;
2008-05-19 08:51:06 +02:00
2008-10-20 21:23:04 +02:00
DEBUG_LOG ( " DarwinKeyboardReloadHandler \n " ) ;
2008-04-17 20:03:31 +02:00
2008-10-20 21:23:04 +02:00
DarwinLoadKeyboardMapping ( & keySyms ) ;
DarwinKeyboardSetDeviceKeyMap ( & keySyms ) ;
2008-04-17 20:03:31 +02: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.
//-----------------------------------------------------------------------------
/*
* 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 ) {
2008-09-25 07:51:03 +02:00
int retval ;
pthread_mutex_lock ( & keyInfo_mutex ) ;
retval = keyInfo . modifierKeycodes [ key ] [ side ] ;
pthread_mutex_unlock ( & keyInfo_mutex ) ;
return retval ;
2008-04-17 20:03:31 +02:00
}
/*
* 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 ;
2008-09-25 07:51:03 +02:00
pthread_mutex_lock ( & keyInfo_mutex ) ;
2008-04-17 20:03:31 +02:00
keycode + = MIN_KEYCODE ;
// search modifierKeycodes for this keycode+side
for ( key = 0 ; key < NX_NUMMODIFIERS ; key + + ) {
for ( side = 0 ; side < = 1 ; side + + ) {
if ( keyInfo . modifierKeycodes [ key ] [ side ] = = keycode ) break ;
}
}
2008-09-25 07:51:03 +02:00
if ( key = = NX_NUMMODIFIERS ) {
pthread_mutex_unlock ( & keyInfo_mutex ) ;
return - 1 ;
}
2008-04-17 20:03:31 +02:00
if ( outSide ) * outSide = side ;
2008-09-25 07:51:03 +02:00
pthread_mutex_unlock ( & keyInfo_mutex ) ;
2008-04-17 20:03:31 +02:00
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 ;
2008-08-20 18:56:06 +02:00
# 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
2008-04-17 20:03:31 +02:00
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 ;
}
/*
2008-08-20 18:56:06 +02:00
* DarwinModifierStringToNXMask
* Returns 0 if string is not a known modifier .
2008-04-17 20:03:31 +02:00
*/
2008-08-20 18:21:44 +02:00
int DarwinModifierStringToNXMask ( const char * str , int separatelr ) {
2008-08-20 18:56:06 +02:00
# ifdef NX_DEVICELSHIFTKEYMASK
2008-08-20 18:21:44 +02:00
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
}
2008-08-20 18:56:06 +02:00
# endif
2008-08-20 18:21:44 +02:00
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 ;
2008-04-17 20:03:31 +02:00
}
/*
* 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 ;
}
2007-12-05 08:18:37 +01:00
static inline UniChar macroman2ucs ( unsigned char c ) {
2003-11-25 20:29:01 +01: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 ,
} ;
2007-11-06 05:25:10 +01:00
if ( c < 128 ) return c ;
else return table [ c - 128 ] ;
2003-11-25 20:29:01 +01:00
}
2007-12-05 08:18:37 +01:00
static KeySym make_dead_key ( KeySym in ) {
2003-11-25 20:29:01 +01:00
int i ;
for ( i = 0 ; i < sizeof ( dead_keys ) / sizeof ( dead_keys [ 0 ] ) ; i + + )
2007-11-06 05:25:10 +01:00
if ( dead_keys [ i ] . normal = = in ) return dead_keys [ i ] . dead ;
2003-11-25 20:29:01 +01:00
return in ;
}
2007-12-11 05:47:48 +01:00
Bool QuartzReadSystemKeymap ( darwinKeyboardInfo * info ) {
2008-11-16 04:45:49 +01:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2008-08-08 09:19:41 +02:00
KeyboardLayoutRef key_layout ;
2008-11-16 04:45:49 +01:00
int is_uchr = 1 ;
2008-08-08 09:19:41 +02:00
# endif
2007-09-21 03:03:51 +02:00
const void * chr_data = NULL ;
2003-11-25 20:29:01 +01:00
int num_keycodes = NUM_KEYCODES ;
UInt32 keyboard_type = 0 ;
2008-11-01 02:58:57 +01:00
int i , j ;
2003-11-25 20:29:01 +01:00
OSStatus err ;
KeySym * k ;
2008-08-30 23:19:47 +02:00
CFDataRef currentKeyLayoutDataRef = NULL ;
2003-11-25 20:29:01 +01:00
2008-11-16 04:45:49 +01:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
2007-09-21 03:03:51 +02:00
TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource ( ) ;
2008-08-08 09:19:41 +02:00
keyboard_type = LMGetKbdType ( ) ;
2007-11-06 05:01:34 +01:00
if ( currentKeyLayoutRef ) {
2008-08-30 23:19:47 +02:00
currentKeyLayoutDataRef = ( CFDataRef ) TISGetInputSourceProperty ( currentKeyLayoutRef , kTISPropertyUnicodeKeyLayoutData ) ;
2008-08-08 09:19:41 +02:00
if ( currentKeyLayoutDataRef )
chr_data = CFDataGetBytePtr ( currentKeyLayoutDataRef ) ;
}
2008-11-16 04:45:49 +01:00
# endif
2008-08-08 09:19:41 +02:00
2008-11-16 04:45:49 +01:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2008-08-08 09:19:41 +02:00
if ( chr_data = = NULL ) {
2008-11-16 04:45:49 +01:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
2008-08-20 19:21:23 +02:00
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 " ) ;
2008-08-20 18:56:06 +02:00
ErrorF ( " X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p \n " ,
( unsigned ) keyboard_type , currentKeyLayoutRef , currentKeyLayoutDataRef , chr_data ) ;
2008-11-16 04:45:49 +01:00
# endif
2008-11-24 21:33:20 +01:00
2008-08-08 09:19:41 +02:00
KLGetCurrentKeyboardLayout ( & key_layout ) ;
KLGetKeyboardLayoutProperty ( key_layout , kKLuchrData , & chr_data ) ;
2008-11-24 21:33:20 +01:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
2008-08-08 09:19:41 +02:00
if ( chr_data ! = NULL ) {
ErrorF ( " X11.app: Fallback succeeded, but this is still a bug. Please report the above information. \n " ) ;
}
2008-11-24 21:33:20 +01:00
# endif
2007-11-06 05:01:34 +01:00
}
2008-07-05 04:23:21 +02:00
2008-08-08 09:19:41 +02:00
if ( chr_data = = NULL ) {
2008-11-24 21:33:20 +01:00
ErrorF ( " X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData. \n " ) ;
2008-08-20 19:21:23 +02:00
ErrorF ( " If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154 \n " ) ;
2008-08-08 09:19:41 +02:00
KLGetKeyboardLayoutProperty ( key_layout , kKLKCHRData , & chr_data ) ;
is_uchr = 0 ;
num_keycodes = 128 ;
2008-11-24 21:33:20 +01:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
2008-08-08 09:19:41 +02:00
if ( chr_data ! = NULL ) {
ErrorF ( " X11.app: Fallback succeeded, but this is still a bug. Please report the above information. \n " ) ;
}
2008-11-24 21:33:20 +01:00
# endif
2008-08-08 09:19:41 +02:00
}
# endif
2008-11-21 19:53:39 +01:00
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
if ( currentKeyLayoutRef )
CFRelease ( currentKeyLayoutRef ) ;
# endif
2007-11-06 05:01:34 +01:00
if ( chr_data = = NULL ) {
ErrorF ( " Couldn't get uchr or kchr resource \n " ) ;
return FALSE ;
}
2008-08-08 09:19:41 +02:00
2003-11-25 20:29:01 +01: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.) */
2008-11-01 02:58:57 +01:00
/* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
must be used instead . */
2003-11-25 20:29:01 +01:00
2007-11-06 05:25:10 +01:00
for ( i = 0 ; i < num_keycodes ; i + + ) {
2003-11-25 20:29:01 +01:00
static const int mods [ 4 ] = { 0 , MOD_SHIFT , MOD_OPTION ,
MOD_OPTION | MOD_SHIFT } ;
k = info - > keyMap + i * GLYPHS_PER_KEY ;
2007-11-06 05:25:10 +01:00
for ( j = 0 ; j < 4 ; j + + ) {
2008-11-16 04:45:49 +01:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2007-11-06 05:25:10 +01:00
if ( is_uchr ) {
2008-11-01 02:58:57 +01:00
# endif
2003-11-25 20:29:01 +01:00
UniChar s [ 8 ] ;
UniCharCount len ;
2007-11-06 05:25:10 +01:00
UInt32 dead_key_state = 0 , extra_dead = 0 ;
2003-11-25 20:29:01 +01:00
err = UCKeyTranslate ( chr_data , i , kUCKeyActionDown ,
mods [ j ] > > 8 , keyboard_type , 0 ,
& dead_key_state , 8 , & len , s ) ;
2007-11-06 05:25:10 +01:00
if ( err ! = noErr ) continue ;
2003-11-25 20:29:01 +01:00
2007-11-06 05:25:10 +01:00
if ( len = = 0 & & dead_key_state ! = 0 ) {
2003-11-25 20:29:01 +01: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 ) ;
2007-11-06 05:25:10 +01:00
if ( err ! = noErr ) continue ;
2003-11-25 20:29:01 +01:00
}
2007-11-06 05:25:10 +01:00
if ( len > 0 & & s [ 0 ] ! = 0x0010 ) {
2003-11-25 20:29:01 +01:00
k [ j ] = ucs2keysym ( s [ 0 ] ) ;
2007-11-06 05:25:10 +01:00
if ( dead_key_state ! = 0 ) k [ j ] = make_dead_key ( k [ j ] ) ;
2003-11-25 20:29:01 +01:00
}
2008-11-16 04:45:49 +01:00
# if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
2007-11-06 05:25:10 +01:00
} else { // kchr
UInt32 c , state = 0 , state2 = 0 ;
2003-11-25 20:29:01 +01: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. */
2007-11-06 05:25:10 +01:00
if ( c ! = 0 & & c ! = 0x0010 ) {
2003-11-25 20:29:01 +01:00
k [ j ] = ucs2keysym ( macroman2ucs ( c & 255 ) ) ;
2007-11-06 05:25:10 +01:00
if ( state ! = 0 ) k [ j ] = make_dead_key ( k [ j ] ) ;
2003-11-25 20:29:01 +01:00
}
}
2008-11-01 02:58:57 +01:00
# endif
2003-11-25 20:29:01 +01:00
}
2007-11-06 05:25:10 +01:00
if ( k [ 3 ] = = k [ 2 ] ) k [ 3 ] = NoSymbol ;
if ( k [ 2 ] = = k [ 1 ] ) k [ 2 ] = NoSymbol ;
if ( k [ 1 ] = = k [ 0 ] ) k [ 1 ] = NoSymbol ;
if ( k [ 0 ] = = k [ 2 ] & & k [ 1 ] = = k [ 3 ] ) k [ 2 ] = k [ 3 ] = NoSymbol ;
2003-11-25 20:29:01 +01:00
}
/* Fix up some things that are normally missing.. */
2007-11-06 05:25:10 +01:00
if ( HACK_MISSING ) {
for ( i = 0 ; i < sizeof ( known_keys ) / sizeof ( known_keys [ 0 ] ) ; i + + ) {
2003-11-25 20:29:01 +01:00
k = info - > keyMap + known_keys [ i ] . keycode * GLYPHS_PER_KEY ;
2007-11-06 05:25:10 +01:00
if ( k [ 0 ] = = NoSymbol & & k [ 1 ] = = NoSymbol
2003-11-25 20:29:01 +01:00
& & k [ 2 ] = = NoSymbol & & k [ 3 ] = = NoSymbol )
2007-11-06 05:25:10 +01:00
k [ 0 ] = known_keys [ i ] . keysym ;
2003-11-25 20:29:01 +01:00
}
}
/* And some more things. We find the right symbols for the numeric
keypad , but not the KP_ keysyms . So try to convert known keycodes . */
2007-11-06 05:25:10 +01:00
if ( HACK_KEYPAD ) {
2003-11-25 20:29:01 +01:00
for ( i = 0 ; i < sizeof ( known_numeric_keys )
2007-11-06 05:25:10 +01:00
/ sizeof ( known_numeric_keys [ 0 ] ) ; i + + ) {
2003-11-25 20:29:01 +01:00
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 ;
}
}
2008-11-21 19:53:39 +01:00
2003-11-25 20:29:01 +01:00
return TRUE ;
}