Compare commits

...

45 Commits

Author SHA1 Message Date
Adam Jackson
08ba40b253 evdev 1.99.3 2008-06-10 17:35:33 -04:00
Peter Hutterer
39dc453691 Disable middle mouse button emulation when a real middle MB event is detected.
Devices may report middle mouse buttons even if they don't have one (PS/2
devices just don't know any better), so we can't be sure until we see the
event.
2008-06-10 22:48:01 +09:30
Peter Hutterer
e8887435ac Enable middle-mouse button emulation.
Ported from xf86-input-mouse, with a few cleanups.
2008-06-10 22:46:20 +09:30
Peter Hutterer
b0f6987ee6 Plug a memory leak, we allocated pEvdev twice, dropping the first memory area. 2008-06-10 22:43:37 +09:30
Sven Wegener
fec73e1418 evdev: Port b4a5a204 "Fix pointer crossing screen bug." to current master branch
The commit b4a5a204 fixed an issue, where we can't move the pointer to
other screens and this happens in current master branch again. This commit
ports the old commit to the current master branch.

Signed-off-by: Sven Wegener <swegener@gentoo.org>
Signed-off-by: Peter Hutterer <peter@cs.unisa.edu.au>
2008-06-08 21:44:57 +09:30
Peter Hutterer
da112737eb Check for XINPUT ABI < 3 (corrected version)
Thanks to Sven Wegener for pointing out the incorrect previous version.
2008-06-08 00:15:26 +09:30
Peter Hutterer
d40125ea8c Revert "Check for XINPUT ABI, parameters of InitValuatorClassRec have changed."
GetMotionEvents() doesn't exist, led to compile errors with servers pre-MPX
merge. Thanks to Sven Wegener for pointing this out.

This reverts commit 42422d8f69.
2008-06-08 00:13:35 +09:30
Peter Hutterer
42422d8f69 Check for XINPUT ABI, parameters of InitValuatorClassRec have changed. 2008-05-26 19:29:32 +09:30
Peter Hutterer
15e0091f0b Fail if the device cannot be grabbed during the probe.
If the grab fails, this is most likely a sign that the device has been grabbed
already (probably by a device specified in xorg.conf). So let's not add the
device to the server's input device list, since it won't generate events
anyway.

Exception: keyboards and kernel 2.4 are not affected.
2008-05-23 09:52:46 +09:30
Adam Jackson
d45f315845 evdev 1.99.2 2008-05-21 15:05:10 -04:00
Dan A. Dickey
a4a7003f7c Fix a trivial bug in testing for absolute axes.
Signed-off-by: Peter Hutterer <peter@cs.unisa.edu.au>
2008-05-20 10:57:06 +09:30
Peter Hutterer
3e0dc9945d Shut up two compiler warnings. 2008-05-19 08:36:20 +09:30
Peter Hutterer
ff6251a2bd Remove unused EvdevOpts and EvdevOptions.
In the mouse driver, these options are only used if XFree86LOADER is
undefined. configure.ac in the xserver forces said define to 1 if we're
building the xfree86 DDX, so I don't see the point of having them around.
Especially since they weren't used in evdev anyway.
2008-05-19 08:24:55 +09:30
Peter Hutterer
e9222a8285 man: Option "Path" is supported in the code, add it to man page. 2008-05-18 11:04:43 +09:30
Peter Hutterer
8b7738457f Don't allow relative and absolute axes on the same device.
This is a bit of a mess. The MS Optical Desktop 2000 registers both relative
and absolute axes on the same device (the mouse). The absolute axes have a
valid min/max range for x/y and thus overwrite the x/y relative axes in the
server (no, this is not a server bug). And I wouldn't be surprised if other
devices have similar issues.

Since the device only sends relative events after that, the mouse is
essentially restricted to the min..max range of 0..255. The server simply
doesn't do unrestricted relative axis and restricted absolute axis on the same
device (not for the same axis numbers anyway).
2008-05-02 11:17:57 +09:30
Sascha Hlusiak
1b9deb8e7e Add XK_Meta_L and XK_Meta_R to list of modifiers
Stopps meta/super key from autorepeating
2008-04-01 17:24:13 +02:00
Daniel Stone
0ec391f51c Keyboard: Don't allow arbitrary keymap settings
Pretty much dead code anyway.
2008-03-28 17:46:38 +02:00
Adam Jackson
f77410e1f9 Map REL_DIAL to REL_HWHEEL.
Some Microsoft mice have this wrong.  And it seems like a sensible thing
to do anyway.
2008-03-14 11:15:01 -04:00
Adam Jackson
d28c2e1efb Filter out repeat events for mouse buttons.
Not many mice do this, but some do, Apple Mighty Mouse in particular, and
it makes click-and-drag pretty much impossible to use.

Arguably we should filter _all_ repeat events from the kernel and handle
synthesizing them in the server.
2008-03-12 13:54:10 -04:00
Adam Jackson
697e850a63 Fix middle/right button munging.
Don't do this in the button map.  That's writeable by clients, which means
they have the chance to get it wrong.  Just swap right and middle around
in event dispatch before you get to the user's map.
2008-03-11 19:07:58 -04:00
Adam Jackson
87037b9953 Force xkb_model to be "evdev".
Or at least, refuse to recognise the config option.  It's nonsensical to
use a model of something other than evdev, and it'll just break if you try.
2008-03-10 17:16:38 -04:00
Dan Nicholson
71f4eaec77 Fix cut-and-paste errors in xkb alternate spellings code
Fixes 2b334d6b69.
2008-03-09 22:52:13 +01:00
Adam Jackson
7208397612 Fix cut-and-paste error in abs-to-rel translation. 2008-03-09 16:15:14 -04:00
Adam Jackson
c250f84383 Fix the default XKB rules to be "base" instead of "xfree86". 2008-03-09 15:54:27 -04:00
Adam Jackson
2b334d6b69 Handle the alternate spellings of the xkb options. 2008-03-09 15:53:40 -04:00
Adam Jackson
9773dac623 Merge branch 'evdev-2.0-branch'
This resets to before the ad-hoc input hotplug state, ports that to
current server ABI, adds input hotplug integration, and re-adds support
for absolute coordinate events and XKB.  Several other small fixes were
cherry-picked from the new 1.2 branch.
2008-03-08 20:27:02 -05:00
Adam Jackson
1a0bc8e64a Force maximum keycode to be 255
Even though we don't have keycodes for anything above 127, make sure our
map always covers up to 255.  This ensures that the keycode range never
changes.

Spiritually cherry-picked from a9e87f29cc
and 6db4a9fb84.
2008-03-08 20:06:24 -05:00
Adam Jackson
6271494faa Add absolute coordinate event support.
There are two major classes here, touchscreens and touchpads.  Touchpads
are logically more like relative devices, in that your initial touch
should not warp the cursor.  So attempt to detect touchpads (via the
existence of BTN_TOUCH) and translate absolute events from those devices
to relative motion.
2008-03-08 19:54:44 -05:00
Adam Jackson
f5bfc7ec3c Nuke the keyboard bell code.
It did nothing, and the core won't invoke it anymore anyway.
2008-03-08 16:52:17 -05:00
Adam Jackson
bf0848ec8e Re-add XKB support.
Almost entirely taken from a patch I did ages ago in bug #3912, with
slight cleanups, and with the KcCGST options removed as per evdev 1.x.
2008-03-08 16:50:20 -05:00
Adam Jackson
f1445feac7 Parse Option "Path" as well as Option "Device".
The hotplug core passes Path not Device.  With this change, hotplugging
works.
2008-03-08 16:09:47 -05:00
Adam Jackson
ad5bdcb50f Ignore button events above BTN_TASK for now. 2008-03-07 20:29:58 -05:00
Adam Jackson
bb36ca65c6 Support the new DIX motion history API
Spiritually cherry-picked from 036b457c1b
2008-03-07 19:43:07 -05:00
Daniel Stone
40a1e1439c remove XFree86LOADER usage
Build evdevModuleData, et al, unconditionally.
2008-03-07 19:38:33 -05:00
Adam Jackson
946beb16f8 Unlibcwrap. 2008-03-07 19:09:35 -05:00
Adam Jackson
305f90d37a Branch for evdev 2.0 2008-03-07 19:06:14 -05:00
Sascha Hlusiak
11cf9c92c0 Updated manpage to reflect current state
Large parts of the manpage were obsolete and confused users. Current state should reflect all available driver options. Some details are still missing.
2008-03-03 13:40:52 +02:00
Sascha Hlusiak
7f1e8146d4 More accurate error messages on device open fail.
The message "cannot open input pEvdev" resulted in a lot of bug reports of confused users that did not
supply a device path. Now we tell them when it is missing or print out a reason when device open fails.
2008-02-20 20:41:08 +01:00
Sascha Hlusiak
8ae4d17ca3 Let kernel autorepeat pass when set on default values
xorg-server won't generate soft autorepeat, when interval/delay are at default of 40/660 (see xkb/ddxCtrls.c:
XkbDDXUsesSoftRepeat). When we hit the defaults, we let the kernel autorepeat pass, if we differ, we swallow them all
and let the server figure out autorepeat in software.
2008-02-19 22:49:51 +01:00
Sascha Hlusiak
134ce2e493 Set repeat_delay and repeat_interval to default values
Set ctrls->repeat_delay and ctrls->repeat_interval so that keys will be automatically repeated in software.
2008-02-19 21:12:36 +01:00
Sascha Hlusiak
10e7c3fbdf Filter all incoming repeated key events
Not just filter modifiers but every repeated key, because the software implementation will take care of what key to
repeat and what not. Otherwise the kernel's autorepeated keys interfere with the software generated ones.
2008-02-19 21:09:13 +01:00
Sascha Hlusiak
f766404fd9 Don't inform kernel evdev driver about autorepeat change
We do autorepeat in software now. Informing the kernel would change the autorepeat speed on virtual terminals, which is
probably not wanted so we leave the settings untouched.
2008-02-19 21:05:49 +01:00
Vinay Bondhugula
d032d3c8b4 Clear EV_ABS_V_USE_TOUCH for devices without a touch button
VMware's absolute pointing device does not have a pressure/touch button.
Although evdev correctly recognizes this, it sets "use_touch" for X and Y axes
regardless of the touch button. This patch clears the USE_TOUCH flag for the X
and Y axes if the device does not have a touch button.
2008-01-29 22:15:22 -08:00
Peter Hutterer
5adbc6b98c Initialise b_map_data to correct size. Bug #13991
X.Org Bug 13991 <http://bugs.freedesktop.org/show_bug.cgi?id=13991>
2008-01-29 14:07:49 +10:30
Julien Cristau
eeb3727004 Don't flush buttons on init (bug#12630) 2007-12-07 17:02:11 +01:00
14 changed files with 1403 additions and 2945 deletions

