1026 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1026 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|    quartzKeyboard.c: Keyboard support for Xquartz
 | |
| 
 | |
|    Copyright (c) 2003-2012 Apple Inc.
 | |
|    Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved.
 | |
|    Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved.
 | |
| 
 | |
|    Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com>
 | |
|    All rights reserved.
 | |
| 
 | |
|    Redistribution and use in source and binary forms, with or without
 | |
|    modification, are permitted provided that the following conditions are met:
 | |
| 
 | |
|      1. Redistributions of source code must retain the above copyright
 | |
|         notice, this list of conditions and the following disclaimer.
 | |
|      2. Redistributions in binary form must reproduce the above copyright
 | |
|         notice, this list of conditions and the following disclaimer in the
 | |
|         documentation and/or other materials provided with the distribution.
 | |
|      3. The name of the author may not be used to endorse or promote products
 | |
|         derived from this software without specific prior written permission.
 | |
| 
 | |
|    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
|    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | |
|    NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
|    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 | |
|    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | |
|    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | |
|    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | |
|    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | |
|    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include "sanitizedCarbon.h"
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #define HACK_MISSING   1
 | |
| #define HACK_KEYPAD    1
 | |
| #define HACK_BLACKLIST 1
 | |
| 
 | |
| #include <unistd.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <errno.h>
 | |
| #include <sys/stat.h>
 | |
| #include <AvailabilityMacros.h>
 | |
| 
 | |
| #include "quartz.h"
 | |
| #include "darwin.h"
 | |
| #include "darwinEvents.h"
 | |
| 
 | |
| #include "quartzKeyboard.h"
 | |
| 
 | |
| #include "X11Application.h"
 | |
| 
 | |
| #include <assert.h>
 | |
| #include <pthread.h>
 | |
| 
 | |
| #include "xkbsrv.h"
 | |
| #include "exevents.h"
 | |
| #include "X11/keysym.h"
 | |
| #include "keysym2ucs.h"
 | |
| 
 | |
| extern void
 | |
| CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
 | |
| 
 | |
| enum {
 | |
|     MOD_COMMAND = 256,
 | |
|     MOD_SHIFT = 512,
 | |
|     MOD_OPTION = 2048,
 | |
|     MOD_CONTROL = 4096,
 | |
| };
 | |
| 
 | |
| #define UKEYSYM(u) ((u) | 0x01000000)
 | |
| 
 | |
| #if HACK_MISSING
 | |
| /* Table of keycode->keysym mappings we use to fallback on for important
 | |
|    keys that are often not in the Unicode mapping. */
 | |
| 
 | |
| const static struct {
 | |
|     unsigned short keycode;
 | |
|     KeySym keysym;
 | |
| } known_keys[] = {
 | |
|     { 55,  XK_Meta_L        },
 | |
|     { 56,  XK_Shift_L       },
 | |
|     { 57,  XK_Caps_Lock     },
 | |
|     { 58,  XK_Alt_L         },
 | |
|     { 59,  XK_Control_L     },
 | |
| 
 | |
|     { 60,  XK_Shift_R       },
 | |
|     { 61,  XK_Alt_R         },
 | |
|     { 62,  XK_Control_R     },
 | |
|     { 63,  XK_Meta_R        },
 | |
| 
 | |
|     { 122, XK_F1            },
 | |
|     { 120, XK_F2            },
 | |
|     { 99,  XK_F3            },
 | |
|     { 118, XK_F4            },
 | |
|     { 96,  XK_F5            },
 | |
|     { 97,  XK_F6            },
 | |
|     { 98,  XK_F7            },
 | |
|     { 100, XK_F8            },
 | |
|     { 101, XK_F9            },
 | |
|     { 109, XK_F10           },
 | |
|     { 103, XK_F11           },
 | |
|     { 111, XK_F12           },
 | |
|     { 105, XK_F13           },
 | |
|     { 107, XK_F14           },
 | |
|     { 113, XK_F15           },
 | |
| };
 | |
| #endif
 | |
| 
 | |
| #if HACK_KEYPAD
 | |
