Compare commits

...

67 Commits

Author SHA1 Message Date
Peter Hutterer
f9b6fa21df xf86-input-libinput 0.19.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-28 13:43:49 +10:00
Peter Hutterer
3f569ec493 conf: rename to 60-libinput.conf
60 sorts higher than the other drivers (evdev has 10, synaptics, wacom and
others have 50) so we keep the same order.

This is part of a two-step solution, the other half is renaming the
xf86-input-wacom's config snippet to sort higher than libinput's.

Currently libinput picks up devices that are (for now) destined to the wacom
driver. Since the wacom driver is more of a leaf package than libinput, the
best option here is to make the wacom driver sort higher and let users
uninstall it when not needed. To avoid crowding the 90-* space where users
usually have custom config snippets, drop libinput down to 60 and bump wacom
up.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Jason Gerecke <jason.gerecke@wacom.com>
2016-04-28 12:29:20 +10:00
Stanislav Ochotnicky
602bb8eefa Fix implicit declaration of function 'xf86Msg' in xf86libinput.c
Addition of xf86.h header fixes compilation issues in some cases.

See: https://bugs.gentoo.org/show_bug.cgi?id=560970

Signed-off-by: Stanislav Ochotnicky <sochotnicky@redhat.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-08 15:37:04 +10:00
Peter Hutterer
13726f404f xf86-input-libinput 0.18.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-07 13:31:28 +10:00
Peter Hutterer
5e7ee73fe2 Support art pen rotation
The art pen is a normal pen, but it does provide a rotation axis.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 14:34:43 +10:00
Peter Hutterer
4564a92d59 Support the mouse/lens tool
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 14:34:43 +10:00
Peter Hutterer
0c2bcd0358 Add support for the airbrush tool axes
Same axes as the pen, but axis number 6 is the wheel (which really is a
slider)

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 14:34:43 +10:00
Peter Hutterer
b4541e4dff Add support for tablet tools
Use two new internal capabilities, CAP_TABLET and CAP_TABLET_TOOL. If a
libinput tablet device is added, add an X device without any classes. This
device will not send events, but once we have pad support in libinput we
may be able to this the pad device.

When a tool comes into proximity, create a new X device for that serial number
and start sending events through it. Since the X device only represents a
single serial number/type combination, some of the wacom-specific
configuration options fall away. This only matters in the case of multiple
tools, in which case a per-tool configuration is preferable anyway, so we
don't lose anything here.

Gesture support only applied to the touch parts on the device, we don't
deal with this here specifically - that event node is handled by libinput as
touchscreen or touchpad.

This already works with GIMP and clients that don't rely on any
wacom-driver-specific properties. Configuration clients like
gnome-settings-daemon will need to change to handle new properties, to be
added as we go along.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 14:34:43 +10:00
Peter Hutterer
8136113139 xf86-input-libinput 0.17.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-26 15:57:48 +10:00
Peter Hutterer
202eb68dc0 Fix compiler warnings about missing tablet event cases
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-01-28 15:02:54 +10:00
Peter Hutterer
e8f5394b07 Add property/option for enabling/disabling tap-n-drag
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2016-01-28 15:01:39 +10:00
Peter Hutterer
20f5269a29 Fix default tapping drack lock property value
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-01-27 11:13:07 +10:00
Peter Hutterer
3dacb28b20 Allow hotplugging a device immediately
This splits the hotplugging code up so we can use it through a callback but
also as an immediate call that gives us back the device just hotplugged. Also
added is the ability to add extra options to the device.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-01-05 11:16:19 +10:00
Peter Hutterer
db8e73141c Change creating subdevices to something more generic
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-01-05 11:16:19 +10:00
Peter Hutterer
0d1851a000 xf86-input-libinput 0.16.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-12-23 13:53:38 +10:00
Peter Hutterer
ad8483b913 Drain the fd after opening
Make sure we don't send any events that may have been enqueued before we
initialized ourselves. Specifically, if we're using systemd-logind the fd
remains open when we disable/enable the device, allowing events to queue up on
the fd. These events are then replayed once the device is re-opened.

This is not the case when VT-switching, in that case logind closes the fd for
us.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
2015-12-17 11:23:28 +10:00
Peter Hutterer
1f43f3921f Split mixed pointer/keyboard devices into two separate X devices
The server struggles with devices that are both, the protocol (especially XI2)
requires a fairly strict separation of pointer vs keyboard devices. Though the
server has a couple of hacks to route events correctly, mixed
devices still experience bugs like [1].

Instead of advertising the device as a single mixed device, split the device
into two X devices, one with only a pointer/touch component, one with only a
keyboard component. This ensures that the device is effectively attached to
both the VCP and the VCK, something the XI2 protocol doesn't really allow.

This patch drops the keyboard capability on a mixed device, duplicates the
input options and attributes and queues a NewInputDeviceRequest call. The new
device only has the keyboard capability but is otherwise unchanged. The
wacom driver has used this approach for years.

The WorkProc is necessary to avoid inconsistent state, the server doesn't
handle a NewInputDeviceRequest during PreInit well.

The approach:
During pre-init we create a struct xf86libinput_device with the
libinput_device and a unique ID. The child device has that ID added to the
options and will look for the other device during its pre-init. The two
devices then share the xf86libinput_device struct.

We only have a single epollfd for all devices  and the server calls read_input
on the first device in the list with the epollfd as pInfo->fd. That shared
struct is used as the userdata on the libinput_device we get back from the
event, and each device is in the xorg_list device_list of that shared struct.
We loop through those to find the ones with the right capabilities and
post the event through that device.

Since devices can be enabled and disabled independently, the rest of the code
makes sure that we only ever add the device to libinput when the first shared
device is enabled, and remove it accordingly.

The server uses pInfo->major/minor to detect if another device is using the
same path for a logind-controlled fd. If so, it reuses that device's
pInfo->fd and sets the "fd" option to that value. That pInfo->fd is the
libinput epollfd though, not the actual device fd.

This doesn't matter for us, since we manage the fds largely ourselves and the
pInfo->fd we use is the epollfd anyway. On unplug however, the udev code
triggers a device removal for all devices, including the duplicated ones. When
we disable device, we restore the pInfo->fd from the "fd" option so that the
server can request logind to close the fd.

That only works if the "fd" option is correct, otherwise the server asks
logind to close the epollfd and everyone is unhappy.

[1] https://bugs.freedesktop.org/show_bug.cgi?id=49950