View File

@@ -1,13 +1,9 @@
Makefile
Makefile.in
ChangeLog
xf86-input-evdev-*.tar.bz2
xf86-input-evdev-*.tar.gz
*.la
*.lo
aclocal.m4
autom4te.cache
compile
config.guess
config.h
config.h.in
@@ -21,5 +17,3 @@ libtool
ltmain.sh
missing
stamp-h1
.*.swp
*~

47
ChangeLog Normal file
View File

@@ -0,0 +1,47 @@
2006-01-09 David Nusinow,,, <set EMAIL_ADDRESS environment variable>
* man/Makefile.am:
* man/evdev.man:
Bugzilla #968 <https://bugs.freedesktop.org/show_bug.cgi?id=968>
Patch #4301 <https://bugs.freedesktop.org/attachment.cgi?id=4301>
Add evdev manpage
2005-12-20 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Update package version for X11R7 release.
2005-12-14 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Update package version number for final X11R7 release candidate.
2005-12-06 Kevin E. Martin <kem-at-freedesktop-dot-org>
* man/Makefile.am:
Change *man_SOURCES ==> *man_PRE to fix autotools warnings.
2005-12-03 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Update package version number for X11R7 RC3 release.
2005-12-01 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Remove extraneous AC_MSG_RESULT.
2005-11-29 Adam Jackson <ajax@freedesktop.org>
* configure.ac:
Only build dlloader modules by default.
2005-11-09 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Update package version number for X11R7 RC2 release.
2005-11-01 Kevin E. Martin <kem-at-freedesktop-dot-org>
* configure.ac:
Update pkgcheck dependencies to work with separate build roots.

View File

@@ -20,14 +20,3 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src man
EXTRA_DIST=ChangeLog
CLEANFILES=ChangeLog
.PHONY: ChangeLog
ChangeLog:
(GIT_DIR=$(top_srcdir)/.git git-log > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2)
dist-hook: ChangeLog

View File

@@ -22,7 +22,7 @@
AC_PREREQ(2.57)
AC_INIT([xf86-input-evdev],
1.2.0,
1.99.3,
[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
xf86-input-evdev)
@@ -71,8 +71,7 @@ inputdir=${moduledir}/input
AC_SUBST(inputdir)
# Checks for extensions
#XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
XORG_DRIVER_CHECK_EXT(XKB, kbproto)
XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
# Checks for pkg-config packages

View File

@@ -1,3 +1,2 @@
Makefile
Makefile.in
evdev.4

View File

@@ -9,12 +9,15 @@ evdev \- Generic Linux input driver
.BI " Identifier \*q" devname \*q
.B " Driver \*qevdev\*q"
.BI " Option \*qDevice\*q \*q" devpath \*q
.BI " Option \*qPath\*q \*q" path \*q
.BI " Option \*qEmulate3Buttons\*q \*q" True \*q
.BI " Option \*qEmulate3Timeout\*q \*q" 50 \*q
\ \ ...
.B EndSection
.fi
.SH DESCRIPTION
.B evdev
is an __xservername__ input driver for Linux's generic event devices. It
is an __xservername__ input driver for Linux\'s generic event devices. It
therefore supports all input devices that the kernel knows about, including
most mice and keyboards.
.PP
@@ -37,301 +40,35 @@ 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 BASIC CONFIGURATIONS
Most users of this driver will probably be quite happy with the following for
all QWERTY keyboards:
.PP
.nf
.B "Section \*qInputDevice\*q"
.BI " Identifier \*q" keyboard \*q
.B " Driver \*qevdev\*q"
.BI " Option \*qevBits\*q \*q" "+1" \*q
.BI " Option \*qkeyBits\*q \*q" "~1\-255 ~352\-511" \*q
.BI " Option \*qPass\*q \*q" "3" \*q
\ \ ...
.B EndSection
.fi
.PP
And the following for all mice:
.PP
.nf
.B "Section \*qInputDevice\*q"
.BI " Identifier \*q" mouse \*q
.B " Driver \*qevdev\*q"
.BI " Option \*qevBits\*q \*q" "+1\-2" \*q
.BI " Option \*qkeyBits\*q \*q" "~272\-287" \*q
.BI " Option \*qrelBits\*q \*q" "~0\-2 ~6 ~8" \*q
.BI " Option \*qPass\*q \*q" "3" \*q
\ \ ...
.B EndSection
.fi
.PP
To understand what those Bits options do, or for more complex
configurations, please see
.BR "ADVANCED OPTIONS"
below.
.PP
.SH ADVANCED OPTIONS
.SS DEVICE SPECIFICATION
For this section you'll want to have knowledge of
.B glob (7)
and our evil
.B "BIT MATCHING SPECIFICATION"
stuff.
.PP
The following driver
.B Options
control what devices are accepted:
are supported:
.TP 7
.BI "Option \*qDevice\*q \*q" string \*q
Specifies the device note through which the device can be accessed.
At this time ONLY
.RI /dev/input/event n ,
where
.I n
is an integer, are matched against this this field.
.fi
This option uses globbing.
.fi
Please note that use of this option is strongly discouraged.
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 unless \*qPath\*q is given, and there is no default setting.
.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.
.fi
This option uses globbing.
.BI "Option \*qPath\*q \*q" string \*q
Specifies the device through which the device can be accessed. This will
generally be of the form \*q/dev/input/by-path/xyz\*q, where xyz includes the
name of the device. The mapping from device node to hardware is
system-dependent. This option has precedence over the \*qDevice\*q option but
one of \*qPath\*q or \*qDevice\*q must be given.
.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 consistent 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.
.fi
This option uses globbing.
.BI "Option \*qEmulate3Buttons\*q \*q" boolean \*q
Enable/disable the emulation of the third (middle) mouse button for mice
which only have two physical buttons. The third button is emulated by
pressing both buttons simultaneously. Default: on, until a middle mouse
button event is registered.
.TP 7
.BI "Option \*q" map "Bits\*q \*q" "bit specifier" \*q
Specifies device capability bits which must be set, possibly set, or unset.
.fi
.IR map "Bits: Where " map
is one of
.BR ev ", " key ", " rel ", " abs ,
.BR msc ", " led ", " snd ", or " ff .
.fi
The bit specifier format is a string consisting of
.RI + n ", \-" n ", and ~" n
space-separated specifiers, where
.I n
is a positive integer or integer range. (The latter given in the format of 2\-6.)
.fi
+ specifies bits which must be set.
.fi
\- specifies bits which must not be set.
.fi
~ is a little more complex, it specifies that at least one of the bits given
with ~ for the field in question must be set, but it doesn't matter how many
or which of the bits. (It is actually the most useful of the 3 specifiers.)
.fi
As an example, \*q+0 +3 \-1\-2 ~5\-10\*q requires bits 0 and 3 be set,
bits 1 and 2 to not be set, and at least one bit in the range of 5 to
10 be set.
.fi
An annoyingly formatted set of bitmasks for your devices can be obtained
by typing \*qcat /proc/bus/input/devices\*q, and
.B /usr/include/linux/input.h
should contain the defines which declare what bits are what for each field.
.TP 7
.BI "Option \*qbustype\*q \*q" n \*q
Specifies the bus ID for the device you wish to use.
.fi
This is either 0 (the default, matches anything), or the
.BI Bus= n
field in
.B /proc/bus/input/devices
for your device.
.fi
This value depends on what type of bus your device is connected to.
.TP 7
.BI "Option \*qvendor\*q \*q" n \*q
Specifies the vendor ID for the device you wish to use.
.fi
This is either 0 (the default, matches anything), or the
.BI Vendor= n
field in
.B /proc/bus/input/devices
for your device.
.fi
This value should remain constant barring perhaps firmware updates to the
device itself.
.TP 7
.BI "Option \*qversion\*q \*q" n \*q
Specifies the version for the device you wish to use.
.fi
This is either 0 (the default, matches anything), or the
.BI Version= n
field in
.B /proc/bus/input/devices
for your device.
.fi
This value should remain constant barring perhaps firmware updates to the
device itself.
.TP 7
.BI "Option \*qproduct\*q \*q" n \*q
Specifies the product ID for the device you wish to use.
.fi
This is either 0 (the default, matches anything), or the
.BI Product= n
field in
.B /proc/bus/input/devices
for your device.
.fi
This value should remain constant barring perhaps firmware updates to the
device itself.
.TP 7
.BI "Option \*qPass\*q \*q" n \*q
Specifies the order in which evdev will scan for devices.
.fi
This is in the range of 0 to 3, and is used for the case
where more then one evdev input section matches the same device.
.fi
An input section with a lower pass number will always beat out
one with a higher pass number. Order when both sections are
the same number is undefined.
.fi
The default is 0.
.PP
.SS RELATIVE AXIS CONFIGURATION
The relative axis portion of this driver handle all reported relative axes.
.fi
The axes are named X, Y, Z, RX, RY, RZ, HWHEEL, DIAL, WHEEL, MISC, 10, 11,
12, 13, 14, and 15.
.fi
The axes are reported to X as valuators, with the default mapping of axes
to valuators being the first axes found to the first valuator, the second
found to the second valuator, and so on, so that if you have axes 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" n \*q
This remaps the axis specified to the specified valuator.
.TP 7
.BI "Option \*q" axis "RelativeAxisButtons\*q \*q" "n n" \*q
This remaps the axis specified to the specified buttons.
.fi
Note that the physical buttons are always remapped around \*qfake\*q 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
.SS ABSOLUTE AXIS CONFIGURATION
The relative axis portion of this driver handle all reported relative axes.
.fi
The axes are named X, Y, Z, RX, RY, RZ, THROTTLE, RUDDER, WHEEL, GAS, BRAKE,
<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 axes are reported to X as valuators, with the default mapping of axes
to valuators being the first axes found to the first valuator, the second
found to the second valuator, and so on, so that if you have axes 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" n \*q
This remaps the axis specified to the specified valuator.
.TP 7
.BI "Option \*qAbsoluteScreen\*q \*q" n \*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
.SS 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 buttons.
.SS 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: \*qxorg\*q for most platforms, but \*qxfree98\*q for the
Japanese PC-98 platforms.
.TP 7
.BI "Option \*qXkbModel\*q \*q" modelname \*q
specifies the XKB keyboard model name. Default: \*qevdev\*q.
.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: \*qus\*q.
.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
.BI "Option \*qEmulate3Timeout\*q \*q" integer \*q
Sets the timeout (in milliseconds) that the driver waits before deciding
if two buttons where pressed "simultaneously" when 3 button emulation is
enabled. Default: 50.
.SH AUTHORS
Zephaniah E. Hull.
.fi
Kristian H\(/ogsberg.
Kristian Høgsberg.
.SH "SEE ALSO"
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__).
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__),
README.mouse.

