//=============================================================================
//
// Keyboard support for the Darwin X Server
//
// Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved.
// Copyright (c) 2003 Apple Computer, Inc. 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 <[email protected]>
// 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.
//
//=============================================================================
/*
===========================================================================
An X keyCode must be in the range XkbMinLegalKeyCode (8) to
XkbMaxLegalKeyCode(255).
The keyCodes we get from the kernel range from 0 to 127, so we need to
offset the range before passing the keyCode to X.
An X KeySym is an extended ascii code that is device independent.
The modifier map is accessed by the keyCode, but the normal map is
accessed by keyCode - MIN_KEYCODE. Sigh.
===========================================================================
*/
// Define this to get a diagnostic output to stderr which is helpful
// in determining how the X server is interpreting the Darwin keymap.
#undef DUMP_DARWIN_KEYMAP
/* Define this to use Alt for Mode_switch. */
#define ALT_IS_MODE_SWITCH 1
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <IOKit/hidsystem/event_status_driver.h>
#include <IOKit/hidsystem/ev_keymap.h>
#include <architecture/byte_order.h> // For the NXSwap*
#include "darwin.h"
#include "darwinKeyboard.h"
#include <assert.h>
#define AltMask Mod1Mask
#define MetaMask Mod2Mask
#define FunctionMask Mod3Mask
// FIXME: It would be nice to support some of the extra keys in XF86keysym.h,
// at least the volume controls that now ship on every Apple keyboard.
#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
};
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
};
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 }
};
int const NUM_KEYPAD = sizeof(normal_to_keypad) / sizeof(normal_to_keypad[0]);
static void DarwinChangeKeyboardControl( DeviceIntPtr device, KeybdCtrl *ctrl )
{
// keyclick, bell volume / pitch, autorepead, LED's
}
static darwinKeyboardInfo keyInfo;
static FILE *fref = NULL;
static char *inBuffer = NULL;
//-----------------------------------------------------------------------------
// 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) );
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.
*/
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) {
ErrorF("Unable to open keymapping file '%s' (errno %d).\n",
darwinKeymapFile, errno);
return FALSE;
}
if (fstat(fileno(fref), &st) == -1) {
ErrorF("Could not stat keymapping file '%s' (errno %d).\n",
darwinKeymapFile, errno);
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) {
ErrorF("Could not read %qd bytes from keymapping file '%s' (errno %d).\n",
st.st_size, darwinKeymapFile, errno);
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
*/
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] =
(left ? XK_Mode_switch : 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[0]) {
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;
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
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;
}
if (darwinSwapAltMeta)
{
switch (k[0])
{
case XK_Alt_L:
k[0] = XK_Meta_L;
break;
case XK_Alt_R:
k[0] = XK_Meta_R;
break;
case XK_Meta_L:
k[0] = XK_Alt_L;
break;
case XK_Meta_R:
k[0] = XK_Alt_R;
break;
}
}
#if ALT_IS_MODE_SWITCH
if (k[0] == XK_Alt_L)
k[0] = XK_Mode_switch;
#endif
}
}
/*
* 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));
if (!DarwinParseNXKeyMapping(&keyInfo)) {
if (!DarwinModeReadSystemKeymap(&keyInfo)) {
FatalError("Could not build a valid keymap.");
}
}
DarwinBuildModifierMaps(&keyInfo);
#ifdef DUMP_DARWIN_KEYMAP
ErrorF("Darwin -> X converted keyboard map\n");
for (i = 0, k = info->keyMap; i < NX_NUMKEYCODES;
i++, k += GLYPHS_PER_KEY)
{
int j;
ErrorF("0x%02x:", i);
for (j = 0; j < GLYPHS_PER_KEY; j++) {
if (k[j] == NoSymbol) {
ErrorF("\tNoSym");
} else {
ErrorF("\t0x%x", k[j]);
}
}
ErrorF("\n");
}
#endif
keySyms->map = keyInfo.keyMap;
keySyms->mapWidth = GLYPHS_PER_KEY;
keySyms->minKeyCode = MIN_KEYCODE;
keySyms->maxKeyCode = MAX_KEYCODE;
}
/*
* 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) */
DarwinModeSystemKeymapSeed();
assert( InitKeyboardDeviceStruct( (DevicePtr)pDev, &keySyms,
keyInfo.modMap, DarwinModeBell,
DarwinChangeKeyboardControl ));
}
/* Borrowed from dix/devices.c */
static Bool
InitModMap(register KeyClassPtr keyc)
{
int i, j;
CARD8 keysPerModifier[8];
CARD8 mask;
if (keyc->modifierKeyMap != NULL)
xfree (keyc->modifierKeyMap);
keyc->maxKeysPerModifier = 0;
for (i = 0; i < 8; i++)
keysPerModifier[i] = 0;
for (i = 8; i < MAP_LENGTH; i++)
{
for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
{
if (mask & keyc->modifierMap[i])
{
if (++keysPerModifier[j] > keyc->maxKeysPerModifier)
keyc->maxKeysPerModifier = keysPerModifier[j];
}
}
}
keyc->modifierKeyMap = (KeyCode *)xalloc(8*keyc->maxKeysPerModifier);
if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier)
return (FALSE);
bzero((char *)keyc->modifierKeyMap, 8*(int)keyc->maxKeysPerModifier);
for (i = 0; i < 8; i++)
keysPerModifier[i] = 0;
for (i = 8; i < MAP_LENGTH; i++)
{
for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
{
if (mask & keyc->modifierMap[i])
{
keyc->modifierKeyMap[(j*keyc->maxKeysPerModifier) +
keysPerModifier[j]] = i;
keysPerModifier[j]++;
}
}
}
return TRUE;
}
void
DarwinKeyboardReload(DeviceIntPtr pDev)
{
KeySymsRec keySyms;
DarwinLoadKeyboardMapping(&keySyms);
if (SetKeySymsMap(&pDev->key->curKeySyms, &keySyms)) {
/* now try to update modifiers. */
memmove(pDev->key->modifierMap, keyInfo.modMap, MAP_LENGTH);
InitModMap(pDev->key);
}
SendMappingNotify(MappingKeyboard, MIN_KEYCODE, NUM_KEYCODES, 0);
SendMappingNotify(MappingModifier, 0, 0, 0);
}
//-----------------------------------------------------------------------------
// 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;
case NX_MODIFIERKEY_SHIFT: return NX_SHIFTMASK;
#ifdef NX_MODIFIERKEY_RSHIFT
case NX_MODIFIERKEY_RSHIFT: return NX_SHIFTMASK;
#endif
case NX_MODIFIERKEY_CONTROL: return NX_CONTROLMASK;
#ifdef NX_MODIFIERKEY_RCONTROL
case NX_MODIFIERKEY_RCONTROL: return NX_CONTROLMASK;
#endif
case NX_MODIFIERKEY_ALTERNATE: return NX_ALTERNATEMASK;
#ifdef NX_MODIFIERKEY_RALTERNATE
case NX_MODIFIERKEY_RALTERNATE: return NX_ALTERNATEMASK;
#endif
case NX_MODIFIERKEY_COMMAND: return NX_COMMANDMASK;
#ifdef NX_MODIFIERKEY_RCOMMAND
case NX_MODIFIERKEY_RCOMMAND: 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;
}
/*
* DarwinModifierStringToNXKey
* Returns -1 if string is not a known modifier.
*/
int DarwinModifierStringToNXKey(const char *str)
{
if (!strcasecmp(str, "shift")) return NX_MODIFIERKEY_SHIFT;
else if (!strcasecmp(str, "control")) return NX_MODIFIERKEY_CONTROL;
else if (!strcasecmp(str, "option")) return NX_MODIFIERKEY_ALTERNATE;
else if (!strcasecmp(str, "command")) return NX_MODIFIERKEY_COMMAND;
else if (!strcasecmp(str, "fn")) return NX_MODIFIERKEY_SECONDARYFN;
else return -1;
}
/*
* 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;
}
|