https://bugs.freedesktop.org/show_bug.cgi?id=92896

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-23 07:26:46 +10:00
Peter Hutterer
83dfd31ec8 Revert "Split mixed pointer/keyboard devices into two separate X devices"
When using logind, this causes the server to hang when a split device is
unplugged. The reason is mostly in the server, when open the device by
requesting the logind fd, the server loops through the device list to check if
any other device has the same major/minor (see systemd_logind_take_fd()) and
returns the pInfo->fd for that device instead of requesting the fd again from
logind.

For libinput devices, the pInfo->fd is the epollfd, not the actual device, so
our second device gets the epollfd assigned. When the devices are removed, we
keep the device fd open and release the epollfd through logind.

This reverts commit c943739a2b.
2015-11-20 10:51:38 +10:00
Peter Hutterer
c943739a2b Split mixed pointer/keyboard devices into two separate X devices
The server struggles with devices that are both, the protocol (especially XI2)
requires a fairly strict separation of pointer vs keyboard devices. Though the
server has a couple of hacks to route events correctly, mixed
devices still experience bugs like [1].

Instead of advertising the device as a single mixed device, split the device
into two X devices, one with only a pointer/touch component, one with only a
keyboard component. This ensures that the device is effectively attached to
both the VCP and the VCK, something the XI2 protocol doesn't really allow.

This patch drops the keyboard capability on a mixed device, duplicates the
input options and attributes and queues a NewInputDeviceRequest call. The new
device only has the keyboard capability but is otherwise unchanged. The
wacom driver has used this approach for years.

The WorkProc is necessary to avoid inconsistent state, the server doesn't
handle a NewInputDeviceRequest during PreInit well.

The approach:
During pre-init we create a struct xf86libinput_device with the
libinput_device and a unique ID. The child device has that ID added to the
options and will look for the other device during its pre-init. The two
devices then share the xf86libinput_device struct.

We only have a single epollfd for all devices  and the server calls read_input
on the first device in the list with the epollfd as pInfo->fd. That shared
struct is used as the userdata on the libinput_device we get back from the
event, and each device is in the xorg_list device_list of that shared struct.
We loop through those to find the ones with the right capabilities and
post the event through that device.

Since devices can be enabled and disabled independently, the rest of the code
makes sure that we only ever add the device to libinput when the first shared
device is enabled, and remove it accordingly.

[1] https://bugs.freedesktop.org/show_bug.cgi?id=49950

https://bugs.freedesktop.org/show_bug.cgi?id=92896

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-20 08:45:40 +10:00
Peter Hutterer
a72e96538a Add a helper function for the driver context initialization
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-18 07:00:29 +10:00
Peter Hutterer
b1a9bea607 Copy the device capabilities to the X driver struct
And use those copied caps instead of the direct device capability calls.

No functional changes at this point, this is preparation work for selectively
disabling capabilities on a device.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-18 07:00:29 +10:00
Peter Hutterer
a6aad69a97 Split type_name detection out into a helper function
No functional changes

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-18 07:00:29 +10:00
Peter Hutterer
6fa5f30129 Unref the libinput context on pre_init failure
A device that fails pre_init has a ref to the libinput context but may not
have a pInfo->private. For those devices we never call libinput_unref() and
the libinput struct never gets freed.

Thus if at least one device didn't pass pre_init, we never cleaned up after
ourselves.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-11-18 07:00:01 +10:00
Peter Hutterer
c53dde1a50 Don't fail DEVICE_CLOSE
We're not doing anything here, so no reason to fail.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-11-13 14:33:02 +10:00
Peter Hutterer
d7331f6e34 Remove unused server_fds list
Obsolete as of 353c52f2be

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-11-13 14:32:31 +10:00
Peter Hutterer
fb56f6d7a5 Set the device to NULL after unref
No real effect in the current code, but it adds a bit of safety.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-11-13 10:02:16 +10:00
Peter Hutterer
c8861d2a2f Plug two memory leaks
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-11-12 10:17:39 +10:00
Peter Hutterer
44f4b2ed70 xf86-input-libinput 0.15.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-10-27 17:08:59 +10:00
Peter Hutterer
0163482e22 Add property support for the accel profiles
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-10-26 10:00:57 +10:00
Peter Hutterer
80c356f58f conf: install the libinput xorg.conf.d snippet
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-09-18 00:29:20 +10:00
Peter Hutterer
1645a79c34 conf: don't hook onto tablets and joysticks
If we install the config file by default, we shouldn't use libinput for
devices we know we can't handle.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-09-18 00:29:17 +10:00
Peter Hutterer
b7f8db12a3 conf: rename 99-libinput.conf to 90-libinput.conf
This way it still sorts after the usual subjects, but it's easier to stack
extra config in afterwards.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-09-18 00:27:43 +10:00
Peter Hutterer
6abd341279 Fix invalid pointer passed to the properties
Takes a void*, not a void**

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-09-03 17:42:20 +10:00
Peter Hutterer
19b42f242d Move the read-only properties into the same condition
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-09-03 17:33:40 +10:00
Peter Hutterer
f48b64c8cd xf86-input-libinput 0.14.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-31 13:27:09 +10:00
Yomi0
b55239ef25 Fix typo in libinput.man
Correct typo. Draging to dragging.
2015-08-30 23:14:25 -04:00
Peter Hutterer
9563334dda Use xf86OpenSerial instead of a direct open() call
This will transparently handle server-side fds for us.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Martin Pieuchot <mpi@openbsd.org>
2015-08-17 09:18:01 +10:00
Peter Hutterer
353c52f2be Revamp server fd opening
The server already stores the server-fd in the options, so we only need to run
through the list of current devices, find a match and extract that fd from the
options. Less magic in our driver and it gives us a pInfo handle in
open_restricted which we'll can use for xf86OpenSerial().

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Martin Pieuchot <mpi@openbsd.org>
2015-08-17 09:16:42 +10:00
Peter Hutterer
f139f14249 Add an option to disable horizontal scrolling
libinput always has horizontal scrolling enabled and punts the decision when
to scroll horizontally to the toolkit/widget. This is the better approach, but
while we have a stack that's not ready for that, and in the X case likely
never will be fully ready provide an option to disable horizontal scrolling.

This option doesn't really disable horizontal scrolling, it merely discards
any horizontal scroll delta. libinput will still think it's scrolling.

https://bugs.freedesktop.org/show_bug.cgi?id=91589

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-08-13 07:53:19 +10:00
Peter Hutterer
e3a888c3ab Add drag lock support
First, why is this here and not in libinput: drag lock should be implemented
in the compositor (not in libinput) so it can provide feedback when it
activates and grouped in with other accessibility features. That will work for
Wayland but in X the compositor cannot filter button events - only the server
and the drivers can.