| /* 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                                    },
 | |
| };
 | |
| #endif
 | |
| 
 | |
| #if HACK_BLACKLIST
 | |
| /* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow
 | |
|  * http://xquartz.macosforge.org/trac/ticket/295
 | |
|  * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html
 | |
|  *
 | |
|  * legacy Mac keycodes for arrow keys that shift-modify to math symbols
 | |
|  */
 | |
| const static unsigned short keycode_blacklist[] = { 66, 70, 72, 77 };
 | |
| #endif
 | |
| 
 | |
| /* 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_apostrophe,  XK_dead_acute                                }, /* US:"=" on a Czech keyboard */
 | |
|     { XK_acute,       XK_dead_acute                                },
 | |
|     { UKEYSYM(0x384), XK_dead_acute                                }, /* US:";" on a Greek keyboard */
 | |
|     //    {XK_Greek_accentdieresis, XK_dead_diaeresis},   /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */
 | |
|     { 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 */
 | |
| };
 | |
| 
 | |
| typedef struct darwinKeyboardInfo_struct {
 | |
|     CARD8 modMap[MAP_LENGTH];
 | |
|     KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY];
 | |
|     unsigned char modifierKeycodes[32][2];
 | |
| } darwinKeyboardInfo;
 | |
| 
 | |
| darwinKeyboardInfo keyInfo;
 | |
| pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
 | |
| 
 | |
| static void
 | |
| DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl)
 | |
| {
 | |
|     // FIXME: to be implemented
 | |
|     // keyclick, bell volume / pitch, autorepead, LED's
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // Utility functions to help parse Darwin keymap
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /*
 | |
|  * DarwinBuildModifierMaps
 | |
|  *      Use the keyMap field of keyboard info structure to populate
 | |
|  *      the modMap and modifierKeycodes fields.
 | |
|  */
 | |
| static void
 | |
| DarwinBuildModifierMaps(darwinKeyboardInfo *info)
 | |
| {
 | |
|     int i;
 | |
|     KeySym *k;
 | |
| 
 | |
|     memset(info->modMap, NoSymbol, sizeof(info->modMap));
 | |
|     memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes));
 | |
| 
 | |
|     for (i = 0; i < NUM_KEYCODES; i++) {
 | |
|         k = info->keyMap + i * GLYPHS_PER_KEY;
 | |
| 
 | |
|         switch (*k) {
 | |
|         case XK_Shift_L:
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
 | |
|             info->modMap[MIN_KEYCODE + i] = ShiftMask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Shift_R:
 | |
| #ifdef NX_MODIFIERKEY_RSHIFT
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i;
 | |
| #else
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
 | |
| #endif
 | |
|             info->modMap[MIN_KEYCODE + i] = ShiftMask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Control_L:
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
 | |
|             info->modMap[MIN_KEYCODE + i] = ControlMask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Control_R:
 | |
| #ifdef NX_MODIFIERKEY_RCONTROL
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i;
 | |
| #else
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
 | |
| #endif
 | |
|             info->modMap[MIN_KEYCODE + i] = ControlMask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Caps_Lock:
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
 | |
|             info->modMap[MIN_KEYCODE + i] = LockMask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Alt_L:
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
 | |
|             info->modMap[MIN_KEYCODE + i] = Mod1Mask;
 | |
|             if (!XQuartzOptionSendsAlt)
 | |
|                 *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
 | |
|             if (!XQuartzOptionSendsAlt)
 | |
|                 *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:
 | |
|             ErrorF(
 | |
|                 "DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n");
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
 | |
| #ifdef NX_MODIFIERKEY_RALTERNATE
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
 | |
| #endif
 | |
|             info->modMap[MIN_KEYCODE + i] = Mod1Mask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Meta_L:
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
 | |
|             info->modMap[MIN_KEYCODE + i] = Mod2Mask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Meta_R:
 | |
| #ifdef NX_MODIFIERKEY_RCOMMAND
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i;
 | |
| #else
 | |
|             info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
 | |
| #endif
 | |
|             info->modMap[MIN_KEYCODE + i] = Mod2Mask;
 | |
|             break;
 | |
| 
 | |
|         case XK_Num_Lock:
 | |
|             info->modMap[MIN_KEYCODE + i] = Mod3Mask;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * DarwinKeyboardInit
 | |
|  *      Get the Darwin keyboard map and compute an equivalent
 | |
|  *      X keyboard map and modifier map. Set the new keyboard
 | |
|  *      device structure.
 | |
|  */
 | |
| void
 | |
| DarwinKeyboardInit(DeviceIntPtr pDev)
 | |
| {
 | |
|     // Open a shared connection to the HID System.
 | |
|     // Note that the Event Status Driver is really just a wrapper
 | |
|     // for a kIOHIDParamConnectType connection.
 | |
|     assert(darwinParamConnect = NXOpenEventStatus());
 | |
| 
 | |
|     InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl);
 | |
| 
 | |
|     DarwinKeyboardReloadHandler();
 | |
| 
 | |
|     CopyKeyClass(pDev, inputInfo.keyboard);
 | |
| }
 | |
| 
 | |
| /* Set the repeat rates based on global preferences and keycodes for modifiers.
 | |
|  * Precondition: Has the keyInfo_mutex lock.
 | |
|  */
 | |
| static void
 | |
| DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue,
 | |
|                         int keyRepeatValue)
 | |
