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 .
The code to parse the Darwin keymap is derived from dumpkeymap . c
by Eric Sunshine , which includes the following copyright :
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 this to get a diagnostic output to stderr which is helpful
// in determining how the X server is interpreting the Darwin keymap.
# define DUMP_DARWIN_KEYMAP
2008-05-19 08:51:06 +02:00
//#define XQUARTZ_USE_XKB
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>
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"
# ifdef NDEBUG
# undef NDEBUG
# include <assert.h>
# define NDEBUG 1
# else
# include <assert.h>
# endif
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"
2008-04-18 02:04:08 +02:00
void QuartzXkbUpdate ( DeviceIntPtr pDev ) ;
2003-11-25 20:29:01 +01:00
enum {
MOD_COMMAND = 256 ,
MOD_SHIFT = 512 ,
MOD_OPTION = 2048 ,
MOD_CONTROL = 4096 ,
} ;
# define UKEYSYM(u) ((u) | 0x01000000)
2008-04-17 20:03:31 +02:00
# define AltMask Mod1Mask
# define MetaMask Mod2Mask
# define FunctionMask Mod3Mask
# define UK(a) NoSymbol // unknown symbol
static KeySym const next_to_x [ 256 ] = {
NoSymbol , NoSymbol , NoSymbol , XK_KP_Enter ,
NoSymbol , NoSymbol , NoSymbol , NoSymbol ,
XK_BackSpace , XK_Tab , XK_Linefeed , NoSymbol ,
NoSymbol , XK_Return , NoSymbol , NoSymbol ,
NoSymbol , NoSymbol , NoSymbol , NoSymbol ,
NoSymbol , NoSymbol , NoSymbol , NoSymbol ,
NoSymbol , NoSymbol , NoSymbol , XK_Escape ,
NoSymbol , NoSymbol , NoSymbol , NoSymbol ,
XK_space , XK_exclam , XK_quotedbl , XK_numbersign ,
XK_dollar , XK_percent , XK_ampersand , XK_apostrophe ,
XK_parenleft , XK_parenright , XK_asterisk , XK_plus ,
XK_comma , XK_minus , XK_period , XK_slash ,
XK_0 , XK_1 , XK_2 , XK_3 ,
XK_4 , XK_5 , XK_6 , XK_7 ,
XK_8 , XK_9 , XK_colon , XK_semicolon ,
XK_less , XK_equal , XK_greater , XK_question ,
XK_at , XK_A , XK_B , XK_C ,
XK_D , XK_E , XK_F , XK_G ,
XK_H , XK_I , XK_J , XK_K ,
XK_L , XK_M , XK_N , XK_O ,
XK_P , XK_Q , XK_R , XK_S ,
XK_T , XK_U , XK_V , XK_W ,
XK_X , XK_Y , XK_Z , XK_bracketleft ,
XK_backslash , XK_bracketright , XK_asciicircum , XK_underscore ,
XK_grave , XK_a , XK_b , XK_c ,
XK_d , XK_e , XK_f , XK_g ,
XK_h , XK_i , XK_j , XK_k ,
XK_l , XK_m , XK_n , XK_o ,
XK_p , XK_q , XK_r , XK_s ,
XK_t , XK_u , XK_v , XK_w ,
XK_x , XK_y , XK_z , XK_braceleft ,
XK_bar , XK_braceright , XK_asciitilde , XK_BackSpace ,
// 128
NoSymbol , XK_Agrave , XK_Aacute , XK_Acircumflex ,
XK_Atilde , XK_Adiaeresis , XK_Aring , XK_Ccedilla ,
XK_Egrave , XK_Eacute , XK_Ecircumflex , XK_Ediaeresis ,
XK_Igrave , XK_Iacute , XK_Icircumflex , XK_Idiaeresis ,
// 144
XK_ETH , XK_Ntilde , XK_Ograve , XK_Oacute ,
XK_Ocircumflex , XK_Otilde , XK_Odiaeresis , XK_Ugrave ,
XK_Uacute , XK_Ucircumflex , XK_Udiaeresis , XK_Yacute ,
XK_THORN , XK_mu , XK_multiply , XK_division ,
// 160
XK_copyright , XK_exclamdown , XK_cent , XK_sterling ,
UK ( fraction ) , XK_yen , UK ( fhook ) , XK_section ,
XK_currency , XK_rightsinglequotemark ,
XK_leftdoublequotemark ,
XK_guillemotleft ,
XK_leftanglebracket ,
XK_rightanglebracket ,
UK ( filigature ) , UK ( flligature ) ,
// 176
XK_registered , XK_endash , XK_dagger , XK_doubledagger ,
XK_periodcentered , XK_brokenbar , XK_paragraph , UK ( bullet ) ,
XK_singlelowquotemark ,
XK_doublelowquotemark ,
XK_rightdoublequotemark ,
XK_guillemotright ,
XK_ellipsis , UK ( permille ) , XK_notsign , XK_questiondown ,
// 192
XK_onesuperior , XK_dead_grave , XK_dead_acute , XK_dead_circumflex ,
XK_dead_tilde , XK_dead_macron , XK_dead_breve , XK_dead_abovedot ,
XK_dead_diaeresis ,
XK_twosuperior , XK_dead_abovering ,
XK_dead_cedilla ,
XK_threesuperior ,
XK_dead_doubleacute ,
XK_dead_ogonek , XK_dead_caron ,
// 208
XK_emdash , XK_plusminus , XK_onequarter , XK_onehalf ,
XK_threequarters ,
XK_agrave , XK_aacute , XK_acircumflex ,
XK_atilde , XK_adiaeresis , XK_aring , XK_ccedilla ,
XK_egrave , XK_eacute , XK_ecircumflex , XK_ediaeresis ,
// 224
XK_igrave , XK_AE , XK_iacute , XK_ordfeminine ,
XK_icircumflex , XK_idiaeresis , XK_eth , XK_ntilde ,
XK_Lstroke , XK_Ooblique , XK_OE , XK_masculine ,
XK_ograve , XK_oacute , XK_ocircumflex , XK_otilde ,
// 240
XK_odiaeresis , XK_ae , XK_ugrave , XK_uacute ,
XK_ucircumflex , XK_idotless , XK_udiaeresis , XK_ygrave ,
XK_lstroke , XK_ooblique , XK_oe , XK_ssharp ,
XK_thorn , XK_ydiaeresis , NoSymbol , NoSymbol ,
} ;
# define MIN_SYMBOL 0xAC
static KeySym const symbol_to_x [ ] = {
XK_Left , XK_Up , XK_Right , XK_Down
} ;
static int const NUM_SYMBOL = sizeof ( symbol_to_x ) / sizeof ( symbol_to_x [ 0 ] ) ;
# define MIN_FUNCKEY 0x20
static KeySym const funckey_to_x [ ] = {
XK_F1 , XK_F2 , XK_F3 , XK_F4 ,
XK_F5 , XK_F6 , XK_F7 , XK_F8 ,
XK_F9 , XK_F10 , XK_F11 , XK_F12 ,
XK_Insert , XK_Delete , XK_Home , XK_End ,
XK_Page_Up , XK_Page_Down , XK_F13 , XK_F14 ,
XK_F15
} ;
static int const NUM_FUNCKEY = sizeof ( funckey_to_x ) / sizeof ( funckey_to_x [ 0 ] ) ;
typedef struct {
KeySym normalSym ;
KeySym keypadSym ;
} darwinKeyPad_t ;
static darwinKeyPad_t const normal_to_keypad [ ] = {
{ XK_0 , XK_KP_0 } ,
{ XK_1 , XK_KP_1 } ,
{ XK_2 , XK_KP_2 } ,
{ XK_3 , XK_KP_3 } ,
{ XK_4 , XK_KP_4 } ,
{ XK_5 , XK_KP_5 } ,
{ XK_6 , XK_KP_6 } ,
{ XK_7 , XK_KP_7 } ,
{ XK_8 , XK_KP_8 } ,
{ XK_9 , XK_KP_9 } ,
{ XK_equal , XK_KP_Equal } ,
{ XK_asterisk , XK_KP_Multiply } ,
{ XK_plus , XK_KP_Add } ,
{ XK_comma , XK_KP_Separator } ,
{ XK_minus , XK_KP_Subtract } ,
{ XK_period , XK_KP_Decimal } ,
{ XK_slash , XK_KP_Divide }
} ;
static int const NUM_KEYPAD = sizeof ( normal_to_keypad ) / sizeof ( normal_to_keypad [ 0 ] ) ;
2003-11-25 20:29:01 +01: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 } ,
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 ;
static FILE * fref = NULL ;
static char * inBuffer = NULL ;
static void DarwinChangeKeyboardControl ( DeviceIntPtr device , KeybdCtrl * ctrl )
{
// FIXME: to be implemented
// keyclick, bell volume / pitch, autorepead, LED's
}
//-----------------------------------------------------------------------------
// Data Stream Object
// Can be configured to treat embedded "numbers" as being composed of
// either 1, 2, or 4 bytes, apiece.
//-----------------------------------------------------------------------------
typedef struct _DataStream {
unsigned char const * data ;
unsigned char const * data_end ;
short number_size ; // Size in bytes of a "number" in the stream.
} DataStream ;
static DataStream * new_data_stream ( unsigned char const * data , int size ) {
DataStream * s = ( DataStream * ) xalloc ( sizeof ( DataStream ) ) ;
if ( s ) {
s - > data = data ;
s - > data_end = data + size ;
s - > number_size = 1 ; // Default to byte-sized numbers.
}
return s ;
}
static void destroy_data_stream ( DataStream * s ) {
xfree ( s ) ;
}
static unsigned char get_byte ( DataStream * s ) {
assert ( s - > data + 1 < = s - > data_end ) ;
return * s - > data + + ;
}
static short get_word ( DataStream * s ) {
short hi , lo ;
assert ( s - > data + 2 < = s - > data_end ) ;
hi = * s - > data + + ;
lo = * s - > data + + ;
return ( ( hi < < 8 ) | lo ) ;
}
static int get_dword ( DataStream * s ) {
int b1 , b2 , b3 , b4 ;
assert ( s - > data + 4 < = s - > data_end ) ;
b4 = * s - > data + + ;
b3 = * s - > data + + ;
b2 = * s - > data + + ;
b1 = * s - > data + + ;
return ( ( b4 < < 24 ) | ( b3 < < 16 ) | ( b2 < < 8 ) | b1 ) ;
}
static int get_number ( DataStream * s ) {
switch ( s - > number_size ) {
case 4 : return get_dword ( s ) ;
case 2 : return get_word ( s ) ;
default : return get_byte ( s ) ;
}
}
//-----------------------------------------------------------------------------
// Utility functions to help parse Darwin keymap
//-----------------------------------------------------------------------------
/*
* bits_set
* Calculate number of bits set in the modifier mask .
*/
static short bits_set ( short mask ) {
short n = 0 ;
for ( ; mask ! = 0 ; mask > > = 1 )
if ( ( mask & 0x01 ) ! = 0 )
n + + ;
return n ;
}
/*
* parse_next_char_code
* Read the next character code from the Darwin keymapping
* and write it to the X keymap .
*/
static void parse_next_char_code ( DataStream * s , KeySym * k ) {
const short charSet = get_number ( s ) ;
const short charCode = get_number ( s ) ;
if ( charSet = = 0 ) { // ascii character
if ( charCode > = 0 & & charCode < 256 )
* k = next_to_x [ charCode ] ;
} else if ( charSet = = 0x01 ) { // symbol character
if ( charCode > = MIN_SYMBOL & &
charCode < = MIN_SYMBOL + NUM_SYMBOL )
* k = symbol_to_x [ charCode - MIN_SYMBOL ] ;
} else if ( charSet = = 0xFE ) { // function key
if ( charCode > = MIN_FUNCKEY & &
charCode < = MIN_FUNCKEY + NUM_FUNCKEY )
* k = funckey_to_x [ charCode - MIN_FUNCKEY ] ;
}
}
/*
* DarwinReadKeymapFile
* Read the appropriate keymapping from a keymapping file .
*/
static Bool DarwinReadKeymapFile ( NXKeyMapping * keyMap ) {
struct stat st ;
NXEventSystemDevice info [ 20 ] ;
int interface = 0 , handler_id = 0 ;
int map_interface , map_handler_id , map_size = 0 ;
unsigned int i , size ;
int * bufferEnd ;
union km_tag {
int * intP ;
char * charP ;
} km ;
fref = fopen ( darwinKeymapFile , " rb " ) ;
if ( fref = = NULL ) {
2008-04-17 20:06:54 +02:00
ErrorF ( " Unable to open keymapping file '%s': %s. \n " ,
darwinKeymapFile , strerror ( errno ) ) ;
2008-04-17 20:03:31 +02:00
return FALSE ;
}
if ( fstat ( fileno ( fref ) , & st ) = = - 1 ) {
2008-04-17 20:06:54 +02:00
ErrorF ( " Could not stat keymapping file '%s': %s. \n " ,
darwinKeymapFile , strerror ( errno ) ) ;
2008-04-17 20:03:31 +02:00
return FALSE ;
}
// check to make sure we don't crash later
if ( st . st_size < = 16 * sizeof ( int ) ) {
ErrorF ( " Keymapping file '%s' is invalid (too small). \n " ,
darwinKeymapFile ) ;
return FALSE ;
}
inBuffer = ( char * ) xalloc ( st . st_size ) ;
bufferEnd = ( int * ) ( inBuffer + st . st_size ) ;
if ( fread ( inBuffer , st . st_size , 1 , fref ) ! = 1 ) {
2008-04-17 20:06:54 +02:00
ErrorF ( " Could not read %qd bytes from keymapping file '%s': %s. \n " ,
st . st_size , darwinKeymapFile , strerror ( errno ) ) ;
2008-04-17 20:03:31 +02:00
return FALSE ;
}
if ( strncmp ( inBuffer , " KYM1 " , 4 ) = = 0 ) {
// Magic number OK.
} else if ( strncmp ( inBuffer , " KYMP " , 4 ) = = 0 ) {
ErrorF ( " Keymapping file '%s' is intended for use with the original NeXT keyboards and cannot be used by XDarwin. \n " , darwinKeymapFile ) ;
return FALSE ;
} else {
ErrorF ( " Keymapping file '%s' has a bad magic number and cannot be used by XDarwin. \n " , darwinKeymapFile ) ;
return FALSE ;
}
// find the keyboard interface and handler id
size = sizeof ( info ) / sizeof ( int ) ;
if ( ! NXEventSystemInfo ( darwinParamConnect , NX_EVS_DEVICE_INFO ,
( NXEventSystemInfoType ) info , & size ) ) {
ErrorF ( " Error reading event status driver info. \n " ) ;
return FALSE ;
}
size = size * sizeof ( int ) / sizeof ( info [ 0 ] ) ;
for ( i = 0 ; i < size ; i + + ) {
if ( info [ i ] . dev_type = = NX_EVS_DEVICE_TYPE_KEYBOARD ) {
Bool hasInterface = FALSE ;
Bool hasMatch = FALSE ;
interface = info [ i ] . interface ;
handler_id = info [ i ] . id ;
// Find an appropriate keymapping:
// The first time we try to match both interface and handler_id.
// If we can't match both, we take the first match for interface.
do {
km . charP = inBuffer ;
km . intP + + ;
while ( km . intP + 3 < bufferEnd ) {
map_interface = NXSwapBigIntToHost ( * ( km . intP + + ) ) ;
map_handler_id = NXSwapBigIntToHost ( * ( km . intP + + ) ) ;
map_size = NXSwapBigIntToHost ( * ( km . intP + + ) ) ;
if ( map_interface = = interface ) {
if ( map_handler_id = = handler_id | | hasInterface ) {
hasMatch = TRUE ;
break ;
} else {
hasInterface = TRUE ;
}
}
km . charP + = map_size ;
}
} while ( hasInterface & & ! hasMatch ) ;
if ( hasMatch ) {
// fill in NXKeyMapping structure
keyMap - > size = map_size ;
keyMap - > mapping = ( char * ) xalloc ( map_size ) ;
memcpy ( keyMap - > mapping , km . charP , map_size ) ;
return TRUE ;
}
} // if dev_id == keyboard device
} // foreach info struct
// The keymapping file didn't match any of the info structs
// returned by NXEventSystemInfo.
ErrorF ( " Keymapping file '%s' did not contain appropriate keyboard interface. \n " , darwinKeymapFile ) ;
return FALSE ;
}
/*
* DarwinParseNXKeyMapping
*/
static Bool DarwinParseNXKeyMapping ( darwinKeyboardInfo * info ) {
KeySym * k ;
int i ;
short numMods , numKeys , numPadKeys = 0 ;
Bool haveKeymap = FALSE ;
NXKeyMapping keyMap ;
DataStream * keyMapStream ;
unsigned char const * numPadStart = 0 ;
if ( darwinKeymapFile ) {
haveKeymap = DarwinReadKeymapFile ( & keyMap ) ;
if ( fref )
fclose ( fref ) ;
if ( inBuffer )
xfree ( inBuffer ) ;
if ( ! haveKeymap ) {
ErrorF ( " Reverting to kernel keymapping. \n " ) ;
}
}
if ( ! haveKeymap ) {
// get the Darwin keyboard map
keyMap . size = NXKeyMappingLength ( darwinParamConnect ) ;
keyMap . mapping = ( char * ) xalloc ( keyMap . size ) ;
if ( ! NXGetKeyMapping ( darwinParamConnect , & keyMap ) ) {
return FALSE ;
}
}
keyMapStream = new_data_stream ( ( unsigned char const * ) keyMap . mapping ,
keyMap . size ) ;
// check the type of map
if ( get_word ( keyMapStream ) ) {
keyMapStream - > number_size = 2 ;
ErrorF ( " Current 16-bit keymapping may not be interpreted correctly. \n " ) ;
}
// Insert X modifier KeySyms into the keyboard map.
numMods = get_number ( keyMapStream ) ;
while ( numMods - - > 0 ) {
int left = 1 ; // first keycode is left
short const charCode = get_number ( keyMapStream ) ;
short numKeyCodes = get_number ( keyMapStream ) ;
// This is just a marker, not a real modifier.
// Store numeric keypad keys for later.
if ( charCode = = NX_MODIFIERKEY_NUMERICPAD ) {
numPadStart = keyMapStream - > data ;
numPadKeys = numKeyCodes ;
}
while ( numKeyCodes - - > 0 ) {
const short keyCode = get_number ( keyMapStream ) ;
if ( charCode ! = NX_MODIFIERKEY_NUMERICPAD ) {
switch ( charCode ) {
case NX_MODIFIERKEY_ALPHALOCK :
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] = XK_Caps_Lock ;
break ;
case NX_MODIFIERKEY_SHIFT :
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] =
( left ? XK_Shift_L : XK_Shift_R ) ;
break ;
case NX_MODIFIERKEY_CONTROL :
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] =
( left ? XK_Control_L : XK_Control_R ) ;
break ;
case NX_MODIFIERKEY_ALTERNATE :
// info->keyMap[keyCode * GLYPHS_PER_KEY] = XK_Mode_switch;
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] =
( left ? XK_Alt_L : XK_Alt_R ) ;
break ;
case NX_MODIFIERKEY_COMMAND :
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] =
( left ? XK_Meta_L : XK_Meta_R ) ;
break ;
case NX_MODIFIERKEY_SECONDARYFN :
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] =
( left ? XK_Control_L : XK_Control_R ) ;
break ;
case NX_MODIFIERKEY_HELP :
// Help is not an X11 modifier; treat as normal key
info - > keyMap [ keyCode * GLYPHS_PER_KEY ] = XK_Help ;
break ;
}
}
left = 0 ;
}
}
// Convert the Darwin keyboard mapping to an X keyboard map.
// A key can have a different character code for each combination of
// modifiers. We currently ignore all modifier combinations except
// those with Shift, AlphaLock, and Alt.
numKeys = get_number ( keyMapStream ) ;
for ( i = 0 , k = info - > keyMap ; i < numKeys ; i + + , k + = GLYPHS_PER_KEY ) {
short const charGenMask = get_number ( keyMapStream ) ;
if ( charGenMask ! = 0xFF ) { // is key bound?
short numKeyCodes = 1 < < bits_set ( charGenMask ) ;
// Record unmodified case
parse_next_char_code ( keyMapStream , k ) ;
numKeyCodes - - ;
// If AlphaLock and Shift modifiers produce different codes,
// we record the Shift case since X handles AlphaLock.
if ( charGenMask & 0x01 ) { // AlphaLock
parse_next_char_code ( keyMapStream , k + 1 ) ;
numKeyCodes - - ;
}
if ( charGenMask & 0x02 ) { // Shift
parse_next_char_code ( keyMapStream , k + 1 ) ;
numKeyCodes - - ;
if ( charGenMask & 0x01 ) { // Shift-AlphaLock
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
}
}
// Skip the Control cases
if ( charGenMask & 0x04 ) { // Control
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
if ( charGenMask & 0x01 ) { // Control-AlphaLock
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
}
if ( charGenMask & 0x02 ) { // Control-Shift
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
if ( charGenMask & 0x01 ) { // Shift-Control-AlphaLock
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
}
}
}
// Process Alt cases
if ( charGenMask & 0x08 ) { // Alt
parse_next_char_code ( keyMapStream , k + 2 ) ;
numKeyCodes - - ;
if ( charGenMask & 0x01 ) { // Alt-AlphaLock
parse_next_char_code ( keyMapStream , k + 3 ) ;
numKeyCodes - - ;
}
if ( charGenMask & 0x02 ) { // Alt-Shift
parse_next_char_code ( keyMapStream , k + 3 ) ;
numKeyCodes - - ;
if ( charGenMask & 0x01 ) { // Alt-Shift-AlphaLock
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
numKeyCodes - - ;
}
}
}
while ( numKeyCodes - - > 0 ) {
get_number ( keyMapStream ) ; get_number ( keyMapStream ) ;
}
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 ;
}
}
// Now we have to go back through the list of keycodes that are on the
// numeric keypad and update the X keymap.
keyMapStream - > data = numPadStart ;
while ( numPadKeys - - > 0 ) {
const short keyCode = get_number ( keyMapStream ) ;
k = & info - > keyMap [ keyCode * GLYPHS_PER_KEY ] ;
for ( i = 0 ; i < NUM_KEYPAD ; i + + ) {
if ( * k = = normal_to_keypad [ i ] . normalSym ) {
k [ 0 ] = normal_to_keypad [ i ] . keypadSym ;
break ;
}
}
}
// free Darwin keyboard map
destroy_data_stream ( keyMapStream ) ;
xfree ( keyMap . mapping ) ;
return TRUE ;
}
/*
* 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 ) {
memset ( keyInfo . keyMap , 0 , sizeof ( keyInfo . keyMap ) ) ;
/* TODO: Clean this up
* QuartzReadSystemKeymap is in quartz / quartzKeyboard . c
* DarwinParseNXKeyMapping is here
*/
if ( ! DarwinParseNXKeyMapping ( & keyInfo ) ) {
DEBUG_LOG ( " DarwinParseNXKeyMapping returned 0... running QuartzReadSystemKeymap(). \n " ) ;
if ( ! QuartzReadSystemKeymap ( & keyInfo ) ) {
FatalError ( " Could not build a valid keymap. " ) ;
}
}
DarwinBuildModifierMaps ( & keyInfo ) ;
# ifdef DUMP_DARWIN_KEYMAP
int i ;
KeySym * k ;
DEBUG_LOG ( " Darwin -> X converted keyboard map \n " ) ;
for ( i = 0 , k = keyInfo . keyMap ; i < NX_NUMKEYCODES ;
i + + , k + = GLYPHS_PER_KEY )
{
int j ;
for ( j = 0 ; j < GLYPHS_PER_KEY ; j + + ) {
if ( k [ j ] = = NoSymbol ) {
DEBUG_LOG ( " 0x%02x: \t NoSym \n " , i ) ;
} else {
DEBUG_LOG ( " 0x%02x: \t 0x%lx \n " , i , k [ j ] ) ;
}
}
}
# endif
keySyms - > map = keyInfo . keyMap ;
keySyms - > mapWidth = GLYPHS_PER_KEY ;
keySyms - > minKeyCode = MIN_KEYCODE ;
keySyms - > maxKeyCode = MAX_KEYCODE ;
}
2008-04-18 02:04:08 +02:00
void QuartzXkbUpdate ( DeviceIntPtr pDev ) {
# ifdef XQUARTZ_USE_XKB
SendDeviceMappingNotify ( serverClient , MappingKeyboard ,
pDev - > key - > curKeySyms . minKeyCode ,
pDev - > key - > curKeySyms . maxKeyCode - pDev - > key - > curKeySyms . minKeyCode , pDev ) ;
SendDeviceMappingNotify ( serverClient , MappingModifier , 0 , 0 , pDev ) ;
SwitchCoreKeyboard ( pDev ) ;
# endif
}
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 ) {
KeySymsRec keySyms ;
// 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 ( ) ) ;
DarwinLoadKeyboardMapping ( & keySyms ) ;
/* Initialize the seed, so we don't reload the keymap unnecessarily
( and possibly overwrite xinitrc changes ) */
QuartzSystemKeymapSeed ( ) ;
2008-04-18 02:04:08 +02:00
# ifdef XQUARTZ_USE_XKB
XkbComponentNamesRec names ;
bzero ( & names , sizeof ( names ) ) ;
2008-07-05 04:23:21 +02:00
/* We need to really have rules... or something... */
2008-04-18 02:04:08 +02:00
XkbSetRulesDflts ( " base " , " pc105 " , " us " , NULL , NULL ) ;
assert ( XkbInitKeyboardDeviceStruct ( pDev , & names , & keySyms , keyInfo . modMap ,
QuartzBell , DarwinChangeKeyboardControl ) ) ;
assert ( SetKeySymsMap ( & pDev - > key - > curKeySyms , & keySyms ) ) ;
assert ( keyInfo . modMap ! = NULL ) ;
assert ( pDev - > key - > modifierMap ! = NULL ) ;
memcpy ( pDev - > key - > modifierMap , keyInfo . modMap , sizeof ( keyInfo . modMap ) ) ;
QuartzXkbUpdate ( pDev ) ;
# else
2008-04-17 20:03:31 +02:00
assert ( InitKeyboardDeviceStruct ( ( DevicePtr ) pDev , & keySyms ,
keyInfo . modMap , QuartzBell ,
DarwinChangeKeyboardControl ) ) ;
SwitchCoreKeyboard ( pDev ) ;
2008-04-18 02:04:08 +02:00
# endif
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 ) {
2008-05-19 08:51:06 +02:00
if ( pDev = = NULL ) pDev = darwinKeyboard ;
DEBUG_LOG ( " DarwinKeyboardReloadHandler(%p) \n " , pDev ) ;
2008-04-17 20:03:31 +02:00
2008-04-18 02:04:08 +02:00
# ifdef XQUARTZ_USE_XKB
2008-05-19 08:51:06 +02:00
QuartzXkbUpdate ( pDev ) ;
2008-04-18 02:04:08 +02:00
# else
KeySymsRec keySyms ;
2008-05-19 08:51:06 +02:00
DarwinLoadKeyboardMapping ( & keySyms ) ;
if ( pDev - > key ) {
if ( pDev - > key - > curKeySyms . map ) xfree ( pDev - > key - > curKeySyms . map ) ;
if ( pDev - > key - > modifierKeyMap ) xfree ( pDev - > key - > modifierKeyMap ) ;
xfree ( pDev - > key ) ;
}
if ( ! InitKeyClassDeviceStruct ( pDev , & keySyms , keyInfo . modMap ) ) {
DEBUG_LOG ( " InitKeyClassDeviceStruct failed \n " ) ;
return ;
}
2008-04-17 20:03:31 +02:00
SendMappingNotify ( MappingKeyboard , MIN_KEYCODE , NUM_KEYCODES , 0 ) ;
SendMappingNotify ( MappingModifier , 0 , 0 , 0 ) ;
2008-04-18 02:04:08 +02:00
# endif
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 ) {
return keyInfo . modifierKeycodes [ key ] [ side ] ;
}
/*
* 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
for ( key = 0 ; key < NX_NUMMODIFIERS ; key + + ) {
for ( side = 0 ; side < = 1 ; side + + ) {
if ( keyInfo . modifierKeycodes [ key ] [ side ] = = keycode ) break ;
}
}
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 ;
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 ;
}
2008-07-09 19:02:41 +02:00
/* TODO: Not thread safe */
2007-12-11 05:47:48 +01:00
unsigned int QuartzSystemKeymapSeed ( void ) {
2008-07-09 19:02:41 +02:00
static unsigned int seed = 0 ;
2008-08-20 18:56:06 +02:00
# if defined(__x86_64__) || defined(__ppc64__)
2008-07-09 19:02:41 +02:00
static TISInputSourceRef last_key_layout = NULL ;
2008-07-05 04:23:21 +02:00
TISInputSourceRef key_layout ;
key_layout = TISCopyCurrentKeyboardLayoutInputSource ( ) ;
2003-11-25 20:29:01 +01:00
2008-07-09 19:02:41 +02:00
if ( last_key_layout ) {
if ( CFEqual ( key_layout , last_key_layout ) ) {
CFRelease ( key_layout ) ;
} else {
seed + + ;
CFRelease ( last_key_layout ) ;
last_key_layout = key_layout ;
}
} else {
last_key_layout = key_layout ;
}
2008-08-08 09:19:41 +02:00
# else
static KeyboardLayoutRef last_key_layout ;
KeyboardLayoutRef key_layout ;
2008-07-09 19:02:41 +02:00
2008-08-08 09:19:41 +02:00
KLGetCurrentKeyboardLayout ( & key_layout ) ;
if ( key_layout ! = last_key_layout )
seed + + ;
last_key_layout = key_layout ;
# endif
2003-11-25 20:29:01 +01:00
return seed ;
}
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-08-20 18:56:06 +02:00
# if !defined(__x86_64__) && !defined(__ppc64__)
2008-08-08 09:19:41 +02:00
KeyboardLayoutRef key_layout ;
# 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 ;
2007-11-05 14:44:54 +01:00
int is_uchr = 1 , i , j ;
2003-11-25 20:29:01 +01:00
OSStatus err ;
KeySym * k ;
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 ) {
CFDataRef currentKeyLayoutDataRef = ( CFDataRef ) TISGetInputSourceProperty ( currentKeyLayoutRef , kTISPropertyUnicodeKeyLayoutData ) ;
2008-08-08 09:19:41 +02:00
if ( currentKeyLayoutDataRef )
chr_data = CFDataGetBytePtr ( currentKeyLayoutDataRef ) ;
}
2008-08-20 18:56:06 +02:00
# if !defined(__x86_64__) && !defined(__ppc64__)
2008-08-08 09:19:41 +02:00
if ( chr_data = = NULL ) {
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-08-08 09:19:41 +02:00
KLGetCurrentKeyboardLayout ( & key_layout ) ;
KLGetKeyboardLayoutProperty ( key_layout , kKLuchrData , & chr_data ) ;
if ( chr_data ! = NULL ) {
ErrorF ( " X11.app: Fallback succeeded, but this is still a bug. Please report the above information. \n " ) ;
}
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-08-20 18:56:06 +02:00
ErrorF ( " X11.app: Debug Info: kKLuchrData fallback 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 ;
if ( chr_data ! = NULL ) {
ErrorF ( " X11.app: Fallback succeeded, but this is still a bug. Please report the above information. \n " ) ;
}
}
# 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.) */
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 + + ) {
if ( is_uchr ) {
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
}
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
}
}
}
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 ;
}
}
2007-11-06 05:25:10 +01:00
if ( currentKeyLayoutRef ) CFRelease ( currentKeyLayoutRef ) ;
2003-11-25 20:29:01 +01:00
return TRUE ;
}