This patch adds mostly the same functionality that evdev provides with two
options on how it works:
* a single button number configures the given button to lock the next button
  pressed in a logically down state until a press+ release of that same button
  again
* a set of button number pairs configures each button with the to-be-locked
  logical button, i.e. a pair of "1 3" will hold 3 logically down after a
  button 1 press

The property and the xorg.conf options take the same configuration as the
evdev driver (though the property has a different prefix, libinput instead of
Evdev).

The behavior difference to evdev is in how releases are handled, evdev sends
the release on the second button press event, this implementation sends the
release on the second release event.

https://bugs.freedesktop.org/show_bug.cgi?id=85577

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-08-13 07:52:48 +10:00
Martin Pieuchot
cd61ddb040 Remove unneeded header, epoll(7) interface is not directly used.
Signed-off-by: Martin Pieuchot <mpi@openbsd.org>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-12 10:16:11 +10:00
Martin Pieuchot
a199880057 Rename a local variable to not shadow the BSD strmode(3) function.
Signed-off-by: Martin Pieuchot <mpi@openbsd.org>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-12 10:16:01 +10:00
Peter Hutterer
cc57eecd72 gitignore: add patterns for automake test suite and misc other bits
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-11 15:06:43 +10:00
Peter Hutterer
fe58cff48b Rename main source file to x86libinput.c
To avoid conflict and confusion with libinput's sources. This was originally
triggered by needing a header file for the driver which cannot be named
libinput.h. That need went away after other refacturing, but we might as well
rename it now, sooner or later we'll need a xf86libinput.h file.

Can't do much about the libinput-properties header though, not worth breaking
other projects and it's namespaced into /usr/include/xorg anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-11 15:05:29 +10:00
Peter Hutterer
4b2bed6912 xf86-input-libinput 0.13.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-04 17:08:22 +10:00
Stephen Chandler Paul
223be9f62b Add a property for Disable While Typing
Signed-off-by: Stephen Chandler Paul <cpaul@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-08-04 14:14:48 +10:00
Peter Hutterer
d3ee745a24 man: minor man page improvements
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-07-21 11:21:47 +10:00
Peter Hutterer
b550b70a00 Fix compiler warnings about touchpad gestures
We don't do anything with them though.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-07-21 11:16:06 +10:00
Peter Hutterer
254b1f27a0 xf86-input-libinput 0.12.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-07-14 16:18:38 +10:00
Peter Hutterer
bfedf7dbac Add a property for tap drag lock
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-07-09 11:08:23 +10:00
Peter Hutterer
9c5cf97143 Support buttons > BTN_BACK on mice
https://bugzilla.redhat.com/show_bug.cgi?id=1230945

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-06-15 10:20:18 +10:00
Peter Hutterer
449b496a3a xf86-input-libinput 0.11.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-06-05 13:40:31 +10:00
Peter Hutterer
d4e0b5420f Fix missing scroll methods default/scroll button property
Even if no scroll method is enabled by default, we still want those
properties.

Introduced in 8d4e03570c.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-06-01 11:46:33 +10:00
Peter Hutterer
19c91044e4 Use the new unaccelerated valuator ValuatorMask features
SDL Games like openarena rely on relative input that's handled by the DGA code
in the server. That code casts the driver's input data to int and sends it to
the client. libinput does pointer acceleration for us, so sending any deltas
of less than 1 (likely for slow movements) ends up being 0.

Use the new ValuatorMask accelerated/unaccelerated values to pass the
unaccelerated values along, the server can then decide what to do with it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-05-22 07:42:15 +10:00
Peter Hutterer
3d6afca975 Only init abs axes if we don't have acceleration
A lot of devices (mainly MS input devices) have abs axes on top of the
relative axes. Those axes are usually mute but with the current code we set up
absolute axes for those devices. Relative events are then scaled by the server
which makes the device appear slow.

As an immediate fix always prefer relative axes and only set up absolute axes
if the device has a calibration matrix but no pointer acceleration.
This may mess up other devices where the relative axes are dead, we'll deal
with this when it comes.