| {
 | |
|     if (initialKeyRepeatValue == 300000) { // off
 | |
|         /* Turn off repeats globally */
 | |
|         XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff);
 | |
|     }
 | |
|     else {
 | |
|         int i;
 | |
|         XkbControlsPtr ctrl;
 | |
|         XkbControlsRec old;
 | |
| 
 | |
|         /* Turn on repeats globally */
 | |
|         XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
 | |
| 
 | |
|         /* Setup the bit mask for individual key repeats */
 | |
|         ctrl = pDev->key->xkbInfo->desc->ctrls;
 | |
|         old = *ctrl;
 | |
| 
 | |
|         ctrl->repeat_delay = initialKeyRepeatValue * 15;
 | |
|         ctrl->repeat_interval = keyRepeatValue * 15;
 | |
| 
 | |
|         /* Turn off key-repeat for modifier keys, on for others */
 | |
|         /* First set them all on */
 | |
|         for (i = 0; i < XkbPerKeyBitArraySize; i++)
 | |
|             ctrl->per_key_repeat[i] = -1;
 | |
| 
 | |
|         /* Now turn off the modifiers */
 | |
|         for (i = 0; i < 32; i++) {
 | |
|             unsigned char keycode;
 | |
| 
 | |
|             keycode = keyInfo.modifierKeycodes[i][0];
 | |
|             if (keycode)
 | |
|                 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
 | |
| 
 | |
|             keycode = keyInfo.modifierKeycodes[i][1];
 | |
|             if (keycode)
 | |
|                 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
 | |
|         }
 | |
| 
 | |
|         /* Hurray for data duplication */
 | |
|         if (pDev->kbdfeed)
 | |
|             memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat,
 | |
|                    XkbPerKeyBitArraySize);
 | |
| 
 | |
|         //ErrorF("per_key_repeat =\n");
 | |
|         //for(i=0; i < XkbPerKeyBitArraySize; i++)
 | |
|         //    ErrorF("%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n");
 | |
| 
 | |
|         /* And now we notify the puppies about the changes */
 | |
|         XkbDDXChangeControls(pDev, &old, ctrl);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| DarwinKeyboardReloadHandler(void)
 | |