View File

@@ -26,7 +26,8 @@
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
@DRIVER_NAME@_drv_la_CFLAGS = -Wall
@DRIVER_NAME@_drv_ladir = @inputdir@
@DRIVER_NAME@_drv_la_SOURCES = evdev.c evdev.h evdev_axes.c evdev_btn.c evdev_key.c
@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
@DRIVER_NAME@.h \
emuMB.c

308
src/emuMB.c Normal file
View File

@@ -0,0 +1,308 @@
/*
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
* Copyright 1993 by David Dawes <dawes@xfree86.org>
* Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
* Copyright 1994-2002 by The XFree86 Project, Inc.
* Copyright 2002 by Paul Elliott
* (Ported from xf86-input-mouse, above copyrights taken from there)
* Copyright © 2008 University of South Australia
*
* 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.
*
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL THE AUTHORS 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.
*
*/
/* Middle mouse button emulation code. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "evdev.h"
/*
* Lets create a simple finite-state machine for 3 button emulation:
*
* We track buttons 1 and 3 (left and right). There are 11 states:
* 0 ground - initial state
* 1 delayed left - left pressed, waiting for right
* 2 delayed right - right pressed, waiting for left
* 3 pressed middle - right and left pressed, emulated middle sent
* 4 pressed left - left pressed and sent
* 5 pressed right - right pressed and sent
* 6 released left - left released after emulated middle
* 7 released right - right released after emulated middle
* 8 repressed left - left pressed after released left
* 9 repressed right - right pressed after released right
* 10 pressed both - both pressed, not emulating middle
*
* At each state, we need handlers for the following events
* 0: no buttons down
* 1: left button down
* 2: right button down
* 3: both buttons down
* 4: emulate3Timeout passed without a button change
* Note that button events are not deltas, they are the set of buttons being
* pressed now. It's possible (ie, mouse hardware does it) to go from (eg)
* left down to right down without anything in between, so all cases must be
* handled.
*
* a handler consists of three values:
* 0: action1
* 1: action2
* 2: new emulation state
*
* action > 0: ButtonPress
* action = 0: nothing
* action < 0: ButtonRelease
*
* The comment preceeding each section is the current emulation state.
* The comments to the right are of the form
* <button state> (<events>) -> <new emulation state>
* which should be read as
* If the buttons are in <button state>, generate <events> then go to
* <new emulation state>.
*/
static signed char stateTab[11][5][3] = {
/* 0 ground */
{
{ 0, 0, 0 }, /* nothing -> ground (no change) */
{ 0, 0, 1 }, /* left -> delayed left */
{ 0, 0, 2 }, /* right -> delayed right */
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
{ 0, 0, -1 } /* timeout N/A */
},
/* 1 delayed left */
{
{ 1, -1, 0 }, /* nothing (left event) -> ground */
{ 0, 0, 1 }, /* left -> delayed left (no change) */
{ 1, -1, 2 }, /* right (left event) -> delayed right */
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
{ 1, 0, 4 }, /* timeout (left press) -> pressed left */
},
/* 2 delayed right */
{
{ 3, -3, 0 }, /* nothing (right event) -> ground */
{ 3, -3, 1 }, /* left (right event) -> delayed left (no change) */
{ 0, 0, 2 }, /* right -> delayed right (no change) */
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
{ 3, 0, 5 }, /* timeout (right press) -> pressed right */
},
/* 3 pressed middle */
{
{ -2, 0, 0 }, /* nothing (middle release) -> ground */
{ 0, 0, 7 }, /* left -> released right */
{ 0, 0, 6 }, /* right -> released left */
{ 0, 0, 3 }, /* left & right -> pressed middle (no change) */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 4 pressed left */
{
{ -1, 0, 0 }, /* nothing (left release) -> ground */
{ 0, 0, 4 }, /* left -> pressed left (no change) */
{ -1, 0, 2 }, /* right (left release) -> delayed right */
{ 3, 0, 10 }, /* left & right (right press) -> pressed both */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 5 pressed right */
{
{ -3, 0, 0 }, /* nothing (right release) -> ground */
{ -3, 0, 1 }, /* left (right release) -> delayed left */
{ 0, 0, 5 }, /* right -> pressed right (no change) */
{ 1, 0, 10 }, /* left & right (left press) -> pressed both */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 6 released left */
{
{ -2, 0, 0 }, /* nothing (middle release) -> ground */
{ -2, 0, 1 }, /* left (middle release) -> delayed left */
{ 0, 0, 6 }, /* right -> released left (no change) */
{ 1, 0, 8 }, /* left & right (left press) -> repressed left */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 7 released right */
{
{ -2, 0, 0 }, /* nothing (middle release) -> ground */
{ 0, 0, 7 }, /* left -> released right (no change) */
{ -2, 0, 2 }, /* right (middle release) -> delayed right */
{ 3, 0, 9 }, /* left & right (right press) -> repressed right */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 8 repressed left */
{
{ -2, -1, 0 }, /* nothing (middle release, left release) -> ground */
{ -2, 0, 4 }, /* left (middle release) -> pressed left */
{ -1, 0, 6 }, /* right (left release) -> released left */
{ 0, 0, 8 }, /* left & right -> repressed left (no change) */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 9 repressed right */
{
{ -2, -3, 0 }, /* nothing (middle release, right release) -> ground */
{ -3, 0, 7 }, /* left (right release) -> released right */
{ -2, 0, 5 }, /* right (middle release) -> pressed right */
{ 0, 0, 9 }, /* left & right -> repressed right (no change) */
{ 0, 0, -1 }, /* timeout N/A */
},
/* 10 pressed both */
{
{ -1, -3, 0 }, /* nothing (left release, right release) -> ground */
{ -3, 0, 4 }, /* left (right release) -> pressed left */
{ -1, 0, 5 }, /* right (left release) -> pressed right */
{ 0, 0, 10 }, /* left & right -> pressed both (no change) */
{ 0, 0, -1 }, /* timeout N/A */
},
};
int
EvdevMBEmuTimer(InputInfoPtr pInfo)
{
EvdevPtr pEvdev = pInfo->private;
int sigstate;
int id;
sigstate = xf86BlockSIGIO ();
pEvdev->emulateMB.pending = FALSE;
if ((id = stateTab[pEvdev->emulateMB.state][4][0]) != 0) {
xf86PostButtonEvent(pInfo->dev, 0, abs(id), (id >= 0), 0, 0);
pEvdev->emulateMB.state =
stateTab[pEvdev->emulateMB.state][4][2];
} else {
ErrorF("Got unexpected buttonTimer in state %d\n",
pEvdev->emulateMB.state);
}
xf86UnblockSIGIO (sigstate);
return 0;
}
/**
* Emulate a middle button on button press.
*
* @param code Evdev event code (BTN_LEFT or BTN_RIGHT)
* @param press TRUE if press, FALSE if release.
*
* @return TRUE if event was swallowed by middle mouse button emulation, FALSE
* otherwise.
*/
BOOL
EvdevMBEmuFilterEvent(InputInfoPtr pInfo, int code, BOOL press)
{
EvdevPtr pEvdev = pInfo->private;
int id;
int *btstate;
int ret = FALSE;
if (!pEvdev->emulateMB.enabled)
return ret;
/* don't care about other buttons */
if (code != BTN_LEFT && code != BTN_RIGHT)
return ret;
btstate = &pEvdev->emulateMB.buttonstate;
if (press)
*btstate |= (code == BTN_LEFT) ? 0x1 : 0x2;
else
*btstate &= (code == BTN_LEFT) ? ~0x1 : ~0x2;
if ((id = stateTab[pEvdev->emulateMB.state][*btstate][0]) != 0)
{
xf86PostButtonEvent(pInfo->dev, 0, abs(id), (id >= 0), 0, 0);
ret = TRUE;
}
if ((id = stateTab[pEvdev->emulateMB.state][*btstate][1]) != 0)
{
xf86PostButtonEvent(pInfo->dev, 0, abs(id), (id >= 0), 0, 0);
ret = TRUE;
}
pEvdev->emulateMB.state =
stateTab[pEvdev->emulateMB.state][*btstate][2];
if (stateTab[pEvdev->emulateMB.state][4][0] != 0) {
pEvdev->emulateMB.expires = GetTimeInMillis () + pEvdev->emulateMB.timeout;
pEvdev->emulateMB.pending = TRUE;
ret = TRUE;
} else {
pEvdev->emulateMB.pending = FALSE;
}
return ret;
}
void EvdevMBEmuWakeupHandler(pointer data,
int i,
pointer LastSelectMask)
{
InputInfoPtr pInfo = (InputInfoPtr)data;
EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
int ms;
if (pEvdev->emulateMB.pending)
{
ms = pEvdev->emulateMB.expires - GetTimeInMillis();
if (ms <= 0)
EvdevMBEmuTimer(pInfo);
}
}
void EvdevMBEmuBlockHandler(pointer data,
struct timeval **waitTime,
pointer LastSelectMask)
{
InputInfoPtr pInfo = (InputInfoPtr) data;
EvdevPtr pEvdev= (EvdevPtr) pInfo->private;
int ms;
if (pEvdev->emulateMB.pending)
{
ms = pEvdev->emulateMB.expires - GetTimeInMillis ();
if (ms <= 0)
ms = 0;
AdjustWaitForDelay (waitTime, ms);
}
}
void
EvdevMBEmuPreInit(InputInfoPtr pInfo)
{
EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
pEvdev->emulateMB.enabled = xf86SetBoolOption(pInfo->options,
"Emulate3Buttons", TRUE);
pEvdev->emulateMB.timeout = xf86SetIntOption(pInfo->options,
"Emulate3Timeout", 50);
RegisterBlockAndWakeupHandlers (EvdevMBEmuBlockHandler,
EvdevMBEmuWakeupHandler,
(pointer)pInfo);
}
/* Enable/disable middle mouse button emulation. */
void
EvdevMBEmuEnable(InputInfoPtr pInfo, BOOL enable)
{
EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
pEvdev->emulateMB.enabled = enable;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,272 +1,80 @@
/*
* Copyright © 2006-2007 Zephaniah E. Hull
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2004-2008 Red Hat, Inc.
* Copyright © 2008 University of South Australia
*
* 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.
* 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.
*
* 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.
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL THE AUTHORS 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.
*
* Authors:
* Zephaniah E. Hull (warp@aehallh.com)
* Kristian Høgsberg (krh@redhat.com)
* Kristian Høgsberg (krh@redhat.com)
* Adam Jackson (ajax@redhat.com)
* Peter Hutterer (peter@cs.unisa.edu.au)
*/
#ifndef __EVDEV_H
#define __EVDEV_H
#define _XF86_ANSIC_H
#define XF86_LIBC_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef EVDEV_H
#define EVDEV_H
#include <linux/input.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <xf86Xinput.h>
#include <xf86_OSproc.h>
#ifndef BITS_PER_LONG
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#endif
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define LONG(x) ((x)/BITS_PER_LONG)
#define MASK(x) (1UL << ((x) & (BITS_PER_LONG - 1)))
#ifndef test_bit
#define test_bit(bit, array) (!!(array[LONG(bit)] & MASK(bit)))
#endif
#ifndef set_bit
#define set_bit(bit, array) (array[LONG(bit)] |= MASK(bit))
#endif
#ifndef clear_bit
#define clear_bit(bit, array) (array[LONG(bit)] &= ~MASK(bit))
#endif
#include <X11/extensions/XKB.h>
#if defined(XKB)
/* XXX VERY WRONG. this is a client side header. */
#include <X11/extensions/XKBstr.h>
/*
* At the moment, ABS_MAX is larger then REL_MAX.
* As they are the only two providors of axes, ABS_MAX is it.
*/
#define AXES_MAX ABS_MAX
#define BTN_MAX 96
struct _evdevDevice;
/*
* FIXME: The mode option here is a kludge.
* It can be 0 (rel mode), 1 (abs mode), or -1 (input side has no clue).
*
* Worse, it arguably shouldn't even be the sender that decides here.
* And only the Axes targets and sources care at all right now.
*/
typedef void (*evdev_map_func_f)(InputInfoPtr pInfo, int value, int mode, void *map_data);
#endif
typedef struct {
unsigned long ev[NBITS(EV_MAX)];
unsigned long key[NBITS(KEY_MAX)];
unsigned long rel[NBITS(REL_MAX)];
unsigned long abs[NBITS(ABS_MAX)];
unsigned long msc[NBITS(MSC_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
unsigned long ff[NBITS(FF_MAX)];
} evdevBitsRec, *evdevBitsPtr;
int kernel24;
int screen;
int min_x, min_y, max_x, max_y;
int abs_x, abs_y, old_x, old_y;
int flags;
int tool;
#define EV_BTN_B_PRESENT (1<<0)
/* XKB stuff has to be per-device rather than per-driver */
int noXkb;
#ifdef XKB
char *xkb_rules;
char *xkb_model;
char *xkb_layout;
char *xkb_variant;
char *xkb_options;
XkbComponentNamesRec xkbnames;
#endif
/* Middle mouse button emulation */
struct {
BOOL enabled;
BOOL pending; /* timer waiting? */
int buttonstate; /* phys. button state */
int state; /* state machine (see bt3emu.c) */
Time expires; /* time of expiry */
Time timeout;
} emulateMB;
} EvdevRec, *EvdevPtr;
typedef struct {
int real_buttons;
int buttons;
int b_flags[BTN_MAX];
void *b_map_data[ABS_MAX];
evdev_map_func_f b_map[BTN_MAX];
void (*callback[BTN_MAX])(InputInfoPtr pInfo, int button, int value);
} evdevBtnRec, *evdevBtnPtr;
/* Middle Button emulation */
int EvdevMBEmuTimer(InputInfoPtr);
BOOL EvdevMBEmuFilterEvent(InputInfoPtr, int, BOOL);
void EvdevMBEmuWakeupHandler(pointer, int, pointer);
void EvdevMBEmuBlockHandler(pointer, struct timeval**, pointer);
void EvdevMBEmuPreInit(InputInfoPtr);
void EvdevMBEmuEnable(InputInfoPtr, BOOL);
#define EV_ABS_V_PRESENT (1<<0)
#define EV_ABS_V_M_AUTO (1<<1)
#define EV_ABS_V_M_REL (1<<2)
#define EV_ABS_V_INVERT (1<<3)
#define EV_ABS_V_RESET (1<<4)
#define EV_ABS_V_USE_TOUCH (1<<5)
#define EV_ABS_USE_TOUCH (1<<0)
#define EV_ABS_TOUCH (1<<1)
#define EV_ABS_UPDATED (1<<2)
typedef struct {
int flags;
int axes;
int v[ABS_MAX];
int v_flags[ABS_MAX];
void *v_map_data[ABS_MAX];
evdev_map_func_f v_map[ABS_MAX];
} evdevAbsRec, *evdevAbsPtr;
#define EV_REL_V_PRESENT (1<<0)
#define EV_REL_V_INVERT (1<<1)
#define EV_REL_UPDATED (1<<0)
typedef struct {
int flags;
int v_flags[REL_MAX];
int v[REL_MAX];
int axes;
void *v_map_data[REL_MAX];
evdev_map_func_f v_map[REL_MAX];
} evdevRelRec, *evdevRelPtr;
#define EV_AXES_V_M_ABS (1<<0)
#define EV_AXES_V_M_REL (1<<1)
#define EV_AXES_V_PRESENT (1<<2)
#define EV_AXES_V_UPDATED (1<<3)
#define EV_AXES_V_M_MASK (EV_AXES_V_M_ABS | EV_AXES_V_M_REL)
#define EV_AXES_UPDATED (1<<0)
typedef struct {
int axes;
int flags;
int v_flags[AXES_MAX];
int v_min[AXES_MAX];
int v_max[AXES_MAX];
int v[AXES_MAX];
int rotation;
float rot_sin, rot_cos;
int x, y;
} evdevAxesRec, *evdevAxesPtr;
typedef struct {
char *xkb_rules;
char *xkb_model;
char *xkb_layout;
char *xkb_variant;
char *xkb_options;
XkbComponentNamesRec xkbnames;
} evdevKeyRec, *evdevKeyPtr;
typedef struct _evdevState {
Bool can_grab;
Bool sync;
evdevBtnPtr btn;
evdevAbsPtr abs;
evdevRelPtr rel;
evdevKeyPtr key;
evdevAxesPtr axes;
} evdevStateRec, *evdevStatePtr;
typedef struct _evdevDevice {
const char *device;
evdevBitsRec bits;
evdevStateRec state;
} evdevDeviceRec, *evdevDevicePtr;
int EvdevBtnInit (DeviceIntPtr device);
int EvdevBtnOn (DeviceIntPtr device);
int EvdevBtnOff (DeviceIntPtr device);
int EvdevBtnNew0(InputInfoPtr pInfo);
int EvdevBtnNew1(InputInfoPtr pInfo);
void EvdevBtnProcess (InputInfoPtr pInfo, struct input_event *ev);
void EvdevBtnPostFakeClicks(InputInfoPtr pInfo, int button, int count);
int EvdevBtnFind (InputInfoPtr pInfo, const char *button);
int EvdevBtnExists (InputInfoPtr pInfo, int button);
int EvdevAxesInit (DeviceIntPtr device);
int EvdevAxesOn (DeviceIntPtr device);
int EvdevAxesOff (DeviceIntPtr device);
int EvdevAxesNew0(InputInfoPtr pInfo);
int EvdevAxesNew1(InputInfoPtr pInfo);
void EvdevAxesAbsProcess (InputInfoPtr pInfo, struct input_event *ev);
void EvdevAxesRelProcess (InputInfoPtr pInfo, struct input_event *ev);
void EvdevAxesSynRep (InputInfoPtr pInfo);
void EvdevAxesSynCfg (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);
/*
* Option handling stuff.
*/
typedef struct evdev_option_token_s {
const char *str;
struct evdev_option_token_s *chain;
struct evdev_option_token_s *next;
} evdev_option_token_t;
typedef Bool (*evdev_parse_opt_func_f)(InputInfoPtr pInfo, const char *name, evdev_option_token_t *token, int *flags);
typedef Bool (*evdev_parse_map_func_f)(InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func);
evdev_option_token_t *EvdevTokenize (const char *option, const char *tokens);
void EvdevFreeTokens (evdev_option_token_t *token);
Bool EvdevParseMapToRelAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func);
Bool EvdevParseMapToAbsAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func);
Bool
EvdevParseMapToButton (InputInfoRec *pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func);
Bool
EvdevParseMapToButtons (InputInfoRec *pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func);
typedef struct {
char *name;
evdev_parse_map_func_f func;
} evdev_map_parsers_t;
extern evdev_map_parsers_t evdev_map_parsers[];
Bool EvdevParseMapOption (InputInfoRec *pInfo, char *option, char *def, void **map_data, evdev_map_func_f *map_func);
#endif /* __EVDEV_H */
#endif

View File

@@ -1,930 +0,0 @@
/*
* Copyright © 2006-2007 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>
#include <string.h>
#include "evdev.h"
#include <xf86.h>
#include <xf86Module.h>
#include <mipointer.h>
#include <xf86_OSproc.h>
#undef DEBUG
static char *rel_axis_names[] = {
"X",
"Y",
"Z",
"RX",
"RY",
"RZ",
"HWHEEL",
"DIAL",
"WHEEL",
"MISC",
"10",
"11",
"12",
"13",
"14",
"15",
NULL
};
static char *abs_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 EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value);
void
EvdevAxesMapAxis (InputInfoPtr pInfo, int value, int mode, void *map_data)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long map = (long) map_data;
if (map >= AXES_MAX || !axes || !(axes->v_flags[map] & (EV_AXES_V_M_ABS | EV_AXES_V_M_REL)))
return;
axes->v[map] = value;
if (mode == 0) {
axes->v_flags[map] &= ~EV_AXES_V_M_ABS;
axes->v_flags[map] |= EV_AXES_V_M_REL;
} else if (mode == 1) {
axes->v_flags[map] &= ~EV_AXES_V_M_REL;
axes->v_flags[map] |= EV_AXES_V_M_ABS;
}
axes->v_flags[map] |= EV_AXES_V_UPDATED;
axes->flags |= EV_AXES_UPDATED;
}
static Bool
EvdevParseRelOptions (InputInfoPtr pInfo, const char *name, evdev_option_token_t *option, int *flags)
{
if (!option)
return 0;
for (; option; option = option->next) {
if (!strcasecmp (option->str, "invert"))
*flags |= EV_REL_V_INVERT;
else
xf86Msg(X_ERROR, "%s: %s unknown relative option '%s'.\n", pInfo->name, name, option->str);
}
*flags |= EV_REL_V_PRESENT;
return 1;
}
static Bool
EvdevParseAbsOptions (InputInfoPtr pInfo, const char *name, evdev_option_token_t *option, int *flags)
{
if (!option)
return 0;
for (; option; option = option->next) {
if (!strcasecmp (option->str, "invert"))
*flags |= EV_ABS_V_INVERT;
else if (!strcasecmp (option->str, "use_touch"))
*flags |= EV_ABS_V_USE_TOUCH;
else if (!strcasecmp (option->str, "mode_auto"))
*flags |= EV_ABS_V_M_AUTO;
else if (!strcasecmp (option->str, "mode_rel"))
*flags |= EV_ABS_V_M_REL;
else
xf86Msg(X_ERROR, "%s: %s unknown absolute option '%s'.\n", pInfo->name, name, option->str);
}
*flags |= EV_ABS_V_PRESENT;
return 1;
}
Bool
EvdevParseMapToRelAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long i;
errno = 0;
i = strtol (option->str, NULL, 0);
if (errno) {
for (i = 0; rel_axis_names[i]; i++) {
if (!strcmp (option->str, rel_axis_names[i]))
break;
}
if (!rel_axis_names[i])
return 0;
}
if ((i < 0) || (i > AXES_MAX))
return 0;
if (axes->v_flags[i] & EV_AXES_V_PRESENT)
return 0;
axes->v_flags[i] = EV_AXES_V_M_REL | EV_AXES_V_PRESENT;
*map_data = (void *) i;
*map_func = EvdevAxesMapAxis;
return 1;
}
Bool
EvdevParseMapToAbsAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long i;
errno = 0;
i = strtol (option->str, NULL, 0);
if (errno) {
for (i = 0; abs_axis_names[i]; i++) {
if (!strcmp (option->str, abs_axis_names[i]))
break;
}
if (!abs_axis_names[i]) {
xf86Msg (X_ERROR, "%s: %s: No axis named '%s'.\n", pInfo->name, name, option->str);
return 0;
}
}
if ((i < 0) || (i > AXES_MAX)) {
xf86Msg (X_ERROR, "%s: %s: Axis %ld out of range.\n", pInfo->name, name, i);
return 0;
}
if (axes->v_flags[i] & EV_AXES_V_PRESENT) {
xf86Msg (X_ERROR, "%s: %s: Axis %ld already claimed.\n", pInfo->name, name, i);
return 0;
}
option = option->next;
if (!option) {
xf86Msg (X_ERROR, "%s: %s: No min.\n", pInfo->name, name);
return 0;
}
errno = 0;
axes->v_min[i] = strtol (option->str, NULL, 0);
if (errno) {
xf86Msg (X_ERROR, "%s: %s: Unable to parse '%s' as min. (%s)\n", pInfo->name, name, option->str, strerror(errno));
return 0;
}
option = option->next;
if (!option) {
xf86Msg (X_ERROR, "%s: %s: No max.\n", pInfo->name, name);
return 0;
}
errno = 0;
axes->v_max[i] = strtol (option->str, NULL, 0);
if (errno) {
xf86Msg (X_ERROR, "%s: %s: Unable to parse '%s' as max. (%s)\n", pInfo->name, name, option->str, strerror(errno));
return 0;
}
axes->v_flags[i] = EV_AXES_V_M_ABS | EV_AXES_V_PRESENT;
*map_data = (void *) i;
*map_func = EvdevAxesMapAxis;
return 1;
}
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;
}
/*
* Rotation and rep code, this is a mess and much of it needs to live in mi/
* after a cleanup.
*/
static void
EvdevAxesDoRotation (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
DeviceIntPtr dev = pInfo->dev;
AbsoluteClassRec *dabs = dev->absolute;
/*
* Rotation.
* Cache the sine and cosine results so we're not doing it every time.
*/
if (dabs->rotation != axes->rotation || (axes->rot_cos == axes->rot_sin)) {
axes->rotation = dabs->rotation % 360;
axes->rot_cos = cos ( ((float) axes->rotation) * (M_PI/180));
axes->rot_sin = sin ( ((float) axes->rotation) * (M_PI/180));
}
if (axes->rotation) {
float x = axes->v[0], y = axes->v[1];
axes->v[0] = (x * axes->rot_cos) - (y * axes->rot_sin);
axes->v[1] = (y * axes->rot_cos) + (x * axes->rot_sin);
axes->v_flags[0] |= EV_AXES_V_UPDATED;
axes->v_flags[1] |= EV_AXES_V_UPDATED;
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): rotation=%d, cos=%f, sin=%f, x=%f, y=%f, v[0]=%d, v[1]=%d\n", __FILE__, __LINE__, __FUNCTION__,
axes->rotation, axes->rot_cos, axes->rot_sin, x, y, axes->v[0], axes->v[1]);
#endif
}
}
/*
* Cx - raw data from touch screen
* Sxhigh - scaled highest dimension
* (remember, this is of rows - 1 because of 0 origin)
* Sxlow - scaled lowest dimension
* Rxhigh - highest raw value from touch screen calibration
* Rxlow - lowest raw value from touch screen calibration
*
* This function is the same for X or Y coordinates.
* You may have to reverse the high and low values to compensate for
* different orgins on the touch screen vs X.
*/
_X_EXPORT int
EvdevScaleAxis(int Cx,
int Sxlow,
int Sxhigh,
int Rxlow,
int Rxhigh)
{
int X;
int dSx = Sxhigh - Sxlow;
int dRx = Rxhigh - Rxlow;
/* This is +, because Cx is negitive, so we're really subtracting. */
if (Cx < 0)
Cx = Rxhigh + Cx;
dSx = Sxhigh - Sxlow;
if (dRx) {
X = ((dSx * (Cx - Rxlow)) / dRx) + Sxlow;
}
else {
X = 0;
ErrorF ("Divide by Zero in evdevScaleAxis");
}
if (X < Sxlow)
X = Sxlow;
if (X > Sxhigh)
X = Sxhigh;
return (X);
}
void
EvdevAxesSynRep (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
DeviceIntPtr dev = pInfo->dev;
AbsoluteClassRec *dabs = dev->absolute;
int i, start, run, mode;
if (!axes || !(axes->flags & EV_AXES_UPDATED))
return;
start = 0;
mode = 0;
run = 0;
/*
* This handles most, but not all, of the ABS_CALIB and ABS_AREA
* additions to XInput 1.0.
*
* Note, we do this if both X and Y are set to absolute, or a more
* limited subset if both X and Y are relative, we don't do anything
* if we lack X or Y, or if they are not both set to both be ABS or REL.
*/
if (axes->axes >= 2 && dabs) {
if ((axes->v_flags[0] & EV_AXES_V_M_ABS) &&
(axes->v_flags[1] & EV_AXES_V_M_ABS) &&
((axes->v_flags[0] & EV_AXES_V_UPDATED) ||
(axes->v_flags[1] & EV_AXES_V_UPDATED))
) {
int width, height, min_x, max_x, min_y, max_y;
if (axes->v_flags[0] & EV_AXES_V_UPDATED) axes->x = axes->v[0];
else axes->v[0] = axes->x;
if (axes->v_flags[1] & EV_AXES_V_UPDATED) axes->y = axes->v[1];
else axes->v[1] = axes->y;
if (dabs->width > 0)
width = dabs->width;
else
width = screenInfo.screens[dabs->screen]->width;
if (dabs->height > 0)
height = dabs->height;
else
height = screenInfo.screens[dabs->screen]->height;
if (dabs->flip_x)
axes->v[0] = dabs->max_x - axes->v[0];
if (dabs->flip_y)
axes->v[1] = dabs->max_y - axes->v[1];
/*
* In some cases we need to swap width and height.
* This depends on the rotation.
*/
if ( (axes->rotation >= 45 && axes->rotation < 135) ||
(axes->rotation >= 225 && axes->rotation < 315)) {
min_x = dabs->min_y;
max_x = dabs->max_y;
min_y = dabs->min_x;
max_y = dabs->max_x;
} else {
min_x = dabs->min_x;
max_x = dabs->max_x;
min_y = dabs->min_y;
max_y = dabs->max_y;
}
EvdevAxesDoRotation (pInfo);
axes->v[0] = EvdevScaleAxis (axes->v[0], 0, width, min_x, max_x);
axes->v[1] = EvdevScaleAxis (axes->v[1], 0, height, min_y, max_y);
axes->v[0] += dabs->offset_x;
axes->v[1] += dabs->offset_y;
xf86XInputSetScreen (pInfo, dabs->screen, axes->v[0], axes->v[1]);
} else if ((axes->v_flags[0] & EV_AXES_V_M_REL) &&
(axes->v_flags[1] & EV_AXES_V_M_REL) &&
((axes->v_flags[0] & EV_AXES_V_UPDATED) ||
(axes->v_flags[1] & EV_AXES_V_UPDATED))
) {
if (axes->v_flags[0] & EV_AXES_V_UPDATED) axes->x = axes->v[0];
else axes->v[0] = axes->x;
if (axes->v_flags[1] & EV_AXES_V_UPDATED) axes->y = axes->v[1];
else axes->v[1] = axes->y;
if (dabs->flip_x)
axes->v[0] = -axes->v[0];
if (dabs->flip_y)
axes->v[1] = -axes->v[1];
EvdevAxesDoRotation (pInfo);
}
}
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): v[0]=%d%s%s, v[1]=%d%s%s, v[2]=%d%s%s\n", __FILE__, __LINE__, __FUNCTION__,
axes->v[0],
axes->v_flags[0] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[0] & EV_AXES_V_UPDATED ? "*" : "",
axes->v[1],
axes->v_flags[1] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[1] & EV_AXES_V_UPDATED ? "*" : "",
axes->v[2],
axes->v_flags[2] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[2] & EV_AXES_V_UPDATED ? "*" : "");
#endif
for (i = 0; i < axes->axes; i++) {
if (axes->v_flags[i] & EV_AXES_V_UPDATED) {
if (run) {
if (mode != (axes->v_flags[i] & EV_AXES_V_M_MASK)) {
mode = (mode == EV_AXES_V_M_ABS);
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): mode=%d, start=%d, i - start=%d\n", __FILE__, __LINE__, __FUNCTION__,
mode, start, i - start);
#endif
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
start = i;
mode = axes->v_flags[i] & EV_AXES_V_M_MASK;
}
} else {
start = i;
mode = axes->v_flags[i] & EV_AXES_V_M_MASK;
}
run = 1;
axes->v_flags[i] &= ~EV_AXES_V_UPDATED;
} else if (run) {
mode = (mode == EV_AXES_V_M_ABS);
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
run = 0;
}
}
if (run) {
mode = (mode == EV_AXES_V_M_ABS);
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
}
}
/*
* End rotation and rep code, this is a mess and much of it needs to live in mi/
* after a cleanup.
*/
void
EvdevAxesSynCfg (InputInfoPtr pInfo)
{
/* EvdevAxesAbsSynCfg (pInfo);*/
/* EvdevAxesRelSynCfg (pInfo);*/
}
void
EvdevAxesAbsProcess (InputInfoPtr pInfo, struct input_event *ev)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAbsRec *abs = state->abs;
int value, v_flags, is_rel;
if (ev->code >= ABS_MAX || !abs->v_map[ev->code])
return;
value = ev->value;
v_flags = abs->v_flags[ev->code];
if ((v_flags & EV_ABS_V_USE_TOUCH) && !(state->abs->flags & EV_ABS_TOUCH))
return;
#if 0
if (v_flags & EV_ABS_V_INVERT)
value = -value;
#endif
if (v_flags & EV_ABS_V_M_REL)
is_rel = 1;
else if ((v_flags & EV_ABS_V_M_AUTO) && pInfo->dev->valuator->mode == Relative)
is_rel = 1;
else
is_rel = 0;
if (is_rel) {
if ((v_flags & EV_ABS_V_RESET) && value != abs->v[ev->code]) {
abs->v_flags[ev->code] &= ~EV_ABS_V_RESET;
} else
abs->v_map[ev->code](pInfo, value - abs->v[ev->code], 0, abs->v_map_data[ev->code]);
abs->v[ev->code] = value;
} else
abs->v_map[ev->code](pInfo, value, 1, abs->v_map_data[ev->code]);
}
void
EvdevAxesRelProcess (InputInfoPtr pInfo, struct input_event *ev)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevRelRec *rel = state->rel;
int value, v_flags;
if (ev->code >= REL_MAX || !rel->v_map[ev->code])
return;
value = ev->value;
v_flags = rel->v_flags[ev->code];
if (v_flags & EV_REL_V_INVERT)
value = -value;
rel->v_map[ev->code](pInfo, value, 0, rel->v_map_data[ev->code]);
}
int
EvdevAxesOn (DeviceIntPtr device)
{
return Success;
}
int
EvdevAxesOff (DeviceIntPtr device)
{
return Success;
}
static int
EvdevAxisAbsNew(InputInfoPtr pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevAbsRec *abs;
struct input_absinfo absinfo;
char option[128], value[128];
const char *s;
int i, j, real_axes;
evdev_option_token_t *tokens;
real_axes = 0;
for (i = 0; i < ABS_MAX; i++)
if (test_bit (i, pEvdev->bits.abs))
real_axes++;
if (!real_axes)
return !Success;
state->abs = abs = Xcalloc (sizeof (evdevAbsRec));
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 (!test_bit (i, pEvdev->bits.abs))
continue;
if (ioctl (pInfo->fd, EVIOCGABS(i), &absinfo) < 0) {
xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno));
return !Success;
}
snprintf(option, sizeof(option), "Abs%sMapTo", abs_axis_names[i]);
snprintf(value, sizeof(value), "AbsAxis %d %d %d", j, absinfo.minimum, absinfo.maximum);
EvdevParseMapOption (pInfo, option, value, &abs->v_map_data[i], &abs->v_map[i]);
snprintf(option, sizeof(option), "Abs%sOptions", abs_axis_names[i]);
if (i == ABS_X || i == ABS_Y)
s = xf86SetStrOption(pInfo->options, option, "use_touch mode_auto");
else
s = xf86SetStrOption(pInfo->options, option, "");
if (s[0]) {
tokens = EvdevTokenize (s, " ");
if (!EvdevParseAbsOptions (pInfo, option, tokens, &abs->v_flags[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as absolute options.\n", pInfo->name, s);
EvdevFreeTokens (tokens);
}
abs->v_flags[i] |= EV_ABS_V_PRESENT;
j++;
}
state->abs->axes = real_axes;
return Success;
}
static int
EvdevAxisAbsNew1(InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
char *s;
if (!state->abs)
return !Success;
xf86Msg(X_CONFIG, "%s: Configuring %d absolute axes.\n", pInfo->name,
state->abs->axes);
{
int btn;
s = xf86SetStrOption(pInfo->options, "AbsoluteTouch", "DIGI_Touch");
btn = EvdevBtnFind (pInfo, s);
if (btn != -1) {
if (EvdevBtnExists (pInfo, btn)) {
state->abs->flags |= EV_ABS_USE_TOUCH;
xf86Msg(X_ERROR, "%s: Button: %d.\n", pInfo->name, btn);
xf86Msg(X_ERROR, "%s: state->btn: %p.\n", pInfo->name, state->btn);
state->btn->callback[btn] = &EvdevAxesTouchCallback;
} else {
xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' does not exist.\n", pInfo->name, s);
}
} else {
xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' is not a valid button name.\n", pInfo->name, s);
}
}
return Success;
}
static int
EvdevAxisRelNew(InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevRelPtr rel;
char *s, option[128], value[128];
int i, j, real_axes;
evdev_option_token_t *tokens;
real_axes = 0;
for (i = 0; i < REL_MAX; i++)
if (test_bit (i, pEvdev->bits.rel))
real_axes++;
if (!real_axes && (!state->abs || state->abs->axes < 2))
return !Success;
state->rel = rel = Xcalloc (sizeof (evdevRelRec));
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 (!test_bit (i, pEvdev->bits.rel))
continue;
snprintf(option, sizeof(option), "Rel%sMapTo", rel_axis_names[i]);
if (i == REL_WHEEL || i == REL_Z)
snprintf(value, sizeof(value), "Buttons 4 5 1");
else if (i == REL_HWHEEL)
snprintf(value, sizeof(value), "Buttons 6 7 1");
else
snprintf(value, sizeof(value), "RelAxis %d", j);
EvdevParseMapOption (pInfo, option, value, &rel->v_map_data[i], &rel->v_map[i]);
snprintf(option, sizeof(option), "Rel%sOptions", rel_axis_names[i]);
s = xf86SetStrOption(pInfo->options, option, "");
if (s[0]) {
tokens = EvdevTokenize (s, " ");
if (!EvdevParseRelOptions (pInfo, option, tokens, &rel->v_flags[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as relative options.\n", pInfo->name, s);
EvdevFreeTokens (tokens);
}
rel->v_flags[i] |= EV_REL_V_PRESENT;
j++;
}
return Success;
}
int
EvdevAxesNew0 (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int ret = Success;
state->axes = Xcalloc (sizeof (evdevAxesRec));
if (EvdevAxisAbsNew(pInfo) != Success)
ret = !Success;
if (EvdevAxisRelNew(pInfo) != Success)
ret = !Success;
if (!state->abs && !state->rel) {
Xfree (state->axes);
state->axes = NULL;
}
return ret;
}
int
EvdevAxesNew1 (InputInfoPtr pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevAxesRec *axes = state->axes;
int i, ret = Success;
if (!state->axes)
return ret;
for (i = 0; i < AXES_MAX; i++)
if (axes->v_flags[i] & EV_AXES_V_PRESENT)
axes->axes = i + 1;
if (EvdevAxisAbsNew1(pInfo) != Success)
ret = !Success;
if (!state->abs && !state->rel) {
Xfree (state->axes);
state->axes = NULL;
}
return ret;
}
static void
EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
{
/* Nothing to do, dix handles all settings */
}
int
EvdevAxesInit (DeviceIntPtr device)
{
InputInfoPtr pInfo = device->public.devicePrivate;
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesRec *axes = state->axes;
AbsoluteClassRec *dev_abs;
int i;
const char *s;
if (!axes || !axes->axes)
return Success;
xf86Msg(X_CONFIG, "%s: %d valuators.\n", pInfo->name,
axes->axes);
if (!InitValuatorClassDeviceStruct(device, axes->axes,
GetMotionHistory,
GetMotionHistorySize(),
0))
return !Success;
/*
* This has to go in Init, because until now there is no valuator struct
* allocated.
*/
s = xf86SetStrOption(pInfo->options, "Mode", "Absolute");
if (!strcasecmp(s, "Absolute")) {
pInfo->dev->valuator->mode = Absolute;
xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
} else if (!strcasecmp(s, "Relative")) {
pInfo->dev->valuator->mode = Relative;
xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
} else {
pInfo->dev->valuator->mode = Absolute;
xf86Msg(X_CONFIG, "%s: Unknown Mode: %s.\n", pInfo->name, s);
}
/*
* Yes, we want to do this for relative devices too.
* Some of the settings are useful for both.
*/
if ((axes->v_flags[0] & EV_AXES_V_PRESENT) &&
(axes->v_flags[1] & EV_AXES_V_PRESENT) &&
InitAbsoluteClassDeviceStruct (device)) {
dev_abs = device->absolute;
if (axes->v_min[0] != axes->v_max[1] && axes->v_min[1] != axes->v_max[1]) {
device->absolute->min_x = axes->v_min[0];
device->absolute->max_x = axes->v_max[0];
device->absolute->min_y = axes->v_min[1];
device->absolute->max_y = axes->v_max[1];
}
}
for (i = 0; i < axes->axes; i++) {
xf86InitValuatorAxisStruct(device, i, -1, -1, 1, 1, 1);
xf86InitValuatorDefaults(device, i);
}
if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
return !Success;
return Success;
}
static void
EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int i;
#if DEBUG
xf86Msg(X_INFO, "%s: Touch callback; %d.\n", pInfo->name, value);
#endif
if (state->abs->flags & EV_ABS_USE_TOUCH) {
if (value) {
state->abs->flags |= EV_ABS_TOUCH;
for (i = 0; i < ABS_MAX; i++)
if (state->abs->v_flags[i] & EV_ABS_V_USE_TOUCH)
state->abs->v_flags[i] |= EV_ABS_V_RESET;
} else
state->abs->flags &= ~EV_ABS_TOUCH;
}
}

View File

@@ -1,477 +0,0 @@
/*
* Copyright © 2006-2007 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 "evdev.h"
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/extensions/XIproto.h>
#include <linux/input.h>
#include <misc.h>
#include <xf86.h>
#include <xf86str.h>
#include <xf86_OSproc.h>
#include <xf86Xinput.h>
#include <exevents.h>
#include <mipointer.h>
#include <xf86Module.h>
static char *button_names[] = {
"MISC_0",
"MISC_1",
"MISC_2",
"MISC_3",
"MISC_4",
"MISC_5",
"MISC_6",
"MISC_7",
"MISC_8",
"MISC_9",
"MISC_10",
"MISC_11",
"MISC_12",
"MISC_13",
"MISC_14",
"MISC_15",
"MOUSE_LEFT",
"MOUSE_RIGHT",
"MOUSE_MIDDLE",
"MOUSE_SIDE",
"MOUSE_EXTRA",
"MOUSE_FORWARD",
"MOUSE_BACK",
"MOUSE_TASK",
"MOUSE_8",
"MOUSE_9",
"MOUSE_10",
"MOUSE_12",
"MOUSE_13",
"MOUSE_14",
"MOUSE_15",
"JOY_TRIGGER",
"JOY_THUMB",
"JOY_THUMB2",
"JOY_TOP",
"JOY_TOP2",
"JOY_PINKIE",
"JOY_BASE",
"JOY_BASE2",
"JOY_BASE3",
"JOY_BASE4",
"JOY_BASE5",
"JOY_BASE6",
"JOY_12",
"JOY_13",
"JOY_14",
"JOY_DEAD",
"GAME_A",
"GAME_B",
"GAME_C",
"GAME_X",
"GAME_Y",
"GAME_Z",
"GAME_TL",
"GAME_TR",
"GAME_TL2",
"GAME_TR2",
"GAME_SELECT",
"GAME_START",
"GAME_MODE",
"GAME_THUMBL",
"GAME_THUMBR",
"GAME_15",
"DIGI_TOOL_PEN",
"DIGI_TOOL_RUBBER",
"DIGI_TOOL_BRUSH",
"DIGI_TOOL_PENCIL",
"DIGI_TOOL_AIRBRUSH",
"DIGI_TOOL_FINGER",
"DIGI_TOOL_MOUSE",
"DIGI_TOOL_LENS",
"DIGI_8",
"DIGI_9",
"DIGI_TOUCH",
"DIGI_STYLUS",
"DIGI_STYLUS2",
"DIGI_TOOL_DOUBLETAP",
"DIGI_TOOL_TRIPLETAP",
"DIGI_15",
"WHEEL_GEAR_UP",
"WHEEL_GEAR_DOWN",
"WHEEL_2",
"WHEEL_3",
"WHEEL_4",
"WHEEL_5",
"WHEEL_6",
"WHEEL_7",
"WHEEL_8",
"WHEEL_9",
"WHEEL_10",
"WHEEL_11",
"WHEEL_12",
"WHEEL_13",
"WHEEL_14",
"WHEEL_15",
NULL
};
void
EvdevBtnPostFakeClicks(InputInfoRec *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
EvdevMapButton (InputInfoRec *pInfo, int value, int mode, void *map_data)
{
long button = (long) map_data;
xf86PostButtonEvent (pInfo->dev, 0, button, value, 0, 0);
}
Bool
EvdevParseMapToButton (InputInfoRec *pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevBtnRec *btn = state->btn;
int button;
errno = 0;
button = strtol (option->str, NULL, 0);
if (errno)
button = EvdevBtnFind (pInfo, option->str);
if ((button < 0) || (button > BTN_MAX)) {
xf86Msg (X_ERROR, "%s: %s: Button %d out of range.\n", pInfo->name, name, button);
return 0;
}
if (btn->b_flags[button] & EV_BTN_B_PRESENT) {
xf86Msg (X_ERROR, "%s: %s: Button %d already claimed.\n", pInfo->name, name, button);
return 0;
}
btn->b_flags[button] = EV_BTN_B_PRESENT;
*map_data = (void *) button;
*map_func = EvdevMapButton;
return 1;
}
typedef struct {
int button_plus;
int button_minus;
int step;
int count;
} MapButtons_t;
static void
EvdevMapButtons (InputInfoRec *pInfo, int value, int mode, void *map_data)
{
MapButtons_t *map = map_data;
int i;
if (!map)
return;
map->count += value;
i = map->count / map->step;
if (i) {
map->count -= i * map->step;
if (i > 0)
EvdevBtnPostFakeClicks (pInfo, map->button_plus, i);
else
EvdevBtnPostFakeClicks (pInfo, map->button_minus, -i);
}
}
Bool
EvdevParseMapToButtons (InputInfoRec *pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevBtnRec *btn = state->btn;
int btn_plus, btn_minus;
MapButtons_t *map;
errno = 0;
btn_plus = strtol (option->str, NULL, 0);
if (errno)
btn_plus = EvdevBtnFind (pInfo, option->str);
if ((btn_plus < 0) || (btn_plus > BTN_MAX)) {
xf86Msg (X_ERROR, "%s: %s: Button %d out of range.\n", pInfo->name, name, btn_plus);
return 0;
}
if (btn->b_flags[btn_plus] & EV_BTN_B_PRESENT) {
xf86Msg (X_ERROR, "%s: %s: Button %d already claimed.\n", pInfo->name, name, btn_plus);
return 0;
}
option = option->next;
if (!option) {
xf86Msg (X_ERROR, "%s: %s: No button minus.\n", pInfo->name, name);
return 0;
}
errno = 0;
btn_minus = strtol (option->str, NULL, 0);
if (errno)
btn_minus = EvdevBtnFind (pInfo, option->str);
if ((btn_minus < 0) || (btn_minus > BTN_MAX)) {
xf86Msg (X_ERROR, "%s: %s: Button %d out of range.\n", pInfo->name, name, btn_minus);
return 0;
}
if (btn->b_flags[btn_minus] & EV_BTN_B_PRESENT) {
xf86Msg (X_ERROR, "%s: %s: Button %d already claimed.\n", pInfo->name, name, btn_minus);
return 0;
}
errno = 0;
btn->b_flags[btn_plus] = EV_BTN_B_PRESENT;
btn->b_flags[btn_minus] = EV_BTN_B_PRESENT;
map = calloc(1, sizeof (MapButtons_t));
map->button_plus = btn_plus;
map->button_minus = btn_minus;
map->step = 1;
*map_data = (void *) map;
*map_func = EvdevMapButtons;
return 1;
}
int
EvdevBtnInit (DeviceIntRec *device)
{
InputInfoRec *pInfo = device->public.devicePrivate;
evdevDeviceRec *pEvdev = pInfo->private;
CARD8 *map;
int i;
if (!pEvdev->state.btn)
return Success;
map = Xcalloc (sizeof (CARD8) * (pEvdev->state.btn->buttons + 1));
for (i = 0; i <= pEvdev->state.btn->buttons; i++)
map[i] = i;
xf86Msg(X_CONFIG, "%s: Registering %d buttons.\n", pInfo->name,
pEvdev->state.btn->buttons);
if (!InitButtonClassDeviceStruct (device, pEvdev->state.btn->buttons, map)) {
pEvdev->state.btn->buttons = 0;
return !Success;
}
Xfree (map);
return Success;
}
int
EvdevBtnOn (DeviceIntRec *device)
{
InputInfoRec *pInfo = device->public.devicePrivate;
evdevDeviceRec *pEvdev = pInfo->private;
int i, blocked;
if (!pEvdev->state.btn)
return Success;
blocked = xf86BlockSIGIO ();
for (i = 1; i <= pEvdev->state.btn->buttons; i++)
xf86PostButtonEvent (device, 0, i, 0, 0, 0);
xf86UnblockSIGIO (blocked);
return Success;
}
int
EvdevBtnOff (DeviceIntRec *device)
{
return Success;
}
int
EvdevBtnNew0(InputInfoRec *pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
state->btn = Xcalloc (sizeof (evdevBtnRec));
return Success;
}
int
EvdevBtnNew1(InputInfoRec *pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevBtnRec *btn = state->btn;
char option[128], value[128];
int i, b, j, target;
if (!btn)
return !Success;
for (i = 0; i < BTN_MAX; i++) {
b = i + BTN_MISC;
if (!test_bit (b, pEvdev->bits.key))
continue;
btn->real_buttons++;
snprintf(option, sizeof(option), "Button%sMapTo", button_names[i]);
if (b >= BTN_DIGI && b < BTN_WHEEL)
target = -1;
else if (b == BTN_RIGHT)
target = 3;
else if (b == BTN_MIDDLE)
target = 2;
else if (b >= BTN_MOUSE && b < BTN_JOYSTICK)
target = 1 + i - (BTN_MOUSE - BTN_MISC);
else if (b >= BTN_MISC && b < BTN_MOUSE)
target = 1 + i + (BTN_MOUSE - BTN_MISC);
else
target = 1 + i;
if (btn->b_flags[target] & EV_BTN_B_PRESENT) {
for (j = target; j < BTN_MAX; j++)
if (!(btn->b_flags[j] & EV_BTN_B_PRESENT)) {
target = j;
break;
}
}
if (target > 0)
snprintf (value, sizeof (value), "Button %d", target);
else
snprintf (value, sizeof (value), "null");
EvdevParseMapOption (pInfo, option, value, &btn->b_map_data[i], &btn->b_map[i]);
}
if (state->btn->real_buttons)
xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name, state->btn->real_buttons);
for (i = 0; i < BTN_MAX; i++)
if (btn->b_flags[i] & EV_BTN_B_PRESENT)
btn->buttons = i + 1;
if (state->btn->buttons)
xf86Msg(X_INFO, "%s: Configured %d mouse buttons.\n", pInfo->name, state->btn->buttons);
else {
Xfree (state->btn);
state->btn = NULL;
return !Success;
}
pInfo->flags |= XI86_SEND_DRAG_EVENTS | XI86_CONFIGURED;
/*
* FIXME: Mouse may not be accurate.
* Check buttons to see if we're actually a joystick or something.
*/
pInfo->type_name = XI_MOUSE;
return Success;
}
void
EvdevBtnProcess (InputInfoRec *pInfo, struct input_event *ev)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
int button;
if (!state->btn)
return;
button = ev->code;
button -= BTN_MISC;
if (state->btn->callback[button])
state->btn->callback[button](pInfo, button, ev->value);
if (state->btn->b_map[button])
state->btn->b_map[button](pInfo, ev->value, -1, state->btn->b_map_data[button]);
}
int
EvdevBtnFind (InputInfoRec *pInfo, const char *button)
{
int i;
for (i = 0; button_names[i]; i++)
if (!strcasecmp(button, button_names[i]))
return i + 1;
return -1;
}
int
EvdevBtnExists (InputInfoRec *pInfo, int button)
{
evdevDeviceRec *pEvdev = pInfo->private;
xf86Msg(X_INFO, "%s: Checking button %s (%d)\n", pInfo->name, button_names[button], button);
button += BTN_MISC;
xf86Msg(X_INFO, "%s: Checking bit %d\n", pInfo->name, button);
return test_bit(button, pEvdev->bits.key);
}

