diff options
Diffstat (limited to 'hw/kdrive/src/kinput.c')
-rw-r--r-- | hw/kdrive/src/kinput.c | 1331 |
1 files changed, 1331 insertions, 0 deletions
diff --git a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c new file mode 100644 index 000000000..27207ac1e --- /dev/null +++ b/hw/kdrive/src/kinput.c @@ -0,0 +1,1331 @@ +/* + * $Id$ + * + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE 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: $ */ + +#include "kdrive.h" +#include "inputstr.h" + +#include <X11/keysym.h> +#include "kkeymap.h" +#include <signal.h> +#include <stdio.h> + +static DeviceIntPtr pKdKeyboard, pKdPointer; + +static KdMouseFuncs *kdMouseFuncs; +static KdKeyboardFuncs *kdKeyboardFuncs; +static int kdMouseFd = -1; +static int kdKeyboardFd = -1; +static unsigned long kdEmulationTimeout; +static Bool kdTimeoutPending; +static int kdBellPitch; +static int kdBellDuration; +static int kdLeds; + +int kdMinScanCode; +int kdMaxScanCode; +int kdMinKeyCode; +int kdMaxKeyCode; +int kdKeymapWidth = KD_MAX_WIDTH; +KeySym kdKeymap[KD_MAX_LENGTH * KD_MAX_WIDTH]; +CARD8 kdModMap[MAP_LENGTH]; +KeySymsRec kdKeySyms; + + +void +KdResetInputMachine (void); + +#define KD_MOUSEBUTTON_COUNT 3 + +#define KD_KEY_COUNT 248 + +CARD8 kdKeyState[KD_KEY_COUNT/8]; + +#define IsKeyDown(key) ((kdKeyState[(key) >> 3] >> ((key) & 7)) & 1) + +void +KdSigio (int sig) +{ + if (kdMouseFd >= 0) + (*kdMouseFuncs->Read) (kdMouseFd); + if (kdKeyboardFd >= 0) + (*kdKeyboardFuncs->Read) (kdKeyboardFd); +} + +void +KdBlockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_BLOCK, &set, 0); +} + +void +KdUnblockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_UNBLOCK, &set, 0); +} + +#define VERIFY_SIGIO +#ifdef VERIFY_SIGIO + +void +KdAssertSigioBlocked (char *where) +{ + sigset_t set, old; + + sigemptyset (&set); + sigprocmask (SIG_BLOCK, &set, &old); + if (!sigismember (&old, SIGIO)) + ErrorF ("SIGIO not blocked at %s\n", where); +} + +#else + +#define KdVerifySigioBlocked(s) + +#endif + +static int kdnFds; + +#ifdef FNONBLOCK +#define NOBLOCK FNONBLOCK +#else +#define NOBLOCK FNDELAY +#endif + +void +KdAddFd (int fd) +{ + int flags; + struct sigaction act; + sigset_t set; + + kdnFds++; + fcntl (fd, F_SETOWN, getpid()); + flags = fcntl (fd, F_GETFL); + flags |= FASYNC|NOBLOCK; + fcntl (fd, F_SETFL, flags); + AddEnabledDevice (fd); + act.sa_handler = KdSigio; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + act.sa_restorer = 0; + sigaction (SIGIO, &act, 0); + sigemptyset (&set); + sigprocmask (SIG_SETMASK, &set, 0); +} + +void +KdRemoveFd (int fd) +{ + struct sigaction act; + int flags; + + kdnFds--; + RemoveEnabledDevice (fd); + flags = fcntl (fd, F_GETFL); + flags &= ~(FASYNC|NOBLOCK); + fcntl (fd, F_SETFL, flags); + if (kdnFds == 0) + { + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + act.sa_restorer = 0; + sigaction (SIGIO, &act, 0); + } +} + +void +KdDisableInput (void) +{ + if (kdMouseFd >= 0) + KdRemoveFd (kdMouseFd); + if (kdKeyboardFd >= 0) + KdRemoveFd (kdKeyboardFd); +} + +void +KdEnableInput (void) +{ + if (kdMouseFd >= 0) + KdAddFd (kdMouseFd); + if (kdKeyboardFd >= 0) + KdAddFd (kdKeyboardFd); +} + +static int +KdMouseProc(DeviceIntPtr pDevice, int onoff) +{ + BYTE map[4]; + DevicePtr pDev = (DevicePtr)pDevice; + int i; + + if (!pDev) + return BadImplementation; + + switch (onoff) + { + case DEVICE_INIT: + for (i = 1; i <= KD_MOUSEBUTTON_COUNT; i++) + map[i] = i; + InitPointerDeviceStruct(pDev, map, KD_MOUSEBUTTON_COUNT, + miPointerGetMotionEvents, + (PtrCtrlProcPtr)NoopDDA, + miPointerGetMotionBufferSize()); + break; + + case DEVICE_ON: + pDev->on = TRUE; + pKdPointer = pDevice; + if (kdMouseFuncs) + { + kdMouseFd = (*kdMouseFuncs->Init) (); + if (kdMouseFd >= 0) + KdAddFd (kdMouseFd); + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + if (pDev->on) + { + pDev->on = FALSE; + pKdPointer = 0; + if (kdMouseFd >= 0) + { + KdRemoveFd (kdMouseFd); + (*kdMouseFuncs->Fini) (kdMouseFd); + kdMouseFd = -1; + } + } + break; + } + return Success; +} + +Bool +LegalModifier(unsigned int key, DevicePtr pDev) +{ + return TRUE; +} + +static void +KdBell (int volume, DeviceIntPtr pDev, pointer ctrl, int something) +{ + (*kdKeyboardFuncs->Bell) (volume, kdBellPitch, kdBellDuration); +} + + +static void +KdSetLeds (void) +{ + (*kdKeyboardFuncs->Leds) (kdLeds); +} + +void +KdSetLed (int led, Bool on) +{ + NoteLedState (pKdKeyboard, led, on); + kdLeds = pKdKeyboard->kbdfeed->ctrl.leds; + KdSetLeds (); +} + +static void +KdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + kdLeds = ctrl->leds; + kdBellPitch = ctrl->bell_pitch; + kdBellDuration = ctrl->bell_duration; + KdSetLeds (); +} + +static int +KdKeybdProc(DeviceIntPtr pDevice, int onoff) +{ + Bool ret; + DevicePtr pDev = (DevicePtr)pDevice; + + if (!pDev) + return BadImplementation; + + switch (onoff) + { + case DEVICE_INIT: + if (pDev != LookupKeyboardDevice()) + { + return !Success; + } + ret = InitKeyboardDeviceStruct(pDev, + &kdKeySyms, + kdModMap, + KdBell, KdKbdCtrl); + if (!ret) + return BadImplementation; + break; + case DEVICE_ON: + pDev->on = TRUE; + pKdKeyboard = pDevice; + if (kdKeyboardFuncs) + { + kdKeyboardFd = (*kdKeyboardFuncs->Init) (); + if (kdKeyboardFd >= 0) + KdAddFd (kdKeyboardFd); + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + pKdKeyboard = 0; + if (pDev->on) + { + pDev->on = FALSE; + if (kdKeyboardFd >= 0) + { + KdRemoveFd (kdKeyboardFd); + (*kdKeyboardFuncs->Fini) (kdKeyboardFd); + kdKeyboardFd = -1; + } + } + break; + } + return Success; +} + +extern KeybdCtrl defaultKeyboardControl; + +void +InitAutoRepeats (void) +{ + int key_code; + unsigned char mask; + int i; + unsigned char *repeats; + + repeats = defaultKeyboardControl.autoRepeats; + memset (repeats, '\0', 32); + for (key_code = KD_MIN_KEYCODE; key_code <= KD_MAX_KEYCODE; key_code++) + { + if (!kdModMap[key_code]) + { + i = key_code >> 3; + mask = 1 << (key_code & 7); + repeats[i] |= mask; + } + } +} + +void +InitModMap (void) +{ + int key_code; + int row; + int width; + KeySym *syms; + + width = kdKeySyms.mapWidth; + for (key_code = kdMinKeyCode; key_code <= kdMaxKeyCode; key_code++) + { + kdModMap[key_code] = 0; + syms = kdKeymap + (key_code - kdMinKeyCode) * width; + for (row = 0; row < width; row++, syms++) + { + switch (*syms) { + case XK_Control_L: + case XK_Control_R: + kdModMap[key_code] |= ControlMask; + break; + case XK_Shift_L: + case XK_Shift_R: + kdModMap[key_code] |= ShiftMask; + break; + case XK_Caps_Lock: + case XK_Shift_Lock: + kdModMap[key_code] |= LockMask; + break; + case XK_Alt_L: + case XK_Alt_R: + case XK_Meta_L: + case XK_Meta_R: + kdModMap[key_code] |= Mod1Mask; + break; + case XK_Num_Lock: + kdModMap[key_code] |= Mod2Mask; + break; + case XK_Super_L: + case XK_Super_R: + case XK_Hyper_L: + case XK_Hyper_R: + kdModMap[key_code] |= Mod3Mask; + break; + case XK_Mode_switch: + kdModMap[key_code] |= Mod4Mask; + break; + } + } + } +} + +void +KdInitInput(KdMouseFuncs *pMouseFuncs, + KdKeyboardFuncs *pKeyboardFuncs) +{ + DeviceIntPtr pKeyboard, pPointer; + + kdMouseFuncs = pMouseFuncs; + kdKeyboardFuncs = pKeyboardFuncs; + memset (kdKeyState, '\0', sizeof (kdKeyState)); + if (kdKeyboardFuncs) + (*kdKeyboardFuncs->Load) (); + kdMinKeyCode = kdMinScanCode + KD_KEY_OFFSET; + kdMaxKeyCode = kdMaxScanCode + KD_KEY_OFFSET; + kdKeySyms.map = kdKeymap; + kdKeySyms.minKeyCode = kdMinKeyCode; + kdKeySyms.maxKeyCode = kdMaxKeyCode; + kdKeySyms.mapWidth = kdKeymapWidth; + kdLeds = 0; + kdBellPitch = 1000; + kdBellDuration = 200; + InitModMap (); + InitAutoRepeats (); + KdResetInputMachine (); + pPointer = AddInputDevice(KdMouseProc, TRUE); + pKeyboard = AddInputDevice(KdKeybdProc, TRUE); + RegisterPointerDevice(pPointer); + RegisterKeyboardDevice(pKeyboard); + miRegisterPointerDevice(screenInfo.screens[0], pPointer); + mieqInit(&pKeyboard->public, &pPointer->public); +} + +/* + * Middle button emulation state machine + * + * Possible transitions: + * Button 1 press v1 + * Button 1 release ^1 + * Button 2 press v2 + * Button 2 release ^2 + * Button 3 press v3 + * Button 3 release ^3 + * Mouse motion <> + * Keyboard event k + * timeout ... + * outside box <-> + * + * States: + * start + * button_1_pend + * button_1_down + * button_2_down + * button_3_pend + * button_3_down + * synthetic_2_down_13 + * synthetic_2_down_3 + * synthetic_2_down_1 + * + * Transition diagram + * + * start + * v1 -> (hold) (settimeout) button_1_pend + * ^1 -> (deliver) start + * v2 -> (deliver) button_2_down + * ^2 -> (deliever) start + * v3 -> (hold) (settimeout) button_3_pend + * ^3 -> (deliver) start + * <> -> (deliver) start + * k -> (deliver) start + * + * button_1_pend (button 1 is down, timeout pending) + * ^1 -> (release) (deliver) start + * v2 -> (release) (deliver) button_1_down + * ^2 -> (release) (deliver) button_1_down + * v3 -> (cleartimeout) (generate v2) synthetic_2_down_13 + * ^3 -> (release) (deliver) button_1_down + * <-> -> (release) (deliver) button_1_down + * <> -> (deliver) button_1_pend + * k -> (release) (deliver) button_1_down + * ... -> (release) button_1_down + * + * button_1_down (button 1 is down) + * ^1 -> (deliver) start + * v2 -> (deliver) button_1_down + * ^2 -> (deliver) button_1_down + * v3 -> (deliver) button_1_down + * ^3 -> (deliver) button_1_down + * <> -> (deliver) button_1_down + * k -> (deliver) button_1_down + * + * button_2_down (button 2 is down) + * v1 -> (deliver) button_2_down + * ^1 -> (deliver) button_2_down + * ^2 -> (deliver) start + * v3 -> (deliver) button_2_down + * ^3 -> (deliver) button_2_down + * <> -> (deliver) button_2_down + * k -> (deliver) button_2_down + * + * button_3_pend (button 3 is down, timeout pending) + * v1 -> (generate v2) synthetic_2_down + * ^1 -> (release) (deliver) button_3_down + * v2 -> (release) (deliver) button_3_down + * ^2 -> (release) (deliver) button_3_down + * ^3 -> (release) (deliver) start + * <-> -> (release) (deliver) button_3_down + * <> -> (deliver) button_3_pend + * k -> (release) (deliver) button_3_down + * ... -> (release) button_3_down + * + * button_3_down (button 3 is down) + * v1 -> (deliver) button_3_down + * ^1 -> (deliver) button_3_down + * v2 -> (deliver) button_3_down + * ^2 -> (deliver) button_3_down + * ^3 -> (deliver) start + * <> -> (deliver) button_3_down + * k -> (deliver) button_3_down + * + * synthetic_2_down_13 (button 1 and 3 are down) + * ^1 -> (generate ^2) synthetic_2_down_3 + * v2 -> synthetic_2_down_13 + * ^2 -> synthetic_2_down_13 + * ^3 -> (generate ^2) synthetic_2_down_1 + * <> -> (deliver) synthetic_2_down_13 + * k -> (deliver) synthetic_2_down_13 + * + * synthetic_2_down_3 (button 3 is down) + * v1 -> (deliver) synthetic_2_down_3 + * ^1 -> (deliver) synthetic_2_down_3 + * v2 -> synthetic_2_down_3 + * ^2 -> synthetic_2_down_3 + * ^3 -> start + * <> -> (deliver) synthetic_2_down_3 + * k -> (deliver) synthetic_2_down_3 + * + * synthetic_2_down_1 (button 1 is down) + * ^1 -> start + * v2 -> synthetic_2_down_1 + * ^2 -> synthetic_2_down_1 + * v3 -> (deliver) synthetic_2_down_1 + * ^3 -> (deliver) synthetic_2_down_1 + * <> -> (deliver) synthetic_2_down_1 + * k -> (deliver) synthetic_2_down_1 + */ + +typedef enum _inputState { + start, + button_1_pend, + button_1_down, + button_2_down, + button_3_pend, + button_3_down, + synth_2_down_13, + synth_2_down_3, + synth_2_down_1, + num_input_states +} KdInputState; + +typedef enum _inputClass { + down_1, up_1, + down_2, up_2, + down_3, up_3, + motion, outside_box, + keyboard, timeout, + num_input_class +} KdInputClass; + +typedef enum _inputAction { + noop, + hold, + setto, + deliver, + release, + clearto, + gen_down_2, + gen_up_2 +} KdInputAction; + +#define MAX_ACTIONS 2 + +typedef struct _inputTransition { + KdInputAction actions[MAX_ACTIONS]; + KdInputState nextState; +} KdInputTransition; + +KdInputTransition kdInputMachine[num_input_states][num_input_class] = { + /* start */ + { + { { hold, setto }, button_1_pend }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { hold, setto }, button_3_pend }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, start }, /* <> */ + { { deliver, noop }, start }, /* <-> */ + { { deliver, noop }, start }, /* k */ + { { noop, noop }, start }, /* ... */ + }, + /* button_1_pend */ + { + { { noop, noop }, button_1_pend }, /* v1 */ + { { release, deliver }, start }, /* ^1 */ + { { release, deliver }, button_1_down }, /* v2 */ + { { release, deliver }, button_1_down }, /* ^2 */ + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v3 */ + { { release, deliver }, button_1_down }, /* ^3 */ + { { deliver, noop }, button_1_pend }, /* <> */ + { { release, deliver }, button_1_down }, /* <-> */ + { { release, deliver }, button_1_down }, /* k */ + { { release, noop }, button_1_down }, /* ... */ + }, + /* button_1_down */ + { + { { noop, noop }, button_1_down }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_1_down }, /* v2 */ + { { deliver, noop }, button_1_down }, /* ^2 */ + { { deliver, noop }, button_1_down }, /* v3 */ + { { deliver, noop }, button_1_down }, /* ^3 */ + { { deliver, noop }, button_1_down }, /* <> */ + { { deliver, noop }, button_1_down }, /* <-> */ + { { deliver, noop }, button_1_down }, /* k */ + { { noop, noop }, button_1_down }, /* ... */ + }, + /* button_2_down */ + { + { { deliver, noop }, button_2_down }, /* v1 */ + { { deliver, noop }, button_2_down }, /* ^1 */ + { { noop, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { deliver, noop }, button_2_down }, /* v3 */ + { { deliver, noop }, button_2_down }, /* ^3 */ + { { deliver, noop }, button_2_down }, /* <> */ + { { deliver, noop }, button_2_down }, /* <-> */ + { { deliver, noop }, button_2_down }, /* k */ + { { noop, noop }, button_2_down }, /* ... */ + }, + /* button_3_pend */ + { + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v1 */ + { { release, deliver }, button_3_down }, /* ^1 */ + { { release, deliver }, button_3_down }, /* v2 */ + { { release, deliver }, button_3_down }, /* ^2 */ + { { release, deliver }, button_3_down }, /* v3 */ + { { release, deliver }, start }, /* ^3 */ + { { deliver, noop }, button_3_pend }, /* <> */ + { { release, deliver }, button_3_down }, /* <-> */ + { { release, deliver }, button_3_down }, /* k */ + { { release, noop }, button_3_down }, /* ... */ + }, + /* button_3_down */ + { + { { deliver, noop }, button_3_down }, /* v1 */ + { { deliver, noop }, button_3_down }, /* ^1 */ + { { deliver, noop }, button_3_down }, /* v2 */ + { { deliver, noop }, button_3_down }, /* ^2 */ + { { noop, noop }, button_3_down }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, button_3_down }, /* <> */ + { { deliver, noop }, button_3_down }, /* <-> */ + { { deliver, noop }, button_3_down }, /* k */ + { { noop, noop }, button_3_down }, /* ... */ + }, + /* synthetic_2_down_13 */ + { + { { noop, noop }, synth_2_down_13 }, /* v1 */ + { { gen_up_2, noop }, synth_2_down_3 }, /* ^1 */ + { { noop, noop }, synth_2_down_13 }, /* v2 */ + { { noop, noop }, synth_2_down_13 }, /* ^2 */ + { { noop, noop }, synth_2_down_13 }, /* v3 */ + { { gen_up_2, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_13 }, /* <> */ + { { deliver, noop }, synth_2_down_13 }, /* <-> */ + { { deliver, noop }, synth_2_down_13 }, /* k */ + { { noop, noop }, synth_2_down_13 }, /* ... */ + }, + /* synthetic_2_down_3 */ + { + { { deliver, noop }, synth_2_down_3 }, /* v1 */ + { { deliver, noop }, synth_2_down_3 }, /* ^1 */ + { { deliver, noop }, synth_2_down_3 }, /* v2 */ + { { deliver, noop }, synth_2_down_3 }, /* ^2 */ + { { noop, noop }, synth_2_down_3 }, /* v3 */ + { { noop, noop }, start }, /* ^3 */ + { { deliver, noop }, synth_2_down_3 }, /* <> */ + { { deliver, noop }, synth_2_down_3 }, /* <-> */ + { { deliver, noop }, synth_2_down_3 }, /* k */ + { { noop, noop }, synth_2_down_3 }, /* ... */ + }, + /* synthetic_2_down_1 */ + { + { { noop, noop }, synth_2_down_1 }, /* v1 */ + { { noop, noop }, start }, /* ^1 */ + { { deliver, noop }, synth_2_down_1 }, /* v2 */ + { { deliver, noop }, synth_2_down_1 }, /* ^2 */ + { { deliver, noop }, synth_2_down_1 }, /* v3 */ + { { deliver, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_1 }, /* <> */ + { { deliver, noop }, synth_2_down_1 }, /* <-> */ + { { deliver, noop }, synth_2_down_1 }, /* k */ + { { noop, noop }, synth_2_down_1 }, /* ... */ + }, +}; + +Bool kdEventHeld; +xEvent kdHeldEvent; +int kdEmulationDx, kdEmulationDy; + +#define EMULATION_WINDOW 10 +#define EMULATION_TIMEOUT 30 + +#define EventX(e) ((e)->u.keyButtonPointer.rootX) +#define EventY(e) ((e)->u.keyButtonPointer.rootY) + +KdInsideEmulationWindow (xEvent *ev) +{ + if (ev->u.keyButtonPointer.pad1) + { + kdEmulationDx += EventX(ev); + kdEmulationDy += EventY(ev); + } + else + { + kdEmulationDx = EventX(&kdHeldEvent) - EventX(ev); + kdEmulationDy = EventY(&kdHeldEvent) - EventY(ev); + } + return (abs (kdEmulationDx) < EMULATION_WINDOW && + abs (kdEmulationDy) < EMULATION_WINDOW); +} + +KdInputClass +KdClassifyInput (xEvent *ev) +{ + switch (ev->u.u.type) { + case ButtonPress: + switch (ev->u.u.detail) { + case 1: return down_1; + case 2: return down_2; + case 3: return down_3; + } + break; + case ButtonRelease: + switch (ev->u.u.detail) { + case 1: return up_1; + case 2: return up_2; + case 3: return up_3; + } + break; + case MotionNotify: + if (kdEventHeld && !KdInsideEmulationWindow(ev)) + return outside_box; + else + return motion; + default: + return keyboard; + } +} + +#ifndef NDEBUG +char *kdStateNames[] = { + "start", + "button_1_pend", + "button_1_down", + "button_2_down", + "button_3_pend", + "button_3_down", + "synth_2_down_13", + "synth_2_down_3", + "synthetic_2_down_1", + "num_input_states" +}; + +char *kdClassNames[] = { + "down_1", "up_1", + "down_2", "up_2", + "down_3", "up_3", + "motion", "ouside_box", + "keyboard", "timeout", + "num_input_class" +}; + +char *kdActionNames[] = { + "noop", + "hold", + "setto", + "deliver", + "release", + "clearto", + "gen_down_2", + "gen_up_2", +}; +#endif + +static void +KdQueueEvent (xEvent *ev) +{ + KdAssertSigioBlocked ("KdQueueEvent"); + if (ev->u.u.type == MotionNotify) + { + if (ev->u.keyButtonPointer.pad1) + { + ev->u.keyButtonPointer.pad1 = 0; + miPointerDeltaCursor (ev->u.keyButtonPointer.rootX, + ev->u.keyButtonPointer.rootY, + ev->u.keyButtonPointer.time); + } + else + { + miPointerAbsoluteCursor(ev->u.keyButtonPointer.rootX, + ev->u.keyButtonPointer.rootY, + ev->u.keyButtonPointer.time); + } + } + else + { + mieqEnqueue (ev); + } +} + +KdInputState kdInputState; + +static void +KdRunInputMachine (KdInputClass c, xEvent *ev) +{ + KdInputTransition *t; + int a; + + t = &kdInputMachine[kdInputState][c]; + for (a = 0; a < MAX_ACTIONS; a++) + { + switch (t->actions[a]) { + case noop: + break; + case hold: + kdEventHeld = TRUE; + kdEmulationDx = 0; + kdEmulationDy = 0; + kdHeldEvent = *ev; + break; + case setto: + kdEmulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; + kdTimeoutPending = TRUE; + break; + case deliver: + KdQueueEvent (ev); + break; + case release: + kdEventHeld = FALSE; + kdTimeoutPending = FALSE; + KdQueueEvent (&kdHeldEvent); + break; + case clearto: + kdTimeoutPending = FALSE; + break; + case gen_down_2: + ev->u.u.detail = 2; + kdEventHeld = FALSE; + KdQueueEvent (ev); + break; + case gen_up_2: + ev->u.u.detail = 2; + KdQueueEvent (ev); + break; + } + } + kdInputState = t->nextState; +} + +void +KdResetInputMachine (void) +{ + kdInputState = start; + kdEventHeld = FALSE; +} + +void +KdHandleEvent (xEvent *ev) +{ + if (kdEmulateMiddleButton) + KdRunInputMachine (KdClassifyInput (ev), ev); + else + KdQueueEvent (ev); +} + +void +KdReceiveTimeout (void) +{ + KdRunInputMachine (timeout, 0); +} + +#define KILL_SEQUENCE ((1L << KK_CONTROL)|(1L << KK_ALT)|(1L << KK_F8)|(1L << KK_F10)) +#define SPECIAL_SEQUENCE ((1L << KK_CONTROL) | (1L << KK_ALT)) +#define SETKILLKEY(b) (KdSpecialKeys |= (1L << (b))) +#define CLEARKILLKEY(b) (KdSpecialKeys &= ~(1L << (b))) +#define KEYMAP (pKdKeyboard->key->curKeySyms) +#define KEYCOL1(k) (KEYMAP.map[((k)-kdMinKeyCode)*KEYMAP.mapWidth]) + +CARD32 KdSpecialKeys = 0; + +extern char dispatchException; + +/* + * kdCheckTermination + * + * This function checks for the key sequence that terminates the server. When + * detected, it sets the dispatchException flag and returns. The key sequence + * is: + * Control-Alt + * It's assumed that the server will be waken up by the caller when this + * function returns. + */ + +extern int nClients; + +void +KdCheckSpecialKeys(xEvent *xE) +{ + KeySym sym; + + if (!pKdKeyboard) return; + + /* + * Ignore key releases + */ + + if (xE->u.u.type == KeyRelease) return; + + /* + * Check for control/alt pressed + */ + if ((pKdKeyboard->key->state & (ControlMask|Mod1Mask)) != + (ControlMask|Mod1Mask)) + return; + + sym = KEYCOL1(xE->u.u.detail); + + /* + * Let OS function see keysym first + */ + + if (kdOsFuncs->SpecialKey) + if ((*kdOsFuncs->SpecialKey) (sym)) + return; + + /* + * Now check for backspace or delete; these signal the + * X server to terminate + */ + switch (sym) { + case XK_BackSpace: + case XK_Delete: + case XK_KP_Delete: + /* + * Set the dispatch exception flag so the server will terminate the + * next time through the dispatch loop. + */ + dispatchException |= DE_TERMINATE; + break; + } +} + +/* + * kdEnqueueKeyboardEvent + * + * This function converts hardware keyboard event information into an X event + * and enqueues it using MI. It wakes up the server before returning so that + * the event will be processed normally. + * + */ + +void +KdHandleKeyboardEvent (xEvent *ev) +{ + int key = ev->u.u.detail; + int byte; + CARD8 bit; + + byte = key >> 3; + bit = 1 << (key & 7); + switch (ev->u.u.type) { + case KeyPress: + kdKeyState[byte] |= bit; + break; + case KeyRelease: + kdKeyState[byte] &= ~bit; + break; + } + KdHandleEvent (ev); +} + +void +KdReleaseAllKeys (void) +{ + xEvent xE; + int key; + + for (key = 0; key < KD_KEY_COUNT; key++) + if (IsKeyDown(key)) + { + xE.u.keyButtonPointer.time = GetTimeInMillis(); + xE.u.u.type = KeyRelease; + xE.u.u.detail = key; + KdHandleKeyboardEvent (&xE); + } +} + +void +KdCheckLock (void) +{ + KeyClassPtr keyc = pKdKeyboard->key; + Bool isSet, shouldBeSet; + + if (kdKeyboardFuncs->LockLed) + { + isSet = (kdLeds & (1 << (kdKeyboardFuncs->LockLed-1))) != 0; + shouldBeSet = (keyc->state & LockMask) != 0; + if (isSet != shouldBeSet) + { + KdSetLed (kdKeyboardFuncs->LockLed, shouldBeSet); + } + } +} + +void +KdEnqueueKeyboardEvent(unsigned char scan_code, + unsigned char is_up) +{ + unsigned char key_code; + xEvent xE; + int e; + KeyClassPtr keyc; + + if (!pKdKeyboard) + return; + keyc = pKdKeyboard->key; + + xE.u.keyButtonPointer.time = GetTimeInMillis(); + + if (kdMinScanCode <= scan_code && scan_code <= kdMaxScanCode) + { + key_code = scan_code + KD_MIN_KEYCODE - kdMinScanCode; + + /* + * Set up this event -- the type may be modified below + */ + if (is_up) + xE.u.u.type = KeyRelease; + else + xE.u.u.type = KeyPress; + xE.u.u.detail = key_code; + + switch (KEYCOL1(key_code)) + { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + if (xE.u.u.type == KeyRelease) + return; + if (IsKeyDown (key_code)) + xE.u.u.type = KeyRelease; + else + xE.u.u.type = KeyPress; + } + + /* + * Check pressed keys which are already down + */ + if (IsKeyDown (key_code) && xE.u.u.type == KeyPress) + { + KeybdCtrl *ctrl = &pKdKeyboard->kbdfeed->ctrl; + + /* + * Check auto repeat + */ + if (!ctrl->autoRepeat || keyc->modifierMap[key_code] || + !(ctrl->autoRepeats[key_code >> 3] & (1 << (key_code & 7)))) + { + return; + } + } + if (xE.u.u.type == KeyRelease && !IsKeyDown (key_code)) + { + xE.u.u.type = KeyPress; + KdHandleKeyboardEvent (&xE); + xE.u.u.type = KeyRelease; + } + KdCheckSpecialKeys (&xE); + KdHandleKeyboardEvent (&xE); + } +} + +#define SetButton(b,v, s) \ +{\ + xE.u.u.detail = b; \ + xE.u.u.type = v; \ + KdHandleEvent (&xE); \ +} + +#define Press(b) SetButton(b+1,ButtonPress,"Down") +#define Release(b) SetButton(b+1,ButtonRelease,"Up") + +unsigned char ButtonState = 0; + +/* + * kdEnqueueMouseEvent + * + * This function converts hardware mouse event information into X event + * information. A mouse movement event is passed off to MI to generate + * a MotionNotify event, if appropriate. Button events are created and + * passed off to MI for enqueueing. + */ + +static int +KdMouseAccelerate (DeviceIntPtr device, int delta) +{ + PtrCtrl *pCtrl = &device->ptrfeed->ctrl; + + if (abs(delta) > pCtrl->threshold) + delta = (delta * pCtrl->num) / pCtrl->den; + return delta; +} + +void +KdEnqueueMouseEvent(unsigned long flags, int x, int y) +{ + CARD32 ms; + xEvent xE; + unsigned char buttons; + + if (!pKdPointer) + return; + + ms = GetTimeInMillis(); + + if (flags & KD_MOUSE_DELTA) + { + x = KdMouseAccelerate (pKdPointer, x); + y = KdMouseAccelerate (pKdPointer, y); + xE.u.keyButtonPointer.pad1 = 1; + } + else + xE.u.keyButtonPointer.pad1 = 0; + xE.u.keyButtonPointer.time = ms; + xE.u.keyButtonPointer.rootX = x; + xE.u.keyButtonPointer.rootY = y; + + xE.u.u.type = MotionNotify; + xE.u.u.detail = 0; + KdHandleEvent (&xE); + + buttons = flags; + + if ((ButtonState & KD_BUTTON_1) ^ (buttons & KD_BUTTON_1)) + { + if (buttons & KD_BUTTON_1) + { + Press(0); + } + else + { + Release(0); + } + } + if ((ButtonState & KD_BUTTON_2) ^ (buttons & KD_BUTTON_2)) + { + if (buttons & KD_BUTTON_2) + { + Press(1); + } + else + { + Release(1); + } + } + if ((ButtonState & KD_BUTTON_3) ^ (buttons & KD_BUTTON_3)) + { + if (buttons & KD_BUTTON_3) + { + Press(2); + } + else + { + Release(2); + } + } + ButtonState = buttons; +} + +void +KdEnqueueMotionEvent (int x, int y) +{ + xEvent xE; + CARD32 ms; + + ms = GetTimeInMillis(); + + xE.u.u.type = MotionNotify; + xE.u.keyButtonPointer.time = ms; + xE.u.keyButtonPointer.rootX = x; + xE.u.keyButtonPointer.rootY = y; + + KdHandleEvent (&xE); +} + +void +KdBlockHandler (int screen, + pointer blockData, + pointer timeout, + pointer readmask) +{ + struct timeval **pTimeout = timeout; + + if (kdTimeoutPending) + { + static struct timeval tv; + int ms; + + ms = kdEmulationTimeout - GetTimeInMillis (); + if (ms < 0) + ms = 0; + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms % 1000) * 1000; + if (*pTimeout) + { + if ((*pTimeout)->tv_sec > tv.tv_sec || + ((*pTimeout)->tv_sec == tv.tv_sec && + (*pTimeout)->tv_usec > tv.tv_usec)) + { + *pTimeout = &tv; + } + } + else + *pTimeout = &tv; + } +} + +void +KdWakeupHandler (int screen, + pointer data, + unsigned long result, + pointer readmask) +{ + fd_set *pReadmask = (fd_set *) readmask; + + if (kdMouseFd >= 0 && FD_ISSET (kdMouseFd, pReadmask)) + { + KdBlockSigio (); + (*kdMouseFuncs->Read) (kdMouseFd); + KdUnblockSigio (); + } + if (kdKeyboardFd >= 0 && FD_ISSET (kdKeyboardFd, pReadmask)) + { + KdBlockSigio (); + (*kdKeyboardFuncs->Read) (kdKeyboardFd); + KdUnblockSigio (); + } + if (kdTimeoutPending) + { + if ((long) (GetTimeInMillis () - kdEmulationTimeout) >= 0) + { + kdTimeoutPending = FALSE; + KdBlockSigio (); + KdReceiveTimeout (); + KdUnblockSigio (); + } + } + if (kdSwitchPending) + KdProcessSwitch (); +} + +static Bool +KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + ScreenPtr pScreen = *ppScreen; + int n; + + if (kdDisableZaphod || screenInfo.numScreens <= 1) + return FALSE; + if (*x < 0) + { + n = pScreen->myNum - 1; + if (n < 0) + n = screenInfo.numScreens - 1; + pScreen = screenInfo.screens[n]; + *x += pScreen->width; + *ppScreen = pScreen; + return TRUE; + } + else if (*x >= pScreen->width) + { + n = pScreen->myNum + 1; + if (n >= screenInfo.numScreens) + n = 0; + *x -= pScreen->width; + pScreen = screenInfo.screens[n]; + *ppScreen = pScreen; + return TRUE; + } + return FALSE; +} + +static void +KdCrossScreen(ScreenPtr pScreen, Bool entering) +{ + if (entering) + KdEnableScreen (pScreen); + else + KdDisableScreen (pScreen); +} + +static void +KdWarpCursor (ScreenPtr pScreen, int x, int y) +{ + KdBlockSigio (); + miPointerWarpCursor (pScreen, x, y); + KdUnblockSigio (); +} + +miPointerScreenFuncRec kdPointerScreenFuncs = +{ + KdCursorOffScreen, + KdCrossScreen, + KdWarpCursor +}; + +void +ProcessInputEvents () +{ + (void)mieqProcessInputEvents(); + miPointerUpdate(); + if (kdSwitchPending) + KdProcessSwitch (); + KdCheckLock (); +} + |