| {
 | |
|     KeySymsRec keySyms;
 | |
|     CFIndex initialKeyRepeatValue, keyRepeatValue;
 | |
|     BOOL ok;
 | |
|     DeviceIntPtr pDev;
 | |
|     const char *xmodmap = PROJECTROOT "/bin/xmodmap";
 | |
|     const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap";
 | |
|     const char *homedir = getenv("HOME");
 | |
|     char usermodmap[PATH_MAX], cmd[PATH_MAX];
 | |
| 
 | |
|     DEBUG_LOG("DarwinKeyboardReloadHandler\n");
 | |
| 
 | |
|     /* Get our key repeat settings from GlobalPreferences */
 | |
|     (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
 | |
| 
 | |
|     initialKeyRepeatValue =
 | |
|         CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"),
 | |
|                                         CFSTR(".GlobalPreferences"), &ok);
 | |
|     if (!ok)
 | |
|         initialKeyRepeatValue = 35;
 | |
| 
 | |
|     keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR(
 | |
|                                                          "KeyRepeat"),
 | |
|                                                      CFSTR(
 | |
|                                                          ".GlobalPreferences"),
 | |
|                                                      &ok);
 | |
|     if (!ok)
 | |
|         keyRepeatValue = 6;
 | |
| 
 | |
|     pthread_mutex_lock(&keyInfo_mutex);
 | |
|     {
 | |
|         /* Initialize our keySyms */
 | |
|         keySyms.map = keyInfo.keyMap;
 | |
|         keySyms.mapWidth = GLYPHS_PER_KEY;
 | |
|         keySyms.minKeyCode = MIN_KEYCODE;
 | |
|         keySyms.maxKeyCode = MAX_KEYCODE;
 | |
| 
 | |
|         // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap
 | |
|         /* Apply the mappings to darwinKeyboard */
 | |
|         XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode,
 | |
|                               keySyms.maxKeyCode - keySyms.minKeyCode + 1,
 | |
|                               keyInfo.modMap, serverClient);
 | |
|         DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue,
 | |
|                                 keyRepeatValue);
 | |
| 
 | |
|         /* Apply the mappings to the core keyboard */
 | |
|         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
 | |
|             if ((pDev->coreEvents ||
 | |
|                  pDev == inputInfo.keyboard) && pDev->key) {
 | |
|                 XkbApplyMappingChange(
 | |
|                     pDev, &keySyms, keySyms.minKeyCode,
 | |
|                     keySyms.maxKeyCode -
 | |
|                     keySyms.minKeyCode + 1,
 | |
|                     keyInfo.modMap, serverClient);
 | |
|                 DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue,
 | |
|                                         keyRepeatValue);
 | |
|             }
 | |
|         }
 | |
|     } pthread_mutex_unlock(&keyInfo_mutex);
 | |
| 
 | |
|     /* Modify with xmodmap */
 | |
|     if (access(xmodmap, F_OK) == 0) {
 | |
|         /* Check for system .Xmodmap */
 | |
|         if (access(sysmodmap, F_OK) == 0) {
 | |
|             if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap,
 | |
|                          sysmodmap) < sizeof(cmd)) {
 | |
|                 X11ApplicationLaunchClient(cmd);
 | |
|             }
 | |
