diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw/sun/sunKbd.c')
-rw-r--r-- | nx-X11/programs/Xserver/hw/sun/sunKbd.c | 1071 |
1 files changed, 1071 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/sun/sunKbd.c b/nx-X11/programs/Xserver/hw/sun/sunKbd.c new file mode 100644 index 000000000..a11026d6f --- /dev/null +++ b/nx-X11/programs/Xserver/hw/sun/sunKbd.c @@ -0,0 +1,1071 @@ +/* $Xorg: sunKbd.c,v 1.3 2000/08/17 19:48:30 cpqbld Exp $ */ +/*- + * Copyright 1987 by the Regents of the University of California + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +/************************************************************ +Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright no- +tice appear in all copies and that both that copyright no- +tice and this permission notice appear in supporting docu- +mentation, and that the names of Sun or The Open Group +not be used in advertising or publicity pertaining to +distribution of the software without specific prior +written permission. Sun and The Open Group make no +representations about the suitability of this software for +any purpose. It is provided "as is" without any express or +implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ +/* $XFree86: xc/programs/Xserver/hw/sun/sunKbd.c,v 1.8 2001/10/28 03:33:11 tsi Exp $ */ + +#define NEED_EVENTS +#include "sun.h" +#include "keysym.h" +#include "Sunkeysym.h" +#include "mi.h" + +#ifdef XKB +#include <X11/extensions/XKB.h> +#include <X11/extensions/XKBstr.h> +#include <X11/extensions/XKBsrv.h> +#endif + +#define SUN_LED_MASK 0x0f +#define MIN_KEYCODE 7 /* necessary to avoid the mouse buttons */ +#define MAX_KEYCODE 255 /* limited by the protocol */ +#ifndef KB_SUN4 +#define KB_SUN4 4 +#endif + +#define AUTOREPEAT_INITIATE 400 +#define AUTOREPEAT_DELAY 50 + +#define tvminus(tv, tv1, tv2) /* tv = tv1 - tv2 */ \ + if ((tv1).tv_usec < (tv2).tv_usec) { \ + (tv1).tv_usec += 1000000; \ + (tv1).tv_sec -= 1; \ + } \ + (tv).tv_usec = (tv1).tv_usec - (tv2).tv_usec; \ + (tv).tv_sec = (tv1).tv_sec - (tv2).tv_sec; + +#define tvplus(tv, tv1, tv2) /* tv = tv1 + tv2 */ \ + (tv).tv_sec = (tv1).tv_sec + (tv2).tv_sec; \ + (tv).tv_usec = (tv1).tv_usec + (tv2).tv_usec; \ + if ((tv).tv_usec > 1000000) { \ + (tv).tv_usec -= 1000000; \ + (tv).tv_sec += 1; \ + } + +extern KeySymsRec sunKeySyms[]; +extern SunModmapRec* sunModMaps[]; + +long sunAutoRepeatInitiate = 1000 * AUTOREPEAT_INITIATE; +long sunAutoRepeatDelay = 1000 * AUTOREPEAT_DELAY; + +static int autoRepeatKeyDown = 0; +static int autoRepeatReady; +static int autoRepeatFirst; +#if defined(_LP64) || defined(_I32LPx) +static struct timeval32 autoRepeatLastKeyDownTv; +static struct timeval32 autoRepeatDeltaTv; +#else +static struct timeval autoRepeatLastKeyDownTv; +static struct timeval autoRepeatDeltaTv; +#endif + +void sunKbdWait() +{ + static struct timeval lastChngKbdTransTv; + struct timeval tv; + struct timeval lastChngKbdDeltaTv; + unsigned int lastChngKbdDelta; + + X_GETTIMEOFDAY(&tv); + if (!lastChngKbdTransTv.tv_sec) + lastChngKbdTransTv = tv; + tvminus(lastChngKbdDeltaTv, tv, lastChngKbdTransTv); + lastChngKbdDelta = TVTOMILLI(lastChngKbdDeltaTv); + if (lastChngKbdDelta < 750) { + unsigned wait; + /* + * We need to guarantee at least 750 milliseconds between + * calls to KIOCTRANS. YUCK! + */ + wait = (750L - lastChngKbdDelta) * 1000L; + usleep (wait); + X_GETTIMEOFDAY(&tv); + } + lastChngKbdTransTv = tv; +} + +static void SwapLKeys(keysyms) + KeySymsRec* keysyms; +{ + unsigned int i; + KeySym k; + + for (i = 2; i < keysyms->maxKeyCode * keysyms->mapWidth; i++) + if (keysyms->map[i] == XK_L1 || + keysyms->map[i] == XK_L2 || + keysyms->map[i] == XK_L3 || + keysyms->map[i] == XK_L4 || + keysyms->map[i] == XK_L5 || + keysyms->map[i] == XK_L6 || + keysyms->map[i] == XK_L7 || + keysyms->map[i] == XK_L8 || + keysyms->map[i] == XK_L9 || + keysyms->map[i] == XK_L10) { + /* yes, I could have done a clever two line swap! */ + k = keysyms->map[i - 2]; + keysyms->map[i - 2] = keysyms->map[i]; + keysyms->map[i] = k; + } +} + +static void SetLights (ctrl, fd) + KeybdCtrl* ctrl; + int fd; +{ +#ifdef KIOCSLED + static unsigned char led_tab[16] = { + 0, + LED_NUM_LOCK, + LED_SCROLL_LOCK, + LED_SCROLL_LOCK | LED_NUM_LOCK, + LED_COMPOSE, + LED_COMPOSE | LED_NUM_LOCK, + LED_COMPOSE | LED_SCROLL_LOCK, + LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK, + LED_CAPS_LOCK, + LED_CAPS_LOCK | LED_NUM_LOCK, + LED_CAPS_LOCK | LED_SCROLL_LOCK, + LED_CAPS_LOCK | LED_SCROLL_LOCK | LED_NUM_LOCK, + LED_CAPS_LOCK | LED_COMPOSE, + LED_CAPS_LOCK | LED_COMPOSE | LED_NUM_LOCK, + LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK, + LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK + }; + if (ioctl (fd, KIOCSLED, (caddr_t)&led_tab[ctrl->leds & 0x0f]) == -1) + Error("Failed to set keyboard lights"); +#endif +} + + +static void ModLight (device, on, led) + DeviceIntPtr device; + Bool on; + int led; +{ + KeybdCtrl* ctrl = &device->kbdfeed->ctrl; + sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; + + if(on) { + ctrl->leds |= led; + pPriv->leds |= led; + } else { + ctrl->leds &= ~led; + pPriv->leds &= ~led; + } + SetLights (ctrl, pPriv->fd); +} + +/*- + *----------------------------------------------------------------------- + * sunBell -- + * Ring the terminal/keyboard bell + * + * Results: + * Ring the keyboard bell for an amount of time proportional to + * "loudness." + * + * Side Effects: + * None, really... + * + *----------------------------------------------------------------------- + */ + +static void bell ( + int fd, + int duration) +{ + int kbdCmd; /* Command to give keyboard */ + + kbdCmd = KBD_CMD_BELL; + if (ioctl (fd, KIOCCMD, &kbdCmd) == -1) { + Error("Failed to activate bell"); + return; + } + if (duration) usleep (duration); + kbdCmd = KBD_CMD_NOBELL; + if (ioctl (fd, KIOCCMD, &kbdCmd) == -1) + Error ("Failed to deactivate bell"); +} + +static void sunBell ( + int percent, + DeviceIntPtr device, + pointer ctrl, + int unused) +{ + KeybdCtrl* kctrl = (KeybdCtrl*) ctrl; + sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; + + if (percent == 0 || kctrl->bell == 0) + return; + + bell (pPriv->fd, kctrl->bell_duration * 1000); +} + +static void sunEnqueueEvent (xE) + xEvent* xE; +{ +#ifndef i386 + sigset_t holdmask; + +#ifdef SVR4 + (void) sigaddset (&holdmask, SIGPOLL); +#else + (void) sigaddset (&holdmask, SIGIO); +#endif + (void) sigprocmask (SIG_BLOCK, &holdmask, (sigset_t*)NULL); + mieqEnqueue (xE); + (void) sigprocmask (SIG_UNBLOCK, &holdmask, (sigset_t*)NULL); +#else + int oldmask = sigblock (sigmask (SIGIO)); + + mieqEnqueue (xE); + sigsetmask (oldmask); +#endif +} + + +#define XLED_NUM_LOCK 0x1 +#define XLED_COMPOSE 0x4 +#define XLED_SCROLL_LOCK 0x2 +#define XLED_CAPS_LOCK 0x8 + +static KeyCode LookupKeyCode (keysym, keysymsrec) + KeySym keysym; + KeySymsPtr keysymsrec; +{ + KeyCode i; + int ii, index = 0; + + for (i = keysymsrec->minKeyCode; i < keysymsrec->maxKeyCode; i++) + for (ii = 0; ii < keysymsrec->mapWidth; ii++) + if (keysymsrec->map[index++] == keysym) + return i; + return 0; +} + +static void pseudoKey(device, down, keycode) + DeviceIntPtr device; + Bool down; + KeyCode keycode; +{ + int bit; + CARD8 modifiers; + CARD16 mask; + BYTE* kptr; + + kptr = &device->key->down[keycode >> 3]; + bit = 1 << (keycode & 7); + modifiers = device->key->modifierMap[keycode]; + if (down) { + /* fool dix into thinking this key is now "down" */ + int i; + *kptr |= bit; + device->key->prev_state = device->key->state; + for (i = 0, mask = 1; modifiers; i++, mask <<= 1) + if (mask & modifiers) { + device->key->modifierKeyCount[i]++; + device->key->state += mask; + modifiers &= ~mask; + } + } else { + /* fool dix into thinking this key is now "up" */ + if (*kptr & bit) { + int i; + *kptr &= ~bit; + device->key->prev_state = device->key->state; + for (i = 0, mask = 1; modifiers; i++, mask <<= 1) + if (mask & modifiers) { + if (--device->key->modifierKeyCount[i] <= 0) { + device->key->state &= ~mask; + device->key->modifierKeyCount[i] = 0; + } + modifiers &= ~mask; + } + } + } +} + +static void DoLEDs(device, ctrl, pPriv) + DeviceIntPtr device; /* Keyboard to alter */ + KeybdCtrl* ctrl; + sunKbdPrivPtr pPriv; +{ +#ifdef XKB + if (noXkbExtension) { +#endif + if ((ctrl->leds & XLED_CAPS_LOCK) && !(pPriv->leds & XLED_CAPS_LOCK)) + pseudoKey(device, TRUE, + LookupKeyCode(XK_Caps_Lock, &device->key->curKeySyms)); + + if (!(ctrl->leds & XLED_CAPS_LOCK) && (pPriv->leds & XLED_CAPS_LOCK)) + pseudoKey(device, FALSE, + LookupKeyCode(XK_Caps_Lock, &device->key->curKeySyms)); + + if ((ctrl->leds & XLED_NUM_LOCK) && !(pPriv->leds & XLED_NUM_LOCK)) + pseudoKey(device, TRUE, + LookupKeyCode(XK_Num_Lock, &device->key->curKeySyms)); + + if (!(ctrl->leds & XLED_NUM_LOCK) && (pPriv->leds & XLED_NUM_LOCK)) + pseudoKey(device, FALSE, + LookupKeyCode(XK_Num_Lock, &device->key->curKeySyms)); + + if ((ctrl->leds & XLED_SCROLL_LOCK) && !(pPriv->leds & XLED_SCROLL_LOCK)) + pseudoKey(device, TRUE, + LookupKeyCode(XK_Scroll_Lock, &device->key->curKeySyms)); + + if (!(ctrl->leds & XLED_SCROLL_LOCK) && (pPriv->leds & XLED_SCROLL_LOCK)) + pseudoKey(device, FALSE, + LookupKeyCode(XK_Scroll_Lock, &device->key->curKeySyms)); + + if ((ctrl->leds & XLED_COMPOSE) && !(pPriv->leds & XLED_COMPOSE)) + pseudoKey(device, TRUE, + LookupKeyCode(SunXK_Compose, &device->key->curKeySyms)); + + if (!(ctrl->leds & XLED_COMPOSE) && (pPriv->leds & XLED_COMPOSE)) + pseudoKey(device, FALSE, + LookupKeyCode(SunXK_Compose, &device->key->curKeySyms)); +#ifdef XKB + } +#endif + pPriv->leds = ctrl->leds & 0x0f; + SetLights (ctrl, pPriv->fd); +} + +/*- + *----------------------------------------------------------------------- + * sunKbdCtrl -- + * Alter some of the keyboard control parameters + * + * Results: + * None. + * + * Side Effects: + * Some... + * + *----------------------------------------------------------------------- + */ + +static void sunKbdCtrl ( + DeviceIntPtr device, + KeybdCtrl* ctrl) +{ + sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; + + if (pPriv->fd < 0) return; + + if (ctrl->click != pPriv->click) { + int kbdClickCmd; + + pPriv->click = ctrl->click; + kbdClickCmd = pPriv->click ? KBD_CMD_CLICK : KBD_CMD_NOCLICK; + if (ioctl (pPriv->fd, KIOCCMD, &kbdClickCmd) == -1) + Error("Failed to set keyclick"); + } + if ((pPriv->type == KB_SUN4) && (pPriv->leds != (ctrl->leds & 0x0f))) + DoLEDs(device, ctrl, pPriv); +} + +/*- + *----------------------------------------------------------------------- + * sunInitKbdNames -- + * Handle the XKB initialization + * + * Results: + * None. + * + * Comments: + * This function needs considerable work, in conjunctions with + * the need to add geometry descriptions of Sun Keyboards. + * It would also be nice to have #defines for all the keyboard + * layouts so that we don't have to have these hard-coded + * numbers. + * + *----------------------------------------------------------------------- + */ +#ifdef XKB +static void sunInitKbdNames ( + XkbComponentNamesRec* names, + sunKbdPrivPtr pKbd) +{ +#ifndef XKBBUFSIZE +#define XKBBUFSIZE 64 +#endif + static char keycodesbuf[XKBBUFSIZE]; + static char geometrybuf[XKBBUFSIZE]; + static char symbolsbuf[XKBBUFSIZE]; + + names->keymap = NULL; + names->compat = "compat/complete"; + names->types = "types/complete"; + names->keycodes = keycodesbuf; + names->geometry = geometrybuf; + names->symbols = symbolsbuf; + (void) strcpy (keycodesbuf, "keycodes/"); + (void) strcpy (geometrybuf, "geometry/"); + (void) strcpy (symbolsbuf, "symbols/"); + + /* keycodes & geometry */ + switch (pKbd->type) { + case KB_SUN2: + (void) strcat (names->keycodes, "sun(type2)"); + (void) strcat (names->geometry, "sun(type2)"); + (void) strcat (names->symbols, "us(sun2)"); + break; + case KB_SUN3: + (void) strcat (names->keycodes, "sun(type3)"); + (void) strcat (names->geometry, "sun(type3)"); + (void) strcat (names->symbols, "us(sun3)"); + break; + case KB_SUN4: + /* First, catch "fully known" models */ + switch (pKbd->layout) { + case 11: /* type4, Sweden */ + (void) strcat (names->geometry, "sun(type4_se)"); + (void) strcat (names->keycodes, + "sun(type4_se_swapctl)"); + (void) strcat (names->symbols, + "sun/se(sun4)+se(fixdollar)"); + return; + break; + case 43: /* type5/5c, Sweden */ + (void) strcat (names->geometry, "sun(type5c_se)"); + (void) strcat (names->keycodes, "sun(type5_se)"); + (void) strcat (names->symbols, + "sun/se(sun5)+se(fixdollar)"); + return; + break; + case 90: /* "Compact 1", Sweden (???) */ + break; /* No specific mapping, yet */ + default: + break; + } + + if (pKbd->layout == 19) { + (void) strcat (names->keycodes, "sun(US101A)"); + (void) strcat (names->geometry, "pc101-NG"); /* XXX */ + (void) strcat (names->symbols, "us(pc101)"); + } else if (pKbd->layout < 33) { + (void) strcat (names->keycodes, "sun(type4)"); + (void) strcat (names->geometry, "sun(type4)"); + if (sunSwapLkeys) + (void) strcat (names->symbols, "sun/us(sun4ol)"); + else + (void) strcat (names->symbols, "sun/us(sun4)"); + } else { + (void) strcat (names->keycodes, "sun(type5)"); + + switch (pKbd->layout) { + case 33: case 80: /* U.S. */ + case 47: case 94: /* Korea */ + case 48: case 95: /* Taiwan */ + case 49: case 96: /* Japan */ + (void) strcat (names->geometry, "sun(type5)"); + break; + case 34: case 81: /* U.S. Unix */ + (void) strcat (names->geometry, "sun(type5unix)"); + break; + default: + (void) strcat (names->geometry, "sun(type5euro)"); + } + + if (sunSwapLkeys) + (void) strcat (names->symbols, "sun/us(sun5ol)"); + else + (void) strcat (names->symbols, "sun/us(sun5)"); + } + break; + default: + names->keycodes = names->geometry = NULL; + break; + } + + /* extra symbols */ + + if (pKbd->type == KB_SUN4) { + switch (pKbd->layout) { + case 4: case 36: case 83: + case 5: case 37: case 84: + case 6: case 38: case 85: + case 8: case 40: case 87: + case 9: case 41: case 88: + case 10: case 42: case 89: +/* case 11: case 43: case 90: */ /* handled earlier */ + case 12: case 44: case 91: + case 13: case 45: case 92: + case 14: case 46: case 93: + (void) strcat (names->symbols, "+iso9995-3(basic)"); break; + } + } + + if (pKbd->type == KB_SUN4) { + switch (pKbd->layout) { + case 0: case 1: case 33: case 34: case 80: case 81: + break; + case 3: + (void) strcat (names->symbols, "+ca"); break; + case 4: case 36: case 83: + (void) strcat (names->symbols, "+dk"); break; + case 5: case 37: case 84: + (void) strcat (names->symbols, "+de"); break; + case 6: case 38: case 85: + (void) strcat (names->symbols, "+it"); break; + case 8: case 40: case 87: + (void) strcat (names->symbols, "+no"); break; + case 9: case 41: case 88: + (void) strcat (names->symbols, "+pt"); break; + case 10: case 42: case 89: + (void) strcat (names->symbols, "+es"); break; + /* case 11: case 43: */ /* handled earlier */ + case 90: + (void) strcat (names->symbols, "+se"); break; + case 12: case 44: case 91: + (void) strcat (names->symbols, "+fr_CH"); break; + case 13: case 45: case 92: + (void) strcat (names->symbols, "+de_CH"); break; + case 14: case 46: case 93: + (void) strcat (names->symbols, "+gb"); break; /* s/b en_UK */ + case 52: + (void) strcat (names->symbols, "+pl"); break; + case 53: + (void) strcat (names->symbols, "+cs"); break; + case 54: + (void) strcat (names->symbols, "+ru"); break; +#if 0 + /* don't have symbols defined for these yet, let them default */ + case 2: + (void) strcat (names->symbols, "+fr_BE"); break; + case 7: case 39: case 86: + (void) strcat (names->symbols, "+nl"); break; + case 50: case 97: + (void) strcat (names->symbols, "+fr_CA"); break; + case 16: case 47: case 94: + (void) strcat (names->symbols, "+ko"); break; + case 17: case 48: case 95: + (void) strcat (names->symbols, "+tw"); break; + case 32: case 49: case 96: + (void) strcat (names->symbols, "+jp"); break; + case 51: + (void) strcat (names->symbols, "+hu"); break; +#endif + /* + * by setting the symbols to NULL XKB will use the symbols in + * the "default" keymap. + */ + default: + names->symbols = NULL; return; break; + } + } +} +#endif /* XKB */ + +/*- + *----------------------------------------------------------------------- + * sunKbdProc -- + * Handle the initialization, etc. of a keyboard. + * + * Results: + * None. + * + *----------------------------------------------------------------------- + */ + +int sunKbdProc ( + DeviceIntPtr device, + int what) +{ + int i; + DevicePtr pKeyboard = (DevicePtr) device; + sunKbdPrivPtr pPriv; + KeybdCtrl* ctrl = &device->kbdfeed->ctrl; + extern int XkbDfltRepeatDelay, XkbDfltRepeatInterval; + + static CARD8 *workingModMap = NULL; + static KeySymsRec *workingKeySyms; + + switch (what) { + case DEVICE_INIT: + if (pKeyboard != LookupKeyboardDevice()) { + ErrorF ("Cannot open non-system keyboard\n"); + return (!Success); + } + + if (!workingKeySyms) { + workingKeySyms = &sunKeySyms[sunKbdPriv.type]; + + if (sunKbdPriv.type == KB_SUN4 && sunSwapLkeys) + SwapLKeys(workingKeySyms); + + if (workingKeySyms->minKeyCode < MIN_KEYCODE) { + workingKeySyms->minKeyCode += MIN_KEYCODE; + workingKeySyms->maxKeyCode += MIN_KEYCODE; + } + if (workingKeySyms->maxKeyCode > MAX_KEYCODE) + workingKeySyms->maxKeyCode = MAX_KEYCODE; + } + + if (!workingModMap) { + workingModMap=(CARD8 *)xalloc(MAP_LENGTH); + (void) memset(workingModMap, 0, MAP_LENGTH); + for(i=0; sunModMaps[sunKbdPriv.type][i].key != 0; i++) + workingModMap[sunModMaps[sunKbdPriv.type][i].key + MIN_KEYCODE] = + sunModMaps[sunKbdPriv.type][i].modifiers; + } + + (void) memset ((void *) defaultKeyboardControl.autoRepeats, + ~0, sizeof defaultKeyboardControl.autoRepeats); + +#ifdef XKB + if (noXkbExtension) { + sunAutoRepeatInitiate = XkbDfltRepeatDelay * 1000; + sunAutoRepeatDelay = XkbDfltRepeatInterval * 1000; +#endif + autoRepeatKeyDown = 0; +#ifdef XKB + } +#endif + pKeyboard->devicePrivate = (pointer)&sunKbdPriv; + pKeyboard->on = FALSE; + +#ifdef XKB + if (noXkbExtension) { +#endif + InitKeyboardDeviceStruct(pKeyboard, + workingKeySyms, workingModMap, + sunBell, sunKbdCtrl); +#ifdef XKB + } else { + XkbComponentNamesRec names; + sunInitKbdNames (&names, &sunKbdPriv); + XkbInitKeyboardDeviceStruct((DeviceIntPtr) pKeyboard, &names, + workingKeySyms, workingModMap, + sunBell, sunKbdCtrl); + } +#endif + break; + + case DEVICE_ON: + pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; + /* + * Set the keyboard into "direct" mode and turn on + * event translation. + */ + if (sunChangeKbdTranslation(pPriv->fd,TRUE) == -1) + FatalError("Can't set keyboard translation\n"); + AddEnabledDevice(pPriv->fd); + pKeyboard->on = TRUE; + break; + + case DEVICE_CLOSE: + case DEVICE_OFF: + pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; + if (pPriv->type == KB_SUN4) { + /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */ + pPriv->leds = 0; + ctrl->leds = 0; + SetLights(ctrl, pPriv->fd); + } + /* + * Restore original keyboard directness and translation. + */ + if (sunChangeKbdTranslation(pPriv->fd,FALSE) == -1) + FatalError("Can't reset keyboard translation\n"); + RemoveEnabledDevice(pPriv->fd); + pKeyboard->on = FALSE; + break; + default: + FatalError("Unknown keyboard operation\n"); + } + return Success; +} + +/*- + *----------------------------------------------------------------------- + * sunKbdGetEvents -- + * Return the events waiting in the wings for the given keyboard. + * + * Results: + * A pointer to an array of Firm_events or (Firm_event *)0 if no events + * The number of events contained in the array. + * A boolean as to whether more events might be available. + * + * Side Effects: + * None. + *----------------------------------------------------------------------- + */ + +Firm_event* sunKbdGetEvents ( + int fd, + Bool on, + int* pNumEvents, + Bool* pAgain) +{ + int nBytes; /* number of bytes of events available. */ + static Firm_event evBuf[MAXEVENTS]; /* Buffer for Firm_events */ + + if ((nBytes = read (fd, evBuf, sizeof(evBuf))) == -1) { + if (errno == EWOULDBLOCK) { + *pNumEvents = 0; + *pAgain = FALSE; + } else { + Error ("Reading keyboard"); + FatalError ("Could not read the keyboard"); + } + } else { + if (on) { + *pNumEvents = nBytes / sizeof (Firm_event); + *pAgain = (nBytes == sizeof (evBuf)); + } else { + *pNumEvents = 0; + *pAgain = FALSE; + } + } + return evBuf; +} + +/*- + *----------------------------------------------------------------------- + * sunKbdEnqueueEvent -- + * + *----------------------------------------------------------------------- + */ +static xEvent autoRepeatEvent; +static int composeCount; + +static Bool DoSpecialKeys(device, xE, fe) + DeviceIntPtr device; + xEvent* xE; + Firm_event* fe; +{ + int shift_index, map_index, bit; + KeySym ksym; + BYTE* kptr; + sunKbdPrivPtr pPriv = (sunKbdPrivPtr)device->public.devicePrivate; + BYTE keycode = xE->u.u.detail; + CARD8 keyModifiers = device->key->modifierMap[keycode]; + + /* look up the present idea of the keysym */ + shift_index = 0; + if (device->key->state & ShiftMask) + shift_index ^= 1; + if (device->key->state & LockMask) + shift_index ^= 1; + map_index = (fe->id - 1) * device->key->curKeySyms.mapWidth; + ksym = device->key->curKeySyms.map[shift_index + map_index]; + if (ksym == NoSymbol) + ksym = device->key->curKeySyms.map[map_index]; + + /* + * Toggle functionality is hardcoded. This is achieved by always + * discarding KeyReleases on these keys, and converting every other + * KeyPress into a KeyRelease. + */ + if (xE->u.u.type == KeyRelease + && (ksym == XK_Num_Lock + || ksym == XK_Scroll_Lock + || ksym == SunXK_Compose + || (keyModifiers & LockMask))) + return TRUE; + + kptr = &device->key->down[keycode >> 3]; + bit = 1 << (keycode & 7); + if ((*kptr & bit) && + (ksym == XK_Num_Lock || ksym == XK_Scroll_Lock || + ksym == SunXK_Compose || (keyModifiers & LockMask))) + xE->u.u.type = KeyRelease; + + if (pPriv->type == KB_SUN4) { + if (ksym == XK_Num_Lock) { + ModLight (device, xE->u.u.type == KeyPress, XLED_NUM_LOCK); + } else if (ksym == XK_Scroll_Lock) { + ModLight (device, xE->u.u.type == KeyPress, XLED_SCROLL_LOCK); + } else if (ksym == SunXK_Compose) { + ModLight (device, xE->u.u.type == KeyPress, XLED_COMPOSE); + if (xE->u.u.type == KeyPress) composeCount = 2; + else composeCount = 0; + } else if (keyModifiers & LockMask) { + ModLight (device, xE->u.u.type == KeyPress, XLED_CAPS_LOCK); + } + if (xE->u.u.type == KeyRelease) { + if (composeCount > 0 && --composeCount == 0) { + pseudoKey(device, FALSE, + LookupKeyCode(SunXK_Compose, &device->key->curKeySyms)); + ModLight (device, FALSE, XLED_COMPOSE); + } + } + } + + if ((xE->u.u.type == KeyPress) && (keyModifiers == 0)) { + /* initialize new AutoRepeater event & mark AutoRepeater on */ + autoRepeatEvent = *xE; + autoRepeatFirst = TRUE; + autoRepeatKeyDown++; + autoRepeatLastKeyDownTv = fe->time; + } + return FALSE; +} + +void sunKbdEnqueueEvent ( + DeviceIntPtr device, + Firm_event *fe) +{ + xEvent xE; + BYTE keycode; + CARD8 keyModifiers; + + keycode = (fe->id & 0x7f) + MIN_KEYCODE; + + keyModifiers = device->key->modifierMap[keycode]; +#ifdef XKB + if (noXkbExtension) { +#endif + if (autoRepeatKeyDown && (keyModifiers == 0) && + ((fe->value == VKEY_DOWN) || (keycode == autoRepeatEvent.u.u.detail))) { + /* + * Kill AutoRepeater on any real non-modifier key down, or auto key up + */ + autoRepeatKeyDown = 0; + } +#ifdef XKB + } +#endif + xE.u.keyButtonPointer.time = TVTOMILLI(fe->time); + xE.u.u.type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress); + xE.u.u.detail = keycode; +#ifdef XKB + if (noXkbExtension) { +#endif + if (DoSpecialKeys(device, &xE, fe)) + return; +#ifdef XKB + } +#endif /* ! XKB */ + mieqEnqueue (&xE); +} + +void sunEnqueueAutoRepeat () +{ + int delta; + int i, mask; + DeviceIntPtr device = (DeviceIntPtr)LookupKeyboardDevice(); + KeybdCtrl* ctrl = &device->kbdfeed->ctrl; + sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; + + if (ctrl->autoRepeat != AutoRepeatModeOn) { + autoRepeatKeyDown = 0; + return; + } + i=(autoRepeatEvent.u.u.detail >> 3); + mask=(1 << (autoRepeatEvent.u.u.detail & 7)); + if (!(ctrl->autoRepeats[i] & mask)) { + autoRepeatKeyDown = 0; + return; + } + + /* + * Generate auto repeat event. XXX one for now. + * Update time & pointer location of saved KeyPress event. + */ + + delta = TVTOMILLI(autoRepeatDeltaTv); + autoRepeatFirst = FALSE; + + /* + * Fake a key up event and a key down event + * for the last key pressed. + */ + autoRepeatEvent.u.keyButtonPointer.time += delta; + autoRepeatEvent.u.u.type = KeyRelease; + + /* + * hold off any more inputs while we get these safely queued up + * further SIGIO are + */ + sunEnqueueEvent (&autoRepeatEvent); + autoRepeatEvent.u.u.type = KeyPress; + sunEnqueueEvent (&autoRepeatEvent); + if (ctrl->click) bell (pPriv->fd, 0); + + /* Update time of last key down */ + tvplus(autoRepeatLastKeyDownTv, autoRepeatLastKeyDownTv, + autoRepeatDeltaTv); +} + +/*- + *----------------------------------------------------------------------- + * sunChangeKbdTranslation + * Makes operating system calls to set keyboard translation + * and direction on or off. + * + * Results: + * -1 if failure, else 0. + * + * Side Effects: + * Changes kernel management of keyboard. + * + *----------------------------------------------------------------------- + */ +int sunChangeKbdTranslation( + int fd, + Bool makeTranslated) + +{ + int tmp; +#ifndef i386 /* { */ + sigset_t hold_mask, old_mask; +#else /* }{ */ + int old_mask; +#endif /* } */ + int toread; + char junk[8192]; + +#ifndef i386 /* { */ + (void) sigfillset(&hold_mask); + (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask); +#else /* }{ */ + old_mask = sigblock (~0); +#endif /* } */ + sunKbdWait(); + if (makeTranslated) { + /* + * Next set the keyboard into "direct" mode and turn on + * event translation. If either of these fails, we can't go + * on. + */ + tmp = 1; + if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) { + Error ("Setting keyboard direct mode"); + return -1; + } + tmp = TR_UNTRANS_EVENT; + if (ioctl (fd, KIOCTRANS, &tmp) == -1) { + Error ("Setting keyboard translation"); + ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd); + return -1; + } + } else { + /* + * Next set the keyboard into "indirect" mode and turn off + * event translation. + */ + tmp = 0; + (void)ioctl (fd, KIOCSDIRECT, &tmp); + tmp = TR_ASCII; + (void)ioctl (fd, KIOCTRANS, &tmp); + } + if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) { + while (toread) { + tmp = toread; + if (toread > sizeof (junk)) + tmp = sizeof (junk); + (void) read (fd, junk, tmp); + toread -= tmp; + } + } +#ifndef i386 /* { */ + (void) sigprocmask(SIG_SETMASK, &old_mask, (sigset_t *)NULL); +#else /* }{ */ + sigsetmask (old_mask); +#endif /* } */ + return 0; +} + +/*ARGSUSED*/ +Bool LegalModifier(key, pDev) + unsigned int key; + DevicePtr pDev; +{ + return TRUE; +} + +/*ARGSUSED*/ +void sunBlockHandler(nscreen, pbdata, pptv, pReadmask) + int nscreen; + pointer pbdata; + struct timeval **pptv; + pointer pReadmask; +{ + KeybdCtrl* ctrl = &((DeviceIntPtr)LookupKeyboardDevice())->kbdfeed->ctrl; + static struct timeval artv = { 0, 0 }; /* autorepeat timeval */ + + if (!autoRepeatKeyDown) + return; + + if (ctrl->autoRepeat != AutoRepeatModeOn) + return; + + if (autoRepeatFirst == TRUE) + artv.tv_usec = sunAutoRepeatInitiate; + else + artv.tv_usec = sunAutoRepeatDelay; + *pptv = &artv; + +} + +/*ARGSUSED*/ +void sunWakeupHandler(nscreen, pbdata, err, pReadmask) + int nscreen; + pointer pbdata; + unsigned long err; + pointer pReadmask; +{ + KeybdCtrl* ctrl = &((DeviceIntPtr)LookupKeyboardDevice())->kbdfeed->ctrl; + struct timeval tv; + + if (ctrl->autoRepeat != AutoRepeatModeOn) + return; + + if (autoRepeatKeyDown) { + X_GETTIMEOFDAY(&tv); + tvminus(autoRepeatDeltaTv, tv, autoRepeatLastKeyDownTv); + if (autoRepeatDeltaTv.tv_sec > 0 || + (!autoRepeatFirst && autoRepeatDeltaTv.tv_usec > + sunAutoRepeatDelay) || + (autoRepeatDeltaTv.tv_usec > + sunAutoRepeatInitiate)) + autoRepeatReady++; + } + + if (autoRepeatReady) + { + sunEnqueueAutoRepeat (); + autoRepeatReady = 0; + } +} |