//============================================================================= // // 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 // 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. =========================================================================== */ #ifdef HAVE_DIX_CONFIG_H #include #endif // 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 #include #include #include #include #include #include #include // For the NXSwap* #include "darwin.h" #include "darwinKeyboard.h" #ifdef NDEBUG #undef NDEBUG #include #define NDEBUG 1 #else #include #endif #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 }; 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 } 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] = XK_Mode_switch; // (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; 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: // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. #ifdef NX_MODIFIERKEY_RALTERNATE info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; #endif info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 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) { int i; KeySym *k; memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); /* TODO: Clean this up * DarwinModeReadSystemKeymap is in quartz/quartzKeyboard.c * DarwinParseNXKeyMapping is here */ if (!DarwinParseNXKeyMapping(&keyInfo)) { DEBUG_LOG("DarwinParseNXKeyMapping returned 0... running DarwinModeReadSystemKeymap().\n"); if (!DarwinModeReadSystemKeymap(&keyInfo)) { FatalError("Could not build a valid keymap."); } } DarwinBuildModifierMaps(&keyInfo); #ifdef DUMP_DARWIN_KEYMAP 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:\tNoSym\n", i); } else { DEBUG_LOG("0x%02x:\t0x%lx\n", i, k[j]); } } } #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); // DarwinKeyboardReload(pDev); /* 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; // darwinKeyc = keyc; 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); } else DEBUG_LOG("SetKeySymsMap=0\n"); 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; } const char *DarwinModifierNXMaskTostring(int mask) { switch (mask) { case NX_ALPHASHIFTMASK: return "NX_ALPHASHIFTMASK"; case NX_SHIFTMASK: return "NX_SHIFTMASK"; case NX_DEVICELSHIFTKEYMASK: return "NX_DEVICELSHIFTKEYMASK"; case NX_DEVICERSHIFTKEYMASK: return "NX_DEVICERSHIFTKEYMASK"; case NX_CONTROLMASK: return "NX_CONTROLMASK"; case NX_DEVICELCTLKEYMASK: return "NX_DEVICELCTLKEYMASK"; case NX_DEVICERCTLKEYMASK: return "NX_DEVICERCTLKEYMASK"; case NX_ALTERNATEMASK: return "NX_ALTERNATEMASK"; case NX_DEVICELALTKEYMASK: return "NX_DEVICELALTKEYMASK"; case NX_DEVICERALTKEYMASK: return "NX_DEVICERALTKEYMASK"; case NX_COMMANDMASK: return "NX_COMMANDMASK"; case NX_DEVICELCMDKEYMASK: return "NX_DEVICELCMDKEYMASK"; case NX_DEVICERCMDKEYMASK: return "NX_DEVICERCMDKEYMASK"; case NX_NUMERICPADMASK: return "NX_NUMERICPADMASK"; case NX_HELPMASK: return "NX_HELPMASK"; case NX_SECONDARYFNMASK: return "NX_SECONDARYFNMASK"; } return "unknown mask"; } /* * 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; }