This patch (attached) add support under Linux for talking to mice directly from the event interface, IE, /dev/input/event<n>.
It is stashed as a os specific protocol, evdev, the Device option is not
a device, but instead is the device name, such as
'A4Tech USB Optical Mouse'.
It has some limits, specificly if you unplug a USB mouse and plug it
back in you have to cause it to be deactivated and reactivated, a good
way of doing that is to change VTs away from X, and then change back.
Also if you have two identical mice with the same label it is somewhat
indeterminate which you will get, this could be improved.
Another item to be improved is that it should attempt to handle all
forms of mice, such as tables (absolute positions, with pressure
sensitive readings), that said, I can't quite do that without the
hardware, so, someone else will have to.
The big gain from this at the moment is the second mouse wheel.
Comments appreciated.
Zephaniah E. Hull.
--
1024D/E65A7801 Zephaniah E. Hull <[EMAIL PROTECTED]>
92ED 94E4 B1E6 3624 226D 5727 4453 008B E65A 7801
CCs of replies from mailing lists are requested.
There are mushrooms that can survive weeks, months without air or
food. They just dry out and when water comes back, they wake up
again. And call the helldesk about their password expiring.
-- after Jens Benecke and Tanuki the Raccoon-dog, in ASR:
diff -ur build-tree/xc/programs/Xserver/hw/xfree86/os-support/linux/Imakefile
build-tree.mine/xc/programs/Xserver/hw/xfree86/os-support/linux/Imakefile
--- xc/programs/Xserver/hw/xfree86/os-support/linux/Imakefile 2000-11-16
14:45:03.000000000 -0500
+++ xc/programs/Xserver/hw/xfree86/os-support/linux/Imakefile 2002-11-09
+06:06:23.000000000 -0500
@@ -50,7 +50,8 @@
$(AXP_OBJ) lnx_kmod.o lnx_agp.o
INCLUDES = -I$(XF86COMSRC) -I$(XF86OSSRC) -I. -I$(SERVERSRC)/include \
- -I$(XINCLUDESRC) -I$(EXTINCSRC) -I$(XF86OSSRC)/shared
+ -I$(XINCLUDESRC) -I$(EXTINCSRC) -I$(XF86OSSRC)/shared \
+ -I$(SERVERSRC)/mi
RESDEFINES = -DUSESTDRES
diff -ur build-tree/xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_mouse.c
build-tree.mine/xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_mouse.c
--- xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_mouse.c 1999-05-17
09:17:18.000000000 -0400
+++ xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_mouse.c 2002-11-09
+11:21:23.000000000 -0500
@@ -6,8 +6,24 @@
#include "X.h"
#include "xf86.h"
+#include "xf86Priv.h"
+#include "xf86_OSlib.h"
#include "xf86Xinput.h"
#include "xf86OSmouse.h"
+#include "mipointer.h"
+#include <linux/input.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define OFF(x) ((x)%BITS_PER_LONG)
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+/* Names of protocols that are handled internally here. */
+static const char *internalNames[] = {
+ "evdev",
+ NULL
+};
static int
SupportedInterfaces(void)
@@ -15,6 +31,260 @@
return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_XPS2 | MSE_AUTO;
}
+static const char **
+BuiltinNames(void)
+{
+ return internalNames;
+}
+
+static Bool
+CheckProtocol(const char *protocol)
+{
+ int i;
+
+ for (i = 0; internalNames[i]; i++)
+ if (xf86NameCmp(protocol, internalNames[i]) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+typedef struct _evdevMseRec {
+ int packetSize;
+ int buttons;
+} evdevMseRec, *evdevMsePtr;
+
+static int
+evdevFindMouse (const char *want)
+{
+ char dev[20];
+ char name[256] = "";
+ int fd, i;
+
+ i = 0;
+ while (1) {
+ snprintf(dev, sizeof(dev), "/dev/input/event%d", i);
+ SYSCALL(fd = open (dev, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ return -1;
+ ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+ if (xf86NameCmp(name, want) == 0) {
+ return fd;
+ }
+ close(fd);
+ }
+ return -1;
+}
+
+static void
+evdevReadInput(InputInfoPtr pInfo)
+{
+ MouseDevPtr pMse;
+ evdevMsePtr evdevMse;
+ struct input_event *ev;
+ int n, bit;
+
+ pMse = pInfo->private;
+ ev = (struct input_event *) pMse->buffer;
+ evdevMse = pMse->mousePriv;
+
+ if (pInfo->fd == -1)
+ return;
+
+ do {
+ int dx = 0, dy = 0, dz = 0, dw = 0;
+ n = read(pInfo->fd, pMse->buffer, sizeof(struct input_event));
+ if (n == -1) {
+ xf86Msg(X_ERROR, "%s: Error in reading! (%s) Disabiling.\n",
+ pInfo->name, strerror(errno));
+ RemoveEnabledDevice(pInfo->fd);
+ xf86RemoveSIGIOHandler(pInfo->fd);
+ close (pInfo->fd);
+ pMse->device->public.on = FALSE;
+ pInfo->fd = -1;
+ return;
+ }
+ if (n != sizeof(struct input_event)) {
+ xf86Msg(X_WARNING, "%s: incomplete packet, size %d\n", pInfo->name, n);
+ return;
+ }
+
+ switch (ev->type) {
+ case EV_REL:
+ switch (ev->code) {
+ case REL_X:
+ dx += ev->value;
+ break;
+ case REL_Y:
+ dy += ev->value;
+ break;
+ case REL_Z:
+ case REL_WHEEL:
+ dz -= ev->value;
+ break;
+ case REL_HWHEEL:
+ dw -= ev->value;
+ break;
+ }
+ break;
+ case EV_KEY:
+ if ((ev->code < BTN_MOUSE) || (ev->code >= BTN_JOYSTICK))
+ break;
+ switch (ev->code) {
+ case BTN_RIGHT: bit = 1 << 0; break; /* 1 */
+ case BTN_MIDDLE: bit = 1 << 1; break; /* 2 */
+ case BTN_LEFT: bit = 1 << 2; break; /* 3 */
+ default: bit = 1 << (ev->code - BTN_MOUSE); break;
+ }
+ evdevMse->buttons &= ~bit;
+ if (ev->value)
+ evdevMse->buttons |= bit;
+ break;
+ }
+
+ pMse->PostEvent(pInfo, evdevMse->buttons, dx, dy, dz, dw);
+ } while (xf86WaitForInput(pInfo->fd, 0));
+
+ return;
+}
+
+static void
+evdevSigioReadInput (int fd, void *closure)
+{
+ evdevReadInput ((InputInfoPtr) closure);
+}
+
+static int
+evdevMouseProc(DeviceIntPtr pPointer, int what)
+{
+ InputInfoPtr pInfo;
+ MouseDevPtr pMse;
+ evdevMsePtr evdevMse;
+ unsigned char map[MSE_MAXBUTTONS + 1];
+ char *dev;
+ int i, blocked;
+
+ pInfo = pPointer->public.devicePrivate;
+ pMse = pInfo->private;
+ pMse->device = pPointer;
+ evdevMse = pMse->mousePriv;
+
+ switch (what) {
+ case DEVICE_INIT:
+ pPointer->public.on = FALSE;
+
+ for (i = 0; i < MSE_MAXBUTTONS; ++i)
+ map[i + 1] = i + 1;
+
+ InitPointerDeviceStruct((DevicePtr)pPointer, map,
+ min(pMse->buttons, MSE_MAXBUTTONS),
+ miPointerGetMotionEvents, pMse->Ctrl,
+ miPointerGetMotionBufferSize());
+
+ /* X valuator */
+ xf86InitValuatorAxisStruct(pPointer, 0, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(pPointer, 0);
+ /* Y valuator */
+ xf86InitValuatorAxisStruct(pPointer, 1, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(pPointer, 1);
+ xf86MotionHistoryAllocate(pInfo);
+ break;
+
+ case DEVICE_ON:
+ dev = xf86SetStrOption (pInfo->options, "Device", NULL);
+ if ((pInfo->fd = evdevFindMouse (dev)) == -1) {
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ return BadRequest;
+ }
+
+ xf86FlushInput(pInfo->fd);
+ if (!xf86InstallSIGIOHandler (pInfo->fd, evdevSigioReadInput, pInfo))
+ AddEnabledDevice(pInfo->fd);
+ pMse->lastButtons = 0;
+ pMse->emulateState = 0;
+ evdevMse->buttons = 0;
+ pPointer->public.on = TRUE;
+ /*
+ * send button up events for sanity. If no button down is pending
+ * xf86PostButtonEvent() will discard them. So we are on the safe side.
+ */
+ blocked = xf86BlockSIGIO ();
+ for (i = 1; i <= 5; i++)
+ xf86PostButtonEvent(pPointer,0,i,0,0,0);
+ xf86UnblockSIGIO (blocked);
+ break;
+
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ if (pInfo->fd != -1) {
+ RemoveEnabledDevice(pInfo->fd);
+ xf86RemoveSIGIOHandler(pInfo->fd);
+ close (pInfo->fd);
+ pInfo->fd = -1;
+ }
+ pPointer->public.on = FALSE;
+ usleep(300000);
+ break;
+ }
+ return Success;
+}
+
+
+/* This function is called when the protocol is "evdev". */
+static Bool
+evdevPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
+{
+ unsigned long evtype_bits[NBITS(KEY_MAX)];
+ unsigned long evkey_bits[NBITS(KEY_MAX)];
+ MouseDevPtr pMse = pInfo->private;
+ char *dev;
+ int i, j;
+
+ pMse->protocol = protocol;
+ xf86Msg(X_CONFIG, "%s: Protocol: %s\n", pInfo->name, protocol);
+
+ /* Collect the options, and process the common options. */
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ dev = xf86SetStrOption (pInfo->options, "Device", NULL);
+ if ((pInfo->fd = evdevFindMouse (dev)) == -1)
+ return FALSE; /* FIXME: Print a message or something too? */
+
+ ioctl(pInfo->fd, EVIOCGBIT(0, EV_MAX), evtype_bits);
+ if (test_bit(EV_KEY, evtype_bits)) {
+ ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, EV_MAX), evkey_bits);
+ i = BTN_LEFT;
+ pMse->buttons = 0;
+ for (i = BTN_LEFT, j = 0; i <= BTN_BACK; i++)
+ if (test_bit(i, evkey_bits))
+ pMse->buttons++;
+ }
+
+ close(pInfo->fd);
+ pInfo->fd = -1;
+
+ if (sizeof(struct input_event) <= sizeof(pMse->protoBuf))
+ pMse->buffer = pMse->protoBuf;
+ else
+ pMse->buffer = xalloc(sizeof(struct input_event));
+ pMse->mousePriv = xalloc(sizeof(evdevMseRec));;
+ if ((pMse->buffer == NULL) || (pMse->mousePriv == NULL)) {
+ xf86Msg(X_ERROR, "%s: cannot allocate buffer\n", pInfo->name);
+ xfree(pMse);
+ return FALSE;
+ }
+
+ pMse->CommonOptions(pInfo);
+
+ /* Setup the local procs. */
+ pInfo->device_control = evdevMouseProc;
+ pInfo->read_input = evdevReadInput;
+
+ pInfo->flags |= XI86_CONFIGURED;
+
+ return TRUE;
+}
+
OSMouseInfoPtr
xf86OSMouseInit(int flags)
{
@@ -24,6 +294,9 @@
if (!p)
return NULL;
p->SupportedInterfaces = SupportedInterfaces;
+ p->CheckProtocol = CheckProtocol;
+ p->BuiltinNames = BuiltinNames;
+ p->PreInit = evdevPreInit;
return p;
}
msg10690/pgp00000.pgp
Description: PGP signature
