mirror of
https://github.com/X11Libre/xf86-input-evdev.git
synced 2026-03-27 19:18:29 +00:00
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.
This commit is contained in:
29
ChangeLog
29
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:
|
||||
|
||||
@@ -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
|
||||
|
||||
148
man/evdev.man
148
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.
|
||||
|
||||
@@ -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
|
||||
|
||||
827
src/evdev.c
827
src/evdev.c
@@ -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
213
src/evdev.h
Normal 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
348
src/evdev_abs.c
Normal 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
284
src/evdev_brain.c
Normal 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
229
src/evdev_btn.c
Normal 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
433
src/evdev_key.c
Normal 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
271
src/evdev_rel.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user