View File

@@ -1,549 +0,0 @@
/*
* Copyright © 2006-2007 Zephaniah E. Hull
* Copyright © 2004 Red Hat, Inc.
*
* 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.
*
* Authors:
* Zephaniah E. Hull (warp@aehallh.com),
* Kristian Høgsberg (krh@redhat.com)
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "evdev.h"
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/extensions/XIproto.h>
#include <linux/input.h>
#include <misc.h>
#include <xf86.h>
#include <xf86str.h>
#include <xf86_OSproc.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>
#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
/* 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,
/* 0x70 */ NoSymbol, NoSymbol, /* KEY_MACRO */
/* 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,
/* 0x80 */ NoSymbol, NoSymbol,
/* 0x81 */ NoSymbol, NoSymbol,
/* 0x82 */ NoSymbol, NoSymbol,
/* 0x83 */ NoSymbol, NoSymbol,
/* 0x84 */ NoSymbol, NoSymbol,
/* 0x85 */ NoSymbol, NoSymbol,
/* 0x86 */ NoSymbol, NoSymbol,
/* 0x87 */ NoSymbol, NoSymbol,
/* 0x88 */ NoSymbol, NoSymbol,
/* 0x89 */ NoSymbol, NoSymbol,
/* 0x8a */ NoSymbol, NoSymbol,
/* 0x8b */ NoSymbol, NoSymbol,
/* 0x8c */ NoSymbol, NoSymbol,
/* 0x8d */ NoSymbol, NoSymbol,
/* 0x8e */ NoSymbol, NoSymbol,
/* 0x8f */ NoSymbol, NoSymbol,
/* 0x90 */ NoSymbol, NoSymbol,
/* 0x91 */ NoSymbol, NoSymbol,
/* 0x92 */ NoSymbol, NoSymbol,
/* 0x93 */ NoSymbol, NoSymbol,
/* 0x94 */ NoSymbol, NoSymbol,
/* 0x95 */ NoSymbol, NoSymbol,
/* 0x96 */ NoSymbol, NoSymbol,
/* 0x97 */ NoSymbol, NoSymbol,
/* 0x98 */ NoSymbol, NoSymbol,
/* 0x99 */ NoSymbol, NoSymbol,
/* 0x9a */ NoSymbol, NoSymbol,
/* 0x9b */ NoSymbol, NoSymbol,
/* 0x9c */ NoSymbol, NoSymbol,
/* 0x9d */ NoSymbol, NoSymbol,
/* 0x9e */ NoSymbol, NoSymbol,
/* 0x9f */ NoSymbol, NoSymbol,
/* 0xa0 */ NoSymbol, NoSymbol,
/* 0xa1 */ NoSymbol, NoSymbol,
/* 0xa2 */ NoSymbol, NoSymbol,
/* 0xa3 */ NoSymbol, NoSymbol,
/* 0xa4 */ NoSymbol, NoSymbol,
/* 0xa5 */ NoSymbol, NoSymbol,
/* 0xa6 */ NoSymbol, NoSymbol,
/* 0xa7 */ NoSymbol, NoSymbol,
/* 0xa8 */ NoSymbol, NoSymbol,
/* 0xa9 */ NoSymbol, NoSymbol,
/* 0xaa */ NoSymbol, NoSymbol,
/* 0xab */ NoSymbol, NoSymbol,
/* 0xac */ NoSymbol, NoSymbol,
/* 0xad */ NoSymbol, NoSymbol,
/* 0xae */ NoSymbol, NoSymbol,
/* 0xaf */ NoSymbol, NoSymbol,
/* 0xb0 */ NoSymbol, NoSymbol,
/* 0xb1 */ NoSymbol, NoSymbol,
/* 0xb2 */ NoSymbol, NoSymbol,
/* 0xb3 */ NoSymbol, NoSymbol,
/* 0xb4 */ NoSymbol, NoSymbol,
/* 0xb5 */ NoSymbol, NoSymbol,
/* 0xb6 */ NoSymbol, NoSymbol,
/* 0xb7 */ NoSymbol, NoSymbol,
/* 0xb8 */ NoSymbol, NoSymbol,
/* 0xb9 */ NoSymbol, NoSymbol,
/* 0xba */ NoSymbol, NoSymbol,
/* 0xbb */ NoSymbol, NoSymbol,
/* 0xbc */ NoSymbol, NoSymbol,
/* 0xbd */ NoSymbol, NoSymbol,
/* 0xbe */ NoSymbol, NoSymbol,
/* 0xbf */ NoSymbol, NoSymbol,
/* 0xc0 */ NoSymbol, NoSymbol,
/* 0xc1 */ NoSymbol, NoSymbol,
/* 0xc2 */ NoSymbol, NoSymbol,
/* 0xc3 */ NoSymbol, NoSymbol,
/* 0xc4 */ NoSymbol, NoSymbol,
/* 0xc5 */ NoSymbol, NoSymbol,
/* 0xc6 */ NoSymbol, NoSymbol,
/* 0xc7 */ NoSymbol, NoSymbol,
/* 0xc8 */ NoSymbol, NoSymbol,
/* 0xc9 */ NoSymbol, NoSymbol,
/* 0xca */ NoSymbol, NoSymbol,
/* 0xcb */ NoSymbol, NoSymbol,
/* 0xcc */ NoSymbol, NoSymbol,
/* 0xcd */ NoSymbol, NoSymbol,
/* 0xce */ NoSymbol, NoSymbol,
/* 0xcf */ NoSymbol, NoSymbol,
/* 0xd0 */ NoSymbol, NoSymbol,
/* 0xd1 */ NoSymbol, NoSymbol,
/* 0xd2 */ NoSymbol, NoSymbol,
/* 0xd3 */ NoSymbol, NoSymbol,
/* 0xd4 */ NoSymbol, NoSymbol,
/* 0xd5 */ NoSymbol, NoSymbol,
/* 0xd6 */ NoSymbol, NoSymbol,
/* 0xd7 */ NoSymbol, NoSymbol,
/* 0xd8 */ NoSymbol, NoSymbol,
/* 0xd9 */ NoSymbol, NoSymbol,
/* 0xda */ NoSymbol, NoSymbol,
/* 0xdb */ NoSymbol, NoSymbol,
/* 0xdc */ NoSymbol, NoSymbol,
/* 0xdd */ NoSymbol, NoSymbol,
/* 0xde */ NoSymbol, NoSymbol,
/* 0xdf */ NoSymbol, NoSymbol,
/* 0xe0 */ NoSymbol, NoSymbol,
/* 0xe1 */ NoSymbol, NoSymbol,
/* 0xe2 */ NoSymbol, NoSymbol,
/* 0xe3 */ NoSymbol, NoSymbol,
/* 0xe4 */ NoSymbol, NoSymbol,
/* 0xe5 */ NoSymbol, NoSymbol,
/* 0xe6 */ NoSymbol, NoSymbol,
/* 0xe7 */ NoSymbol, NoSymbol,
/* 0xe8 */ NoSymbol, NoSymbol,
/* 0xe9 */ NoSymbol, NoSymbol,
/* 0xea */ NoSymbol, NoSymbol,
/* 0xeb */ NoSymbol, NoSymbol,
/* 0xec */ NoSymbol, NoSymbol,
/* 0xed */ NoSymbol, NoSymbol,
/* 0xee */ NoSymbol, NoSymbol,
/* 0xef */ NoSymbol, NoSymbol,
/* 0xf0 */ NoSymbol, NoSymbol,
/* 0xf1 */ NoSymbol, NoSymbol,
/* 0xf2 */ NoSymbol, NoSymbol,
/* 0xf3 */ NoSymbol, NoSymbol,
/* 0xf4 */ NoSymbol, NoSymbol,
/* 0xf5 */ NoSymbol, NoSymbol,
/* 0xf6 */ NoSymbol, NoSymbol,
/* 0xf7 */ NoSymbol, NoSymbol,
};
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));
if (device->key && device->key->xkbInfo && device->key->xkbInfo->desc
&& device->key->xkbInfo->desc->ctrls) {
XkbControlsRec *ctrls = device->key->xkbInfo->desc->ctrls;
ev[0].type = EV_REP;
ev[0].code = REP_DELAY;
ev[0].value = ctrls->repeat_delay;
ev[1].type = EV_REP;
ev[1].code = REP_PERIOD;
ev[1].value = ctrls->repeat_interval;
write(pInfo->fd, ev, sizeof(ev[0]) * 2);
}
}
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->key->xkb_rules, state->key->xkb_model,
state->key->xkb_layout, state->key->xkb_variant,
state->key->xkb_options);
XkbInitKeyboardDeviceStruct (device, &state->key->xkbnames, &keySyms, modMap,
NULL, 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;
}
}
}
int
EvdevKeyNew (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int i, keys = 0;
for (i = 0; i <= 0xF7; i++)
if (test_bit (i, pEvdev->bits.key)) {
keys = 1;
break;
}
if (!keys)
return !Success;
state->key = Xcalloc (sizeof (evdevKeyRec));
pInfo->type_name = XI_KEYBOARD;
pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
SetXkbOption (pInfo, "xkb_rules", NULL, &state->key->xkb_rules);
if (!state->key->xkb_rules)
SetXkbOption (pInfo, "XkbRules", __XKBDEFRULES__,
&state->key->xkb_rules);
SetXkbOption (pInfo, "xkb_model", NULL, &state->key->xkb_model);
if (!state->key->xkb_model)
SetXkbOption (pInfo, "XkbModel", "evdev", &state->key->xkb_model);
SetXkbOption (pInfo, "xkb_layout", NULL, &state->key->xkb_layout);
if (!state->key->xkb_layout)
SetXkbOption (pInfo, "XkbLayout", "us", &state->key->xkb_layout);
SetXkbOption (pInfo, "xkb_variant", NULL, &state->key->xkb_variant);
if (!state->key->xkb_variant)
SetXkbOption (pInfo, "XkbVariant", NULL, &state->key->xkb_variant);
SetXkbOption (pInfo, "xkb_options", NULL, &state->key->xkb_options);
if (!state->key->xkb_options)
SetXkbOption (pInfo, "XkbOptions", NULL, &state->key->xkb_options);
return Success;
}
int
EvdevKeyOn (DeviceIntPtr device)
{
return Success;
}
int
EvdevKeyOff (DeviceIntPtr device)
{
unsigned int i;
KeyClassRec *keyc = device->key;
KeySym *map = keyc->curKeySyms.map;
/*
* A bit of a hack, vaguely stolen from xf86-input-keyboard.
*
* Don't leave any keys in the down state if we are getting turned
* off, as they are likely to be released before we are turned back
* on.
* (For example, if the user switches VTs, or if we are unplugged.)
*/
for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map;
i < keyc->curKeySyms.maxKeyCode;
i++, map += keyc->curKeySyms.mapWidth)
if ((keyc->down[i >> 3] & (1 << (i & 7))))
{
switch (*map) {
/* Don't release the lock keys */
case XK_Caps_Lock:
case XK_Shift_Lock:
case XK_Num_Lock:
case XK_Scroll_Lock:
case XK_Kana_Lock:
break;
default:
xf86PostKeyboardEvent(device, i, 0);
}
}
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);
}