/* darwin-keyboard.c -- Keyboard support for the Darwin X Server
Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved.
Copyright (c) 2003 Apple Computer, Inc. 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. */
/* $XFree86: xc/programs/Xserver/hw/darwin/darwinKeyboard.c,v 1.16 2002/03/28 02:21:08 torrey Exp $ */
/* 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 "darwin.h"
#include "darwin-keyboard.h"
#include <stdio.h>
#include <stdlib.h>
#include "darwin.h"
#include "quartz-audio.h"
/* For NX_ constants */
#include <IOKit/hidsystem/IOLLEvent.h>
#include <IOKit/hidsystem/ev_keymap.h>
#include "keysym.h"
static darwin_keyboard_info info;
static void
DarwinChangeKeyboardControl (DeviceIntPtr device, KeybdCtrl *ctrl)
{
/* keyclick, bell volume / pitch, autorepeat, LED's */
}
/* Use the key_map field of INFO to populate the mod_map and
modifier_keycodes fields */
static void
build_modifier_maps (darwin_keyboard_info *info)
{
int i;
KeySym *k;
memset (info->mod_map, NoSymbol, sizeof (info->mod_map));
memset (info->modifier_keycodes, 0, sizeof (info->modifier_keycodes));
for (i = 0; i < NUM_KEYCODES; i++)
{
k = info->key_map + i * GLYPHS_PER_KEY;
switch (k[0])
{
case XK_Shift_L:
info->modifier_keycodes[NX_MODIFIERKEY_SHIFT][0] = i;
info->mod_map[MIN_KEYCODE + i] = ShiftMask;
break;
case XK_Shift_R:
info->modifier_keycodes[NX_MODIFIERKEY_SHIFT][1] = i;
info->mod_map[MIN_KEYCODE + i] = ShiftMask;
break;
case XK_Control_L:
info->modifier_keycodes[NX_MODIFIERKEY_CONTROL][0] = i;
info->mod_map[MIN_KEYCODE + i] = ControlMask;
break;
case XK_Control_R:
info->modifier_keycodes[NX_MODIFIERKEY_CONTROL][1] = i;
info->mod_map[MIN_KEYCODE + i] = ControlMask;
break;
case XK_Caps_Lock:
info->modifier_keycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
info->mod_map[MIN_KEYCODE + i] = LockMask;
break;
case XK_Alt_L:
info->modifier_keycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
break;
case XK_Alt_R:
info->modifier_keycodes[NX_MODIFIERKEY_ALTERNATE][1] = i;
info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
break;
case XK_Mode_switch:
info->mod_map[MIN_KEYCODE + i] = Mod1Mask;
break;
case XK_Meta_L:
info->modifier_keycodes[NX_MODIFIERKEY_COMMAND][0] = i;
info->mod_map[MIN_KEYCODE + i] = Mod2Mask;
break;
case XK_Meta_R:
info->modifier_keycodes[NX_MODIFIERKEY_COMMAND][1] = i;
info->mod_map[MIN_KEYCODE + i] = Mod2Mask;
break;
case XK_Num_Lock:
info->mod_map[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_Alt_R)
k[0] = XK_Mode_switch;
#endif
}
}
static void
load_keyboard_mapping (KeySymsRec *keysyms)
{
memset (info.key_map, 0, sizeof (info.key_map));
if (darwinKeymapFile == NULL
|| !DarwinParseKeymapFile (&info))
{
/* Load the system keymapping. */
DarwinReadSystemKeymap (&info);
}
build_modifier_maps (&info);
#ifdef DUMP_DARWIN_KEYMAP
ErrorF("Darwin -> X converted keyboard map\n");
for (i = 0, k = map; 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 = info.key_map;
keysyms->mapWidth = GLYPHS_PER_KEY;
keysyms->minKeyCode = MIN_KEYCODE;
keysyms->maxKeyCode = MAX_KEYCODE;
}
/* 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;
BellProcPtr bellProc;
load_keyboard_mapping (&keysyms);
/* Initialize the seed, so we don't reload the keymap unnecessarily
(and possibly overwrite xinitrc changes) */
DarwinSystemKeymapSeed ();
bellProc = QuartzBell;
InitKeyboardDeviceStruct ((DevicePtr) pDev, &keysyms, info.mod_map,
bellProc, 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;
load_keyboard_mapping (&keysyms);
if (SetKeySymsMap (&pDev->key->curKeySyms, &keysyms))
{
/* now try to update modifiers. */
memmove (pDev->key->modifierMap, info.mod_map, MAP_LENGTH);
InitModMap (pDev->key);
}
SendMappingNotify (MappingKeyboard, MIN_KEYCODE, NUM_KEYCODES, 0);
SendMappingNotify (MappingModifier, 0, 0, 0);
}
/* 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 info.modifier_keycodes[key][side];
}
/* This allows the ddx layer to prevent some keys from being remapped
as modifier keys. */
Bool
LegalModifier (unsigned int key, DevicePtr pDev)
{
return 1;
}