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.
This commit is contained in:
Zephaniah E. Hull
2006-02-14 14:57:37 +00:00
parent edbe44da9a
commit e7d4e6b11e
11 changed files with 2196 additions and 591 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -1,3 +1,33 @@
/*
* 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.
*
@@ -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
#include <xf86_OSproc.h>
#ifndef EV_SYN
#define EV_SYN EV_RST
#endif
/* end compat */
/*
* FIXME: This should most definitely not be here.
* But I need it, even if it _is_ private.
*/
#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;
for (i = 0; i < count; i++) {
xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
}
}
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)
{
/* 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)
EvdevSigioReadInput (int fd, void *data)
{
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;
}
static int
EvdevAddButtonClass(DeviceIntPtr device)
{
CARD8 map[32];
InputInfoPtr pInfo;
int i;
pInfo = device->public.devicePrivate;
/* FIXME: count number of actual buttons */
for (i = 0; i < ArrayLength(map); i++)
map[i] = i;
/* 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 (!InitButtonClassDeviceStruct(device, ArrayLength(map), map))
return !Success;
pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
return Success;
}
static int
EvdevInit(DeviceIntPtr device)
{
InputInfoPtr pInfo;
pInfo = device->public.devicePrivate;
/* FIXME: This doesn't add buttons for keyboards with
* scrollwheels. */
if (pInfo->flags & XI86_KEYBOARD_CAPABLE) {
EvdevAddKeyClass(device);
}
if (pInfo->flags & XI86_POINTER_CAPABLE) {
EvdevAddButtonClass(device);
EvdevAddRelClass(device);
}
return Success;
EvdevReadInput ((InputInfoPtr) data);
}
static int
EvdevProc(DeviceIntPtr device, int what)
{
InputInfoPtr pInfo;
EvdevPtr pEvdev;
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
InputInfoPtr pInfo = device->public.devicePrivate;
evdevDevicePtr pEvdev = pInfo->private;
switch (what)
{
case DEVICE_INIT:
return EvdevInit(device);
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;
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);
xf86Msg(X_INFO, "%s: On\n", pInfo->name);
if (device->public.on)
break;
if ((pInfo->fd = evdevGetFDForDevice (pEvdev)) == -1) {
xf86Msg(X_ERROR, "%s: cannot open input device.\n", pInfo->name);
if (pEvdev->phys)
xfree(pEvdev->phys);
pEvdev->phys = NULL;
if (pEvdev->device)
xfree(pEvdev->device);
pEvdev->device = NULL;
return BadRequest;
}
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));
xf86FlushInput (pInfo->fd);
if (!xf86InstallSIGIOHandler (pInfo->fd, EvdevSigioReadInput, pInfo))
AddEnabledDevice (pInfo->fd);
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;
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;
case DEVICE_CLOSE:
xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
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);
}
device->public.on = FALSE;
break;
}
return Success;
}
static int
EvdevSwitchMode (ClientPtr client, DeviceIntPtr device, int mode)
{
InputInfoPtr pInfo = device->public.devicePrivate;
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
switch (mode)
{
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)
{
if (first == 0 && num == 2) {
*x = v0;
*y = v1;
return TRUE;
}
else
return FALSE;
}
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 (ioctl(pInfo->fd,
EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) < 0) {
xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno));
return 1;
}
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;
}
has_axes = FALSE;
has_buttons = FALSE;
has_keys = FALSE;
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;
}
if (TestBit(BTN_LEFT, key_bitmask)) {
xf86Msg(X_INFO, "%s: Found mouse buttons\n", pInfo->name);
has_buttons = TRUE;
}
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 (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;
}
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 ((pInfo->flags & XI86_CONFIGURED) == 0) {
xf86Msg(X_WARNING, "%s: Don't know how to use device\n",
pInfo->name);
return 1;
}
return 0;
}
static InputInfoPtr
EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
{
InputInfoPtr pInfo;
MessageType deviceFrom = X_CONFIG;
const char *device;
EvdevPtr pEvdev;
char name[512] = {0};
if (!(pInfo = xf86AllocateInput(drv, 0)))
return NULL;
if (!(pInfo = xf86AllocateInput(driver->drv, 0)))
return 0;
/* Initialise the InputInfoRec. */
pInfo->name = dev->identifier;
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->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;
pInfo->conf_idev = driver->dev;
if (!(pEvdev = xcalloc(sizeof(*pEvdev), 1)))
return pInfo;
pInfo->private = pEvdev;
pInfo->private = device;
device->callback = EvdevProc;
device->pInfo = pInfo;
xf86CollectInputOptions(pInfo, NULL, NULL);
xf86ProcessCommonOptions(pInfo, pInfo->options);
xf86ProcessCommonOptions(pInfo, pInfo->options);
device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
if (!device) {
xf86Msg(X_ERROR, "%s: No device specified.\n", pInfo->name);
xfree(pEvdev);
return pInfo;
}
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);
xfree(pEvdev);
return pInfo;
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;
}
if (EvdevProbe(pInfo))
xfree(pEvdev);
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);
}
return pInfo;
/* 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 (driver->configured) {
xf86ActivateDevice (pInfo);
pInfo->dev->inited = (device->callback(device->pInfo->dev, DEVICE_INIT) == Success);
EnableDevice (pInfo->dev);
}
return 1;
}
static InputInfoPtr
EvdevCorePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
evdevDriverPtr pEvdev;
if (!(pEvdev = Xcalloc(sizeof(*pEvdev))))
return NULL;
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);
pEvdev->callback = EvdevNew;
pEvdev->dev = dev;
pEvdev->drv = drv;
if (!pEvdev->name && !pEvdev->phys && !pEvdev->device) {
xf86Msg(X_ERROR, "%s: No device identifiers specified.\n", dev->identifier);
xfree(pEvdev);
return NULL;
}
if (!evdevStart (drv)) {
xf86Msg(X_ERROR, "%s: cannot start evdev brain.\n", dev->identifier);
xfree(pEvdev);
return NULL;
}
evdevNewDriver (pEvdev);
if (pEvdev->devices && pEvdev->devices->pInfo)
return pEvdev->devices->pInfo;
return NULL;
}
_X_EXPORT InputDriverRec EVDEV = {
1,
"evdev",
NULL,
EvdevPreInit,
EvdevCorePreInit,
NULL,
NULL,
0

213
src/evdev.h Normal file
View File

@@ -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_ */

348
src/evdev_abs.c Normal file
View File

@@ -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;
}

284
src/evdev_brain.c Normal file
View File

@@ -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;
}

229
src/evdev_btn.c Normal file
View File

@@ -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. */
}
}

433
src/evdev_key.c Normal file
View File

@@ -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);
}

271
src/evdev_rel.c Normal file
View File

@@ -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;
}