|             else {
 | |
|                 ErrorF(
 | |
|                     "X11.app: Unable to create / execute xmodmap command line");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Check for user's local .Xmodmap */
 | |
|         if ((homedir != NULL) &&
 | |
|             (snprintf(usermodmap, sizeof(usermodmap), "%s/.Xmodmap",
 | |
|                       homedir) < sizeof(usermodmap))) {
 | |
|             if (access(usermodmap, F_OK) == 0) {
 | |
|                 if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap,
 | |
|                              usermodmap) < sizeof(cmd)) {
 | |
|                     X11ApplicationLaunchClient(cmd);
 | |
|                 }
 | |
|                 else {
 | |
|                     ErrorF(
 | |
|                         "X11.app: Unable to create / execute xmodmap command line");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             ErrorF("X11.app: Unable to determine path to user's .Xmodmap");
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // 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)
 | |
| {
 | |
|     int retval;
 | |
|     pthread_mutex_lock(&keyInfo_mutex);
 | |
|     retval = keyInfo.modifierKeycodes[key][side];
 | |
|     pthread_mutex_unlock(&keyInfo_mutex);
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * DarwinModifierNXKeycodeToNXKey
 | |
|  *      Returns -1 if keycode+side is not a modifier key
 | |
|  *      outSide may be NULL, else it gets 0 for left and 1 for right.
 | |
|  */
 | |
| int
 | |
| DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide)
 | |
| {
 | |
|     int key, side;
 | |
| 
 | |
|     keycode += MIN_KEYCODE;
 | |
| 
 | |
|     // search modifierKeycodes for this keycode+side
 | |
|     pthread_mutex_lock(&keyInfo_mutex);
 | |
|     for (key = 0; key < NX_NUMMODIFIERS; key++) {
 | |
|         for (side = 0; side <= 1; side++) {
 | |
|             if (keyInfo.modifierKeycodes[key][side] == keycode) break;
 | |
|         }
 | |
|     }
 | |
|     pthread_mutex_unlock(&keyInfo_mutex);
 | |
| 
 | |
|     if (key == NX_NUMMODIFIERS) {
 | |
|         return -1;
 | |
|     }
 | |
|     if (outSide) *outSide = side;
 | |
| 
 | |
|     return key;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * DarwinModifierNXMaskToNXKey
 | |
|  *      Returns -1 if mask is not a known modifier mask.
 | |
|  */
 | |
| int
 | |
| DarwinModifierNXMaskToNXKey(int mask)
 | |
| {
 | |
|     switch (mask) {
 | |
|     case NX_ALPHASHIFTMASK:
 | |
|         return NX_MODIFIERKEY_ALPHALOCK;
 | |
| 
 | |
|     case NX_SHIFTMASK:
 | |
|         return NX_MODIFIERKEY_SHIFT;
 | |
| 
 | |
| #ifdef NX_DEVICELSHIFTKEYMASK
 | |
|     case NX_DEVICELSHIFTKEYMASK:
 | |
|         return NX_MODIFIERKEY_SHIFT;
 | |
| 
 | |
|     case NX_DEVICERSHIFTKEYMASK:
 | |
|         return NX_MODIFIERKEY_RSHIFT;
 | |
| 
 | |
| #endif
 | |
|     case NX_CONTROLMASK:
 | |
|         return NX_MODIFIERKEY_CONTROL;
 | |
| 
 | |
| #ifdef NX_DEVICELCTLKEYMASK
 | |
|     case NX_DEVICELCTLKEYMASK:
 | |
|         return NX_MODIFIERKEY_CONTROL;
 | |
| 
 | |
|     case NX_DEVICERCTLKEYMASK:
 | |
|         return NX_MODIFIERKEY_RCONTROL;
 | |
| 
 | |
| #endif
 | |
|     case NX_ALTERNATEMASK:
 | |
|         return NX_MODIFIERKEY_ALTERNATE;
 | |
| 
 | |
| #ifdef NX_DEVICELALTKEYMASK
 | |
|     case NX_DEVICELALTKEYMASK:
 | |
|         return NX_MODIFIERKEY_ALTERNATE;
 | |
| 
 | |
|     case NX_DEVICERALTKEYMASK:
 | |
|         return NX_MODIFIERKEY_RALTERNATE;
 | |
| 
 | |
| #endif
 | |
|     case NX_COMMANDMASK:
 | |
|         return NX_MODIFIERKEY_COMMAND;
 | |
| 
 | |
| #ifdef NX_DEVICELCMDKEYMASK
 | |
|     case NX_DEVICELCMDKEYMASK:
 | |
|         return NX_MODIFIERKEY_COMMAND;
 | |
| 
 | |
|     case NX_DEVICERCMDKEYMASK:
 | |
|         return NX_MODIFIERKEY_RCOMMAND;
 | |
| 
 | |
| #endif
 | |
|     case NX_NUMERICPADMASK:
 | |
|         return NX_MODIFIERKEY_NUMERICPAD;
 | |
| 
 | |
|     case NX_HELPMASK:
 | |
|         return NX_MODIFIERKEY_HELP;
 | |
| 
 | |
|     case NX_SECONDARYFNMASK:
 | |
|         return NX_MODIFIERKEY_SECONDARYFN;
 | |
|     }
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * DarwinModifierNXKeyToNXMask
 | |
|  *      Returns 0 if key is not a known modifier key.
 | |
|  */
 | |
| int
 | |
| DarwinModifierNXKeyToNXMask(int key)
 | |
| {
 | |
|     switch (key) {
 | |
|     case NX_MODIFIERKEY_ALPHALOCK:
 | |
|         return NX_ALPHASHIFTMASK;
 | |
| 
 | |
| #ifdef NX_DEVICELSHIFTKEYMASK
 | |
|     case NX_MODIFIERKEY_SHIFT:
 | |
|         return NX_DEVICELSHIFTKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_RSHIFT:
 | |
|         return NX_DEVICERSHIFTKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_CONTROL:
 | |
|         return NX_DEVICELCTLKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_RCONTROL:
 | |
|         return NX_DEVICERCTLKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_ALTERNATE:
 | |
|         return NX_DEVICELALTKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_RALTERNATE:
 | |
|         return NX_DEVICERALTKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_COMMAND:
 | |
|         return NX_DEVICELCMDKEYMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_RCOMMAND:
 | |
|         return NX_DEVICERCMDKEYMASK;
 | |
| 
 | |
| #else
 | |
|     case NX_MODIFIERKEY_SHIFT:
 | |
|         return NX_SHIFTMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_CONTROL:
 | |
|         return NX_CONTROLMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_ALTERNATE:
 | |
|         return NX_ALTERNATEMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_COMMAND:
 | |
|         return NX_COMMANDMASK;
 | |
| 
 | |
| #endif
 | |
|     case NX_MODIFIERKEY_NUMERICPAD:
 | |
|         return NX_NUMERICPADMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_HELP:
 | |
|         return NX_HELPMASK;
 | |
| 
 | |
|     case NX_MODIFIERKEY_SECONDARYFN:
 | |
|         return NX_SECONDARYFNMASK;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * DarwinModifierStringToNXMask
 | |
|  *      Returns 0 if string is not a known modifier.
 | |
|  */
 | |
| int
 | |
| DarwinModifierStringToNXMask(const char *str, int separatelr)
 | |
| {
 | |
| #ifdef NX_DEVICELSHIFTKEYMASK
 | |
|     if (separatelr) {
 | |
|         if (!strcasecmp(str,
 | |
|                         "shift")) return NX_DEVICELSHIFTKEYMASK |
 | |
|                    NX_DEVICERSHIFTKEYMASK;
 | |
|         if (!strcasecmp(str,
 | |
|                         "control")) return NX_DEVICELCTLKEYMASK |
 | |
|                    NX_DEVICERCTLKEYMASK;
 | |
|         if (!strcasecmp(str,
 | |
|                         "option")) return NX_DEVICELALTKEYMASK |
 | |
|                    NX_DEVICERALTKEYMASK;
 | |
|         if (!strcasecmp(str,
 | |
|                         "alt")) return NX_DEVICELALTKEYMASK |
 | |
|                    NX_DEVICERALTKEYMASK;
 | |
|         if (!strcasecmp(str,
 | |
|                         "command")) return NX_DEVICELCMDKEYMASK |
 | |
|                    NX_DEVICERCMDKEYMASK;
 | |
|         if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK;
 | |
|         if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK;
 | |
|         if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK;
 | |
|         if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK;
 | |
|         if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK;
 | |
|         if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK;
 | |
|         if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK;
 | |
|         if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK;
 | |
|         if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK;
 | |
|         if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK;
 | |
|     }
 | |
|     else {
 | |
| #endif
 | |
|     if (!strcasecmp(str, "shift")) return NX_SHIFTMASK;
 | |
|     if (!strcasecmp(str, "control")) return NX_CONTROLMASK;
 | |
|     if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "command")) return NX_COMMANDMASK;
 | |
|     if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK;
 | |
|     if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK;
 | |
|     if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK;
 | |
|     if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK;
 | |
|     if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK;
 | |
|     if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK;
 | |
|     if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK;
 | |
| #ifdef NX_DEVICELSHIFTKEYMASK
 | |
| }
 | |
| #endif
 | |
|     if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK;
 | |
|     if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK;
 | |
|     if (!strcasecmp(str, "help")) return NX_HELPMASK;
 | |
|     if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * LegalModifier
 | |
|  *      This allows the ddx layer to prevent some keys from being remapped
 | |
|  *      as modifier keys.
 | |
|  */
 | |
| Bool
 | |
| LegalModifier(unsigned int key, DeviceIntPtr pDev)
 | |
| {
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | |
| static inline UniChar
 | |
| macroman2ucs(unsigned char c)
 | |
| {
 | |
|     /* 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,
 | |
|     };
 | |
| 
 | |
|     if (c < 128) return c;
 | |
|     else return table[c - 128];
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static KeySym
 | |
| make_dead_key(KeySym in)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < ARRAY_SIZE(dead_keys); i++)
 | |
|         if (dead_keys[i].normal == in) return dead_keys[i].dead;
 | |
| 
 | |
|     return in;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| QuartzReadSystemKeymap(darwinKeyboardInfo *info)
 | |
| {
 | |
| #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | |
|     KeyboardLayoutRef key_layout;
 | |
|     int is_uchr = 1;
 | |
| #endif
 | |
|     const void *chr_data = NULL;
 | |
|     int num_keycodes = NUM_KEYCODES;
 | |
|     UInt32 keyboard_type = LMGetKbdType();
 | |
|     int i, j;
 | |
|     OSStatus err;
 | |
|     KeySym *k;
 | |
|     CFDataRef currentKeyLayoutDataRef = NULL;
 | |
| 
 | |
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 | |
|     TISInputSourceRef currentKeyLayoutRef =
 | |
|         TISCopyCurrentKeyboardLayoutInputSource();
 | |
| 
 | |
|     if (currentKeyLayoutRef) {
 | |
|         currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(
 | |
|             currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData);
 | |
|         if (currentKeyLayoutDataRef)
 | |
|             chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #ifdef __clang__
 | |
| #pragma clang diagnostic push
 | |
| #pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty
 | |
| #endif
 | |
| 
 | |
| #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | |
|     if (chr_data == NULL) {
 | |
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 | |
|         ErrorF(
 | |
|             "X11.app: Error detected in determining keyboard layout.  If you are using an Apple-provided keyboard layout, please report this error at http://xquartz.macosforge.org and http://bugreport.apple.com\n");
 | |
|         ErrorF(
 | |
|             "X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n",
 | |
|             (unsigned)keyboard_type, currentKeyLayoutRef,
 | |
|             currentKeyLayoutDataRef, chr_data);
 | |
| #endif
 | |
| 
 | |
|         KLGetCurrentKeyboardLayout(&key_layout);
 | |
|         KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
 | |
| 
 | |
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 | |
|         if (chr_data != NULL) {
 | |
|             ErrorF(
 | |
|                 "X11.app: Fallback succeeded, but this is still a bug.  Please report the above information.\n");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     if (chr_data == NULL) {
 | |
|         ErrorF(
 | |
|             "X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
 | |
|         ErrorF(
 | |
|             "If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n");
 | |
|         KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
 | |
|         is_uchr = 0;
 | |
|         num_keycodes = 128;
 | |
| 
 | |
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 | |
|         if (chr_data != NULL) {
 | |
|             ErrorF(
 | |
|                 "X11.app: Fallback succeeded, but this is still a bug.  Please report the above information.\n");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #ifdef __clang__
 | |
| #pragma clang diagnostic pop
 | |
| #endif
 | |
| 
 | |
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 | |
|     if (currentKeyLayoutRef)
 | |
|         CFRelease(currentKeyLayoutRef);
 | |
| #endif
 | |
| 
 | |
|     if (chr_data == NULL) {
 | |
|         ErrorF("Couldn't get uchr or kchr resource\n");
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     /* 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.) */
 | |
| 
 | |
|     /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
 | |
|        must be used instead. */
 | |
| 
 | |
|     for (i = 0; i < num_keycodes; i++) {
 | |
|         static const int mods[4] = {
 | |
|             0, MOD_SHIFT, MOD_OPTION,
 | |
|             MOD_OPTION | MOD_SHIFT
 | |
|         };
 | |
| 
 | |
|         k = info->keyMap + i * GLYPHS_PER_KEY;
 | |
| 
 | |
|         for (j = 0; j < 4; j++) {
 | |
| #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | |
|             if (is_uchr) {
 | |
| #endif
 | |
|             UniChar s[8];
 | |
|             UniCharCount len;
 | |
|             UInt32 dead_key_state = 0, extra_dead = 0;
 | |
| 
 | |
|             err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
 | |
|                                  mods[j] >> 8, keyboard_type, 0,
 | |
|                                  &dead_key_state, 8, &len, s);
 | |
|             if (err != noErr) continue;
 | |
| 
 | |
|             if (len == 0 && dead_key_state != 0) {
 | |
|                 /* 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);
 | |
|                 if (err != noErr) continue;
 | |
|             }
 | |
| 
 | |
|             /* Not sure why 0x0010 is there.
 | |
|              * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
 | |
|              */
 | |
|             if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
 | |
|                 k[j] = ucs2keysym(s[0]);
 | |
|                 if (dead_key_state != 0) k[j] = make_dead_key(k[j]);
 | |
|             }
 | |
| #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
 | |
|         }
 | |
|         else {       // kchr
 | |
|             UInt32 c, state = 0, state2 = 0;
 | |
|             UInt16 code;
 | |
| 
 | |
|             code = i | mods[j];
 | |
| 
 | |
| #ifdef __clang__
 | |
| #pragma clang diagnostic push
 | |
| #pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate
 | |
| #endif
 | |
| 
 | |
|             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);
 | |
| 
 | |
| #ifdef __clang__
 | |
| #pragma clang diagnostic pop
 | |
| #endif
 | |
| 
 | |
|             /* Characters seem to be in MacRoman encoding. */
 | |
| 
 | |
|             if (c != 0 && c != 0x0010) {
 | |
|                 k[j] = ucs2keysym(macroman2ucs(c & 255));
 | |
| 
 | |
|                 if (state != 0) k[j] = make_dead_key(k[j]);
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         if (k[3] == k[2]) k[3] = NoSymbol;
 | |
|         if (k[1] == k[0]) k[1] = NoSymbol;
 | |
|         if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
 | |
|         if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
 | |
|     }
 | |
| 
 | |
| #if HACK_MISSING
 | |
|     /* Fix up some things that are normally missing.. */
 | |
| 
 | |
|     for (i = 0; i < ARRAY_SIZE(known_keys); i++) {
 | |
|         k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
 | |
| 
 | |
|         if (k[0] == NoSymbol && k[1] == NoSymbol
 | |
|             && k[2] == NoSymbol && k[3] == NoSymbol)
 | |
|             k[0] = known_keys[i].keysym;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #if HACK_KEYPAD
 | |
|     /* And some more things. We find the right symbols for the numeric
 | |
|        keypad, but not the KP_ keysyms. So try to convert known keycodes. */
 | |
|     for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) {
 | |
|         k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
 | |
| 
 | |
|         if (k[0] == known_numeric_keys[i].normal)
 | |
|             k[0] = known_numeric_keys[i].keypad;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #if HACK_BLACKLIST
 | |
|     for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) {
 | |
|         k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY;
 | |
|         k[0] = k[1] = k[2] = k[3] = NoSymbol;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     DarwinBuildModifierMaps(info);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| QuartsResyncKeymap(Bool sendDDXEvent)
 | |
| {
 | |
|     Bool retval;
 | |
|     /* Update keyInfo */
 | |
|     pthread_mutex_lock(&keyInfo_mutex);
 | |
|     memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap));
 | |
|     retval = QuartzReadSystemKeymap(&keyInfo);
 | |
|     pthread_mutex_unlock(&keyInfo_mutex);
 | |
| 
 | |
|     /* Tell server thread to deal with new keyInfo */
 | |
|     if (sendDDXEvent)
 | |
|         DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
 | |
| 
 | |
|     return retval;
 | |
| }
 |