aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZephaniah E. Hull <warp@aehallh.com>2006-02-14 14:57:37 +0000
committerZephaniah E. Hull <warp@aehallh.com>2006-02-14 14:57:37 +0000
commite7d4e6b11eb4cc026e91fd561fda24d9cf19adc4 (patch)
treee39330364b81f0e36cb3baaaeaaf3668b7b03ed4
parentAdd evdev manpage (diff)
downloadxf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.tar.gz
xf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.tar.bz2
xf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.zip
Bugzilla #5696 <https://bugs.freedesktop.org/show_bug.cgi?id=5696> Slightly
updated version of the patch listed. Basicly a rewrite of the driver, with a few pieces of the old. XKB support, proper device matching, basic absolute pointer support. Lots more, will require some user config changes.
-rw-r--r--ChangeLog29
-rw-r--r--configure.ac3
-rw-r--r--man/evdev.man148
-rw-r--r--src/Makefile.am2
-rw-r--r--src/evdev.c781
-rw-r--r--src/evdev.h213
-rw-r--r--src/evdev_abs.c348
-rw-r--r--src/evdev_brain.c284
-rw-r--r--src/evdev_btn.c229
-rw-r--r--src/evdev_key.c433
-rw-r--r--src/evdev_rel.c271
11 files changed, 2173 insertions, 568 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c448ae..b712978 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2006-02-14 Zephaniah E. Hull,,, <set EMAIL_ADDRESS environment variable>
+
+ * configure.ac:
+ * man/evdev.man:
+ * src/Makefile.am:
+ * src/evdev.c: (EvdevReadInput), (EvdevSigioReadInput),
+ (EvdevProc), (EvdevSwitchMode), (EvdevNew), (EvdevCorePreInit):
+ * src/evdev.h:
+ * src/evdev_abs.c: (EvdevPtrCtrlProc), (EvdevConvert),
+ (EvdevAbsSyn), (EvdevAbsProcess), (EvdevAbsInit), (EvdevAbsOn),
+ (EvdevAbsOff), (EvdevAbsNew):
+ * src/evdev_brain.c: (glob_match), (evdevGetFDForDevice),
+ (evdevRescanDevices), (evdevReadInput), (evdevControl),
+ (evdevStart), (evdevNewDriver):
+ * src/evdev_btn.c: (EvdevBtnPostFakeClicks), (EvdevBtnInit),
+ (EvdevBtnOn), (EvdevBtnOff), (EvdevBtnCalcRemap), (EvdevBtnNew),
+ (EvdevBtnProcess):
+ * src/evdev_key.c: (EvdevKbdBell), (EvdevKbdCtrl), (EvdevKeyInit),
+ (SetXkbOption), (EvdevKeyNew), (EvdevKeyOn), (EvdevKeyOff),
+ (EvdevKeyProcess):
+ * src/evdev_rel.c: (EvdevPtrCtrlProc), (EvdevConvert),
+ (EvdevRelSyn), (EvdevRelProcess), (EvdevRelInit), (EvdevRelOn),
+ (EvdevRelOff), (EvdevRelNew):
+ Bugzilla #5696 <https://bugs.freedesktop.org/show_bug.cgi?id=5696>
+ Slightly updated version of the patch listed.
+ Basicly a rewrite of the driver, with a few pieces of the old.
+ XKB support, proper device matching, basic absolute pointer support.
+ Lots more, will require some user config changes.
+
2006-01-09 David Nusinow,,, <set EMAIL_ADDRESS environment variable>
* man/Makefile.am:
diff --git a/configure.ac b/configure.ac
index 438f7ae..7e05d58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,7 +71,8 @@ inputdir=${moduledir}/input
AC_SUBST(inputdir)
# Checks for extensions
-XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
+#XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
+XORG_DRIVER_CHECK_EXT(XKB, kbproto)
XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
# Checks for pkg-config packages
diff --git a/man/evdev.man b/man/evdev.man
index 2ad5552..910dba8 100644
--- a/man/evdev.man
+++ b/man/evdev.man
@@ -37,17 +37,155 @@ Please refer to __xconfigfile__(__filemansuffix__) for general configuration
details and for options that can be used with all input drivers. This
section only covers configuration details specific to this driver.
.PP
+.SH GENERAL OPTIONS
The following driver
.B Options
-are supported:
+control what devices are accepted, note that globbing is used in all cases:
.TP 7
.BI "Option \*qDevice\*q \*q" string \*q
-Specifies the device through which the device can be accessed. This will
-generally be of the form \*q/dev/input/eventX\*q, where X is some integer.
-The mapping from device node to hardware is system-dependent. This option is
-mandatory, and there is no default setting.
+Specifies the device note through which the device can be accessed. This
+will generally be of the form \*q/dev/input/eventX\*q, where X is some
+integer. The mapping from device node to hardware is system-dependent.
+.fi
+Please note that use of this option is discouraged.
+.TP 7
+.BI "Option \*qName\*q \*q" string \*q
+Specifies the device name for the device you wish to use.
+.fi
+The device name is generally the only consistent identifier for devices
+that are commonly unplugged and plugged back into different ports.
+.fi
+A list of currently plugged in devices and associated device names can be
+obtained by typing \*qcat /proc/bus/input/devices\*q, the \*qName\*q field
+is the value you want for this option.
+.TP 7
+.BI "Option \*qPhys\*q \*q" string \*q
+Specifies the device phys string for the device you wish to use.
+.fi
+The phys string is generally consistant to the USB port a device is plugged
+into.
+.fi
+A list of currently plugged in devices and associated device names can be
+obtained by typing \*qcat /proc/bus/input/devices\*q, the \*qPhys\*q field
+is the value you want for this option.
+.PP
+.SH RELATIVE AXIS CONFIGURATION
+The relative axis portion of this driver handle all reported relative axies.
+.fi
+The axies are named X, Y, Z, RX, RY, RZ, HWHEEL, DIAL, WHEEL, MISC, 10, 11,
+12, 13, 14, and 15.
+.fi
+The axies are reported to X as valuators, with the default mapping of axies
+to valuators being the first axies found to the first valuator, the second
+found to the second valuator, and so on, so that if you have axies X, Y,
+HWHEEL, and WHEEL, you would have X=0, Y=1, HWHEEL=2, WHEEL=3.
+.fi
+If the driver is reporting core events, valuators 0 and 1 are always mapped
+to x and y coordinates, respectively.
+.fi
+The following driver
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*q<axis>RelativeAxisMap\*q \*q" number \*q
+This remaps the axis specified to the specified valuator.
+.TP 7
+.BI "Option \*q<axis>RelativeAxisButtons\*q \*q" number " number\*q
+This remaps the axis specified to the specified buttons.
+.fi
+Note that the physical buttons are always remapped around 'fake' buttons
+created by this option, so that if you have physical buttons 1 2 3 4 5,
+and map the Wheel axis to buttons 4 5, you get buttons 1 2 3
+.B 4 5
+6 7, with buttons 6 and 7 being physical buttons 4 and 5.
+.PP
+.SH ABSOLUTE AXIS CONFIGURATION
+The relative axis portion of this driver handle all reported relative axies.
+.fi
+The axies are named X, Y, Z, RX, RY, RZ, THROTTLE, RUDDER, WHEEL, GAS, BREAK,
+<11-15>, HAT0X, HAT0Y, HAT1X, HAT1Y, HAT2X, HAT2Y, HAT3X, HAT3Y, PRESSURE,
+TILT_X, TILT_Y, TOOL_WIDTH, VOLUME, <29-39>, MISC, <41-62>.
+.fi
+The axies are reported to X as valuators, with the default mapping of axies
+to valuators being the first axies found to the first valuator, the second
+found to the second valuator, and so on, so that if you have axies X, Y,
+TILT_X, and TILT_Y, you would have X=0, Y=1, TILT_X=2, TILT_Y=3.
+.fi
+If the driver is reporting core events, valuators 0 and 1 are always mapped
+to x and y coordinates, respectively.
+.fi
+The following driver
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*q<axis>AbsoluteAxisMap\*q \*q" number \*q
+This remaps the axis specified to the specified valuator.
+.TP 7
+.BI "Option \*qAbsoluteScreen\*q \*q" number \*q
+This binds the device to a specific screen, scaling it to
+the coordinate space of that screen.
+.fi
+The number can either be -1, or a valid screen number.
+.fi
+If -1 or if in relative mode no scaling or screen fixing is done.
+.fi
+This is of most use for digitizers, where the screen and the input
+device are the same surface.
+.TP 7
+.BI "Option \*qMode\*q \*q" <mode>\*q
+This selects the default mode for the device.
+.fi
+Valid values are \*qabsolute\*q and \*qrelative\*q.
+.fi
+This can be set at run time per actual device with the xinput utility.
+.PP
+.SH BUTTON CONFIGURATION
+At the moment, the button portion of this driver only handles buttons
+reported as mouse buttons, that is from BTN_MOUSE to BTN_JOYSTICK - 1.
+.fi
+At this time there are no configuration options for buttens.
+.SH KEYBOARD CONFIGURATION
+The keyboard portion of this driver handles all keys reported and requires
+XKB support.
+.fi
+The following driver
+.B Options
+control the relative axis portion of the driver:
+.TP 7
+.BI "Option \*qXkbRules\*q \*q" rules \*q
+specifies which XKB rules file to use for interpreting the
+.BR XkbModel ,
+.BR XkbLayout ,
+.BR XkbVariant ,
+and
+.B XkbOptions
+settings. Default: "xorg" for most platforms, but "xfree98" for the
+Japanese PC-98 platforms.
+.TP 7
+.BI "Option \*qXkbModel\*q \*q" modelname \*q
+specifies the XKB keyboard model name. Default: "evdev".
+.TP 7
+.BI "Option \*qXkbLayout\*q \*q" layoutname \*q
+specifies the XKB keyboard layout name. This is usually the country or
+language type of the keyboard. Default: "us".
+.TP 7
+.BI "Option \*qXkbVariant\*q \*q" variants \*q
+specifies the XKB keyboard variant components. These can be used to
+enhance the keyboard layout details. Default: not set.
+.TP 7
+.BI "Option \*qXkbOptions\*q \*q" options \*q
+specifies the XKB keyboard option components. These can be used to
+enhance the keyboard behaviour. Default: not set.
+.PP
+Some other XKB-related options are available, but they are incompatible
+with the ones listed above and are not recommended, so they are not
+documented here.
+
+.TP 7
.SH AUTHORS
Kristian Høgsberg.
+.fi
+Zephaniah E. Hull.
.SH "SEE ALSO"
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__),
README.mouse.
diff --git a/src/Makefile.am b/src/Makefile.am
index 2221bbc..189e486 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,4 +28,4 @@
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
@DRIVER_NAME@_drv_ladir = @inputdir@
-@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c
+@DRIVER_NAME@_drv_la_SOURCES = evdev.c evdev_brain.c evdev_abs.c evdev_rel.c evdev_btn.c evdev_key.c
diff --git a/src/evdev.c b/src/evdev.c
index aa1eb5d..ed15134 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1,4 +1,34 @@
/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+/*
* Copyright © 2004 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
@@ -31,99 +61,32 @@
#include <X11/XF86keysym.h>
#include <X11/extensions/XIproto.h>
+#include <string.h>
+
/* The libc wrapper just blows... linux/input.h must be included
* before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl
* twice. */
+#include "evdev.h"
-#include <linux/input.h>
-
-#include <misc.h>
#include <xf86.h>
-#include <xf86str.h>
-#include <xf86_OSproc.h>
-#include <xf86_ansic.h>
-#include <xf86_libc.h>
-#include <xf86Xinput.h>
-#include <exevents.h>
-#include <mipointer.h>
#include <xf86Module.h>
-/* 2.4 compatibility */
-#ifndef EVIOCGRAB
-#define EVIOCGRAB _IOW('E', 0x90, int)
-#endif
-
-#ifndef BTN_TASK
-#define BTN_TASK 0x117
-#endif
-
-#ifndef EV_SYN
-#define EV_SYN EV_RST
-#endif
-/* end compat */
-
-#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
-
-#define MIN_KEYCODE 8
-#define GLYPHS_PER_KEY 2
-#define AltMask Mod1Mask
-#define NumLockMask Mod2Mask
-#define AltLangMask Mod3Mask
-#define KanaMask Mod4Mask
-#define ScrollLockMask Mod5Mask
-
-#define CAPSFLAG 1
-#define NUMFLAG 2
-#define SCROLLFLAG 4
-#define MODEFLAG 8
-#define COMPOSEFLAG 16
-
-typedef struct {
- int kernel24;
-} EvdevRec, *EvdevPtr;
-
-static int wheel_up_button = 4;
-static int wheel_down_button = 5;
-static int wheel_left_button = 6;
-static int wheel_right_button = 7;
-static void
-PostButtonClicks(InputInfoPtr pInfo, int button, int count)
-{
- int i;
+#include <xf86_OSproc.h>
- for (i = 0; i < count; i++) {
- xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
- xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
- }
-}
+/*
+ * FIXME: This should most definitely not be here.
+ * But I need it, even if it _is_ private.
+ */
-static void
-PostKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
-{
- /* filter repeat events for chording keys */
- if (value == 2 &&
- (ev->code == KEY_LEFTCTRL || ev->code == KEY_RIGHTCTRL ||
- ev->code == KEY_LEFTSHIFT || ev->code == KEY_RIGHTSHIFT ||
- ev->code == KEY_LEFTALT || ev->code == KEY_RIGHTALT ||
- ev->code == KEY_LEFTMETA || ev->code == KEY_RIGHTMETA ||
- ev->code == KEY_CAPSLOCK || ev->code == KEY_NUMLOCK ||
- ev->code == KEY_SCROLLLOCK)) /* XXX windows keys? */
- return;
-
- xf86PostKeyboardEvent(pInfo->dev, ev->code + MIN_KEYCODE, value);
-}
+void xf86ActivateDevice(InputInfoPtr pInfo);
static void
EvdevReadInput(InputInfoPtr pInfo)
{
struct input_event ev;
int len, value;
- int dx, dy;
-
- dx = 0;
- dy = 0;
while (xf86WaitForInput (pInfo->fd, 0) > 0) {
len = read(pInfo->fd, &ev, sizeof ev);
@@ -139,573 +102,269 @@ EvdevReadInput(InputInfoPtr pInfo)
switch (ev.type) {
case EV_REL:
- switch (ev.code) {
- case REL_X:
- dx += value;
- break;
-
- case REL_Y:
- dy += value;
- break;
-
- case REL_WHEEL:
- if (value > 0)
- PostButtonClicks(pInfo, wheel_up_button, value);
- if (value < 0)
- PostButtonClicks(pInfo, wheel_down_button, -value);
- break;
-
- case REL_HWHEEL:
- if (value > 0)
- PostButtonClicks(pInfo, wheel_right_button, value);
- if (value < 0)
- PostButtonClicks(pInfo, wheel_left_button, -value);
- break;
- }
- break;
+ EvdevRelProcess (pInfo, &ev);
+ break;
case EV_ABS:
+ EvdevAbsProcess (pInfo, &ev);
break;
case EV_KEY:
- switch (ev.code) {
- case BTN_LEFT:
- case BTN_RIGHT:
- case BTN_MIDDLE:
- xf86PostButtonEvent(pInfo->dev, 0, ev.code - BTN_LEFT + 1,
- value, 0, 0);
- break;
-
- case BTN_SIDE:
- case BTN_EXTRA:
- case BTN_FORWARD:
- case BTN_BACK:
- case BTN_TASK:
- xf86PostButtonEvent(pInfo->dev, 0, ev.code - BTN_LEFT + 5,
- value, 0, 0);
- break;
-
- default:
- PostKbdEvent(pInfo, &ev, value);
- }
- break;
+ if ((ev.code >= BTN_MISC) && (ev.code < KEY_OK))
+ EvdevBtnProcess (pInfo, &ev);
+ else
+ EvdevKeyProcess (pInfo, &ev);
+ break;
case EV_SYN:
+ if (ev.code == SYN_REPORT) {
+ EvdevRelSyn (pInfo);
+ EvdevAbsSyn (pInfo);
+ /* EvdevBtnSyn (pInfo); */
+ /* EvdevKeySyn (pInfo); */
+ }
break;
}
}
-
- if (dx != 0 || dy != 0)
- xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
}
-#define TestBit(bit, array) (array[(bit) / 8] & (1 << ((bit) % 8)))
-
static void
-EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+EvdevSigioReadInput (int fd, void *data)
{
- /* Nothing to do, dix handles all settings */
-}
-
-/* FIXME: this map works with evdev keyboards, but all the xkb maps
- * probably don't. The easiest is to remap the event keycodes. */
-
-static KeySym map[] = {
- /* 0x00 */ NoSymbol, NoSymbol,
- /* 0x01 */ XK_Escape, NoSymbol,
- /* 0x02 */ XK_1, XK_exclam,
- /* 0x03 */ XK_2, XK_at,
- /* 0x04 */ XK_3, XK_numbersign,
- /* 0x05 */ XK_4, XK_dollar,
- /* 0x06 */ XK_5, XK_percent,
- /* 0x07 */ XK_6, XK_asciicircum,
- /* 0x08 */ XK_7, XK_ampersand,
- /* 0x09 */ XK_8, XK_asterisk,
- /* 0x0a */ XK_9, XK_parenleft,
- /* 0x0b */ XK_0, XK_parenright,
- /* 0x0c */ XK_minus, XK_underscore,
- /* 0x0d */ XK_equal, XK_plus,
- /* 0x0e */ XK_BackSpace, NoSymbol,
- /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,
- /* 0x10 */ XK_Q, NoSymbol,
- /* 0x11 */ XK_W, NoSymbol,
- /* 0x12 */ XK_E, NoSymbol,
- /* 0x13 */ XK_R, NoSymbol,
- /* 0x14 */ XK_T, NoSymbol,
- /* 0x15 */ XK_Y, NoSymbol,
- /* 0x16 */ XK_U, NoSymbol,
- /* 0x17 */ XK_I, NoSymbol,
- /* 0x18 */ XK_O, NoSymbol,
- /* 0x19 */ XK_P, NoSymbol,
- /* 0x1a */ XK_bracketleft, XK_braceleft,
- /* 0x1b */ XK_bracketright,XK_braceright,
- /* 0x1c */ XK_Return, NoSymbol,
- /* 0x1d */ XK_Control_L, NoSymbol,
- /* 0x1e */ XK_A, NoSymbol,
- /* 0x1f */ XK_S, NoSymbol,
- /* 0x20 */ XK_D, NoSymbol,
- /* 0x21 */ XK_F, NoSymbol,
- /* 0x22 */ XK_G, NoSymbol,
- /* 0x23 */ XK_H, NoSymbol,
- /* 0x24 */ XK_J, NoSymbol,
- /* 0x25 */ XK_K, NoSymbol,
- /* 0x26 */ XK_L, NoSymbol,
- /* 0x27 */ XK_semicolon, XK_colon,
- /* 0x28 */ XK_quoteright, XK_quotedbl,
- /* 0x29 */ XK_quoteleft, XK_asciitilde,
- /* 0x2a */ XK_Shift_L, NoSymbol,
- /* 0x2b */ XK_backslash, XK_bar,
- /* 0x2c */ XK_Z, NoSymbol,
- /* 0x2d */ XK_X, NoSymbol,
- /* 0x2e */ XK_C, NoSymbol,
- /* 0x2f */ XK_V, NoSymbol,
- /* 0x30 */ XK_B, NoSymbol,
- /* 0x31 */ XK_N, NoSymbol,
- /* 0x32 */ XK_M, NoSymbol,
- /* 0x33 */ XK_comma, XK_less,
- /* 0x34 */ XK_period, XK_greater,
- /* 0x35 */ XK_slash, XK_question,
- /* 0x36 */ XK_Shift_R, NoSymbol,
- /* 0x37 */ XK_KP_Multiply, NoSymbol,
- /* 0x38 */ XK_Alt_L, XK_Meta_L,
- /* 0x39 */ XK_space, NoSymbol,
- /* 0x3a */ XK_Caps_Lock, NoSymbol,
- /* 0x3b */ XK_F1, NoSymbol,
- /* 0x3c */ XK_F2, NoSymbol,
- /* 0x3d */ XK_F3, NoSymbol,
- /* 0x3e */ XK_F4, NoSymbol,
- /* 0x3f */ XK_F5, NoSymbol,
- /* 0x40 */ XK_F6, NoSymbol,
- /* 0x41 */ XK_F7, NoSymbol,
- /* 0x42 */ XK_F8, NoSymbol,
- /* 0x43 */ XK_F9, NoSymbol,
- /* 0x44 */ XK_F10, NoSymbol,
- /* 0x45 */ XK_Num_Lock, NoSymbol,
- /* 0x46 */ XK_Scroll_Lock, NoSymbol,
- /* These KP keys should have the KP_7 keysyms in the numlock
- * modifer... ? */
- /* 0x47 */ XK_KP_Home, XK_KP_7,
- /* 0x48 */ XK_KP_Up, XK_KP_8,
- /* 0x49 */ XK_KP_Prior, XK_KP_9,
- /* 0x4a */ XK_KP_Subtract, NoSymbol,
- /* 0x4b */ XK_KP_Left, XK_KP_4,
- /* 0x4c */ XK_KP_Begin, XK_KP_5,
- /* 0x4d */ XK_KP_Right, XK_KP_6,
- /* 0x4e */ XK_KP_Add, NoSymbol,
- /* 0x4f */ XK_KP_End, XK_KP_1,
- /* 0x50 */ XK_KP_Down, XK_KP_2,
- /* 0x51 */ XK_KP_Next, XK_KP_3,
- /* 0x52 */ XK_KP_Insert, XK_KP_0,
- /* 0x53 */ XK_KP_Delete, XK_KP_Decimal,
- /* 0x54 */ NoSymbol, NoSymbol,
- /* 0x55 */ XK_F13, NoSymbol,
- /* 0x56 */ XK_less, XK_greater,
- /* 0x57 */ XK_F11, NoSymbol,
- /* 0x58 */ XK_F12, NoSymbol,
- /* 0x59 */ XK_F14, NoSymbol,
- /* 0x5a */ XK_F15, NoSymbol,
- /* 0x5b */ XK_F16, NoSymbol,
- /* 0x5c */ XK_F17, NoSymbol,
- /* 0x5d */ XK_F18, NoSymbol,
- /* 0x5e */ XK_F19, NoSymbol,
- /* 0x5f */ XK_F20, NoSymbol,
- /* 0x60 */ XK_KP_Enter, NoSymbol,
- /* 0x61 */ XK_Control_R, NoSymbol,
- /* 0x62 */ XK_KP_Divide, NoSymbol,
- /* 0x63 */ XK_Print, XK_Sys_Req,
- /* 0x64 */ XK_Alt_R, XK_Meta_R,
- /* 0x65 */ NoSymbol, NoSymbol, /* KEY_LINEFEED */
- /* 0x66 */ XK_Home, NoSymbol,
- /* 0x67 */ XK_Up, NoSymbol,
- /* 0x68 */ XK_Prior, NoSymbol,
- /* 0x69 */ XK_Left, NoSymbol,
- /* 0x6a */ XK_Right, NoSymbol,
- /* 0x6b */ XK_End, NoSymbol,
- /* 0x6c */ XK_Down, NoSymbol,
- /* 0x6d */ XK_Next, NoSymbol,
- /* 0x6e */ XK_Insert, NoSymbol,
- /* 0x6f */ XK_Delete, NoSymbol,
- /* 0x6f */ NoSymbol, NoSymbol, /* KEY_MACRO */
- /* 0x70 */ NoSymbol, NoSymbol,
- /* 0x71 */ NoSymbol, NoSymbol,
- /* 0x72 */ NoSymbol, NoSymbol,
- /* 0x73 */ NoSymbol, NoSymbol,
- /* 0x74 */ NoSymbol, NoSymbol,
- /* 0x75 */ XK_KP_Equal, NoSymbol,
- /* 0x76 */ NoSymbol, NoSymbol,
- /* 0x77 */ NoSymbol, NoSymbol,
- /* 0x78 */ XK_F21, NoSymbol,
- /* 0x79 */ XK_F22, NoSymbol,
- /* 0x7a */ XK_F23, NoSymbol,
- /* 0x7b */ XK_F24, NoSymbol,
- /* 0x7c */ XK_KP_Separator, NoSymbol,
- /* 0x7d */ XK_Meta_L, NoSymbol,
- /* 0x7e */ XK_Meta_R, NoSymbol,
- /* 0x7f */ XK_Multi_key, NoSymbol,
-};
-
-static void
-EvdevKbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused)
-{
- /* hat */
-}
-
-static void
-EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
-{
- static struct { int xbit, code; } bits[] = {
- { CAPSFLAG, LED_CAPSL },
- { NUMFLAG, LED_NUML },
- { SCROLLFLAG, LED_SCROLLL },
- { MODEFLAG, LED_KANA },
- { COMPOSEFLAG, LED_COMPOSE }
- };
-
- InputInfoPtr pInfo;
- struct input_event ev[ArrayLength(bits)];
- int i;
-
- pInfo = device->public.devicePrivate;
- for (i = 0; i < ArrayLength(bits); i++) {
- ev[i].type = EV_LED;
- ev[i].code = bits[i].code;
- ev[i].value = (ctrl->leds & bits[i].xbit) > 0;
- }
-
- write(pInfo->fd, ev, sizeof ev);
-}
-
-static int
-EvdevAddKeyClass(DeviceIntPtr device)
-{
- InputInfoPtr pInfo;
- KeySymsRec keySyms;
- CARD8 modMap[MAP_LENGTH];
- KeySym sym;
- int i, j;
-
- static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
- { XK_Shift_L, ShiftMask },
- { XK_Shift_R, ShiftMask },
- { XK_Control_L, ControlMask },
- { XK_Control_R, ControlMask },
- { XK_Caps_Lock, LockMask },
- { XK_Alt_L, AltMask },
- { XK_Alt_R, AltMask },
- { XK_Num_Lock, NumLockMask },
- { XK_Scroll_Lock, ScrollLockMask },
- { XK_Mode_switch, AltLangMask }
- };
-
- /* TODO:
- * Ctrl-Alt-Backspace and other Ctrl-Alt-stuff should work
- * XKB, let's try without the #ifdef nightmare
- * Get keyboard repeat under control (right now caps lock repeats!)
- */
-
- pInfo = device->public.devicePrivate;
-
- /* Compute the modifier map */
- memset(modMap, 0, sizeof modMap);
-
- for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
- sym = map[i * GLYPHS_PER_KEY];
- for (j = 0; j < ArrayLength(modifiers); j++) {
- if (modifiers[j].keysym == sym)
- modMap[i + MIN_KEYCODE] = modifiers[j].mask;
- }
- }
-
- keySyms.map = map;
- keySyms.mapWidth = GLYPHS_PER_KEY;
- keySyms.minKeyCode = MIN_KEYCODE;
- keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
-
- if (!InitKeyClassDeviceStruct(device, &keySyms, modMap))
- return !Success;
-
- if (!InitFocusClassDeviceStruct(device))
- return !Success;
-
- if (!InitKbdFeedbackClassDeviceStruct(device, EvdevKbdBell, EvdevKbdCtrl))
- return !Success;
-
- pInfo->flags |= XI86_KEYBOARD_CAPABLE;
-
- return Success;
-}
-
-static int
-EvdevAddRelClass(DeviceIntPtr device)
-{
- InputInfoPtr pInfo;
-
- pInfo = device->public.devicePrivate;
-
- if (!InitValuatorClassDeviceStruct(device, 2,
- miPointerGetMotionEvents,
- miPointerGetMotionBufferSize(), 0))
- return !Success;
-
- /* X valuator */
- xf86InitValuatorAxisStruct(device, 0, 0, -1, 1, 0, 1);
- xf86InitValuatorDefaults(device, 0);
-
- /* Y valuator */
- xf86InitValuatorAxisStruct(device, 1, 0, -1, 1, 0, 1);
- xf86InitValuatorDefaults(device, 1);
- xf86MotionHistoryAllocate(pInfo);
-
- if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
- return !Success;
-
- return Success;
+ EvdevReadInput ((InputInfoPtr) data);
}
static int
-EvdevAddButtonClass(DeviceIntPtr device)
+EvdevProc(DeviceIntPtr device, int what)
{
- CARD8 map[32];
- InputInfoPtr pInfo;
- int i;
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
- pInfo = device->public.devicePrivate;
+ switch (what)
+ {
+ case DEVICE_INIT:
+ if (pEvdev->state.abs_axes)
+ EvdevAbsInit (device);
+ if (pEvdev->state.rel_axes)
+ EvdevRelInit (device);
+ if (pEvdev->state.buttons)
+ EvdevBtnInit (device);
+ if (pEvdev->state.keys)
+ EvdevKeyInit (device);
+ xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
+ break;
- /* FIXME: count number of actual buttons */
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "%s: On\n", pInfo->name);
+ if (device->public.on)
+ break;
- for (i = 0; i < ArrayLength(map); i++)
- map[i] = i;
+ if ((pInfo->fd = evdevGetFDForDevice (pEvdev)) == -1) {
+ xf86Msg(X_ERROR, "%s: cannot open input device.\n", pInfo->name);
- /* Linux reports BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, which should map
- * to buttons 1, 2 and 3, so swap 2 and 3 in the map */
- map[2] = 3;
- map[3] = 2;
+ if (pEvdev->phys)
+ xfree(pEvdev->phys);
+ pEvdev->phys = NULL;
- if (!InitButtonClassDeviceStruct(device, ArrayLength(map), map))
- return !Success;
+ if (pEvdev->device)
+ xfree(pEvdev->device);
+ pEvdev->device = NULL;
- pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+ return BadRequest;
+ }
- return Success;
-}
+ if (pEvdev->state.can_grab)
+ if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1))
+ xf86Msg(X_ERROR, "%s: Unable to grab device (%s).\n", pInfo->name, strerror(errno));
-static int
-EvdevInit(DeviceIntPtr device)
-{
- InputInfoPtr pInfo;
+ xf86FlushInput (pInfo->fd);
+ if (!xf86InstallSIGIOHandler (pInfo->fd, EvdevSigioReadInput, pInfo))
+ AddEnabledDevice (pInfo->fd);
- pInfo = device->public.devicePrivate;
+ device->public.on = TRUE;
- /* FIXME: This doesn't add buttons for keyboards with
- * scrollwheels. */
+ if (pEvdev->state.abs_axes)
+ EvdevAbsOn (device);
+ if (pEvdev->state.rel_axes)
+ EvdevRelOn (device);
+ if (pEvdev->state.buttons)
+ EvdevBtnOn (device);
+ if (pEvdev->state.keys)
+ EvdevKeyOn (device);
+ break;
- if (pInfo->flags & XI86_KEYBOARD_CAPABLE) {
- EvdevAddKeyClass(device);
- }
+ case DEVICE_CLOSE:
+ case DEVICE_OFF:
+ xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
+ if (pInfo->fd != -1) {
+ if (pEvdev->state.can_grab)
+ ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
+
+ RemoveEnabledDevice (pInfo->fd);
+ xf86RemoveSIGIOHandler (pInfo->fd);
+ close (pInfo->fd);
+
+ if (pEvdev->state.abs_axes)
+ EvdevAbsOff (device);
+ if (pEvdev->state.rel_axes)
+ EvdevRelOff (device);
+ if (pEvdev->state.buttons)
+ EvdevBtnOff (device);
+ if (pEvdev->state.keys)
+ EvdevKeyOff (device);
+ }
- if (pInfo->flags & XI86_POINTER_CAPABLE) {
- EvdevAddButtonClass(device);
- EvdevAddRelClass(device);
+ device->public.on = FALSE;
+ break;
}
return Success;
}
static int
-EvdevProc(DeviceIntPtr device, int what)
+EvdevSwitchMode (ClientPtr client, DeviceIntPtr device, int mode)
{
- InputInfoPtr pInfo;
- EvdevPtr pEvdev;
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
- pInfo = device->public.devicePrivate;
- pEvdev = pInfo->private;
-
- switch (what)
+ switch (mode)
{
- case DEVICE_INIT:
- return EvdevInit(device);
-
- case DEVICE_ON:
- if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)1))
- xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
- strerror(errno));
- xf86AddEnabledDevice(pInfo);
- device->public.on = TRUE;
- break;
-
- case DEVICE_OFF:
- if (!pEvdev->kernel24 && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
- xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
- strerror(errno));
- xf86RemoveEnabledDevice(pInfo);
- device->public.on = FALSE;
- break;
-
- case DEVICE_CLOSE:
- xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
- break;
+ case Absolute:
+ case Relative:
+ if (state->abs_axes)
+ state->mode = mode;
+ else
+ return !Success;
+ break;
+ case SendCoreEvents:
+ case DontSendCoreEvents:
+ xf86XInputSetSendCoreEvents (pInfo, (mode == SendCoreEvents));
+ break;
+ default:
+ return !Success;
}
return Success;
}
static Bool
-EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
- int v3, int v4, int v5, int *x, int *y)
+EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
{
- if (first == 0 && num == 2) {
- *x = v0;
- *y = v1;
- return TRUE;
- }
- else
- return FALSE;
-}
+ InputInfoPtr pInfo;
+ char name[512] = {0};
-static int
-EvdevProbe(InputInfoPtr pInfo)
-{
- char key_bitmask[(KEY_MAX + 7) / 8];
- char rel_bitmask[(REL_MAX + 7) / 8];
- int i, has_axes, has_buttons, has_keys;
- EvdevPtr pEvdev = pInfo->private;
-
- if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1) && errno == EINVAL) {
- /* keyboards are unsafe in 2.4 */
- pEvdev->kernel24 = 1;
- } else {
- ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
- }
+ if (!(pInfo = xf86AllocateInput(driver->drv, 0)))
+ return 0;
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) < 0) {
- xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
- return 1;
- }
+ /* Initialise the InputInfoRec. */
+ strncat (name, driver->dev->identifier, sizeof(name));
+ strncat (name, "-", sizeof(name));
+ strncat (name, device->phys, sizeof(name));
+ pInfo->name = xstrdup(name);
+ pInfo->flags = 0;
+ pInfo->type_name = "UNKNOWN";
+ pInfo->device_control = EvdevProc;
+ pInfo->read_input = EvdevReadInput;
+ pInfo->switch_mode = EvdevSwitchMode;
+ pInfo->motion_history_proc = xf86GetMotionEvents;
+ pInfo->conf_idev = driver->dev;
- if (ioctl(pInfo->fd,
- EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) {
- xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
- return 1;
- }
+ pInfo->private = device;
- has_axes = FALSE;
- has_buttons = FALSE;
- has_keys = FALSE;
+ device->callback = EvdevProc;
+ device->pInfo = pInfo;
- if (TestBit(REL_X, rel_bitmask) && TestBit(REL_Y, rel_bitmask)) {
- xf86Msg(X_INFO, "%s: Found x and y relative axes\n", pInfo->name);
- has_axes = TRUE;
- }
-
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
- if (TestBit(BTN_LEFT, key_bitmask)) {
- xf86Msg(X_INFO, "%s: Found mouse buttons\n", pInfo->name);
- has_buttons = TRUE;
+ if ((pInfo->fd = evdevGetFDForDevice (device)) == -1) {
+ xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
+ pInfo->private = NULL;
+ xf86DeleteInput (pInfo, 0);
+ return 0;
}
- for (i = 0; i < BTN_MISC; i++)
- if (TestBit(i, key_bitmask))
- break;
-
- if (i < BTN_MISC) {
- xf86Msg(X_INFO, "%s: Found keys\n", pInfo->name);
- has_keys = TRUE;
+ if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
+ xf86Msg(X_INFO, "%s: Unable to grab device (%s). Cowardly refusing to check use as keyboard.\n", pInfo->name, strerror(errno));
+ device->state.can_grab = 0;
+ } else {
+ device->state.can_grab = 1;
+ ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
}
- if (has_axes && has_buttons) {
- xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
- pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
- XI86_CONFIGURED;
- pInfo->type_name = XI_MOUSE;
+ /* XXX: Note, the order of these is important. */
+ EvdevAbsNew (pInfo);
+ EvdevRelNew (pInfo);
+ EvdevBtnNew (pInfo);
+ if (device->state.can_grab)
+ EvdevKeyNew (pInfo);
+
+ close (pInfo->fd);
+ pInfo->fd = -1;
+
+ pInfo->flags |= XI86_OPEN_ON_INIT;
+ if (!(pInfo->flags & XI86_CONFIGURED)) {
+ xf86Msg(X_ERROR, "%s: Don't know how to use device.\n", pInfo->name);
+ pInfo->private = NULL;
+ xf86DeleteInput (pInfo, 0);
+ return 0;
}
- if (has_keys) {
- if (pEvdev->kernel24) {
- xf86Msg(X_INFO, "%s: Kernel < 2.6 is too old, ignoring keyboard\n",
- pInfo->name);
- } else {
- xf86Msg(X_INFO, "%s: Configuring as keyboard\n", pInfo->name);
- pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
- pInfo->type_name = XI_KEYBOARD;
- }
- }
+ if (driver->configured) {
+ xf86ActivateDevice (pInfo);
- if ((pInfo->flags & XI86_CONFIGURED) == 0) {
- xf86Msg(X_WARNING, "%s: Don't know how to use device\n",
- pInfo->name);
- return 1;
+ pInfo->dev->inited = (device->callback(device->pInfo->dev, DEVICE_INIT) == Success);
+ EnableDevice (pInfo->dev);
}
- return 0;
+ return 1;
}
static InputInfoPtr
-EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+EvdevCorePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
- InputInfoPtr pInfo;
- MessageType deviceFrom = X_CONFIG;
- const char *device;
- EvdevPtr pEvdev;
+ evdevDriverPtr pEvdev;
- if (!(pInfo = xf86AllocateInput(drv, 0)))
- return NULL;
+ if (!(pEvdev = Xcalloc(sizeof(*pEvdev))))
+ return NULL;
- /* Initialise the InputInfoRec. */
- pInfo->name = dev->identifier;
- pInfo->flags = 0;
- pInfo->type_name = "UNKNOWN";
- pInfo->device_control = EvdevProc;
- pInfo->read_input = EvdevReadInput;
- pInfo->motion_history_proc = xf86GetMotionEvents;
- pInfo->history_size = 0;
- pInfo->control_proc = NULL;
- pInfo->close_proc = NULL;
- pInfo->switch_mode = NULL;
- pInfo->conversion_proc = EvdevConvert;
- pInfo->reverse_conversion_proc = NULL;
- pInfo->dev = NULL;
- pInfo->private_flags = 0;
- pInfo->always_core_feedback = 0;
- pInfo->conf_idev = dev;
-
- if (!(pEvdev = xcalloc(sizeof(*pEvdev), 1)))
- return pInfo;
- pInfo->private = pEvdev;
+ pEvdev->name = xf86CheckStrOption(dev->commonOptions, "Name", NULL);
+ pEvdev->phys = xf86CheckStrOption(dev->commonOptions, "Phys", NULL);
+ pEvdev->device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
+ xf86Msg(X_ERROR, "%s: name: %s, phys: %s, device: %s.\n", dev->identifier,
+ pEvdev->name, pEvdev->phys, pEvdev->device);
- xf86CollectInputOptions(pInfo, NULL, NULL);
- xf86ProcessCommonOptions(pInfo, pInfo->options);
+ pEvdev->callback = EvdevNew;
+
+ pEvdev->dev = dev;
+ pEvdev->drv = drv;
- device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
- if (!device) {
- xf86Msg(X_ERROR, "%s: No device specified.\n", pInfo->name);
+ if (!pEvdev->name && !pEvdev->phys && !pEvdev->device) {
+ xf86Msg(X_ERROR, "%s: No device identifiers specified.\n", dev->identifier);
xfree(pEvdev);
- return pInfo;
+ return NULL;
}
-
- xf86Msg(deviceFrom, "%s: Device: \"%s\"\n", pInfo->name, device);
- do {
- pInfo->fd = open(device, O_RDWR, 0);
- }
- while (pInfo->fd < 0 && errno == EINTR);
- if (pInfo->fd < 0) {
- xf86Msg(X_ERROR, "Unable to open evdev device \"%s\".\n", device);
+ if (!evdevStart (drv)) {
+ xf86Msg(X_ERROR, "%s: cannot start evdev brain.\n", dev->identifier);
xfree(pEvdev);
- return pInfo;
+ return NULL;
}
- if (EvdevProbe(pInfo))
- xfree(pEvdev);
+ evdevNewDriver (pEvdev);
+
+ if (pEvdev->devices && pEvdev->devices->pInfo)
+ return pEvdev->devices->pInfo;
- return pInfo;
+ return NULL;
}
_X_EXPORT InputDriverRec EVDEV = {
1,
"evdev",
NULL,
- EvdevPreInit,
+ EvdevCorePreInit,
NULL,
NULL,
0
diff --git a/src/evdev.h b/src/evdev.h
new file mode 100644
index 0000000..0cd021e
--- /dev/null
+++ b/src/evdev.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * 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 Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT 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.
+ *
+ * Author: Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifndef EVDEV_BRAIN_H_
+#define EVDEV_BRAIN_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <linux/input.h>
+#include <xf86Xinput.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 BIT(x) (1UL<<((x)%BITS_PER_LONG))
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+/* 2.4 compatibility */
+#ifndef EVIOCGSW
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+
+#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
+
+#define EV_SW 0x05
+#endif
+
+#ifndef EVIOCGRAB
+#define EVIOCGRAB _IOW('E', 0x90, int)
+#endif
+
+#ifndef BTN_TASK
+#define BTN_TASK 0x117
+#endif
+
+#ifndef EV_SYN
+#define EV_SYN EV_RST
+#endif
+/* end compat */
+
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+
+
+/*
+ * Switch events
+ */
+
+#define EV_SW_0 0x00
+#define EV_SW_1 0x01
+#define EV_SW_2 0x02
+#define EV_SW_3 0x03
+#define EV_SW_4 0x04
+#define EV_SW_5 0x05
+#define EV_SW_6 0x06
+#define EV_SW_7 0x07
+#define EV_SW_MAX 0x0f
+
+#define EV_BUS_GSC 0x1A
+
+#define EVDEV_MAXBUTTONS 128
+
+typedef struct _evdevState {
+ Bool can_grab;
+ Bool sync;
+ int real_buttons;
+ int buttons;
+ CARD8 buttonMap[EVDEV_MAXBUTTONS];
+
+ int mode; /* Either Absolute or Relative. */
+
+ int abs_axes;
+ int abs_n; /* Which abs_v is current, and which is previous. */
+ int abs_v[2][ABS_MAX];
+ int abs_min[ABS_MAX];
+ int abs_max[ABS_MAX];
+ int absMap[ABS_MAX];
+ Bool abs_scale;
+ int abs_scale_x;
+ int abs_scale_y;
+ int abs_screen; /* Screen number for this device. */
+
+ int rel_axes;
+ int rel_v[REL_MAX];
+ CARD8 relToBtnMap[REL_MAX][2];
+ int relMap[REL_MAX];
+
+ Bool keys;
+ char *xkb_rules;
+ char *xkb_model;
+ char *xkb_layout;
+ char *xkb_variant;
+ char *xkb_options;
+ XkbComponentNamesRec xkbnames;
+} evdevStateRec, *evdevStatePtr;
+
+typedef struct _evdevDevice {
+ const char *name;
+ const char *phys;
+ const char *device;
+ int seen;
+
+ InputInfoPtr pInfo;
+ int (*callback)(DeviceIntPtr cb_data, int what);
+
+ evdevStateRec state;
+
+ struct _evdevDevice *next;
+} evdevDeviceRec, *evdevDevicePtr;
+
+typedef struct _evdevDriver {
+ const char *name;
+ const char *phys;
+ const char *device;
+
+ InputDriverPtr drv;
+ IDevPtr dev;
+ Bool (*callback)(struct _evdevDriver *driver, evdevDevicePtr device);
+ evdevDevicePtr devices;
+ Bool configured;
+
+ struct _evdevDriver *next;
+} evdevDriverRec, *evdevDriverPtr;
+
+int evdevGetFDForDevice (evdevDevicePtr driver);
+Bool evdevStart (InputDriverPtr drv);
+Bool evdevNewDriver (evdevDriverPtr driver);
+
+int EvdevBtnInit (DeviceIntPtr device);
+int EvdevBtnOn (DeviceIntPtr device);
+int EvdevBtnOff (DeviceIntPtr device);
+int EvdevBtnNew(InputInfoPtr pInfo);
+void EvdevBtnProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevBtnPostFakeClicks(InputInfoPtr pInfo, int button, int count);
+
+int EvdevAbsInit (DeviceIntPtr device);
+int EvdevAbsOn (DeviceIntPtr device);
+int EvdevAbsOff (DeviceIntPtr device);
+int EvdevAbsNew(InputInfoPtr pInfo);
+void EvdevAbsProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevAbsSyn (InputInfoPtr pInfo);
+
+int EvdevRelInit (DeviceIntPtr device);
+int EvdevRelOn (DeviceIntPtr device);
+int EvdevRelOff (DeviceIntPtr device);
+int EvdevRelNew(InputInfoPtr pInfo);
+void EvdevRelProcess (InputInfoPtr pInfo, struct input_event *ev);
+void EvdevRelSyn (InputInfoPtr pInfo);
+
+int EvdevKeyInit (DeviceIntPtr device);
+int EvdevKeyNew (InputInfoPtr pInfo);
+int EvdevKeyOn (DeviceIntPtr device);
+int EvdevKeyOff (DeviceIntPtr device);
+void EvdevKeyProcess (InputInfoPtr pInfo, struct input_event *ev);
+
+#endif /* LNX_EVDEV_H_ */
diff --git a/src/evdev_abs.c b/src/evdev_abs.c
new file mode 100644
index 0000000..2b6113a
--- /dev/null
+++ b/src/evdev_abs.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+/* The libc wrapper just blows... linux/input.h must be included
+ * before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl
+ * twice. */
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86_ansic.h>
+#include <xf86_libc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+#include "evdev.h"
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+#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 TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+static char *axis_names[] = {
+ "X",
+ "Y",
+ "Z",
+ "RX",
+ "RY",
+ "RZ",
+ "THROTTLE",
+ "RUDDER",
+ "WHEEL",
+ "GAS",
+ "BRAKE",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "HAT0X",
+ "HAT0Y",
+ "HAT1X",
+ "HAT1Y",
+ "HAT2X",
+ "HAT2Y",
+ "HAT3X",
+ "HAT3Y",
+ "PRESSURE",
+ "TILT_X",
+ "TILT_Y",
+ "TOOL_WIDTH",
+ "VOLUME",
+ "29",
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "MISC",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "46",
+ "47",
+ "48",
+ "49",
+ "50",
+ "51",
+ "52",
+ "53",
+ "54",
+ "55",
+ "56",
+ "57",
+ "58",
+ "59",
+ "60",
+ "61",
+ "62",
+ NULL
+};
+
+static void
+EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ /* Nothing to do, dix handles all settings */
+}
+
+static Bool
+EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y)
+{
+ if (first == 0) {
+ *x = v0;
+ *y = v1;
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+/*
+ * FIXME: Verify that the C standard lets us pass more variable arguments
+ * then we specify.
+ */
+void
+EvdevAbsSyn (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i;
+ int n = state->abs_n & 1;
+
+ if (!state->abs_axes)
+ return;
+
+ if (state->mode == Absolute) {
+ if ((state->abs_screen >= 0) && state->abs_axes >= 2) {
+ int conv_x, conv_y;
+
+ for (i = 0; i < 2; i++)
+ state->abs_v[n][i] = xf86ScaleAxis (state->abs_v[n][i], 0,
+ state->abs_scale_x,
+ state->abs_min[i], state->abs_max[i]);
+
+
+ EvdevConvert (pInfo, 0, 2, state->abs_v[n][0], state->abs_v[n][1],
+ 0, 0, 0, 0, &conv_x, &conv_y);
+ xf86XInputSetScreen (pInfo, state->abs_screen, conv_x, conv_y);
+ }
+
+
+ xf86PostMotionEvent(pInfo->dev, 1, 0, state->abs_axes,
+ state->abs_v[n][0],
+ state->abs_v[n][1], state->abs_v[n][2], state->abs_v[n][3],
+ state->abs_v[n][4], state->abs_v[n][5], state->abs_v[n][6],
+ state->abs_v[n][7], state->abs_v[n][8], state->abs_v[n][9],
+ state->abs_v[n][10], state->abs_v[n][11], state->abs_v[n][12],
+ state->abs_v[n][13], state->abs_v[n][14], state->abs_v[n][15]);
+ } else {
+ for (i = 0; i < 2; i++)
+ state->rel_v[i] = state->abs_v[n][i] - state->abs_v[!n][i];
+ }
+
+ state->abs_n++;
+}
+
+void
+EvdevAbsProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int n = state->abs_n & 1;
+ int map;
+
+ if (ev->code >= ABS_MAX)
+ return;
+
+ map = pEvdev->state.absMap[ev->code];
+ if (map >= 0)
+ pEvdev->state.abs_v[n][map] += ev->value;
+ else
+ pEvdev->state.abs_v[n][-map] -= ev->value;
+
+ if (!pEvdev->state.sync)
+ EvdevAbsSyn (pInfo);
+}
+
+int
+EvdevAbsInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ int i;
+
+ if (!InitValuatorClassDeviceStruct(device, pEvdev->state.abs_axes,
+ miPointerGetMotionEvents,
+ miPointerGetMotionBufferSize(), 0))
+ return !Success;
+
+ for (i = 0; i < pEvdev->state.abs_axes; i++) {
+ xf86InitValuatorAxisStruct(device, i, 0, 0, 0, 0, 1);
+ xf86InitValuatorDefaults(device, i);
+ }
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
+ return Success;
+}
+
+int
+EvdevAbsOn (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevAbsOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevAbsNew(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ long abs_bitmask[NBITS(KEY_MAX)];
+ struct input_absinfo absinfo;
+ char *s, option[64];
+ int i, j, k = 0, real_axes;
+
+ if (ioctl(pInfo->fd,
+ EVIOCGBIT(EV_ABS, ABS_MAX), abs_bitmask) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+ return !Success;
+ }
+
+ real_axes = 0;
+ for (i = 0; i < ABS_MAX; i++)
+ if (TestBit (i, abs_bitmask))
+ real_axes++;
+
+ if (!real_axes)
+ return !Success;
+
+ xf86Msg(X_INFO, "%s: Found %d absolute axes.\n", pInfo->name, real_axes);
+ xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
+ pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
+ XI86_CONFIGURED;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->conversion_proc = EvdevConvert;
+
+ for (i = 0, j = 0; i < ABS_MAX; i++) {
+ if (!TestBit (i, abs_bitmask))
+ continue;
+
+ snprintf(option, sizeof(option), "%sAbsoluteAxisMap", axis_names[i]);
+ k = xf86SetIntOption(pInfo->options, option, -1);
+ if (k != -1)
+ state->absMap[i] = k;
+ else
+ state->absMap[i] = j;
+
+ if (k != -1)
+ xf86Msg(X_CONFIG, "%s: %s: %d.\n", pInfo->name, option, k);
+
+ if (ioctl (pInfo->fd, EVIOCGABS(i), &absinfo) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno));
+ return !Success;
+ }
+ state->abs_min[state->absMap[i]] = absinfo.minimum;
+ state->abs_max[state->absMap[i]] = absinfo.maximum;
+
+ j++;
+ }
+
+ state->abs_axes = real_axes;
+ for (i = 0; i < ABS_MAX; i++) {
+ if (state->absMap[i] > state->abs_axes)
+ state->abs_axes = state->absMap[i];
+ }
+
+ if (state->abs_axes != real_axes)
+ xf86Msg(X_CONFIG, "%s: Configuring %d absolute axes.\n", pInfo->name,
+ state->abs_axes);
+
+ s = xf86SetStrOption(pInfo->options, "Mode", "Absolute");
+ if (!strcasecmp(s, "Absolute")) {
+ state->mode = Absolute;
+ xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
+ } else if (!strcasecmp(s, "Relative")) {
+ state->mode = Relative;
+ xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
+ } else {
+ state->mode = Absolute;
+ xf86Msg(X_CONFIG, "%s: Unknown Mode: %s.\n", pInfo->name, s);
+ }
+
+ if (TestBit (ABS_X, abs_bitmask) && TestBit (ABS_Y, abs_bitmask))
+ k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", 0);
+ else
+ k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", -1);
+ if (k < screenInfo.numScreens) {
+ state->abs_screen = k;
+ xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d.\n", pInfo->name, k);
+ } else {
+ state->abs_screen = 0;
+ xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d is not a valid screen.\n", pInfo->name, k);
+ }
+
+ state->abs_scale_x = screenInfo.screens[state->abs_screen]->width;
+ state->abs_scale_y = screenInfo.screens[state->abs_screen]->height;
+
+ return Success;
+}
diff --git a/src/evdev_brain.c b/src/evdev_brain.c
new file mode 100644
index 0000000..feafc34
--- /dev/null
+++ b/src/evdev_brain.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define HAVE_WRAPPER_DECLS
+#include "xf86_OSlib.h"
+
+#include "evdev.h"
+
+#include <xf86.h>
+
+#ifndef SYSCALL
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+#endif
+
+static Bool evdev_alive = FALSE;
+static InputInfoPtr evdev_pInfo = NULL;
+static evdevDriverPtr evdev_drivers = NULL;
+static int evdev_seq;
+
+static int
+glob_match(const char *pattern, const char *matchp)
+{
+ int i, j = 0, ret = 0;
+ if (!(pattern && matchp))
+ return (strlen(pattern) == strlen(matchp));
+
+ for (i = 0; matchp[i]; i++) {
+ if (pattern[j] == '\\')
+ j++;
+ else if (pattern[j] == '*') {
+ if (pattern[j + 1]) {
+ if (!glob_match(pattern+j+1,matchp+i))
+ return 0;
+ } else
+ return 0;
+ continue;
+ } else if (pattern[j] == '?') {
+ j++;
+ continue;
+ }
+
+ if ((ret = (pattern[j] - matchp[i])))
+ return ret;
+
+ j++;
+ }
+ if (!pattern[j] || ((pattern[j] == '*') && !pattern[j + 1]))
+ return 0;
+ else
+ return 1;
+}
+
+
+int
+evdevGetFDForDevice (evdevDevicePtr device)
+{
+ int fd;
+
+ if (!device)
+ return -1;
+
+
+ if (device->device) {
+ SYSCALL(fd = open (device->device, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ xf86Msg(X_ERROR, "%s (%d): Open failed: %s\n", __FILE__, __LINE__, strerror(errno));
+ return fd;
+ } else
+ return -1;
+}
+
+#define device_add(driver,device) do { \
+ device->next = driver->devices; \
+ driver->devices = device; \
+} while (0)
+
+static void
+evdevRescanDevices (InputInfoPtr pInfo)
+{
+ char dev[20];
+ char name[256], phys[256];
+ int fd, i;
+ int old_seq = evdev_seq;
+ evdevDriverPtr driver;
+ evdevDevicePtr device;
+ Bool found;
+
+ evdev_seq++;
+ xf86Msg(X_INFO, "%s: Rescanning devices (%d).\n", pInfo->name, evdev_seq);
+
+ for (i = 0; i < 32; i++) {
+ snprintf(dev, sizeof(dev), "/dev/input/event%d", i);
+ SYSCALL(fd = open (dev, O_RDWR | O_NONBLOCK));
+ if (fd == -1)
+ continue;
+
+ if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) == -1)
+ name[0] = '\0';
+ if (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) == -1)
+ phys[0] = '\0';
+
+ for (driver = evdev_drivers; driver; driver = driver->next) {
+ if (driver->name && glob_match(driver->name, name))
+ continue;
+ if (driver->phys && glob_match(driver->phys, phys))
+ continue;
+ if (driver->device && glob_match(driver->device, dev))
+ continue;
+
+ found = 0;
+ for (device = driver->devices; device; device = device->next) {
+ xf86Msg(X_INFO, "%s: %s %d -> %s %d.\n", pInfo->name, name, evdev_seq, device->name, device->seen);
+ if (!strcmp(device->name, name)) {
+ if (device->seen != old_seq) {
+ device->device = xstrdup(dev);
+ device->phys = xstrdup(phys);
+ device->callback(device->pInfo->dev, DEVICE_ON);
+ }
+
+ device->seen = evdev_seq;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ device = Xcalloc (sizeof (evdevDeviceRec));
+
+ device->device = xstrdup(dev);
+ device->name = xstrdup(name);
+ device->phys = xstrdup(phys);
+ device->seen = evdev_seq;
+ device_add(driver, device);
+ driver->callback(driver, device);
+ }
+
+ device->seen = evdev_seq;
+ break;
+ }
+ close (fd);
+ }
+
+ for (driver = evdev_drivers; driver; driver = driver->next)
+ for (device = driver->devices; device; device = device->next)
+ if (device->seen == old_seq) {
+ device->callback(device->pInfo->dev, DEVICE_OFF);
+
+ if (device->device)
+ xfree(device->device);
+ device->device = NULL;
+
+ if (device->phys)
+ xfree(device->phys);
+ device->phys = NULL;
+ }
+}
+
+static void
+evdevReadInput (InputInfoPtr pInfo)
+{
+ /*
+ * XXX: Freezing the server for a moment is not really friendly.
+ * But we need to wait until udev has actually created the device.
+ */
+ usleep (500000);
+ evdevRescanDevices (pInfo);
+}
+
+static int
+evdevControl(DeviceIntPtr pPointer, int what)
+{
+ InputInfoPtr pInfo;
+
+ pInfo = pPointer->public.devicePrivate;
+
+ switch (what) {
+ case DEVICE_INIT:
+ pPointer->public.on = FALSE;
+ break;
+
+ case DEVICE_ON:
+ /*
+ * XXX: We do /proc/bus/usb/devices instead of /proc/bus/input/devices
+ * because the only hotplug input devices at the moment are USB...
+ * And because the latter is useless to poll/select against.
+ * FIXME: Get a patch in the kernel which fixes the latter.
+ */
+ pInfo->fd = open ("/proc/bus/usb/devices", O_RDONLY);
+ if (pInfo->fd == -1) {
+ xf86Msg(X_ERROR, "%s: cannot open /proc/bus/usb/devices.\n", pInfo->name);
+ return BadRequest;
+ }
+ xf86FlushInput(pInfo->fd);
+ AddEnabledDevice(pInfo->fd);
+ pPointer->public.on = TRUE;
+ evdevRescanDevices (pInfo);
+ break;
+
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ if (pInfo->fd != -1) {
+ RemoveEnabledDevice(pInfo->fd);
+ close (pInfo->fd);
+ pInfo->fd = -1;
+ }
+ pPointer->public.on = FALSE;
+ break;
+ }
+ return Success;
+}
+
+Bool
+evdevStart (InputDriverPtr drv)
+{
+ InputInfoRec *pInfo;
+
+ if (evdev_alive)
+ return TRUE;
+
+ if (!(pInfo = xf86AllocateInput(drv, 0)))
+ return FALSE;
+
+ evdev_alive = TRUE;
+
+ pInfo->name = "evdev brain";
+ pInfo->type_name = "evdev brain";
+ pInfo->device_control = evdevControl;
+ pInfo->read_input = evdevReadInput;
+ pInfo->fd = -1;
+ pInfo->flags = XI86_CONFIGURED | XI86_OPEN_ON_INIT;
+
+ evdev_pInfo = pInfo;
+ return TRUE;
+}
+
+Bool
+evdevNewDriver (evdevDriverPtr driver)
+{
+ if (!evdev_alive)
+ return FALSE;
+ if (!(driver->name || driver->phys || driver->device))
+ return FALSE;
+ if (!driver->callback)
+ return FALSE;
+
+ driver->next = evdev_drivers;
+ evdev_drivers = driver;
+
+ evdevRescanDevices (evdev_pInfo);
+ driver->configured = TRUE;
+ return TRUE;
+}
diff --git a/src/evdev_btn.c b/src/evdev_btn.c
new file mode 100644
index 0000000..71d0214
--- /dev/null
+++ b/src/evdev_btn.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+/* The libc wrapper just blows... linux/input.h must be included
+ * before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl
+ * twice. */
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86_ansic.h>
+#include <xf86_libc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+#include "evdev.h"
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+#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 TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+void
+EvdevBtnPostFakeClicks(InputInfoPtr pInfo, int button, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+ xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+ }
+}
+
+int
+EvdevBtnInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ CARD8 *map;
+ int i;
+
+ if (!pEvdev->state.buttons)
+ return Success;
+
+ map = Xcalloc (sizeof (CARD8) * pEvdev->state.buttons);
+
+ for (i = 0; i < pEvdev->state.buttons; i++)
+ map[i] = i;
+
+ xf86Msg(X_ERROR, "%s (%d): Registering %d buttons.\n", __FILE__, __LINE__,
+ pEvdev->state.buttons);
+ if (!InitButtonClassDeviceStruct (device, pEvdev->state.buttons, map)) {
+ pEvdev->state.buttons = 0;
+
+ return !Success;
+ }
+
+ Xfree (map);
+
+ return Success;
+}
+
+int
+EvdevBtnOn (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ int i, blocked;
+
+ if (!pEvdev->state.buttons)
+ return Success;
+
+ blocked = xf86BlockSIGIO ();
+ for (i = 1; i <= pEvdev->state.buttons; i++)
+ xf86PostButtonEvent (device, 0, i, 0, 0, 0);
+ xf86UnblockSIGIO (blocked);
+
+ return Success;
+}
+
+int
+EvdevBtnOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+/*
+ * Warning, evil lives here.
+ */
+static void
+EvdevBtnCalcRemap (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ int i, j, base, clear, fake;
+
+ for (i = 0, base = 1, fake = 0; i < pEvdev->state.real_buttons; i++) {
+ do {
+ clear = 1;
+ for (j = 0; j < REL_MAX; j++) {
+ if (pEvdev->state.relToBtnMap[j][0] == (i + base)) {
+ base++;
+ clear = 0;
+ break;
+ }
+ if (pEvdev->state.relToBtnMap[j][1] == (i + base)) {
+ base++;
+ clear = 0;
+ break;
+ }
+ }
+ } while (!clear);
+
+ if (!fake && base != 1)
+ fake = i;
+
+ pEvdev->state.buttons = pEvdev->state.buttonMap[i] = i + base;
+ }
+
+ if (pEvdev->state.real_buttons >= 3 && (!fake || fake >= 3)) {
+ base = pEvdev->state.buttonMap[1];
+ pEvdev->state.buttonMap[1] = pEvdev->state.buttonMap[2];
+ pEvdev->state.buttonMap[2] = base;
+ }
+
+ for (j = 0; j < REL_MAX; j++) {
+ if (pEvdev->state.relToBtnMap[i][0] > pEvdev->state.buttons)
+ pEvdev->state.buttons = pEvdev->state.relToBtnMap[i][0];
+ if (pEvdev->state.relToBtnMap[i][1] > pEvdev->state.buttons)
+ pEvdev->state.buttons = pEvdev->state.relToBtnMap[i][1];
+ }
+}
+
+
+int
+EvdevBtnNew(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ long key_bitmask[NBITS(KEY_MAX)];
+ int i;
+
+ if (ioctl(pInfo->fd,
+ EVIOCGBIT(EV_KEY, KEY_MAX), key_bitmask) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+ return !Success;
+ }
+
+ for (i = 0; i < (BTN_JOYSTICK - BTN_MOUSE); i++)
+ if (TestBit (BTN_MOUSE + i, key_bitmask))
+ pEvdev->state.real_buttons = i + 1;
+
+ if (pEvdev->state.real_buttons)
+ xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name, pEvdev->state.real_buttons);
+
+ EvdevBtnCalcRemap (pInfo);
+
+ if (pEvdev->state.buttons)
+ xf86Msg(X_INFO, "%s: Configured %d mouse buttons\n", pInfo->name, pEvdev->state.buttons);
+ else
+ return !Success;
+
+ pInfo->flags |= XI86_SEND_DRAG_EVENTS | XI86_CONFIGURED;
+ pInfo->type_name = XI_MOUSE;
+
+ return Success;
+}
+
+void
+EvdevBtnProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ int button;
+
+ if (!pEvdev->state.buttons)
+ return;
+
+ if ((ev->code >= BTN_MOUSE) && (ev->code < BTN_JOYSTICK)) {
+ button = ev->code - BTN_MOUSE;
+ button = pEvdev->state.buttonMap[button];
+
+ xf86PostButtonEvent (pInfo->dev, 0, button, ev->value, 0, 0);
+ } else {
+ /* FIXME: Handle the non-mouse case. */
+ }
+}
diff --git a/src/evdev_key.c b/src/evdev_key.c
new file mode 100644
index 0000000..9fddb2b
--- /dev/null
+++ b/src/evdev_key.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * 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 Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT 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.
+ *
+ * Author: Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+/* The libc wrapper just blows... linux/input.h must be included
+ * before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl
+ * twice. */
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86_ansic.h>
+#include <xf86_libc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+#include <X11/extensions/XKBsrv.h>
+
+#include "evdev.h"
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+#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 TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+#define MIN_KEYCODE 8
+#define GLYPHS_PER_KEY 2
+#define AltMask Mod1Mask
+#define NumLockMask Mod2Mask
+#define AltLangMask Mod3Mask
+#define KanaMask Mod4Mask
+#define ScrollLockMask Mod5Mask
+
+#define CAPSFLAG 1
+#define NUMFLAG 2
+#define SCROLLFLAG 4
+#define MODEFLAG 8
+#define COMPOSEFLAG 16
+
+/* FIXME: this map works with evdev keyboards, but all the xkb maps
+ * probably don't. The easiest is to remap the event keycodes. */
+
+static KeySym map[] = {
+ /* 0x00 */ NoSymbol, NoSymbol,
+ /* 0x01 */ XK_Escape, NoSymbol,
+ /* 0x02 */ XK_1, XK_exclam,
+ /* 0x03 */ XK_2, XK_at,
+ /* 0x04 */ XK_3, XK_numbersign,
+ /* 0x05 */ XK_4, XK_dollar,
+ /* 0x06 */ XK_5, XK_percent,
+ /* 0x07 */ XK_6, XK_asciicircum,
+ /* 0x08 */ XK_7, XK_ampersand,
+ /* 0x09 */ XK_8, XK_asterisk,
+ /* 0x0a */ XK_9, XK_parenleft,
+ /* 0x0b */ XK_0, XK_parenright,
+ /* 0x0c */ XK_minus, XK_underscore,
+ /* 0x0d */ XK_equal, XK_plus,
+ /* 0x0e */ XK_BackSpace, NoSymbol,
+ /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,
+ /* 0x10 */ XK_Q, NoSymbol,
+ /* 0x11 */ XK_W, NoSymbol,
+ /* 0x12 */ XK_E, NoSymbol,
+ /* 0x13 */ XK_R, NoSymbol,
+ /* 0x14 */ XK_T, NoSymbol,
+ /* 0x15 */ XK_Y, NoSymbol,
+ /* 0x16 */ XK_U, NoSymbol,
+ /* 0x17 */ XK_I, NoSymbol,
+ /* 0x18 */ XK_O, NoSymbol,
+ /* 0x19 */ XK_P, NoSymbol,
+ /* 0x1a */ XK_bracketleft, XK_braceleft,
+ /* 0x1b */ XK_bracketright,XK_braceright,
+ /* 0x1c */ XK_Return, NoSymbol,
+ /* 0x1d */ XK_Control_L, NoSymbol,
+ /* 0x1e */ XK_A, NoSymbol,
+ /* 0x1f */ XK_S, NoSymbol,
+ /* 0x20 */ XK_D, NoSymbol,
+ /* 0x21 */ XK_F, NoSymbol,
+ /* 0x22 */ XK_G, NoSymbol,
+ /* 0x23 */ XK_H, NoSymbol,
+ /* 0x24 */ XK_J, NoSymbol,
+ /* 0x25 */ XK_K, NoSymbol,
+ /* 0x26 */ XK_L, NoSymbol,
+ /* 0x27 */ XK_semicolon, XK_colon,
+ /* 0x28 */ XK_quoteright, XK_quotedbl,
+ /* 0x29 */ XK_quoteleft, XK_asciitilde,
+ /* 0x2a */ XK_Shift_L, NoSymbol,
+ /* 0x2b */ XK_backslash, XK_bar,
+ /* 0x2c */ XK_Z, NoSymbol,
+ /* 0x2d */ XK_X, NoSymbol,
+ /* 0x2e */ XK_C, NoSymbol,
+ /* 0x2f */ XK_V, NoSymbol,
+ /* 0x30 */ XK_B, NoSymbol,
+ /* 0x31 */ XK_N, NoSymbol,
+ /* 0x32 */ XK_M, NoSymbol,
+ /* 0x33 */ XK_comma, XK_less,
+ /* 0x34 */ XK_period, XK_greater,
+ /* 0x35 */ XK_slash, XK_question,
+ /* 0x36 */ XK_Shift_R, NoSymbol,
+ /* 0x37 */ XK_KP_Multiply, NoSymbol,
+ /* 0x38 */ XK_Alt_L, XK_Meta_L,
+ /* 0x39 */ XK_space, NoSymbol,
+ /* 0x3a */ XK_Caps_Lock, NoSymbol,
+ /* 0x3b */ XK_F1, NoSymbol,
+ /* 0x3c */ XK_F2, NoSymbol,
+ /* 0x3d */ XK_F3, NoSymbol,
+ /* 0x3e */ XK_F4, NoSymbol,
+ /* 0x3f */ XK_F5, NoSymbol,
+ /* 0x40 */ XK_F6, NoSymbol,
+ /* 0x41 */ XK_F7, NoSymbol,
+ /* 0x42 */ XK_F8, NoSymbol,
+ /* 0x43 */ XK_F9, NoSymbol,
+ /* 0x44 */ XK_F10, NoSymbol,
+ /* 0x45 */ XK_Num_Lock, NoSymbol,
+ /* 0x46 */ XK_Scroll_Lock, NoSymbol,
+ /* These KP keys should have the KP_7 keysyms in the numlock
+ * modifer... ? */
+ /* 0x47 */ XK_KP_Home, XK_KP_7,
+ /* 0x48 */ XK_KP_Up, XK_KP_8,
+ /* 0x49 */ XK_KP_Prior, XK_KP_9,
+ /* 0x4a */ XK_KP_Subtract, NoSymbol,
+ /* 0x4b */ XK_KP_Left, XK_KP_4,
+ /* 0x4c */ XK_KP_Begin, XK_KP_5,
+ /* 0x4d */ XK_KP_Right, XK_KP_6,
+ /* 0x4e */ XK_KP_Add, NoSymbol,
+ /* 0x4f */ XK_KP_End, XK_KP_1,
+ /* 0x50 */ XK_KP_Down, XK_KP_2,
+ /* 0x51 */ XK_KP_Next, XK_KP_3,
+ /* 0x52 */ XK_KP_Insert, XK_KP_0,
+ /* 0x53 */ XK_KP_Delete, XK_KP_Decimal,
+ /* 0x54 */ NoSymbol, NoSymbol,
+ /* 0x55 */ XK_F13, NoSymbol,
+ /* 0x56 */ XK_less, XK_greater,
+ /* 0x57 */ XK_F11, NoSymbol,
+ /* 0x58 */ XK_F12, NoSymbol,
+ /* 0x59 */ XK_F14, NoSymbol,
+ /* 0x5a */ XK_F15, NoSymbol,
+ /* 0x5b */ XK_F16, NoSymbol,
+ /* 0x5c */ XK_F17, NoSymbol,
+ /* 0x5d */ XK_F18, NoSymbol,
+ /* 0x5e */ XK_F19, NoSymbol,
+ /* 0x5f */ XK_F20, NoSymbol,
+ /* 0x60 */ XK_KP_Enter, NoSymbol,
+ /* 0x61 */ XK_Control_R, NoSymbol,
+ /* 0x62 */ XK_KP_Divide, NoSymbol,
+ /* 0x63 */ XK_Print, XK_Sys_Req,
+ /* 0x64 */ XK_Alt_R, XK_Meta_R,
+ /* 0x65 */ NoSymbol, NoSymbol, /* KEY_LINEFEED */
+ /* 0x66 */ XK_Home, NoSymbol,
+ /* 0x67 */ XK_Up, NoSymbol,
+ /* 0x68 */ XK_Prior, NoSymbol,
+ /* 0x69 */ XK_Left, NoSymbol,
+ /* 0x6a */ XK_Right, NoSymbol,
+ /* 0x6b */ XK_End, NoSymbol,
+ /* 0x6c */ XK_Down, NoSymbol,
+ /* 0x6d */ XK_Next, NoSymbol,
+ /* 0x6e */ XK_Insert, NoSymbol,
+ /* 0x6f */ XK_Delete, NoSymbol,
+ /* 0x6f */ NoSymbol, NoSymbol, /* KEY_MACRO */
+ /* 0x70 */ NoSymbol, NoSymbol,
+ /* 0x71 */ NoSymbol, NoSymbol,
+ /* 0x72 */ NoSymbol, NoSymbol,
+ /* 0x73 */ NoSymbol, NoSymbol,
+ /* 0x74 */ NoSymbol, NoSymbol,
+ /* 0x75 */ XK_KP_Equal, NoSymbol,
+ /* 0x76 */ NoSymbol, NoSymbol,
+ /* 0x77 */ NoSymbol, NoSymbol,
+ /* 0x78 */ XK_F21, NoSymbol,
+ /* 0x79 */ XK_F22, NoSymbol,
+ /* 0x7a */ XK_F23, NoSymbol,
+ /* 0x7b */ XK_F24, NoSymbol,
+ /* 0x7c */ XK_KP_Separator, NoSymbol,
+ /* 0x7d */ XK_Meta_L, NoSymbol,
+ /* 0x7e */ XK_Meta_R, NoSymbol,
+ /* 0x7f */ XK_Multi_key, NoSymbol,
+};
+
+/*
+ * FIXME: We can't actually _do_ anything here.
+ * Find a way around this.
+ */
+static void
+EvdevKbdBell (int percent, DeviceIntPtr device, pointer ctrl, int unused)
+{
+}
+
+static void
+EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
+{
+ static struct { int xbit, code; } bits[] = {
+ { CAPSFLAG, LED_CAPSL },
+ { NUMFLAG, LED_NUML },
+ { SCROLLFLAG, LED_SCROLLL },
+ { MODEFLAG, LED_KANA },
+ { COMPOSEFLAG, LED_COMPOSE }
+ };
+
+ InputInfoPtr pInfo;
+ struct input_event ev[ArrayLength(bits)];
+ int i;
+
+ pInfo = device->public.devicePrivate;
+ for (i = 0; i < ArrayLength(bits); i++) {
+ ev[i].type = EV_LED;
+ ev[i].code = bits[i].code;
+ ev[i].value = (ctrl->leds & bits[i].xbit) > 0;
+
+ write(pInfo->fd, ev, sizeof ev);
+ }
+}
+
+int
+EvdevKeyInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ KeySymsRec keySyms;
+ CARD8 modMap[MAP_LENGTH];
+ KeySym sym;
+ int i, j;
+
+ static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
+ { XK_Shift_L, ShiftMask },
+ { XK_Shift_R, ShiftMask },
+ { XK_Control_L, ControlMask },
+ { XK_Control_R, ControlMask },
+ { XK_Caps_Lock, LockMask },
+ { XK_Alt_L, AltMask },
+ { XK_Alt_R, AltMask },
+ { XK_Num_Lock, NumLockMask },
+ { XK_Scroll_Lock, ScrollLockMask },
+ { XK_Mode_switch, AltLangMask }
+ };
+
+ /* TODO:
+ * Ctrl-Alt-Backspace and other Ctrl-Alt-stuff should work
+ * XKB, let's try without the #ifdef nightmare
+ * Get keyboard repeat under control (right now caps lock repeats!)
+ */
+
+ pInfo = device->public.devicePrivate;
+
+ /* Compute the modifier map */
+ memset(modMap, 0, sizeof modMap);
+
+ for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
+ sym = map[i * GLYPHS_PER_KEY];
+ for (j = 0; j < ArrayLength(modifiers); j++) {
+ if (modifiers[j].keysym == sym)
+ modMap[i + MIN_KEYCODE] = modifiers[j].mask;
+ }
+ }
+
+ keySyms.map = map;
+ keySyms.mapWidth = GLYPHS_PER_KEY;
+ keySyms.minKeyCode = MIN_KEYCODE;
+ keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
+
+
+ XkbSetRulesDflts (state->xkb_rules, state->xkb_model, state->xkb_layout,
+ state->xkb_variant, state->xkb_options);
+
+ XkbInitKeyboardDeviceStruct (device, &state->xkbnames, &keySyms, modMap,
+ EvdevKbdBell, EvdevKbdCtrl);
+
+ return Success;
+}
+
+static void
+SetXkbOption(InputInfoPtr pInfo, char *name, char *value, char **option)
+{
+ char *s;
+
+ if ((s = xf86SetStrOption(pInfo->options, name, value))) {
+ if (!s[0]) {
+ xfree(s);
+ *option = NULL;
+ } else {
+ *option = s;
+ xf86Msg(X_CONFIG, "%s: %s: \"%s\"\n", pInfo->name, name, s);
+ }
+ }
+}
+
+int
+EvdevKeyNew (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ long key_bitmask[NBITS(KEY_MAX)];
+ int i;
+
+ if (ioctl(pInfo->fd,
+ EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+ return !Success;
+ }
+
+ for (i = 0; i <= KEY_UNKNOWN; i++)
+ if (TestBit (i, key_bitmask)) {
+ state->keys = 1;
+ break;
+ }
+
+ if (!state->keys)
+ return !Success;
+
+ pInfo->type_name = XI_KEYBOARD;
+
+ pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
+
+ SetXkbOption (pInfo, "XkbKeymap", NULL, &state->xkbnames.keymap);
+ if (state->xkbnames.keymap) {
+ xf86Msg(X_CONFIG, "%s: XkbKeymap overrides all other XKB settings\n",
+ pInfo->name);
+ } else {
+ SetXkbOption (pInfo, "XkbRules", __XKBDEFRULES__, &state->xkb_rules);
+ SetXkbOption (pInfo, "XkbModel", "evdev", &state->xkb_model);
+ SetXkbOption (pInfo, "XkbLayout", "us", &state->xkb_layout);
+ SetXkbOption (pInfo, "XkbVariant", NULL, &state->xkb_variant);
+ SetXkbOption (pInfo, "XkbOptions", NULL, &state->xkb_options);
+
+ SetXkbOption (pInfo, "XkbKeycodes", NULL, &state->xkbnames.keycodes);
+ SetXkbOption (pInfo, "XkbTypes", NULL, &state->xkbnames.types);
+ SetXkbOption (pInfo, "XkbCompat", NULL, &state->xkbnames.compat);
+ SetXkbOption (pInfo, "XkbSymbols", NULL, &state->xkbnames.symbols);
+ SetXkbOption (pInfo, "XkbGeometry", NULL, &state->xkbnames.geometry);
+ }
+
+ return Success;
+}
+
+int
+EvdevKeyOn (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevKeyOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+void
+EvdevKeyProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ int keycode = ev->code + MIN_KEYCODE;
+
+ /* filter repeat events for chording keys */
+ if (ev->value == 2) {
+ DeviceIntPtr device = pInfo->dev;
+ KeyClassRec *keyc = device->key;
+ KbdFeedbackClassRec *kbdfeed = device->kbdfeed;
+ int num = keycode >> 3;
+ int bit = 1 << (keycode & 7);
+
+ if (keyc->modifierMap[keycode] ||
+ !(kbdfeed->ctrl.autoRepeats[num] & bit))
+ return;
+ }
+
+ xf86PostKeyboardEvent(pInfo->dev, keycode, ev->value);
+}
diff --git a/src/evdev_rel.c b/src/evdev_rel.c
new file mode 100644
index 0000000..9e30bd0
--- /dev/null
+++ b/src/evdev_rel.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright © 2006 Zephaniah E. Hull
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Author: Zephaniah E. Hull (warp@aehallh.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/extensions/XIproto.h>
+
+/* The libc wrapper just blows... linux/input.h must be included
+ * before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl
+ * twice. */
+
+#include <linux/input.h>
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <xf86_OSproc.h>
+#include <xf86_ansic.h>
+#include <xf86_libc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <mipointer.h>
+
+#include <xf86Module.h>
+
+#include "evdev.h"
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+#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 TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+static char *axis_names[] = {
+ "X",
+ "Y",
+ "Z",
+ "RX",
+ "RY",
+ "RZ",
+ "HWHEEL",
+ "DIAL",
+ "WHEEL",
+ "MISC",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ NULL
+};
+
+static void
+EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ /* Nothing to do, dix handles all settings */
+}
+
+static Bool
+EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
+ int v3, int v4, int v5, int *x, int *y)
+{
+ if (first == 0) {
+ *x = v0;
+ *y = v1;
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+/*
+ * FIXME: Verify that the C standard lets us pass more variable arguments
+ * then we specify.
+ */
+void
+EvdevRelSyn (InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ int i, btn;
+
+ if (!state->rel_axes || state->mode != Relative)
+ return;
+
+ for (i = 0; i < state->rel_axes; i++) {
+ if ((state->rel_v[i] > 0) && (btn = state->relToBtnMap[i][0]))
+ EvdevBtnPostFakeClicks (pInfo, btn, state->rel_v[i]);
+ else if ((state->rel_v[i] < 0) && (btn = state->relToBtnMap[i][1]))
+ EvdevBtnPostFakeClicks (pInfo, btn, -state->rel_v[i]);
+ }
+
+ xf86PostMotionEvent(pInfo->dev, 0, 0, state->rel_axes,
+ state->rel_v[0], state->rel_v[1], state->rel_v[2], state->rel_v[3],
+ state->rel_v[4], state->rel_v[5], state->rel_v[6], state->rel_v[7],
+ state->rel_v[8], state->rel_v[9], state->rel_v[10], state->rel_v[11],
+ state->rel_v[12], state->rel_v[13], state->rel_v[14], state->rel_v[15]);
+
+ for (i = 0; i < REL_MAX; i++)
+ state->rel_v[i] = 0;
+}
+
+void
+EvdevRelProcess (InputInfoPtr pInfo, struct input_event *ev)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ int map;
+
+ if (ev->code >= REL_MAX)
+ return;
+
+ map = pEvdev->state.relMap[ev->code];
+ if (map >= 0)
+ pEvdev->state.rel_v[map] += ev->value;
+ else
+ pEvdev->state.rel_v[-map] -= ev->value;
+
+ if (!pEvdev->state.sync)
+ EvdevRelSyn (pInfo);
+}
+
+int
+EvdevRelInit (DeviceIntPtr device)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ evdevDevicePtr pEvdev = pInfo->private;
+ int i;
+
+ if (!InitValuatorClassDeviceStruct(device, pEvdev->state.rel_axes,
+ miPointerGetMotionEvents,
+ miPointerGetMotionBufferSize(), 0))
+ return !Success;
+
+ for (i = 0; i < pEvdev->state.rel_axes; i++) {
+ xf86InitValuatorAxisStruct(device, i, 0, 0, 0, 0, 1);
+ xf86InitValuatorDefaults(device, i);
+ }
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
+ return Success;
+}
+
+int
+EvdevRelOn (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevRelOff (DeviceIntPtr device)
+{
+ return Success;
+}
+
+int
+EvdevRelNew(InputInfoPtr pInfo)
+{
+ evdevDevicePtr pEvdev = pInfo->private;
+ evdevStatePtr state = &pEvdev->state;
+ long rel_bitmask[NBITS(KEY_MAX)];
+ char *s, option[64];
+ int i, j, k = 0, real_axes;
+
+ if (ioctl(pInfo->fd,
+ EVIOCGBIT(EV_REL, REL_MAX), rel_bitmask) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
+ return !Success;
+ }
+
+ real_axes = 0;
+ for (i = 0; i < REL_MAX; i++)
+ if (TestBit (i, rel_bitmask))
+ real_axes++;
+
+ if (!real_axes && (state->abs_axes < 2))
+ return !Success;
+
+ xf86Msg(X_INFO, "%s: Found %d relative axes.\n", pInfo->name,
+ real_axes);
+ xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
+ pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
+ XI86_CONFIGURED;
+ pInfo->type_name = XI_MOUSE;
+ pInfo->conversion_proc = EvdevConvert;
+
+ for (i = 0, j = 0; i < REL_MAX; i++) {
+ if (!TestBit (i, rel_bitmask))
+ continue;
+
+ snprintf(option, sizeof(option), "%sRelativeAxisMap", axis_names[i]);
+ s = xf86SetStrOption(pInfo->options, option, "0");
+ if (s && (k = strtol(s, NULL, 0)))
+ state->relMap[i] = k;
+ else
+ state->relMap[i] = j;
+
+ if (s && k)
+ xf86Msg(X_CONFIG, "%s: %s: %d.\n", pInfo->name, option, k);
+
+
+ snprintf(option, sizeof(option), "%sRelativeAxisButtons", axis_names[i]);
+ if (i == REL_WHEEL || i == REL_Z)
+ s = xf86SetStrOption(pInfo->options, option, "4 5");
+ else if (i == REL_HWHEEL)
+ s = xf86SetStrOption(pInfo->options, option, "6 7");
+ else
+ s = xf86SetStrOption(pInfo->options, option, "0 0");
+
+ k = state->relMap[i];
+
+ if (!s || (sscanf(s, "%d %d", &state->relToBtnMap[k][0],
+ &state->relToBtnMap[k][1]) != 2))
+ state->relToBtnMap[k][0] = state->relToBtnMap[k][1] = 0;
+
+ if (state->relToBtnMap[k][0] || state->relToBtnMap[k][1])
+ xf86Msg(X_CONFIG, "%s: %s: %d %d.\n", pInfo->name, option,
+ state->relToBtnMap[k][0], state->relToBtnMap[k][1]);
+
+ j++;
+ }
+
+ state->rel_axes = real_axes;
+ for (i = 0; i < REL_MAX; i++)
+ if (state->relMap[i] > state->rel_axes)
+ state->rel_axes = state->relMap[i];
+
+ if ((state->abs_axes >= 2) && (state->rel_axes < 2))
+ state->rel_axes = 2;
+
+ if (state->rel_axes != real_axes)
+ xf86Msg(X_CONFIG, "%s: Configuring %d relative axes.\n", pInfo->name,
+ state->rel_axes);
+
+ return Success;
+}