https://bugs.freedesktop.org/show_bug.cgi?id=90322

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-05-22 07:42:15 +10:00
Peter Hutterer
158e3264ce xf86-input-libinput 0.10.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-05-21 09:52:40 +10:00
Peter Hutterer
006c802630 Group scroll distances into a struct
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-05-20 14:22:17 +10:00
Peter Hutterer
d6ce065cea Add option "ButtonMapping" (#90206)
With a long entry in the man page to detail what this option does.
Specifically, it's the xorg.conf equivalent to XSetPointerMapping(3), it
doesn't do any physical button remappings, merely the logical ones. If the
physical button isn't mapped to the right logical button by default, that's
either a libiput bug or an xkcd 1172 issue.

X.Org Bug 90206 <http://bugs.freedesktop.org/show_bug.cgi?id=90206>

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-04-30 11:34:15 +10:00
Peter Hutterer
b9a2150576 man: add two linebreaks to make things easier to visually parse
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-04-29 09:19:09 +10:00
Peter Hutterer
9356471f3f Move the option parsing into helper functions
No functional changes, though I did move a free() up a bit in the process (see
sendevents parsing).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-04-29 08:51:12 +10:00
Peter Hutterer
d5fa03c343 Add a property for middle button emulation
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-04-23 17:48:44 +10:00
Peter Hutterer
446401bea9 xf86-input-libinput 0.9.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-04-23 12:23:01 +10:00
Peter Hutterer
8d4e03570c Add "libinput something Default" properties
A client or xorg.conf setting may change the property but once changed it
cannot be reset by a client to the original state without knowledge about the
device.

Export the various libinput_...get_default() functions as properties.

https://bugs.freedesktop.org/show_bug.cgi?id=89574

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-03-18 09:15:40 +10:00
Peter Hutterer
0c5620a29c Add a helper function for making properties
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2015-03-18 09:15:40 +10:00
Peter Hutterer
fb50cef700 man: update the property list in the man page
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-03-18 09:15:40 +10:00
Peter Hutterer
64a0f870e0 Fix a couple of -Wformat warnings
unsigned int vs int

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-03-18 09:15:40 +10:00
Peter Hutterer
e362e4dc4c cosmetic: drop duplicate empty lines
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-03-16 10:38:07 +10:00
15 changed files with 5214 additions and 2113 deletions

8
.gitignore vendored
View File

@@ -76,3 +76,11 @@ core
# Edit the following section as needed
# For example, !report.pc overrides *.pc. See 'man gitignore'
#
*.log
*.trs
*.swp
*.announce
*.sig
test-driver
tags
.vimdir

View File

@@ -21,12 +21,14 @@
DISTCHECK_CONFIGURE_FLAGS = --with-sdkdir='$${includedir}/xorg'
SUBDIRS = src include man
SUBDIRS = src include man test
MAINTAINERCLEANFILES = ChangeLog INSTALL
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-libinput.pc
dist_xorgconf_DATA = conf/60-libinput.conf
.PHONY: ChangeLog INSTALL
INSTALL:
@@ -37,4 +39,4 @@ ChangeLog:
dist-hook: ChangeLog INSTALL
EXTRA_DIST = conf/99-libinput.conf README.md
EXTRA_DIST = README.md

28
conf/60-libinput.conf Normal file
View File

@@ -0,0 +1,28 @@
# Match on all types of devices but tablet devices and joysticks
Section "InputClass"
Identifier "libinput pointer catchall"
MatchIsPointer "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput keyboard catchall"
MatchIsKeyboard "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput touchpad catchall"
MatchIsTouchpad "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput touchscreen catchall"
MatchIsTouchscreen "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection

View File

@@ -1,6 +0,0 @@
# Use the libinput driver for all event devices
Section "InputClass"
Identifier "libinput"
Driver "libinput"
MatchDevicePath "/dev/input/event*"
EndSection

View File

@@ -23,7 +23,7 @@
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT([xf86-input-libinput],
[0.8.0],
[0.19.0],
[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
[xf86-input-libinput])
AC_CONFIG_SRCDIR([Makefile.am])
@@ -45,7 +45,7 @@ XORG_DEFAULT_OPTIONS
# Obtain compiler/linker options from server and required extensions
PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto [inputproto >= 2.2])
PKG_CHECK_MODULES(LIBINPUT, [libinput >= 0.11.0])
PKG_CHECK_MODULES(LIBINPUT, [libinput >= 1.1.901])
# Define a configure option for an alternate input module directory
AC_ARG_WITH(xorg-module-dir,
@@ -56,6 +56,13 @@ AC_ARG_WITH(xorg-module-dir,
inputdir=${moduledir}/input
AC_SUBST(inputdir)
AC_ARG_WITH(xorg-conf-dir,
AC_HELP_STRING([--with-xorg-conf-dir=DIR],
[Default xorg.conf.d directory [[default=$prefix/share/X11/xorg.conf.d/]]]),
[xorgconfdir="$withval"],
[xorgconfdir="$prefix/share/X11/xorg.conf.d"])
AC_SUBST(xorgconfdir)
# X Server SDK location is required to install header files
sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server`
@@ -71,5 +78,6 @@ AC_CONFIG_FILES([Makefile
include/Makefile
src/Makefile
man/Makefile
test/Makefile
xorg-libinput.pc])
AC_OUTPUT

View File

@@ -27,15 +27,51 @@
/* Tapping enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP "libinput Tapping Enabled"
/* Tapping default enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_TAP_DEFAULT "libinput Tapping Enabled Default"
/* Tap drag enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG "libinput Tapping Drag Enabled"
/* Tap drag default enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG_DEFAULT "libinput Tapping Drag Enabled Default"
/* Tap drag lock enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG_LOCK "libinput Tapping Drag Lock Enabled"
/* Tap drag lock default enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG_LOCK_DEFAULT "libinput Tapping Drag Lock Enabled Default"
/* Calibration matrix: FLOAT, 9 values of a 3x3 matrix, in rows */
#define LIBINPUT_PROP_CALIBRATION "libinput Calibration Matrix"
/* Calibration matrix: FLOAT, 9 values of a 3x3 matrix, in rows, read-only*/
#define LIBINPUT_PROP_CALIBRATION_DEFAULT "libinput Calibration Matrix Default"
/* Pointer accel speed: FLOAT, 1 value, 32 bit */
#define LIBINPUT_PROP_ACCEL "libinput Accel Speed"
/* Pointer accel speed: FLOAT, 1 value, 32 bit, read-only*/
#define LIBINPUT_PROP_ACCEL_DEFAULT "libinput Accel Speed Default"
/* Pointer accel profile: BOOL, 2 values in oder adaptive, flat,
* only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE "libinput Accel Profiles Available"
/* Pointer accel profile: BOOL, 2 values in order adaptive, flat,
only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT "libinput Accel Profile Enabled Default"
/* Pointer accel profile: BOOL, 2 values in order adaptive, flat,
only one is enabled at a time at max */
#define LIBINPUT_PROP_ACCEL_PROFILE_ENABLED "libinput Accel Profile Enabled"
/* Natural scrolling: BOOL, 1 value */
#define LIBINPUT_PROP_NATURAL_SCROLL "libinput Natural Scrolling Enabled"
/* Natural scrolling: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_NATURAL_SCROLL_DEFAULT "libinput Natural Scrolling Enabled Default"
/* Send-events mode: BOOL read-only, 2 values in order disabled,
disabled-on-external-mouse */
#define LIBINPUT_PROP_SENDEVENTS_AVAILABLE "libinput Send Events Modes Available"
@@ -44,9 +80,16 @@
disabled-on-external-mouse */
#define LIBINPUT_PROP_SENDEVENTS_ENABLED "libinput Send Events Mode Enabled"
/* Send-events mode: BOOL, 2 values in order disabled,
disabled-on-external-mouse, read-only */
#define LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT "libinput Send Events Mode Enabled Default"
/* Left-handed enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_LEFT_HANDED "libinput Left Handed Enabled"
/* Left-handed enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_LEFT_HANDED_DEFAULT "libinput Left Handed Enabled Default"
/* Scroll method: BOOL read-only, 3 values in order 2fg, edge, button.
shows available scroll methods */
#define LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE "libinput Scroll Methods Available"
@@ -55,9 +98,16 @@
only one is enabled at a time at max */
#define LIBINPUT_PROP_SCROLL_METHOD_ENABLED "libinput Scroll Method Enabled"
/* Scroll method: BOOL, 3 values in order 2fg, edge, button
only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT "libinput Scroll Method Enabled Default"
/* Scroll button for button scrolling: 32-bit int, 1 value */
#define LIBINPUT_PROP_SCROLL_BUTTON "libinput Button Scrolling Button"
/* Scroll button for button scrolling: 32-bit int, 1 value, read-only */
#define LIBINPUT_PROP_SCROLL_BUTTON_DEFAULT "libinput Button Scrolling Button Default"
/* Click method: BOOL read-only, 2 values in order buttonareas, clickfinger
shows available click methods */
#define LIBINPUT_PROP_CLICK_METHODS_AVAILABLE "libinput Click Methods Available"
@@ -66,4 +116,30 @@
only one enabled at a time at max */
#define LIBINPUT_PROP_CLICK_METHOD_ENABLED "libinput Click Method Enabled"
/* Click method: BOOL, 2 values in order buttonareas, clickfinger
only one enabled at a time at max, read-only */
#define LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT "libinput Click Method Enabled Default"
/* Middle button emulation: BOOL, 1 value */
#define LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED "libinput Middle Emulation Enabled"
/* Middle button emulation: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED_DEFAULT "libinput Middle Emulation Enabled Default"
/* Disable while typing: BOOL, 1 value */
#define LIBINPUT_PROP_DISABLE_WHILE_TYPING "libinput Disable While Typing Enabled"
/* Disable while typing: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT "libinput Disable While Typing Enabled Default"
/* Drag lock buttons, either:
CARD8, one value, the meta lock button, or
CARD8, n * 2 values, the drag lock pairs with n being the button and n+1
the target button number */
#define LIBINPUT_PROP_DRAG_LOCK_BUTTONS "libinput Drag Lock Buttons"
/* Horizontal scroll events enabled: BOOL, 1 value (0 or 1).
* If disabled, horizontal scroll events are discarded */
#define LIBINPUT_PROP_HORIZ_SCROLL_ENABLED "libinput Horizonal Scroll Enabled"
#endif /* _LIBINPUT_PROPERTIES_H_ */

View File

@@ -12,6 +12,7 @@ libinput \- libinput-based X.Org input driver
\ \ ...
.B EndSection
.fi
.SH NOTE
This is the man page for the X input driver. If you are looking for the
library documentation, go to
@@ -30,6 +31,7 @@ devices are configured through the
directive (refer to __xconfigfile__(__filemansuffix__)) instead of manual
per-device configuration. Devices configured in the
__xconfigfile__(__filemansuffix__) are not hot-plug capable.
.SH CONFIGURATION DETAILS
Please refer to __xconfigfile__(__filemansuffix__) for general configuration
details and for options that can be used with all input drivers. This
@@ -42,14 +44,40 @@ are supported:
.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.
When using
.B InputClass
directives, this option is set by the server.
The mapping from device node to hardware is system-dependent. Property:
"Device Node" (read-only).
.TP 7
.BI "Option \*qAccelProfile\*q \*q" string \*q
Sets the pointer acceleration profile to the given profile. Permitted values
are
.BI adaptive,
.BI flat.
Not all devices support this option or all profiles. If a profile is
unsupported, the default profile for this is used. For a description on the
profiles and their behavior, see the libinput documentation.
.TP 7
.BI "Option \*qAccelSpeed\*q \*q" float \*q
Sets the pointer acceleration speed within the range [-1, 1]
.TP 7
.BI "Option \*qButtonMapping\*q \*q" string \*q
Sets the logical button mapping for this device, see
XSetPointerMapping(__libmansuffix__). The string must be a
space-separated list of button mappings in the order of the
logical buttons on the device, starting with button 1.
The default mapping is "1 2 3 ... 32". A mapping of 0
deactivates the button. Multiple buttons can have the same mapping.
Invalid mapping strings are discarded and the default mapping
is used for all buttons. Buttons not specified in the user's mapping use the
default mapping. See section
.B BUTTON MAPPING
for more details.
.TP 7
.BI "Option \*qCalibrationMatrix\*q \*q" string \*q
A string of 9 space-separated floating point numbers.
A string of 9 space-separated floating point numbers, in the order
\*qa b c d e f g h i\*q.
Sets the calibration matrix to the 3x3 matrix where the first row is (abc),
the second row is (def) and the third row is (ghi).
.TP 7
@@ -64,6 +92,10 @@ default click method for this device is used.
.BI "Option \*qLeftHanded\*q \*q" bool \*q
Enables left-handed button orientation, i.e. swapping left and right buttons.
.TP 7
.BI "Option \*qMiddleEmulation\*q \*q" bool \*q
Enables middle button emulation. When enabled, pressing the left and right
buttons simultaneously produces a middle mouse button click.
.TP 7
.BI "Option \*qNaturalScrolling\*q \*q" bool \*q
Enables or disables natural scrolling behavior.
.TP 7
@@ -84,25 +116,77 @@ Enables a scroll method. Permitted values are
Not all devices support all options, if an option is unsupported, the
default scroll option for this device is used.
.TP 7
.BI "Option \*qHorizontalScrolling\*q" bool \*q
Disables horizontal scrolling. When disabled, this driver will discard any
horizontal scroll events from libinput. Note that this does not disable
horizontal scrolling, it merely discards the horizontal axis from any scroll
events.
.TP 7
.BI "Option \*qSendEventsMode\*q \*q" (disabled|enabled|disabled-on-external-mouse) \*q
Sets the send events mode to disabled, enabled, or "disable when an external
mouse is connected".
.TP 7
.BI "Option \*qTapping\*q \*q" bool \*q
Enables or disables tap-to-click behavior.
.TP 7
.BI "Option \*qTappingDrag\*q \*q" bool \*q
Enables or disables drag during tapping behavior ("tap-and-drag"). When
enabled, a tap followed by a finger held down causes a single button down
only, all motions of that finger thus translate into dragging motion.
Tap-and-drag requires option
.B Tapping
to be enabled.
.TP 7
.BI "Option \*qTappingDragLock\*q \*q" bool \*q
Enables or disables drag lock during tapping behavior. When enabled, a
finger up during tap-and-drag will not immediately release the button. If
the finger is set down again within the timeout, the dragging process
continues.
.TP 7
.BI "Option \*qDisableWhileTyping\*q \*q" bool \*q
Indicates if the touchpad should be disabled while typing on the keyboard
(this does not apply to modifier keys such as Ctrl or Alt).
.TP 7
.BI "Option \*qDragLockButtons\*q \*q" "L1 B1 L2 B2 ..." \*q
Sets "drag lock buttons" that simulate a button logically down even when it has
been physically released. To logically release a locked button, a second click
of the same button is required.
.IP
If the option is a single button number, that button acts as the
"meta" locking button for the next button number. See section
.B BUTTON DRAG LOCK
for details.
.IP
If the option is a list of button number pairs, the first number of each
number pair is the lock button, the second number the logical button number
to be locked. See section
.B BUTTON DRAG LOCK
for details.
.IP
For both meta and button pair configuration, the button numbers are
device button numbers, i.e. the
.B ButtonMapping
applies after drag lock.
.PP
For all options, the options are only parsed if the device supports that
configuration option. For all options, the default value is the one used by
libinput. On configuration failure, the default value is applied.
.SH SUPPORTED PROPERTIES
The following properties are provided by the
.B libinput
exports runtime-configurable options as properties. If a property listed
below is not available, the matching configuration option is not available
on the device. This however does not imply that the feature is not available
on the device. The following properties are provided by the
.B libinput
driver.
.TP 7
.BI "libinput Tapping Enabled"
1 boolean value (8 bit, 0 or 1). 1 enables tapping
.TP 7
.BI "libinput Tapping Drag Lock Enabled"
1 boolean value (8 bit, 0 or 1). 1 enables drag lock during tapping
.TP 7
.BI "libinput Calibration Matrix"
9 32-bit float values, representing a 3x3 calibration matrix, order is row
1, row 2, row 3
@@ -113,9 +197,105 @@ driver.
.BI "libinput Natural Scrolling Enabled"
1 boolean value (8 bit, 0 or 1). 1 enables natural scrolling
.TP 7
.BI "libinput Send Events Mode"
1 32-bit value, defines the sendevent mode. See the libinput documentation
for the allowed values.
.BI "libinput Send Events Modes Available"
2 boolean values (8 bit, 0 or 1), in order "disabled" and
"disabled-on-external-mouse". Indicates which send-event modes are available
on this device.
.TP 7
.BI "libinput Send Events Mode Enabled"
2 boolean values (8 bit, 0 or 1), in order "disabled" and
"disabled-on-external-mouse". Indicates which send-event modes is currently
enabled on this device.
.TP 7
.BI "libinput Left Handed Enabled"
1 boolean value (8 bit, 0 or 1). Indicates if left-handed mode is enabled or
disabled.
.TP 7
.BI "libinput Scroll Methods Available"
3 boolean values (8 bit, 0 or 1), in order "two-finger", "edge", "button".
Indicates which scroll methods are available on this device.
.TP 7
.BI "libinput Scroll Method Enabled"
3 boolean values (8 bit, 0 or 1), in order "two-finger", "edge", "button".
Indicates which scroll method is currently enabled on this device.
.TP 7
.BI "libinput Button Scrolling Button"
1 32-bit value. Sets the button number to use for button scrolling. This
setting is independent of the scroll method, to enable button scrolling the
method must be set to button-scrolling and a valid button must be set.
.TP 7
.BI "libinput Click Methods Available"
2 boolean values (8 bit, 0 or 1), in order "buttonareas", "clickfinger".
Indicates which click methods are available on this device.
.TP 7
.BI "libinput Click Methods Enabled"
2 boolean values (8 bit, 0 or 1), in order "buttonareas", "clickfinger".
Indicates which click methods are enabled on this device.
.TP 7
.BI "libinput Middle Emulation Enabled"
1 boolean value (8 bit, 0 or 1). Indicates if middle emulation is enabled or
disabled.
.TP 7
.BI "libinput Disable While Typing Enabled"
1 boolean value (8 bit, 0 or 1). Indicates if disable while typing is
enabled or disabled.
.PP
The above properties have a
.BI "libinput <property name> Default"
equivalent that indicates the default value for this setting on this device.
.TP 7
.BI "libinput Drag Lock Buttons"
Either one 8-bit value specifying the meta drag lock button, or a list of
button pairs. See section
.B BUTTON DRAG LOCK
for details.
.TP 7
.BI "libinput Horizontal Scrolling Enabled"
1 boolean value (8 bit, 0 or 1). Indicates whether horizontal scrolling
events are enabled or not.
.SH BUTTON MAPPING
X clients receive events with logical button numbers, where 1, 2, 3
are usually interpreted as left, middle, right and logical buttons 4, 5, 6,
7 are usually interpreted as scroll up, down, left, right. The fourth and
fifth physical buttons on a device will thus send logical buttons 8 and 9.
The
.B ButtonMapping
option adjusts the logical button mapping, it does not affect how a physical
button is mapped to a logical button.
.PP
Traditionally, a device was set to left-handed button mode by applying a
button mapping of
.B "\*q3 2 1 ...\*q"
On systems using the
.B libinput
__xservername__ input driver it is recommended to use the
.B LeftHanded
option instead.
.PP
The
.B libinput
__xservername__ input driver does not use the button mapping after setup.
Use XSetPointerMapping(__libmansuffix__) to modify the button mapping at
runtime.
.SH BUTTON DRAG LOCK
Button drag lock holds a button logically down even when the button itself
has been physically released since. Button drag lock comes in two modes.
.PP
If in "meta" mode, a meta button click activates drag lock for the next
button press of any other button. A button click in the future will keep
that button held logically down until a subsequent click of that same
button. The meta button events themselves are discarded. A separate meta
button click is required each time a drag lock should be activated for a
button in the future.
.PP
If in "pairs" mode, each button can be assigned a target locking button.
On button click, the target lock button is held logically down until the
next click of the same button. The button events themselves are discarded
and only the target button events are sent.
.TP
This feature is provided by this driver, not by libinput.
.SH AUTHORS
Peter Hutterer

View File

@@ -30,8 +30,10 @@ AM_CPPFLAGS =-I$(top_srcdir)/include $(LIBINPUT_CFLAGS)
@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
@DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS)
@DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS) libdraglock.la
@DRIVER_NAME@_drv_ladir = @inputdir@
@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c
@DRIVER_NAME@_drv_la_SOURCES = xf86libinput.c
noinst_LTLIBRARIES = libdraglock.la
libdraglock_la_SOURCES = draglock.c draglock.h

282
src/draglock.c Normal file
View File

@@ -0,0 +1,282 @@
/*
* Copyright © 2015 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.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "draglock.h"
#include <string.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
static int
draglock_parse_config(struct draglock *dl, const char *config)
{
int button = 0, target = 0;
const char *str = NULL;
char *end_str = NULL;
int pairs[DRAGLOCK_MAX_BUTTONS] = {0};
if (!config)
return 0;
/* empty string disables drag lock */
if (*config == '\0') {
dl->mode = DRAGLOCK_DISABLED;
return 0;
}
/* check for a single-number string first, config is "<int>" */
button = strtol(config, &end_str, 10);
if (*end_str == '\0') {
if (button < 0 || button >= DRAGLOCK_MAX_BUTTONS)
return 1;
/* we allow for button 0 so stacked xorg.conf.d snippets can
* disable the config again */
if (button == 0) {
dl->mode = DRAGLOCK_DISABLED;
return 0;
}
return draglock_set_meta(dl, button);
}
dl->mode = DRAGLOCK_DISABLED;
/* check for a set of button pairs, config is
* "<int> <int> <int> <int>..." */
str = config;
while (*str != '\0') {
button = strtol(str, &end_str, 10);
if (*end_str == '\0')
return 1;
str = end_str;
target = strtol(str, &end_str, 10);
if (end_str == str)
return 1;
if (button <= 0 || button >= DRAGLOCK_MAX_BUTTONS || target >= DRAGLOCK_MAX_BUTTONS)
return 1;
pairs[button] = target;
str = end_str;
}
return draglock_set_pairs(dl, pairs, ARRAY_SIZE(pairs));
}
int
draglock_init_from_string(struct draglock *dl, const char *config)
{
dl->mode = DRAGLOCK_DISABLED;
dl->meta_button = 0;
dl->meta_state = false;
memset(dl->lock_pair, 0, sizeof(dl->lock_pair));
memset(dl->lock_state, 0, sizeof(dl->lock_state));
return draglock_parse_config(dl, config);
}
enum draglock_mode
draglock_get_mode(const struct draglock *dl)
{
return dl->mode;
}
int
draglock_get_meta(const struct draglock *dl)
{
if (dl->mode == DRAGLOCK_META)
return dl->meta_button;
return 0;
}
size_t
draglock_get_pairs(const struct draglock *dl, int *array, size_t sz)
{
unsigned int i;
size_t last = 0;
if (dl->mode != DRAGLOCK_PAIRS)
return 0;
/* size 1 array with the meta button */
if (dl->meta_button) {
*array = dl->meta_button;
return 1;
}
/* size N array with a[0] == 0, the rest ordered by button number */
memset(array, 0, sz * sizeof(array[0]));
for (i = 0; i < sz && i < ARRAY_SIZE(dl->lock_pair); i++) {
array[i] = dl->lock_pair[i];
if (array[i] != 0 && i > last)
last = i;
}
return last;
}
int
draglock_set_meta(struct draglock *dl, int meta_button)
{
if (meta_button < 0 || meta_button >= DRAGLOCK_MAX_BUTTONS)
return 1;
dl->meta_button = meta_button;
dl->mode = meta_button ? DRAGLOCK_META : DRAGLOCK_DISABLED;
return 0;
}
int
draglock_set_pairs(struct draglock *dl, const int *array, size_t sz)
{
unsigned int i;
if (sz == 0 || array[0] != 0)
return 1;
for (i = 0; i < sz; i++) {
if (array[i] < 0 || array[i] >= DRAGLOCK_MAX_BUTTONS)
return 1;
}
dl->mode = DRAGLOCK_DISABLED;
for (i = 0; i < sz; i++) {
dl->lock_pair[i] = array[i];
if (dl->lock_pair[i])
dl->mode = DRAGLOCK_PAIRS;
}
return 0;
}
static int
draglock_filter_meta(struct draglock *dl, int *button, int *press)
{
int b = *button,
is_press = *press;
if (b == dl->meta_button) {
if (is_press)
dl->meta_state = true;
*button = 0;
return 0;
}
switch (dl->lock_state[b]) {
case DRAGLOCK_BUTTON_STATE_NONE:
if (dl->meta_state && is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
dl->meta_state = false;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_1:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_UP_1:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_2:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
}
break;
}
*button = b;
return 0;
}
static int
draglock_filter_pair(struct draglock *dl, int *button, int *press)
{
int b = *button,
is_press = *press;
if (dl->lock_pair[b] == 0)
return 0;
switch (dl->lock_state[b]) {
case DRAGLOCK_BUTTON_STATE_NONE:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
b = dl->lock_pair[b];
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_1:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_UP_1:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_2:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
b = dl->lock_pair[b];
}
break;
}
*button = b;
return 0;
}
int
draglock_filter_button(struct draglock *dl, int *button, int *is_press)
{
if (*button == 0)
return 0;
switch(dl->mode) {
case DRAGLOCK_DISABLED:
return 0;
case DRAGLOCK_META:
return draglock_filter_meta(dl, button, is_press);
case DRAGLOCK_PAIRS:
return draglock_filter_pair(dl, button, is_press);
default:
abort();
break;
}
return 0;
}

159
src/draglock.h Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright © 2015 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.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef DRAGLOCK_H
#define DRAGLOCK_H 1
#include <stdbool.h>
#include <stdlib.h>
/* 32 buttons are enough for everybody™
* Note that this is the limit of physical buttons as well as the highest
* allowed target button.
*/
#define DRAGLOCK_MAX_BUTTONS 32
enum draglock_mode
{
DRAGLOCK_DISABLED,
DRAGLOCK_META,
DRAGLOCK_PAIRS
};
enum draglock_button_state
{
DRAGLOCK_BUTTON_STATE_NONE,
DRAGLOCK_BUTTON_STATE_DOWN_1,
DRAGLOCK_BUTTON_STATE_UP_1,
DRAGLOCK_BUTTON_STATE_DOWN_2,
};
struct draglock
{
enum draglock_mode mode;
int meta_button; /* meta key to lock any button */
bool meta_state; /* meta_button state */
unsigned int lock_pair[DRAGLOCK_MAX_BUTTONS + 1];/* specify a meta/lock pair */
enum draglock_button_state lock_state[DRAGLOCK_MAX_BUTTONS + 1]; /* state of any locked buttons */
};
/**
* Initialize the draglock struct based on the config string. The string is
* either a single number to configure DRAGLOCK_META mode or a list of
* number pairs, with pair[0] as button and pair[1] as target lock number to
* configure DRAGLOCK_PAIRS mode.
*
* If config is NULL, the empty string, "0" or an even-numbered list of 0,
* the drag lock mode is DRAGLOCK_DISABLED.
*
* @return 0 on success or nonzero on error
*/
int
draglock_init_from_string(struct draglock *dl, const char *config);
/**
* Get the current drag lock mode.
*
* If the mode is DRAGLOCK_META, a meta button click will cause the next
* subsequent button click to be held logically down until the release of
* the second button click of that same button. Events from the meta button
* are always discarded.
*
* If the mode is DRAGLOCK_PAIRS, any button may be configured with a
* 'target' button number. A click of that button causes the target button
* to be held logically down until the release of the second button click.
*/
enum draglock_mode
draglock_get_mode(const struct draglock *dl);
/**
* @return the meta button number or 0 if the current mode is not
* DRAGLOCK_META.
*/
int
draglock_get_meta(const struct draglock *dl);
/**
* Get the drag lock button mapping pairs. The array is filled with the
* button number as index and the mapped target button number as value, i.e.
* array[3] == 8 means button 3 will draglock button 8.
*
* A value of 0 indicates draglock is disabled for that button.
*
* @note Button numbers start at 1, array[0] is always 0.
*
* @param[in|out] array Caller-allocated array to hold the button mappings.
* @param[in] sz Maximum number of elements in array
*
* @return The number of valid elements in array or 0 if the current mode is
* not DRAGLOCK_PAIRS
*/
size_t
draglock_get_pairs(const struct draglock *dl, int *array, size_t sz);
/**
* Set the drag lock config to the DRAGLOCK_META mode, with the given
* button as meta button.
*
* If the button is 0 the mode becomes DRAGLOCK_DISABLED.
*
* @return 0 on success, nonzero otherwise
*/
int
draglock_set_meta(struct draglock *dl, int meta_button);
/**
* Set the drag lock config to the DRAGLOCK_PAIRS mode. The array
* must be filled with the button number as index and the mapped target
* button number as value, i.e.
* array[3] == 8 means button 3 will draglock button 8.
*
* A value of 0 indicates draglock is disabled for that button. If all
* buttons are 0, the mode becomes DRAGLOCK_DISABLED.
*
* @note Button numbers start at 1, array[0] is always 0.
*
* @return 0 on successor nonzero otherwise
*/
int
draglock_set_pairs(struct draglock *dl, const int *array, size_t sz);
/**
* Process the given button event through the drag lock state machine.
* If the event is to be discarded by the caller, button is set to 0.
* Otherwise, button is set to the button event to process and is_press is
* set to the button state to process.
*
* @param[in|out] button The button number to process
* @param[in|out] is_press nonzero for press, zero for release
*
* @return 0 on success or 1 on error
*/
int
draglock_filter_button(struct draglock *dl, int *button, int *is_press);
#endif /* DRAGLOCK_H */

File diff suppressed because it is too large Load Diff

3904
src/xf86libinput.c Normal file

File diff suppressed because it is too large Load Diff

1
test/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
test-draglock

13
test/Makefile.am Normal file
View File

@@ -0,0 +1,13 @@
AM_CPPFLAGS = $(XORG_CFLAGS) \
$(CWARNFLAGS) \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src
tests = test-draglock
noinst_PROGRAMS = $(tests)
test_draglock_SOURCES = test-draglock.c
test_draglock_LDADD = ../src/libdraglock.la
TESTS = $(tests)

540
test/test-draglock.c Normal file
View File

@@ -0,0 +1,540 @@
/*
* Copyright © 2013-2015 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.
*
* 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.
*/
#include "draglock.h"
#include <assert.h>
#include <string.h>
static void
test_config_empty(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, NULL);
assert(dl.mode == DRAGLOCK_DISABLED);
assert(rc == 0);
}
static void
test_config_invalid(void)
{
struct draglock dl;
int rc;
/* no trailing space */
rc = draglock_init_from_string(&dl, "1 ");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "256");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "-1");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "1 2 3");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0 2");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0 0");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_disable(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_meta_button(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "1");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 1);
rc = draglock_init_from_string(&dl, "2");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 2);
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 10);
}
static void
test_config_button_pairs(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "1 1");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
rc = draglock_init_from_string(&dl, "1 2 3 4 5 6 7 8");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
rc = draglock_init_from_string(&dl, "1 2 3 4 5 0 7 8");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
/* all disabled */
rc = draglock_init_from_string(&dl, "1 0 3 0 5 0 7 0");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_get(void)
{
struct draglock dl;
int rc;
const int sz = 32;
int map[sz];
draglock_init_from_string(&dl, "");
rc = draglock_get_meta(&dl);
assert(rc == 0);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 0);
draglock_init_from_string(&dl, "8");
rc = draglock_get_meta(&dl);
assert(rc == 8);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 0);
draglock_init_from_string(&dl, "1 2 3 4 5 6");
rc = draglock_get_meta(&dl);
assert(rc == 0);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 5);
assert(map[0] == 0);
assert(map[1] == 2);
assert(map[2] == 0);
assert(map[3] == 4);
assert(map[4] == 0);
assert(map[5] == 6);
}
static void
test_set_meta(void)
{
struct draglock dl;
int rc;
draglock_init_from_string(&dl, "");
rc = draglock_set_meta(&dl, 0);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_set_meta(&dl, 1);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
rc = draglock_set_meta(&dl, -1);
assert(rc == 1);
rc = draglock_set_meta(&dl, 32);
assert(rc == 1);
}
static void
test_set_pairs(void)
{
struct draglock dl;
int rc;
const int sz = 32;
int map[sz];
draglock_init_from_string(&dl, "");
memset(map, 0, sizeof(map));
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_set_pairs(&dl, map, 1);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
map[0] = 1;
rc = draglock_set_pairs(&dl, map, 1);
assert(rc == 1);
map[0] = 0;
map[1] = 2;
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
map[0] = 0;
map[1] = 0;
map[10] = 8;
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
}
static void
test_filter_meta_passthrough(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
for (i = 0; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 1);
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 1);
}
}
static void
test_filter_meta_click_meta_only(void)
{
struct draglock dl;
int rc;
int button, press;
rc = draglock_init_from_string(&dl, "10");
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
}
static void
test_filter_meta(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_meta_extra_click(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_meta_interleaved(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
}
for (i = 0; i < 10; i++) {
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_pairs(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "1 11 2 0 3 13 4 0 5 15 6 0 7 17 8 0 9 19");
for (i = 1; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2)
assert(button == i + 10);
else
assert(button == i);
assert(press == 1);
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2) {
assert(button == 0);
} else {
assert(button == i);
assert(press == 0);
}
}
for (i = 1; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2) {
assert(button == 0);
} else {
assert(button == i);
assert(press == 1);
}
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2)
assert(button == i + 10);
else
assert(button == i);
assert(press == 0);
}
}
int
main(int argc, char **argv)
{
test_config_empty();
test_config_invalid();
test_config_disable();
test_config_meta_button();
test_config_button_pairs();
test_config_get();
test_set_meta();
test_set_pairs();
test_filter_meta_passthrough();
test_filter_meta_click_meta_only();
test_filter_meta();
test_filter_meta_extra_click();
test_filter_meta_interleaved();
test_filter_pairs();
return 0;
}