summaryrefslogtreecommitdiff
path: root/hw/kdrive/src/kinput.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/kdrive/src/kinput.c')
-rw-r--r--hw/kdrive/src/kinput.c1331
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 ();
+}
+