The former <X11/extensions/XKBsrv.h> has been pulled into the server now as include/xkbsrv.h, and the world updated to look for it in the new place, since it made no sense to define server API in an extension header. Any further work along this line will need to do similar things with XKBgeom.h and friends.
1676 lines
39 KiB
C
1676 lines
39 KiB
C
/*
|
|
* 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 $ */
|
|
|
|
#include <xgl-config.h>
|
|
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
|
|
#include "xegl.h"
|
|
#include "mipointer.h"
|
|
#include "inputstr.h"
|
|
|
|
#define XK_PUBLISHING
|
|
#include <X11/keysym.h>
|
|
#if HAVE_X11_XF86KEYSYM_H
|
|
#include <X11/XF86keysym.h>
|
|
#endif
|
|
#include "kkeymap.h"
|
|
|
|
#ifdef XKB
|
|
#define XKB_IN_SERVER
|
|
#include <xkbsrv.h>
|
|
#endif
|
|
|
|
static DeviceIntPtr pKdKeyboard, pKdPointer;
|
|
|
|
#define MAX_MOUSE_DRIVERS 6
|
|
|
|
static KdMouseFuncs *kdMouseFuncs[MAX_MOUSE_DRIVERS];
|
|
static int kdNMouseFuncs;
|
|
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 } }
|
|
};
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
KdDisableInput (void)
|
|
{
|
|
int i;
|
|
|
|
KdBlockSigio ();
|
|
|
|
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;
|
|
}
|
|
|
|
static 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);
|
|
|
|
KdUnblockSigio ();
|
|
}
|
|
|
|
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;
|
|
for (i = 0; i < kdNMouseFuncs; i++)
|
|
(*kdMouseFuncs[i]->Init)();
|
|
break;
|
|
case DEVICE_OFF:
|
|
case DEVICE_CLOSE:
|
|
if (pDev->on)
|
|
{
|
|
pDev->on = FALSE;
|
|
pKdPointer = 0;
|
|
for (i = 0; i < kdNMouseFuncs; i++)
|
|
(*kdMouseFuncs[i]->Fini) ();
|
|
}
|
|
break;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
Bool
|
|
KdLegalModifier(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);
|
|
}
|
|
|
|
static void
|
|
KdSetLed (int led, Bool on)
|
|
{
|
|
NoteLedState (pKdKeyboard, led, on);
|
|
kdLeds = pKdKeyboard->kbdfeed->ctrl.leds;
|
|
KdSetLeds ();
|
|
}
|
|
|
|
static void
|
|
KdSetMouseMatrix (KdMouseMatrix *matrix)
|
|
{
|
|
kdMouseMatrix = *matrix;
|
|
}
|
|
|
|
static 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;
|
|
#ifdef XKB
|
|
XkbComponentNamesRec names;
|
|
#endif
|
|
|
|
if (!pDev)
|
|
return BadImplementation;
|
|
|
|
switch (onoff)
|
|
{
|
|
case DEVICE_INIT:
|
|
if (pDev != LookupKeyboardDevice())
|
|
{
|
|
return !Success;
|
|
}
|
|
#ifndef XKB
|
|
ret = InitKeyboardDeviceStruct(pDev,
|
|
&kdKeySyms,
|
|
kdModMap,
|
|
KdBell, KdKbdCtrl);
|
|
#else
|
|
memset(&names, 0, sizeof(XkbComponentNamesRec));
|
|
|
|
XkbSetRulesDflts ("base", "pc101", "us", NULL, NULL);
|
|
ret = XkbInitKeyboardDeviceStruct (pDev,
|
|
&names,
|
|
&kdKeySyms,
|
|
kdModMap,
|
|
KdBell, KdKbdCtrl);
|
|
#endif
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
KdAddMouseDriver(KdMouseFuncs *pMouseFuncs)
|
|
{
|
|
if (kdNMouseFuncs < MAX_MOUSE_DRIVERS)
|
|
kdMouseFuncs[kdNMouseFuncs++] = pMouseFuncs;
|
|
}
|
|
|
|
void
|
|
eglInitInput(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;
|
|
}
|
|
|
|
kdNMouseFuncs = 0;
|
|
KdAddMouseDriver (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);
|
|
ErrorF("Extended Input Devices not yet supported. Impelement it at line %d in %s\n",
|
|
__LINE__, __FILE__);
|
|
}
|
|
#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.
|
|
*/
|
|
if (kdDontZap == FALSE)
|
|
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);
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static 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(ms<myTimeout || myTimeout==0)
|
|
myTimeout=ms;
|
|
}
|
|
}
|
|
/* if we need to poll for events, do that */
|
|
if(kdOsFuncs->pollEvents)
|
|
{
|
|
(*kdOsFuncs->pollEvents)();
|
|
myTimeout=20;
|
|
}
|
|
if(myTimeout>0)
|
|
AdjustWaitForDelay (timeout, myTimeout);
|
|
}
|
|
|
|
void
|
|
KdWakeupHandler (pointer data,
|
|
int result,
|
|
pointer readmask)
|
|
{
|
|
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)->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
|
|
KdProcessInputEvents (void)
|
|
{
|
|
mieqProcessInputEvents();
|
|
miPointerUpdate();
|
|
// if (kdSwitchPending)
|
|
// KdProcessSwitch ();
|
|
KdCheckLock ();
|
|
}
|