1 /* darwin-keyboard.c -- Keyboard support for the Darwin X Server
2 
3    Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved.
4    Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
5 
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions are met:
8 
9      1. Redistributions of source code must retain the above copyright
10         notice, this list of conditions and the following disclaimer.
11      2. Redistributions in binary form must reproduce the above copyright
12         notice, this list of conditions and the following disclaimer in the
13         documentation and/or other materials provided with the distribution.
14      3. The name of the author may not be used to endorse or promote products
15         derived from this software without specific prior written permission.
16 
17    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
20    NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27 
28 /* $XFree86: xc/programs/Xserver/hw/darwin/darwinKeyboard.c,v 1.16 2002/03/28 02:21:08 torrey Exp $ */
29 
30 
31 /* An X keyCode must be in the range XkbMinLegalKeyCode (8) to
32    XkbMaxLegalKeyCode(255).
33 
34    The keyCodes we get from the kernel range from 0 to 127, so we need to
35    offset the range before passing the keyCode to X.
36 
37    An X KeySym is an extended ascii code that is device independent.
38 
39    The modifier map is accessed by the keyCode, but the normal map is
40    accessed by keyCode - MIN_KEYCODE.  Sigh. */
41 
42 
43 /* Define this to get a diagnostic output to stderr which is helpful
44    in determining how the X server is interpreting the Darwin keymap. */
45 #undef DUMP_DARWIN_KEYMAP
46 
47 /* Define this to use Alt for Mode_switch. */
48 #define ALT_IS_MODE_SWITCH 1
49 
50 #include "darwin.h"
51 #include "darwin-keyboard.h"
52 
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include "darwin.h"
56 #include "quartz-audio.h"
57 
58 /* For NX_ constants */
59 #include <IOKit/hidsystem/IOLLEvent.h>
60 #include <IOKit/hidsystem/ev_keymap.h>
61 
62 #include "keysym.h"
63 
64 static darwin_keyboard_info info;
65 
66 static void
DarwinChangeKeyboardControl(DeviceIntPtr device,KeybdCtrl * ctrl)67 DarwinChangeKeyboardControl (DeviceIntPtr device, KeybdCtrl *ctrl)
68 {
69     /* keyclick, bell volume / pitch, autorepeat, LED's */
70 }
71 
72 /* Use the key_map field of INFO to populate the mod_map and
73    modifier_keycodes fields */
74 static void
build_modifier_maps(darwin_keyboard_info * info)75 build_modifier_maps (darwin_keyboard_info *info)
76 {
77     int i;
78     KeySym *k;
79 
80     memset (info->mod_map, NoSymbol, sizeof (info->mod_map));
81     memset (info->modifier_keycodes, 0, sizeof (info->modifier_keycodes));
82 
83     for (i = 0; i < NUM_KEYCODES; i++)
84     {
85 	k = info->key_map + i * GLYPHS_PER_KEY;
86 
87 	switch (k[0])
88 	{
89 	case XK_Shift_L:
90 	    info->modifier_keycodes[NX_MODIFIERKEY_SHIFT][0] = i;
91 	    info->mod_map[MIN_KEYCODE + i] = ShiftMask;
92 	    break;
93 
94 	case XK_Shift_R:
95 	    info->modifier_keycodes[NX_MODIFIERKEY_SHIFT][1] = i;
96 	    info->mod_map[MIN_KEYCODE + i] = ShiftMask;
97 	    break;
98 
99 	case XK_Control_L:
100 	    info->modifier_keycodes[NX_MODIFIERKEY_CONTROL][0] = i;
101 	    info->mod_map[MIN_KEYCODE + i] = ControlMask;
102 	    break;
103 
104 	case XK_Control_R:
105 	    info->modifier_keycodes[NX_MODIFIERKEY_CONTROL][1] = i;
106 	    info->mod_map[MIN_KEYCODE + i] = ControlMask;
107 	    break;
108 
109 	case XK_Caps_Lock:
110 	    info->modifier_keycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
111 	    info->mod_map[MIN_KEYCODE + i] = LockMask;
112 	    break;
113 
114 	case XK_Alt_L:
115 	    info->modifier_keycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
116 	    info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
117 	    break;
118 
119 	case XK_Alt_R:
120 	    info->modifier_keycodes[NX_MODIFIERKEY_ALTERNATE][1] = i;
121 	    info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
122 	    break;
123 
124 	case XK_Mode_switch:
125 	    info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
126 	    break;
127 
128 	case XK_Meta_L:
129 	    info->modifier_keycodes[NX_MODIFIERKEY_COMMAND][0] = i;
130 	    info->mod_map[MIN_KEYCODE + i] = Mod2Mask;
131 	    break;
132 
133 	case XK_Meta_R:
134 	    info->modifier_keycodes[NX_MODIFIERKEY_COMMAND][1] = i;
135 	    info->mod_map[MIN_KEYCODE + i] = Mod2Mask;
136 	    break;
137 
138 	case XK_Num_Lock:
139 	    info->mod_map[MIN_KEYCODE + i] = Mod3Mask;
140 	    break;
141 	}
142 
143 	if (darwinSwapAltMeta)
144 	{
145 	    switch (k[0])
146 	    {
147 	    case XK_Alt_L:
148 		k[0] = XK_Meta_L; break;
149 	    case XK_Alt_R:
150 		k[0] = XK_Meta_R; break;
151 	    case XK_Meta_L:
152 		k[0] = XK_Alt_L; break;
153 	    case XK_Meta_R:
154 		k[0] = XK_Alt_R; break;
155 	    }
156 	}
157 
158 #if ALT_IS_MODE_SWITCH
159 	if (k[0] == XK_Alt_L || k[0] == XK_Alt_R)
160 	    k[0] = XK_Mode_switch;
161 #endif
162     }
163 }
164 
165 static void
load_keyboard_mapping(KeySymsRec * keysyms)166 load_keyboard_mapping (KeySymsRec *keysyms)
167 {
168     memset (info.key_map, 0, sizeof (info.key_map));
169 
170     if (darwinKeymapFile == NULL
171 	|| !DarwinParseKeymapFile (&info))
172     {
173 	/* Load the system keymapping. */
174 
175 	DarwinReadSystemKeymap (&info);
176     }
177 
178     build_modifier_maps (&info);
179 
180 #ifdef DUMP_DARWIN_KEYMAP
181     ErrorF("Darwin -> X converted keyboard map\n");
182     for (i = 0, k = map; i < NX_NUMKEYCODES; i++, k += GLYPHS_PER_KEY) {
183         int j;
184         ErrorF("0x%02x:", i);
185         for (j = 0; j < GLYPHS_PER_KEY; j++) {
186             if (k[j] == NoSymbol) {
187                 ErrorF("\tNoSym");
188             } else {
189                 ErrorF("\t0x%x", k[j]);
190             }
191         }
192         ErrorF("\n");
193     }
194 #endif
195 
196     keysyms->map = info.key_map;
197     keysyms->mapWidth = GLYPHS_PER_KEY;
198     keysyms->minKeyCode = MIN_KEYCODE;
199     keysyms->maxKeyCode = MAX_KEYCODE;
200 }
201 
202 /* Get the Darwin keyboard map and compute an equivalent X keyboard map
203    and modifier map. Set the new keyboard device structure. */
204 void
DarwinKeyboardInit(DeviceIntPtr pDev)205 DarwinKeyboardInit (DeviceIntPtr pDev)
206 {
207     KeySymsRec keysyms;
208     BellProcPtr bellProc;
209 
210     load_keyboard_mapping (&keysyms);
211 
212     /* Initialize the seed, so we don't reload the keymap unnecessarily
213        (and possibly overwrite xinitrc changes) */
214     DarwinSystemKeymapSeed ();
215 
216     bellProc = QuartzBell;
217 
218     InitKeyboardDeviceStruct ((DevicePtr) pDev, &keysyms, info.mod_map,
219 			      bellProc, DarwinChangeKeyboardControl);
220 }
221 
222 /* Borrowed from dix/devices.c */
223 static Bool
InitModMap(register KeyClassPtr keyc)224 InitModMap(register KeyClassPtr keyc)
225 {
226     int i, j;
227     CARD8 keysPerModifier[8];
228     CARD8 mask;
229 
230     if (keyc->modifierKeyMap != NULL)
231 	xfree (keyc->modifierKeyMap);
232 
233     keyc->maxKeysPerModifier = 0;
234     for (i = 0; i < 8; i++)
235 	keysPerModifier[i] = 0;
236     for (i = 8; i < MAP_LENGTH; i++)
237     {
238 	for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
239 	{
240 	    if (mask & keyc->modifierMap[i])
241 	    {
242 		if (++keysPerModifier[j] > keyc->maxKeysPerModifier)
243 		    keyc->maxKeysPerModifier = keysPerModifier[j];
244 	    }
245 	}
246     }
247     keyc->modifierKeyMap = (KeyCode *)xalloc(8*keyc->maxKeysPerModifier);
248     if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier)
249 	return (FALSE);
250     bzero((char *)keyc->modifierKeyMap, 8*(int)keyc->maxKeysPerModifier);
251     for (i = 0; i < 8; i++)
252 	keysPerModifier[i] = 0;
253     for (i = 8; i < MAP_LENGTH; i++)
254     {
255 	for (j = 0, mask = 1; j < 8; j++, mask <<= 1)
256 	{
257 	    if (mask & keyc->modifierMap[i])
258 	    {
259 		keyc->modifierKeyMap[(j*keyc->maxKeysPerModifier) +
260 				     keysPerModifier[j]] = i;
261 		keysPerModifier[j]++;
262 	    }
263 	}
264     }
265     return TRUE;
266 }
267 
268 void
DarwinKeyboardReload(DeviceIntPtr pDev)269 DarwinKeyboardReload (DeviceIntPtr pDev)
270 {
271     KeySymsRec keysyms;
272 
273     load_keyboard_mapping (&keysyms);
274 
275     if (SetKeySymsMap (&pDev->key->curKeySyms, &keysyms))
276     {
277 	/* now try to update modifiers. */
278 
279 	memmove (pDev->key->modifierMap, info.mod_map, MAP_LENGTH);
280 	InitModMap (pDev->key);
281     }
282 
283     SendMappingNotify (MappingKeyboard, MIN_KEYCODE, NUM_KEYCODES, 0);
284     SendMappingNotify (MappingModifier, 0, 0, 0);
285 }
286 
287 /* Return the keycode for an NX_MODIFIERKEY_* modifier. side = 0 for left
288    or 1 for right. Returns 0 if key+side is not a known modifier. */
289 int
DarwinModifierNXKeyToNXKeycode(int key,int side)290 DarwinModifierNXKeyToNXKeycode (int key, int side)
291 {
292     return info.modifier_keycodes[key][side];
293 }
294 
295 /* This allows the ddx layer to prevent some keys from being remapped
296    as modifier keys. */
297 Bool
LegalModifier(unsigned int key,DevicePtr pDev)298 LegalModifier (unsigned int key, DevicePtr pDev)
299 {
300     return 1;
301 }
302