/* * Id: kinput.c,v 1.1 1999/11/02 03:54:46 keithp Exp $ * * 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. */ /* $RCSId: xc/programs/Xserver/hw/kdrive/kinput.c,v 1.30 2002/11/13 16:37:39 keithp Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include "kdrive.h" #include "inputstr.h" #define XK_PUBLISHING #include #if HAVE_X11_XF86KEYSYM_H #include #endif #include "kkeymap.h" #include #include static DeviceIntPtr pKdKeyboard, pKdPointer; static KdMouseFuncs *kdMouseFuncs; static KdKeyboardFuncs *kdKeyboardFuncs; static int kdBellPitch; static int kdBellDuration; static int kdLeds; static Bool kdInputEnabled; static Bool kdOffScreen; static unsigned long kdOffScreenTime; static KdMouseMatrix kdMouseMatrix = { { { 1, 0, 0 }, { 0, 1, 0 } } }; #ifdef TOUCHSCREEN static KdMouseFuncs *kdTsFuncs; #endif int kdMouseButtonCount; 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_KEY_COUNT 248 CARD8 kdKeyState[KD_KEY_COUNT/8]; #define IsKeyDown(key) ((kdKeyState[(key) >> 3] >> ((key) & 7)) & 1) #define KD_MAX_INPUT_FDS 8 typedef struct _kdInputFd { int type; int fd; void (*read) (int fd, void *closure); int (*enable) (int fd, void *closure); void (*disable) (int fd, void *closure); void *closure; } KdInputFd; KdInputFd kdInputFds[KD_MAX_INPUT_FDS]; int kdNumInputFds; int kdInputTypeSequence; static void KdSigio (int sig) { int i; for (i = 0; i < kdNumInputFds; i++) (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); } static void KdBlockSigio (void) { sigset_t set; sigemptyset (&set); sigaddset (&set, SIGIO); sigprocmask (SIG_BLOCK, &set, 0); } static void KdUnblockSigio (void) { sigset_t set; sigemptyset (&set); sigaddset (&set, SIGIO); sigprocmask (SIG_UNBLOCK, &set, 0); } #undef 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 KdAssertSigioBlocked(s) #endif static int kdnFds; #ifdef FNONBLOCK #define NOBLOCK FNONBLOCK #else #define NOBLOCK FNDELAY #endif static void KdNonBlockFd (int fd) { int flags; flags = fcntl (fd, F_GETFL); flags |= FASYNC|NOBLOCK; fcntl (fd, F_SETFL, flags); } static void KdAddFd (int fd) { struct sigaction act; sigset_t set; kdnFds++; fcntl (fd, F_SETOWN, getpid()); KdNonBlockFd (fd); AddEnabledDevice (fd); memset (&act, '\0', sizeof act); act.sa_handler = KdSigio; sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, SIGIO); sigaddset (&act.sa_mask, SIGALRM); sigaddset (&act.sa_mask, SIGVTALRM); sigaction (SIGIO, &act, 0); sigemptyset (&set); sigprocmask (SIG_SETMASK, &set, 0); } static 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) { memset (&act, '\0', sizeof act); act.sa_handler = SIG_IGN; sigemptyset (&act.sa_mask); sigaction (SIGIO, &act, 0); } } int KdAllocInputType (void) { return ++kdInputTypeSequence; } Bool KdRegisterFd (int type, int fd, void (*read) (int fd, void *closure), void *closure) { if (kdNumInputFds == KD_MAX_INPUT_FDS) return FALSE; kdInputFds[kdNumInputFds].type = type; kdInputFds[kdNumInputFds].fd = fd; kdInputFds[kdNumInputFds].read = read; kdInputFds[kdNumInputFds].enable = 0; kdInputFds[kdNumInputFds].disable = 0; kdInputFds[kdNumInputFds].closure = closure; ++kdNumInputFds; if (kdInputEnabled) KdAddFd (fd); return TRUE; } void KdRegisterFdEnableDisable (int fd, int (*enable) (int fd, void *closure), void (*disable) (int fd, void *closure)) { int i; for (i = 0; i < kdNumInputFds; i++) if (kdInputFds[i].fd == fd) { kdInputFds[i].enable = enable; kdInputFds[i].disable = disable; break; } } void KdUnregisterFds (int type, Bool do_close) { int i, j; for (i = 0; i < kdNumInputFds;) { if (kdInputFds[i].type == type) { if (kdInputEnabled) KdRemoveFd (kdInputFds[i].fd); if (do_close) close (kdInputFds[i].fd); --kdNumInputFds; for (j = i; j < kdNumInputFds; j++) kdInputFds[j] = kdInputFds[j+1]; } else i++; } } void KdDisableInput (void) { int i; for (i = 0; i < kdNumInputFds; i++) { KdRemoveFd (kdInputFds[i].fd); if (kdInputFds[i].disable) (*kdInputFds[i].disable) (kdInputFds[i].fd, kdInputFds[i].closure); } kdInputEnabled = FALSE; } void KdEnableInput (void) { xEvent xE; int i; kdInputEnabled = TRUE; for (i = 0; i < kdNumInputFds; i++) { KdNonBlockFd (kdInputFds[i].fd); if (kdInputFds[i].enable) kdInputFds[i].fd = (*kdInputFds[i].enable) (kdInputFds[i].fd, kdInputFds[i].closure); KdAddFd (kdInputFds[i].fd); } /* reset screen saver */ xE.u.keyButtonPointer.time = GetTimeInMillis (); NoticeEventTime (&xE); } static int KdMouseProc(DeviceIntPtr pDevice, int onoff) { BYTE map[KD_MAX_BUTTON]; DevicePtr pDev = (DevicePtr)pDevice; int i; if (!pDev) return BadImplementation; switch (onoff) { case DEVICE_INIT: for (i = 1; i <= kdMouseButtonCount; i++) map[i] = i; InitPointerDeviceStruct(pDev, map, kdMouseButtonCount, miPointerGetMotionEvents, (PtrCtrlProcPtr)NoopDDA, miPointerGetMotionBufferSize()); break; case DEVICE_ON: pDev->on = TRUE; pKdPointer = pDevice; #ifdef TOUCHSCREEN if (kdTsFuncs) (*kdTsFuncs->Init) (); #endif if (kdMouseFuncs) (*kdMouseFuncs->Init) (); break; case DEVICE_OFF: case DEVICE_CLOSE: if (pDev->on) { pDev->on = FALSE; pKdPointer = 0; if (kdMouseFuncs) (*kdMouseFuncs->Fini) (); #ifdef TOUCHSCREEN if (kdTsFuncs) (*kdTsFuncs->Fini) (); #endif } break; } return Success; } Bool LegalModifier(unsigned int key, DevicePtr pDev) { return TRUE; } static void KdBell (int volume, DeviceIntPtr pDev, pointer ctrl, int something) { if (kdInputEnabled) (*kdKeyboardFuncs->Bell) (volume, kdBellPitch, kdBellDuration); } static void KdSetLeds (void) { if (kdInputEnabled) (*kdKeyboardFuncs->Leds) (kdLeds); } void KdSetLed (int led, Bool on) { NoteLedState (pKdKeyboard, led, on); kdLeds = pKdKeyboard->kbdfeed->ctrl.leds; KdSetLeds (); } void KdSetMouseMatrix (KdMouseMatrix *matrix) { kdMouseMatrix = *matrix; } void KdComputeMouseMatrix (KdMouseMatrix *m, Rotation randr, int width, int height) { int x_dir = 1, y_dir = 1; int i, j; int size[2]; size[0] = width; size[1] = height; if (randr & RR_Reflect_X) x_dir = -1; if (randr & RR_Reflect_Y) y_dir = -1; switch (randr & (RR_Rotate_All)) { case RR_Rotate_0: m->matrix[0][0] = x_dir; m->matrix[0][1] = 0; m->matrix[1][0] = 0; m->matrix[1][1] = y_dir; break; case RR_Rotate_90: m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir; m->matrix[1][0] = y_dir; m->matrix[1][1] = 0; break; case RR_Rotate_180: m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0; m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir; break; case RR_Rotate_270: m->matrix[0][0] = 0; m->matrix[0][1] = x_dir; m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0; break; } for (i = 0; i < 2; i++) { m->matrix[i][2] = 0; for (j = 0 ; j < 2; j++) if (m->matrix[i][j] < 0) m->matrix[i][2] = size[j] - 1; } } 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) (*kdKeyboardFuncs->Init) (); break; case DEVICE_OFF: case DEVICE_CLOSE: pKdKeyboard = 0; if (pDev->on) { pDev->on = FALSE; if (kdKeyboardFuncs) (*kdKeyboardFuncs->Fini) (); } break; } return Success; } extern KeybdCtrl defaultKeyboardControl; static void KdInitAutoRepeats (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; } } } const KdKeySymModsRec kdKeySymMods[] = { { XK_Control_L, ControlMask }, { XK_Control_R, ControlMask }, { XK_Shift_L, ShiftMask }, { XK_Shift_R, ShiftMask }, { XK_Caps_Lock, LockMask }, { XK_Shift_Lock, LockMask }, { XK_Alt_L, Mod1Mask }, { XK_Alt_R, Mod1Mask }, { XK_Meta_L, Mod1Mask }, { XK_Meta_R, Mod1Mask }, { XK_Num_Lock, Mod2Mask }, { XK_Super_L, Mod3Mask }, { XK_Super_R, Mod3Mask }, { XK_Hyper_L, Mod3Mask }, { XK_Hyper_R, Mod3Mask }, { XK_Mode_switch, Mod4Mask }, #ifdef TOUCHSCREEN /* PDA specific hacks */ #ifdef XF86XK_Start { XF86XK_Start, ControlMask }, #endif { XK_Menu, ShiftMask }, { XK_telephone, Mod1Mask }, #ifdef XF86XK_AudioRecord { XF86XK_AudioRecord, Mod2Mask }, #endif #ifdef XF86XK_Calendar { XF86XK_Calendar, Mod3Mask } #endif #endif }; #define NUM_SYM_MODS (sizeof(kdKeySymMods) / sizeof(kdKeySymMods[0])) static void KdInitModMap (void) { int key_code; int row; int width; KeySym *syms; int i; 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++) { for (i = 0; i < NUM_SYM_MODS; i++) { if (*syms == kdKeySymMods[i].modsym) kdModMap[key_code] |= kdKeySymMods[i].modbit; } } } } void KdInitInput(KdMouseFuncs *pMouseFuncs, KdKeyboardFuncs *pKeyboardFuncs) { DeviceIntPtr pKeyboard, pPointer; KdMouseInfo *mi; if (!kdMouseInfo) KdParseMouse (0); kdMouseButtonCount = 0; for (mi = kdMouseInfo; mi; mi = mi->next) { if (mi->nbutton > kdMouseButtonCount) kdMouseButtonCount = mi->nbutton; } 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; kdInputEnabled = TRUE; KdInitModMap (); KdInitAutoRepeats (); KdResetInputMachine (); pPointer = AddInputDevice(KdMouseProc, TRUE); pKeyboard = AddInputDevice(KdKeybdProc, TRUE); RegisterPointerDevice(pPointer); RegisterKeyboardDevice(pKeyboard); miRegisterPointerDevice(screenInfo.screens[0], pPointer); mieqInit(&pKeyboard->public, &pPointer->public); #ifdef XINPUT { static long zero1, zero2; SetExtInputCheck (&zero1, &zero2); } #endif } #ifdef TOUCHSCREEN void KdInitTouchScreen(KdMouseFuncs *pTsFuncs) { kdTsFuncs = pTsFuncs; } #endif /* * 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 * Button other press vo * Button other release ^o * 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 * vo -> (deliver) start * ^o -> (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 * vo -> (release) (deliver) button_1_down * ^o -> (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 * vo -> (deliver) button_1_down * ^o -> (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 * vo -> (deliver) button_2_down * ^o -> (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 * vo -> (release) (deliver) button_3_down * ^o -> (release) (deliver) button_3_down * <-> -> (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 * vo -> (deliver) button_3_down * ^o -> (deliver) button_3_down * <> -> (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 * vo -> (deliver) synthetic_2_down_13 * ^o -> (deliver) synthetic_2_down_13 * <> -> (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 * vo -> (deliver) synthetic_2_down_3 * ^o -> (deliver) synthetic_2_down_3 * <> -> (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 * vo -> (deliver) synthetic_2_down_1 * ^o -> (deliver) synthetic_2_down_1 * <> -> (deliver) synthetic_2_down_1 * k -> (deliver) synthetic_2_down_1 */ typedef enum _inputClass { down_1, up_1, down_2, up_2, down_3, up_3, down_o, up_o, 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]; KdMouseState 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 }, /* vo */ { { deliver, noop }, start }, /* ^o */ { { deliver, noop }, start }, /* <> */ { { deliver, noop }, start }, /* <-> */ { { noop, 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 */ { { release, deliver }, button_1_down }, /* vo */ { { release, deliver }, button_1_down }, /* ^o */ { { deliver, noop }, button_1_pend }, /* <> */ { { release, deliver }, button_1_down }, /* <-> */ { { noop, noop }, 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 }, /* vo */ { { deliver, noop }, button_1_down }, /* ^o */ { { deliver, noop }, button_1_down }, /* <> */ { { deliver, noop }, button_1_down }, /* <-> */ { { noop, 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 }, /* vo */ { { deliver, noop }, button_2_down }, /* ^o */ { { deliver, noop }, button_2_down }, /* <> */ { { deliver, noop }, button_2_down }, /* <-> */ { { noop, 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 */ { { release, deliver }, button_3_down }, /* vo */ { { release, deliver }, button_3_down }, /* ^o */ { { deliver, noop }, button_3_pend }, /* <> */ { { release, deliver }, button_3_down }, /* <-> */ { { release, noop }, 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 }, /* vo */ { { deliver, noop }, button_3_down }, /* ^o */ { { deliver, noop }, button_3_down }, /* <> */ { { deliver, noop }, button_3_down }, /* <-> */ { { noop, 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 }, /* vo */ { { deliver, noop }, synth_2_down_13 }, /* ^o */ { { deliver, noop }, synth_2_down_13 }, /* <> */ { { deliver, noop }, synth_2_down_13 }, /* <-> */ { { noop, 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 }, /* vo */ { { deliver, noop }, synth_2_down_3 }, /* ^o */ { { deliver, noop }, synth_2_down_3 }, /* <> */ { { deliver, noop }, synth_2_down_3 }, /* <-> */ { { noop, 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 }, /* vo */ { { deliver, noop }, synth_2_down_1 }, /* ^o */ { { deliver, noop }, synth_2_down_1 }, /* <> */ { { deliver, noop }, synth_2_down_1 }, /* <-> */ { { noop, noop }, synth_2_down_1 }, /* k */ { { noop, noop }, synth_2_down_1 }, /* ... */ }, }; #define EMULATION_WINDOW 10 #define EMULATION_TIMEOUT 100 #define EventX(e) ((e)->u.keyButtonPointer.rootX) #define EventY(e) ((e)->u.keyButtonPointer.rootY) static int KdInsideEmulationWindow (KdMouseInfo *mi, xEvent *ev) { if (ev->u.keyButtonPointer.pad1) { mi->emulationDx += EventX(ev); mi->emulationDy += EventY(ev); } else { mi->emulationDx = EventX(&mi->heldEvent) - EventX(ev); mi->emulationDy = EventY(&mi->heldEvent) - EventY(ev); } return (abs (mi->emulationDx) < EMULATION_WINDOW && abs (mi->emulationDy) < EMULATION_WINDOW); } static KdInputClass KdClassifyInput (KdMouseInfo *mi, 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; default: return down_o; } break; case ButtonRelease: switch (ev->u.u.detail) { case 1: return up_1; case 2: return up_2; case 3: return up_3; default: return up_o; } break; case MotionNotify: if (mi->eventHeld && !KdInsideEmulationWindow(mi, ev)) return outside_box; else return motion; default: return keyboard; } 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); } } static void KdRunMouseMachine (KdMouseInfo *mi, KdInputClass c, xEvent *ev) { KdInputTransition *t; int a; t = &kdInputMachine[mi->mouseState][c]; for (a = 0; a < MAX_ACTIONS; a++) { switch (t->actions[a]) { case noop: break; case hold: mi->eventHeld = TRUE; mi->emulationDx = 0; mi->emulationDy = 0; mi->heldEvent = *ev; break; case setto: mi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; mi->timeoutPending = TRUE; break; case deliver: KdQueueEvent (ev); break; case release: mi->eventHeld = FALSE; mi->timeoutPending = FALSE; KdQueueEvent (&mi->heldEvent); break; case clearto: mi->timeoutPending = FALSE; break; case gen_down_2: ev->u.u.detail = 2; mi->eventHeld = FALSE; KdQueueEvent (ev); break; case gen_up_2: ev->u.u.detail = 2; KdQueueEvent (ev); break; } } mi->mouseState = t->nextState; } void KdResetInputMachine (void) { KdMouseInfo *mi; for (mi = kdMouseInfo; mi; mi = mi->next) { mi->mouseState = start; mi->eventHeld = FALSE; } } static void KdHandleMouseEvent (KdMouseInfo *mi, xEvent *ev) { if (mi->emulateMiddleButton) KdRunMouseMachine (mi, KdClassifyInput (mi, ev), ev); else KdQueueEvent (ev); } static void KdReceiveTimeout (KdMouseInfo *mi) { KdRunMouseMachine (mi, 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; static void KdCheckSpecialKeys(xEvent *xE) { KeySym sym = KEYCOL1(xE->u.u.detail); if (!pKdKeyboard) return; /* * Ignore key releases */ if (xE->u.u.type == KeyRelease) return; #ifdef XIPAQ /* * Check for buttons 1, 2 and 3 on the iPAQ */ if (sym == XK_Pointer_Button1 && kdMouseInfo) { KdEnqueueMouseEvent(kdMouseInfo, KD_MOUSE_DELTA | KD_BUTTON_1, 0, 0); return; } if (sym == XK_Pointer_Button2 && kdMouseInfo) { KdEnqueueMouseEvent(kdMouseInfo, KD_MOUSE_DELTA | KD_BUTTON_2, 0, 0); return; } if (sym == XK_Pointer_Button3 && kdMouseInfo) { KdEnqueueMouseEvent(kdMouseInfo, KD_MOUSE_DELTA | KD_BUTTON_3, 0, 0); return; } #endif /* * Check for control/alt pressed */ if ((pKdKeyboard->key->state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return; /* * 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. * */ static void KdHandleKeyboardEvent (xEvent *ev) { int key = ev->u.u.detail; int byte; CARD8 bit; KdMouseInfo *mi; byte = key >> 3; bit = 1 << (key & 7); switch (ev->u.u.type) { case KeyPress: kdKeyState[byte] |= bit; break; case KeyRelease: kdKeyState[byte] &= ~bit; break; } for (mi = kdMouseInfo; mi; mi = mi->next) KdRunMouseMachine (mi, keyboard, 0); KdQueueEvent (ev); } void KdReleaseAllKeys (void) { xEvent xE; int key; KdBlockSigio (); 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); } KdUnblockSigio (); } static 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; 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; } /* * X delivers press/release even for autorepeat */ xE.u.u.type = KeyRelease; KdHandleKeyboardEvent (&xE); xE.u.u.type = KeyPress; } /* * Check released keys which are already up */ else if (!IsKeyDown (key_code) && xE.u.u.type == KeyRelease) { return; } KdCheckSpecialKeys (&xE); KdHandleKeyboardEvent (&xE); } } #define SetButton(mi, b, v, s) \ {\ xE.u.u.detail = mi->map[b]; \ xE.u.u.type = v; \ KdHandleMouseEvent (mi, &xE); \ } #define Press(mi, b) SetButton(mi, b, ButtonPress, "Down") #define Release(mi, b) SetButton(mi, b, ButtonRelease, "Up") /* * 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 void KdMouseAccelerate (DeviceIntPtr device, int *dx, int *dy) { PtrCtrl *pCtrl = &device->ptrfeed->ctrl; double speed = sqrt (*dx * *dx + *dy * *dy); double accel; double m; /* * Ok, so we want it moving num/den times faster at threshold*2 * * accel = m *threshold + b * 1 = m * 0 + b -> b = 1 * * num/den = m * (threshold * 2) + 1 * * num / den - 1 = m * threshold * 2 * (num / den - 1) / threshold * 2 = m */ m = (((double) pCtrl->num / (double) pCtrl->den - 1.0) / ((double) pCtrl->threshold * 2.0)); accel = m * speed + 1; *dx = accel * *dx; *dy = accel * *dy; } void KdEnqueueMouseEvent(KdMouseInfo *mi, unsigned long flags, int rx, int ry) { CARD32 ms; xEvent xE; unsigned char buttons; int x, y; int (*matrix)[3] = kdMouseMatrix.matrix; unsigned long button; int n; if (!pKdPointer) return; ms = GetTimeInMillis(); if (flags & KD_MOUSE_DELTA) { if (mi->transformCoordinates) { x = matrix[0][0] * rx + matrix[0][1] * ry; y = matrix[1][0] * rx + matrix[1][1] * ry; } else { x = rx; y = ry; } KdMouseAccelerate (pKdPointer, &x, &y); xE.u.keyButtonPointer.pad1 = 1; } else { if (mi->transformCoordinates) { x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2]; y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2]; } else { x = rx; y = ry; } 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; KdHandleMouseEvent (mi, &xE); buttons = flags; for (button = KD_BUTTON_1, n = 0; button <= KD_BUTTON_5; button <<= 1, n++) { if ((mi->buttonState & button) ^ (buttons & button)) { if (buttons & button) { Press(mi, n); } else { Release(mi, n); } } } mi->buttonState = buttons; } void KdEnqueueMotionEvent (KdMouseInfo *mi, 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; KdHandleMouseEvent (mi, &xE); } void KdBlockHandler (int screen, pointer blockData, pointer timeout, pointer readmask) { KdMouseInfo *mi; int myTimeout=0; for (mi = kdMouseInfo; mi; mi = mi->next) { if (mi->timeoutPending) { int ms; ms = mi->emulationTimeout - GetTimeInMillis (); if (ms < 1) ms = 1; if(mspollEvents) { (*kdOsFuncs->pollEvents)(); myTimeout=20; } if(myTimeout>0) AdjustWaitForDelay (timeout, myTimeout); } void KdWakeupHandler (int screen, pointer data, unsigned long lresult, pointer readmask) { int result = (int) lresult; fd_set *pReadmask = (fd_set *) readmask; int i; KdMouseInfo *mi; if (kdInputEnabled && result > 0) { for (i = 0; i < kdNumInputFds; i++) if (FD_ISSET (kdInputFds[i].fd, pReadmask)) { KdBlockSigio (); (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); KdUnblockSigio (); } } for (mi = kdMouseInfo; mi; mi = mi->next) { if (mi->timeoutPending) { if ((long) (GetTimeInMillis () - mi->emulationTimeout) >= 0) { mi->timeoutPending = FALSE; KdBlockSigio (); KdReceiveTimeout (mi); KdUnblockSigio (); } } } if (kdSwitchPending) KdProcessSwitch (); } #define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin)) static Bool KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) { ScreenPtr pScreen = *ppScreen; ScreenPtr pNewScreen; int n; int dx, dy; int best_x, best_y; int n_best_x, n_best_y; CARD32 ms; if (kdDisableZaphod || screenInfo.numScreens <= 1) return FALSE; if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height) return FALSE; ms = GetTimeInMillis (); if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000) return FALSE; kdOffScreen = TRUE; kdOffScreenTime = ms; n_best_x = -1; best_x = 32767; n_best_y = -1; best_y = 32767; for (n = 0; n < screenInfo.numScreens; n++) { pNewScreen = screenInfo.screens[n]; if (pNewScreen == pScreen) continue; dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x; dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y; if (*x < 0) { if (dx <= 0 && -dx < best_x) { best_x = -dx; n_best_x = n; } } else if (*x >= pScreen->width) { if (dx >= 0 && dx < best_x) { best_x = dx; n_best_x = n; } } if (*y < 0) { if (dy <= 0 && -dy < best_y) { best_y = -dy; n_best_y = n; } } else if (*y >= pScreen->height) { if (dy >= 0 && dy < best_y) { best_y = dy; n_best_y = n; } } } if (best_y < best_x) n_best_x = n_best_y; if (n_best_x == -1) return FALSE; pNewScreen = screenInfo.screens[n_best_x]; if (*x < 0) *x += pNewScreen->width; if (*y < 0) *y += pNewScreen->height; if (*x >= pScreen->width) *x -= pScreen->width; if (*y >= pScreen->height) *y -= pScreen->height; *ppScreen = pNewScreen; return TRUE; } static void KdCrossScreen(ScreenPtr pScreen, Bool entering) { #ifndef XIPAQ if (entering) KdEnableScreen (pScreen); else KdDisableScreen (pScreen); #endif } int KdCurScreen; /* current event screen */ static void KdWarpCursor (ScreenPtr pScreen, int x, int y) { KdBlockSigio (); KdCurScreen = pScreen->myNum; miPointerWarpCursor (pScreen, x, y); KdUnblockSigio (); } miPointerScreenFuncRec kdPointerScreenFuncs = { KdCursorOffScreen, KdCrossScreen, KdWarpCursor }; void ProcessInputEvents () { mieqProcessInputEvents(); miPointerUpdate(); if (kdSwitchPending) KdProcessSwitch (); KdCheckLock (); }