Compare commits

...

341 commits

Author SHA1 Message Date
Giulio P
be44b6e6a8 doc: fix typo
Remove a repetition of words in the comments on
libevdev_set_event_value()

Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/131>
2025-12-07 02:31:20 +00:00
Peter Hutterer
139b58e135 libevdev 1.13.6
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2025-12-01 15:12:22 +10:00
Peter Hutterer
c6bf238c4e include: sync event codes with kernel 6.18
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/129>
2025-12-01 14:49:50 +10:00
Peter Hutterer
f3a9c2038d libevdev 1.13.5
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2025-10-20 14:49:38 +10:00
Marcos Alano
9289c9826c Sync headers with kernel 6.17
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/126>
2025-09-28 20:34:21 -03:00
Peter Hutterer
a30a461e82 util: change the bit to shift to ULL
libevdev/libevdev-util.h:45:45: runtime error: left shift of 1 by 63 places cannot be represented in type 'long long'

Fixes: #32
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/127>
2025-08-13 21:23:10 +10:00
Peter Hutterer
d093b4752a include: sync event codes with kernel 6.16
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/125>
2025-07-29 09:07:13 +10:00
Peter Hutterer
ac0056961c libevdev 1.13.4 2025-03-25 09:27:07 +10:00
andeston
d06abb81e5 Always push changed mt events when syncing
If the start and end of a touch are dropped, the slot, according to the
kernel, may have a different state. We should inform the client of these
changes even if the slot is not currently active.

For most axes this doesn't matter too much as we expect them to change
during an active touch anyway so we don't expect the kernel's caching to
be a problem. However where the ABS_MT_TOOL_TYPE changed during a sync
we need to inform the client of the new tool type so that future
touchese won't be erroneously treated as e.g. palms.

For a full reproducer see the test case but it comes down to:
- touch down with MT_TOOL_PALM, make sure libevdev reads the state
- change that slot to MT_TOOL_FINGER, trigger a sync
- ensure that libevdev pushes out that tool type change even if the
  slot is not currently active

Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/124>
2025-01-06 13:21:29 +10:00
Peter Hutterer
cfd803566c CI: update to latest ci-templates
This allows for using @users.noreply addresses and still pass
ci-fairy checks.

Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/123>
2025-01-06 12:57:50 +10:00
Peter Hutterer
1a8324aeb8 Drop the signed-off-by requirement
We've had this for roughly 10y now and it's value is dubious. Most of
xorg no longer requires, mesa accepts but doesn't require it, most of GNOME
doesn't accept it and neither does systemd.

Let's drop the requirement.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/123>
2025-01-06 12:51:05 +10:00
Peter Hutterer
72fa564092 gitlab CI: bump to latest fedoras and ubuntu
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-11-25 10:34:30 +10:00
Peter Hutterer
2342d8c9ee libevdev 1.13.3
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-09-03 12:16:11 +10:00
Peter Hutterer
54c083378e include: sync event codes with kernel 6.10
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-07-15 15:57:02 +10:00
Peter Hutterer
5501633d51 libevdev 1.13.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-05-31 15:16:54 +10:00
Peter Hutterer
080d1d097a include: sync event codes with kernel 6.9
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-05-14 15:23:31 +10:00
Peter Hutterer
414757317d gitlab CI: don't run MR pipelines in forks
Commit originally by Simon Ser in wayland/wayland-protocols!305.

Currently our CI setup has a downside: for each push on a merge
request, two pipelines are triggered. The first is triggered in
the context of the forked repository, and the second is triggered
in the context of the MR in the parent repository.

Replace the workflow rules with the ones in the official docs [1],
so that a branch pipeline isn't triggered when a MR exists for that
branch.

[1]: https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-04-30 08:46:00 +10:00
Peter Hutterer
fb5402020f meson.build: remove superfluous double doxygen check
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:11:08 +10:00
Peter Hutterer
de6ae19483 meson.build: specify the include directory correctly
If libevdev is used as subproject header lookup for libevdev.h fails
because our build directory isn't correctly set as one of the include
directories.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:11:08 +10:00
Peter Hutterer
82560ca9d7 meson.build: declare the file list as such
Not much of an effect but where libevdev is used as subproject those
files are now correctly accessible.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:11:08 +10:00
Peter Hutterer
1ee2399ba8 meson.build: allow disabling building the various tools
A bit of a niche case but this helps with embedding libevdev as static
library when the tools don't matter.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:11:08 +10:00
Peter Hutterer
d852e59dd0 gitlab CI: rebuild the images
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:04:50 +10:00
Peter Hutterer
8d8a3d8fc7 gitlab CI: drop Ubuntu 22.10
Repos are 404

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 16:04:44 +10:00
Peter Hutterer
cd9bea914c gitlab CI: drop unnecessary B2C_VERSION
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 15:52:50 +10:00
Peter Hutterer
179fc4d370 gitlab CI: update to the same b2c image libinput uses
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 15:26:57 +10:00
Peter Hutterer
703999edec gitlab CI: remove the jobs for the scheduled forced rebuild
This scheduled pipeline no long runs, so let's drop this job.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 15:15:01 +10:00
Peter Hutterer
5db8e66bd3 gitlab CI: update to latest Fedoras
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 15:15:01 +10:00
Peter Hutterer
2e0a0cd271 gitlab CI: update to latest template and use the ci-fairy image
Makes life easier because we don't have to deal with the pip complaints.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2024-03-21 15:10:00 +10:00
Peter Hutterer
97d0e4d151 CI: add a comment to the meson build helper
We now have an upstream for it so we can sync changes between projects.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-30 15:18:28 +10:00
Peter Hutterer
d21d826b63 CI: bump to new fedoras and ubuntus
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-08 14:45:10 +10:00
Peter Hutterer
d399abca1a tools/publish-doc: enable pushing docs for specific tags
Historically, I copied the docs on the server directly after pushing latest,
but (especially with meson) it's a lot easier to just build that specific tag
locally and rsync it to the correct target directory.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-07 23:48:44 +00:00
Peter Hutterer
d7139f1314 tools/publish-doc: build the docs with meson before synching
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-07 23:48:44 +00:00
Peter Hutterer
1cc8c6d491 doc: update the ioctl list with missing ioctls
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-08 09:35:37 +10:00
Peter Hutterer
f201583026 doc: remove duplicate doc entry for EVIOCSKEYCODE
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-08 09:18:57 +10:00
Peter Hutterer
4582559b66 libevdev 1.13.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-05-05 10:45:30 +10:00
Peter Hutterer
fb3741e0cd include: sync event codes with kernel 6.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-04-20 08:58:13 +10:00
Enric Balletbo i Serra
bb4404dd91 test: Get the print mode from the CK_VERBOSITY environment variable
On a test run it only prints the summary and one message per failed
test. While having this behaviour by default is nice it might be
interesting in some case to have more information print. Make the print
mode configurable from the environment variable CK_VERBOSITY, which can
have the values "silent", "minimal", "normal" or "verbose" so we can have
different outputs.

    $ sudo CK_VERBOSITY=verbose ./test-libevdev
    Running suite(s): libevdev init tests
     libevdev_has_event tests
     libevdev event tests
     100%: Checks: 79, Failures: 0, Errors: 0
     test-libevdev-init.c:23:P:test_new_device:test_new_device:0: Passed
     test-libevdev-init.c:28:P:test_free_device:test_free_device:0: Passed
     [ ... ]

Note that the default print mode doesn't change after this patch.

Signed-off-by: Enric Balletbo i Serra <eballetbo@redhat.com>
2023-04-19 16:40:14 +02:00
Peter Hutterer
db0d4271ed gitlab CI: add new workflow rules
Required for pipelines to run after some infrastructure changes, see
https://gitlab.freedesktop.org/freedesktop/freedesktop/-/issues/438

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-03-15 10:21:43 +10:00
Peter Hutterer
689d1eb01c gitlab CI: bump to latest fedoras
The F37 update was delayed by https://github.com/systemd/systemd/pull/25941 which
is now available in F37 as of v251.11

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-02-15 08:31:58 +10:00
Benjamin Tissoires
2eb0bb4be4 CI: bump b2c and kernel
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2023-02-08 11:31:02 +01:00
Alyssa Ross
d8c491f57e
Include all include files in dist tarballs
Otherwise, the distribution tarballs will be generated based on what's
in libevdev_la_SOURCES, which only includes the headers for the
operating system the maintainer happens to be running "make dist"
from.  As a result of this, e.g. the 1.13.0 tarball only includes the
headers for Linux, making the tarball unbuildable for FreeBSD.

"meson dist" was already doing the right thing.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-01-13 21:43:04 +00:00
Peter Hutterer
54f4c054ea gitlab CI: sync the meson-build.sh script with libinput
Pulls in the three libinput commits up to 31ecda70087

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-10 08:56:52 +10:00
Peter Hutterer
b2e12fe926 gitlab CI: use b2c instead of qemu
This is copied from libinput's CI but as one large change rather than
cherry-picking the process on how to get here. meson-build.sh is synched
with libinput's version - it is a more generic version anyway.

With this change we no longer require separate images for the qemu runs,
our default image is qemu-capable and can be run in qemu via
boot2container (b2c).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 10:32:01 +10:00
Peter Hutterer
50ac79078e gitlab CI: pass the --no-suite to meson builds
Only use the LIBEVDEV_SKIP_ROOT_TESTS env var in autotools where we need
it, in meson we can use meson to control which tests we (don't) want to
run.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 10:30:47 +10:00
Peter Hutterer
37f71a8493 gitlab CI: drop the ninja dist for every job
Unlike autotools distcheck which ensures we didn't forget to add
anything to the makefiles, ninja dist just zips up the git repo.

It does run the tests though but without suite selection which is a
problem for us here.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 10:26:39 +10:00
Peter Hutterer
6be54f75c8 gitlab CI: skip the right tests in the tarball jobs
Use the new needs-uinput suite specifier for the meson build job, and
use --no-tests for ninja dist in the autotools build job.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 10:26:39 +10:00
Peter Hutterer
427af9d248 meson.build: add the tests that need uinput into a needs-uinput suite
This way we can skip it all by meson test --no-suite=needs-uinput

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 10:25:02 +10:00
Peter Hutterer
6d0d778e59 gitlab CI: replace the meson-build.sh with the libinput one
The libinput one is more generic and expressive, taking arguments and
whatnot.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 09:25:46 +10:00
Peter Hutterer
ac3d44ee7a gitlab CI: drop MESON_SKIP_TEST variables
In the no-check:meson job, the ninja arg was "dist" so the test would be
run as part of that anyway (and skipped, since we didn't have check).

In the no-doxygen-check:meson job, the ninja arg was zero so the test
would be skipped but since we don't have check we might as well just
run it as empty test suite.

And the same applies to the scan-build job, running the test shouldn't
hurt here.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 09:18:17 +10:00
Peter Hutterer
46ed9e53e4 gitlab CI: drop the custom meson to junit conversion script
And always collect test logs, makes it easier to debug when things fail
to go wrong

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-05 09:01:38 +10:00
Peter Hutterer
1e9fb4fe02 test: drop the valgrind make check wrappers from autotools
We have meson with a proper test suite setup and this currently breaks
the CI due to some Arch issues with glibc debuginfo packages. Let's just
drop this so we don't run valgrind unconditionally.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 15:51:58 +10:00
Peter Hutterer
1489287bf1 gitlab CI: bump to newer Ubuntus
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 15:25:06 +10:00
Peter Hutterer
136efe0399 gitlab CI: bump to a newer version of the templates
Required by the debian sid containers, otherwise we fail because of a
missing /etc/apt/sources.list file.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 15:20:33 +10:00
Peter Hutterer
f45bc03d9f gitlab CI: do not retry the qemu runs
See libinput commit fb4f4131a112201c86c510179cfc939fcfa8aece by Benjamin
Tissoires

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 14:46:28 +10:00
Peter Hutterer
4f66455160 gitlab CI: change an explicit Fedora to {{distro}}
See libinput commit 0d602e12a4b66d5b5f27d2a9fd9899d43cf128fe by Benjamin
Tissoires

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 14:43:18 +10:00
Peter Hutterer
09fd1f4e66 gitlab CI: prettify the include of templates
Identical to libinput commit c8c825289f1b7575ee10b849c04f5caa60483a7e by
Benjamin Tissoires.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-01-04 14:41:33 +10:00
illiliti
7820dc8b08 meson: Use proper type for bool object
Fix invalid bool usage which violates official meson specification and thus
breaks muon, an implementation of meson written in C.

Signed-off-by: illiliti <illiliti@protonmail.com>
2022-10-20 23:13:06 +03:00
Zixian Liu
df826a3c54 Correct document 2022-08-16 09:00:08 +00:00
Douglas R. Reno
011946d446 configure.ac: Update the bug report URL.
While I was running the tests for libevdev on a
system, I had a test failure, and it told me to report it to
bugs.freedesktop.org.

This project uses GitLab now, so update the URL.

Signed-off-by: Douglas R. Reno <renodr@linuxfromscratch.org>
2022-08-08 22:26:36 +00:00
Peter Hutterer
ff4276398c libevdev 1.13.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-08-02 11:21:12 +10:00
Peter Hutterer
1da836d0a9 include: sync event codes with kernel 5.19
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-08-02 11:09:51 +10:00
Peter Hutterer
b6c9dfd9d7 meson: drop the uinput.h header listing
This is a noop, meson gets its compile dependencies from the compiler,
listing it here makes no difference.

Same is true for listing the other two linux/input/*.h headers as
sources.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-12 09:50:08 +00:00
Peter Hutterer
0afed6479d meson.build: drop the use of join_paths
Replace with the slash notation supported since 0.49

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-12 09:50:08 +00:00
Peter Hutterer
c6c4d33474 meson.build: use project_source_root() instead of source_root()
The latter is deprecated, so let's bump the meson version requirement
and use the newer, shiny feature.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-12 09:50:08 +00:00
Peter Hutterer
c9781f00f3 uinput: use named initializers for the event struct
With the 64 bit timestamps, the struct layout changes into a flatter
version, so let's use the input_event_(u)sec helpers to transparently
handle this.

Fixes #25

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-11 15:32:59 +10:00
Peter Hutterer
0c7e1d2f67 Fix a few whitespace/coding style issues
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-11 15:31:45 +10:00
Peter Hutterer
2d49be8303 Fix a compiler warning
[1/16] Compiling C object libevdev.so.2.3.0.p/libevdev_libevdev.c.o
../libevdev/libevdev.c:665:40: warning: argument 2 of type ‘struct slot_change_state[dev->num_slots]’ declared as a variable length array [-Wvla-parameter]
  665 |               struct slot_change_state changes_out[dev->num_slots])
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
../libevdev/libevdev.c:47:52: note: previously declared as a pointer ‘struct slot_change_state *’
   47 |                          struct slot_change_state *changes_out);
      |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-11 15:31:45 +10:00
Peter Hutterer
c2eaaa171e meson: up the timeout to 10s per test
Fixes #26

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-07-11 15:28:23 +10:00
Peter Hutterer
de2daf8d36 meson.build: install the mouse-dpi-tool man page
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-03-25 14:37:28 +10:00
Peter Hutterer
8ced382eb8 libevdev 1.12.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-03-25 14:32:48 +10:00
Peter Hutterer
f3c3b0a233 include: sync key codes with kernel 5.17
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-03-22 12:34:08 +10:00
Peter Hutterer
7c43e86944 gitlab CI: update to current distribution versions, drop Centos
No big point building for Centos 7 anywmore, and Centos 8 is now Centos
Stream only which needs fixing in the CI templates first.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-02-02 00:29:35 +00:00
Stephen Kitt
066d9caf55
Add a manpage for mouse-dpi-tool
Signed-off-by: Stephen Kitt <steve@sk2.org>
2021-11-15 08:58:11 +01:00
Peter Hutterer
69403a63ed libevdev 1.12.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-11-09 09:52:06 +10:00
Peter Hutterer
d03f9b6616 tools: add a helper tool to list all currently known codes
A non-installed tool to make it easy to check if newly added codes are
indeed supported correctly.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-11-09 09:46:16 +10:00
Peter Hutterer
fdba5a41dd include: sync event codes with kernel 5.15
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-11-09 08:54:21 +10:00
José Expósito
889fc01c81 doc: fix initialization and setup error
Remove an unnecessary and unmatched curly bracket from the demo code.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
2021-09-04 13:30:17 +02:00
José Expósito
8a4f45df5b doc: fix uinput device creation warnings
The example code for creating uinput devices produces the following
warnings:

warning: unused variable ‘ev’ [-Wunused-variable]
   | struct input_event ev[2];
   |                    ^~
warning: unused variable ‘new_fd’ [-Wunused-variable]
   | int fd, new_fd, uifd;
   |         ^~~~~~
warning: ‘err’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   |     return err;
   |            ^~~

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
2021-09-04 13:21:42 +02:00
Ulrich Ölmann
9b918d316a doc: fix typos
Signed-off-by: Ulrich Ölmann <u.oelmann@pengutronix.de>
2021-08-17 18:33:58 +02:00
Ulrich Ölmann
5fc81553f5 doc: fix uinput example code
Signed-off-by: Ulrich Ölmann <u.oelmann@pengutronix.de>
2021-08-17 15:09:26 +02:00
Peter Hutterer
a6970e1cec gitlab CI: update to latest ci-templates
We can ditch the custom localhost usages and instead use the vmctl and
ssh-config aliases.

Signed-off-by:	Peter Hutterer <peter.hutterer@who-t.net>
2021-07-26 10:23:39 +10:00
Simeon Schaub
662c84d80e
build: properly link against rt
This is especially relevant for cross-compilation, since libevdev uses
`clock_gettime`.
This came up in https://github.com/JuliaPackaging/Yggdrasil/pull/3201.

Signed-off-by: Simeon Schaub <simeondavidschaub99@gmail.com>
2021-06-21 02:56:52 +02:00
Peter Hutterer
bb1cd0dd57 gitlab CI: bump to Fedora 34 and Ubuntu 21.04
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-05-19 10:37:21 +10:00
Peter Hutterer
a53c6d1154 gitlab CI: make the tarball distro selection automatic
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-05-19 10:36:58 +10:00
Peter Hutterer
4e5babd7a1 gitlab CI: make the qemu selection automatic
Generate the snippet for whichever is the last version in the list for the
want_qemu tag.

And move the want_qemu tag up so it's more obvious in the config file.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-05-19 10:36:53 +10:00
Richard Purdie
8d70f44989 make-event-names: Fix determinism issue
The order of dict values is not deterministic in python leading to differing 
header file generation which results in differing build output for the same
configuration. Sort to remove this inconsistency and make the output 
reproducible.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Reviewed-by: Filipe Laíns <lains@archlinux.org>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-02-22 07:06:46 +10:00
Peter Hutterer
8855f1ac59 libevdev 1.11.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-02-01 15:51:10 +10:00
Peter Hutterer
60d4f1b2ae Change to the (always intended) MIT license
Due to what must've been a copy/paste error many years ago, the license text
for libevdev wasn't actually the MIT license. Let's rectify this, it was
always MIT intended anyway.

To make this more obvious and reduce the chance of copy/paste mistakes, use
the SPDX license identifier in the various source files. The two installed
public header files have the full license text.

All contributors with copyrightable contributions have ACKed the license
change to MIT, either in the MR directly [1] or privately in reply to an
email.

[1] https://gitlab.freedesktop.org/libevdev/libevdev/-/merge_requests/69

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Alexander Dahl <ada@thorsis.com>
Acked-by: Andreas Pokorny <andreas.pokorny@canonical.com>
Acked-by: Armin K <krejzi@email.com>
Acked-by: Benjamin Tissoires <btissoir@redhat.com>
Acked-by: David Herrmann <dh.herrmann@gmail.com>
Acked-by: Deepa Dinamani <deepa.kernel@gmail.com>
Acked-by: Emmanuele Bassi <ebassi@gnome.org>
Acked-by: Gaetan Nadon <memsize@videotron.ca>
Acked-by: George Thomas <georgefsthomas@gmail.com>
Acked-by: Michael Forney <mforney@mforney.org>
Acked-by: Nayan Deshmukh <nayan26deshmukh@gmail.com>
Acked-by: Niclas Zeising <zeising@daemonic.se>
Acked-by: Owen W. Taylor <otaylor@fishsoup.net>
Acked-by: Peter Seiderer <ps.report@gmx.net>
Acked-by: Ran Benita <ran234@gmail.com>
Acked-by: Rosen Penev <rosenp@gmail.com>
Acked-by: Scott Jann <sjann@knight-rider.org>
Acked-by: Thilo Schulz <thilo@tjps.eu>
Acked-by: polyphemus <rolfmorel@gmail.com>
2021-01-25 13:46:55 +10:00
Peter Hutterer
7eae5e322c libevdev 1.10.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-01-11 13:07:47 +10:00
Peter Hutterer
70881516f2 doc: fix conflicting documentation for libevdev_get_event_value()
Yes, the value we return is from the currently active slot, but there are a
few niche cases where the active slot changes from what the client may think
it is. So let's call it undefined like the other half of the documentation
already does.

Fixes #20

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-01-08 09:58:16 +10:00
Peter Hutterer
510bde8f47 gitlab CI: use Fedora 33 and Ubuntu 20.10
This requires latest CI templates for the mkosi changes. Since the start_vm.sh
script is now gone, switch to using vmctl instead.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-01-04 11:49:42 +10:00
Peter Hutterer
7f53bcfab3 gitlab CI: make the custom build reference automated
We still require Fedora for the various jobs with custom autotools/meson
configurations. But we might as well make it dependent on the config file
entries only than hardcoding it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-01-04 10:59:25 +10:00
Peter Hutterer
896d087a0e include: sync event codes with kernel 5.10
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-12-14 00:17:15 +00:00
Shuo Wang
74dc7ff245 CODING_STYLE.md: fix a typo
Signed-off-by: Shuo Wang <wangshuo47@huawei.com>
2020-11-03 14:42:25 +08:00
Peter Hutterer
e6f3141eb6 libevdev 1.10.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-26 09:07:01 +10:00
Peter Hutterer
a37d76b49b README: drop an obsolete paragraph
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-26 09:06:09 +10:00
Peter Hutterer
869fda7810 libevdev 1.10rc2 2020-10-20 09:34:05 +10:00
Scott Jann
4226c7801b Add libevdev_disable_property
On some devices, a kernel input property has been set in error and we need the
ability to disable that property.

Signed-off-by: Scott Jann <sjann@knight-rider.org>
2020-10-19 14:47:07 +10:00
Nayan Deshmukh
8e94375bc6 Add link to Rust bindings
Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com>
2020-10-10 03:58:22 +00:00
Peter Hutterer
df677d954c libevdev 1.10rc1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-06 10:19:50 +10:00
Peter Hutterer
f6c0a048c5 tools: add a man page for the touchpad-edge-detector tool
Requires some .gitignore pattern removal too and an autotools fix to actually
dist the man pages.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-06 09:56:33 +10:00
Peter Hutterer
da2eea1dcb meson.build: install the libevdev-tweak-device man page
This got lost in meson conversion

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-06 09:44:45 +10:00
Niclas Zeising
6ea230bc72 tools: Remove signalfd.h include again
Remove the includsion of sys/signalfd.h again, it hasn't been needed
since cca90938 and was accidentally re-added, probably as a mismerge,
in a40e014e.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-09-19 12:13:12 +02:00
Peter Hutterer
44b5c9bd9f include: sync event codes with kernel 5.8
And fix the script to sync the headers up so it syncs event codes for both bsd
and linux, but only syncs input.h for linux.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-09-11 12:13:13 +10:00
Peter Hutterer
b40675c701 doc: fix doxyen complaints after fd6c9b8ca0
Fixes fd6c9b8ca0

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-09-11 12:13:04 +10:00
Peter Hutterer
cb5d56ab80 gitlab ci: run the qemu jobs on F32
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-09-11 11:04:27 +10:00
Peter Hutterer
ed71864c4c gitlab CI: update to use F32
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-09-11 10:38:54 +10:00
Rosen Penev
fb6a84a52a
[clang-tidy] do not use else after return
Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-08-27 00:42:20 -07:00
Rosen Penev
a40e014eca
libevdev: sort includes alphabetically
Found with clang-tidy's llvm-include-order

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-08-27 00:29:54 -07:00
Rosen Penev
cd8bde522f libevdev: remove pointless return in void function
Found with clang-tidy's readability-redundant-control-flow

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-08-27 07:15:28 +00:00
Rosen Penev
fd6c9b8ca0 libevdev: fix inconsistent declarations
Found with clang-tidy's readability-inconsistent-declaration-parameter-name

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-08-27 07:15:28 +00:00
Niclas Zeising
1f54f82f70 Document FreeBSD quirks
Document FreeBSD quirks related to syspath.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
4194023122 tests: Add FreeBSD specific tests
Add two FreeBSD specific tests:
test_uinput_check_devnode_bsd checks that libevdev_uinput_get_devnode()
returns something sensible.  This is modelled on the Linux test
test_uinput_check_syspath_name, but uses devnode instead of syspath, since
reeBSD doesn't have sysfs.
test_uinput_check_syspath_bsd checks that libevdev_uinput_get_syspath()
always returns NULL.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
0af8c4054d tests: Disable attach debugger on FreeBSD
Disable attaching a debugger on FreeBSD, since FreeBSD lacks support for
PTRACE_ATTACH.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
8026722f86 tests: disable force feedback events on FreeBSD
FreeBSD does not support force feedack events.  Disable the test for
this event when running on FreeBSD.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
800946a673 tests: Use CLOCK_MONOTONIC_FAST on FreeBSD
FreeBSD does not have CLOCK_MONOTONIC_RAW, instead use
CLOCK_MONOTONIC_FAST.  This test checks that libevdev_set_clock_id()
fails when called with CLOCK_MONOTONIC_[RAW,FAST].

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
83e446225d uinput: Implement FreeBSD fetch_syspath_and_devnode()
Implement a FreeBSD version of fetch_syspath_and_devnode().
FreeBSD does not have sysfs, so instead fetch the device node directly
as as this matches with what is returned by the UI_GET_SYSNAME ioctl().
Since there is no sysfs, libevdev_uinput.syspath will always be set to NULL.

If the ioctl fail, return -1 from fetch_syspath_and_devnode(), since
there is no other way to figure out the device node path.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
153d8d0a5a uinput: Move SYS_INPUT_DIR to where it is used
Move the definition of SYS_INPUT_DIR to where it is used, instead of at
the top of the file, to make it easier to find.
Undefine it at the end of usage to avoid accidental uses.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
1bf2b41d3f tools: use basename(argv[0]) for program name
Use baename(argv[0]) to get the program name (for usage), instead of
using program_invocation_short_name, which only exists on Linux, not
FreeBSD.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
cca9093887 tools: Remove signalfd() use
Remove signalfd() use from the mouse-dpi-tool and touchpad-edge-detector
tools, in favor of using plain old signals.
FreeBSD does not have signalfd() without pulling in external libraries,
and with this change these tools can be compiled on FreeBSD.
Instead of providing two implementations, one using signalfd() and one
using signal(), just use the signal() implementation everywhere as it is
more portable.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
7ce82709aa Add FreeBSD compatible input.h and uinput.h
Add FreeBSD compatible input.h and uinput.h files.
This is done by moving the linux files to include/linux/linux, adding
the freebsd versions in include/linux/freebsd, and then changing
include/linux/[u]input.h to pull in the right one depending on which OS
we are compiling on.
Make sure that the build infrastructure in meson.build and
autoconf.ac/Makefile.am uses the correct files when building and as
dependency for targets, and ensure that make-event-names.py get the
correct files as arguments.

A similar change has been done in libinput in
61f3e3854458c556a01fb05d7abb22733fd2b7c1

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-14 17:50:56 +02:00
Niclas Zeising
db01b2d606 Don't hardcode /bin/bash
Don't hardcode /bin/bash, use /usr/bin/env bash instead, since not all
platforms install bash as /bin/bash.
FreeBSD, as an example, installs bash in /usr/local/bin/bash by default.

Signed-off-by: Niclas Zeising <zeising@daemonic.se>
2020-08-13 13:11:33 +02:00
Peter Hutterer
bcb79eed39 libevdev 1.9.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-07-16 13:39:45 +10:00
Peter Hutterer
66113fe84f libevdev: any value less than 0 has a NULL name
Fixes https://gitlab.freedesktop.org/libevdev/libevdev/-/issues/15

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-07-15 13:36:18 +10:00
Peter Hutterer
4c1b9f3c70 gitlab CI: move MR check to a later stage
This gives the developer enough time to file an MR after pushing a branch.
Having this run in the first stage means we get false positives because no MR
has been filed yet when the job is run.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-30 10:51:11 +10:00
Peter Hutterer
94a09a40bd gitlab CI: fix the repo name for excluding checks on master
Fixes 2698867311

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-16 16:16:11 +10:00
Peter Hutterer
2698867311 gitlab CI: use ci-fairy to check commits and merge requests
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-16 09:58:56 +10:00
Peter Hutterer
0ebdab6d6c include: sync event codes with kernel 5.7
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-04 12:56:08 +10:00
Peter Hutterer
4c87209826 gitlab CI: move the pip dependencies to before_script
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-04 10:48:04 +10:00
Peter Hutterer
55e70c5fd2 gitlab CI: alpine needs pip explicitly installed now
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-04 10:47:35 +10:00
Peter Hutterer
744a0e0f0b Add a CODING_STYLE document
Copied from libinput with a few minor changes.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-06-02 11:11:20 +10:00
George Thomas
1354b29b17 Add link to Haskell bindings
Signed-off-by: George Thomas <georgefsthomas@gmail.com>
2020-06-02 00:19:59 +01:00
Peter Hutterer
7660726177 Match if/else blocks for curly braces
Where either block has braces, the other half should too.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-05-26 14:10:31 +10:00
Peter Hutterer
2e41b6778b tools: specify width by height in the edge-detector help
Fixes #13

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-05-07 07:56:57 +10:00
Peter Hutterer
c6a765199a gitlab-ci: update to ubuntu 20.04
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-05-01 16:52:51 +10:00
Peter Hutterer
521edcba27 tools: rename the example device in the touchpad-edge-detector
In the hope that people don't blindly type event0 from now on.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-04-28 07:15:53 +10:00
Peter Hutterer
f9302c18b7 gitlab CI: update docs for how to schedule the auth variable
Safer to have this defined in the scheduled job only rather than the project
itself.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-18 12:46:14 +10:00
Peter Hutterer
325839e640 gitlab CI: move to use ci-fairy
ci-templates now has a new tool ci-fairy that replaces our jinja generation
script with something (eventually) unified across project repositories. Let's
move the files to the expected locations .gitlab-ci/config.yml and
.gitlab-ci/ci.template.

ci-fairy also has a wrapper to delete images, let's start using that.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-18 12:43:48 +10:00
Peter Hutterer
9ffed2f2f4 gitlab CI: use the new templates with a single job only
No more ifnot-exists, it's all build now with a variable to control the forced
rebuild.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-17 21:54:17 +10:00
Peter Hutterer
87a91718ef Don't overrun the changes array when synching > MAX_SLOTS
On a device with more than 256 slots we would read (and copy) past our changes
stack-allocated changes array. Fix this by capping to MAX_SLOTS though this
also requires us to memset the target where it is larger than MAX_SLOTS.

There are no real devices with 256+ slots, so this is a theoretical issue
only.

Fixes #11

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 14:07:25 +10:00
Peter Seiderer
103f3870f0 meson.build: use local include path for tests
Fixes:

  ../test/test-common.h: In function ‘print_event’:
  ../test/test-common.h:97:6: error: ‘const struct input_event’ has no member named ‘input_event_sec’
      ev->input_event_sec,
        ^
  ../test/test-common.h:98:6: error: ‘const struct input_event’ has no member named ‘input_event_usec’
      ev->input_event_usec,
        ^
  ../test/test-common.h:102:6: error: ‘const struct input_event’ has no member named ‘input_event_sec’
      ev->input_event_sec,
        ^
  ../test/test-common.h:103:6: error: ‘const struct input_event’ has no member named ‘input_event_usec’
      ev->input_event_usec,
        ^

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 04:01:20 +00:00
Peter Seiderer
fe8238a71a meson.build: use local include path for tools
Fixes the following compile failure with old toolchains and meson
build (autotools build not affected):

  ../tools/mouse-dpi-tool.c: In function ‘handle_event’:
  ../tools/mouse-dpi-tool.c:115:13: error: ‘const struct input_event’ has no member named ‘input_event_sec’
     m->us = ev->input_event_sec * 1000000 + ev->input_event_usec;
               ^
  ../tools/mouse-dpi-tool.c:115:45: error: ‘const struct input_event’ has no member named ‘input_event_usec’
     m->us = ev->input_event_sec * 1000000 + ev->input_event_usec;
                                               ^

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 04:01:20 +00:00
Peter Hutterer
a1fe50635e gitlab CI: rebuild images for the new templates
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 13:01:28 +10:00
Peter Hutterer
68cdac7420 gitlab CI: expand tag lists to 100 per page
Lets make sure we can delete more than 20 tags at a time.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 12:47:55 +10:00
Peter Hutterer
fc501b78ba gitlab CI: use the ifnot-exists templates from ci-templates
Let's not duplicate the functionality, use the upstream templates because
they'll actually see improvements over time.

Define two jobs, one that is the ifnot-exists job and one that is the normal
container-build job. The second one only runs on schedules.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 12:47:55 +10:00
Peter Hutterer
7d2b4b5ffe gitlab CI: remove obsolete variable expansion
gitlab doesn't support double-nested variables so we can assume that these
variables don't need further expansion

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 12:47:55 +10:00
Peter Hutterer
bd8225286a gitlab CI: Use the new fdo CI templates distribution images
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 12:46:54 +10:00
Peter Hutterer
1b1b446597 gitlab CI: make the container-clean dependent on container-prep
This is a test commit only to speed things up when testing the container-clean
phase. In the real instance, we don't want to remove our containers until the
test suite successfully completes on the new container.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-13 12:44:22 +10:00
Peter Seiderer
18ef5f76e0 gitlab CI: add static-build meson pipeline
Signed-off-by: Peter Seiderer <ps.report@gmx.net>
2020-03-11 07:46:59 +01:00
Peter Seiderer
a9d324f82b meson.build: enable static library build
Use meson library() instead of shared_library() to enable
static build.

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
2020-03-10 09:51:27 +01:00
Peter Hutterer
da5bfe22d2 gitlab ci: add a helper script for container deletion
Rather than raw curl requests to the API, use a python script using the gitlab
python package to access everything. This makes things a bit more readable.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-09 08:52:02 +10:00
Peter Hutterer
6441b639aa gitlab CI: update to the distribution-independent CI-templates
These templates get rid of the various distribution-specific naming and
instead default to the namespaced FDO_DISTRIBUTION_<foo> for whatever value we
need. So FEDORA_RPMS, DEBIAN_DEBS etc. becomes FDO_DISTRIBUTION_PACKAGES for
example.

By necessity this is one large commit. gitlab does not allow nested variable
expansion, so the previous approach of global variables didn't work.
Specifically, we'd end up with a template in this form:

variables:
  FEDORA_TAG: 12345

.base_template:
  variables:
     DISTRO_IMAGE: $DISTRO_TAG

.fedora:
  variables:
     $DISTRO_TAG: $FEDORA_TAG

But the actual DISTRO_IMAGE variable would be the literal string $FEDORA_TAG,
not the value of that variable. So all of it needed to be reworked.

Specifically:
- the packages to install moved to the config yaml file
- the distribution tag is now in the config yaml file
- all distributions now share the same tag (because lazyness)
- there are .fedora:30, .debian:stable, etc. templates now with the variables
  defined as needed, jobs will extends those templates as they need those
  distributions
- qemu-prep jobs are now generated too (based on the config yaml file)

Overall, it ends up cleaner despite the mess in this patch.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-09 08:51:59 +10:00
Peter Hutterer
bf72012921 gitlab CI: group the config by distribution type
No functional changes, this produces the same gitlab CI file

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-06 13:32:01 +10:00
Peter Hutterer
59a9c6c5fb gitlab CI: expire the results.xml artifacts
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-06 13:32:01 +10:00
Peter Hutterer
fcaa579bd0 README: note that patches go as MRs to gitlab now
Make the GitLab spelling consistent too and remove the git protocol link, it
looks awkward in the rendering and you can get all that from the gitlab repo
anyway

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-06 07:44:08 +10:00
Peter Hutterer
468760ba11 libevdev 1.9.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-02 14:11:43 +10:00
Peter Hutterer
edb5b92f89 gitlab CI: keep the results of the check-commit job as artifact
Due to how pytest is used, we don't get the actual errors printed in the
commandline log if this job fails. This doesn't matter in merge requests where
the results are displayed nicely but where there's no merge request we can't
get this info out at all. So let's simply store the xml file for an easy
check.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-03-02 14:11:43 +10:00
Peter Hutterer
13775b56e5 Use editorconfig instead of a sprinkling of :vim: instructions
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-27 05:58:05 +00:00
Peter Hutterer
cda3dc664a gitlab CI: drop the distribution "flavor" in favor of just the name
This is a leftover from ci-templates where the name of a distribution didn't
necessarily match the image (arch vs archlinux) and is no longer needed.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-26 13:13:19 +10:00
Peter Hutterer
c12af0864c gitlab CI: move the container-clean git strategy to the parent section
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-26 13:13:16 +10:00
Peter Hutterer
2a51c15683 gitlab CI: don't allow failures on the kvm jobs
This is a leftover from libinput where we have to allow failures because of
frequent issues with timing. We don't have these issues here so a failed job
in the VM indicates a bug.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-26 11:37:46 +10:00
Peter Hutterer
805421582f gitlab CI: update to the latest ci-templates again
Unclear what happend but I suspect a rebase went wrong so
e03cdd1d3f didn't actually update to the new
ci-templates.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-25 17:03:21 +10:00
Peter Hutterer
134b889724 gitlab CI: prefill the junit conversion script from the gitlab environment
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 15:33:00 +10:00
Peter Hutterer
82538647c1 gitlab CI: re-use the meson-build.sh script for normal meson jobs
Let's invoke the same meson steps for every build task.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 14:23:21 +10:00
Peter Hutterer
15e0b024df gitlab CI: hook up junit test reports to the meson results
The KVM tests use this for now, not the container builds where we run meson
directly.

The python script to convert meson test logs to junit results expects suite
names, so let's add all tests to suites so we don't need to carry local
modifications.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 11:52:14 +10:00
Peter Hutterer
e03cdd1d3f gitlab CI: update to latest ci-templates
This gives us a warning where qemu failed to start and it gets rid of the
different "flavor" that only archlinux had different to the distribution name.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 08:44:48 +10:00
Peter Hutterer
0e665a2780 gitlab CI: generate the template list from the config data
Only change in the actual gitlab CI file is that the sorting is now
alphabetical.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 08:44:48 +10:00
Peter Hutterer
db602d0d06 gitlab CI: set the vim filetype for the template file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-24 08:44:48 +10:00
Peter Hutterer
2038781bc2 libevdev 1.9rc1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-21 10:47:53 +10:00
Peter Hutterer
f26679c6eb gitlab CI: move the configuration bits into a YAML file
Only one change: the meson boolean to decide whether to build with meson is
now inside the build: block.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-21 09:23:02 +10:00
Peter Hutterer
12211d452a gitlab CI: extend the generation script to be somewhat more generic
Mostly busywork, it moves the hardcoded paths into a variables, etc.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-21 09:23:02 +10:00
Peter Hutterer
fa0a3fc445 gitlab CI: make the "this is generated" warning more obvious
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-21 09:23:02 +10:00
Peter Hutterer
45c223d394 gitlab CI: add a scan-build target
To avoid dnf updates and outdated packages (and the resulting delay from a dnf
update) we just install the clang-analyzer package into the default Fedora
image. It won't mess with the build expectations too much.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-20 17:17:24 +10:00
Peter Hutterer
5a9368f4da gitlab CI: fix a variable substitution
Single quotes means we're not expanding the variable here

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-20 17:06:14 +10:00
Peter Hutterer
283dfc07f9 gitlab CI: correct some meson builddirs
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-20 17:06:14 +10:00
Peter Hutterer
f7ef246635 meson.build: drop an unused variable
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-20 16:26:19 +10:00
Peter Hutterer
03f7b2be46 test: remove unreachable switch case
We only test up to 5 slots, so this cannot ever be reached.

Found by coverity

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:33:32 +10:00
Peter Hutterer
4b26eac8ad Fix (theoretical) use of uninitialized variable
This cannot ever be unset on any real device, but coverity is unhappy and
that's not making me happy.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:31:48 +10:00
Peter Hutterer
27aaba81d5 Don't try to send BTN_TOOL events for zero fingers
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:28:38 +10:00
Peter Hutterer
6ccee710bd Ignore slot sync for slots > 256
Clang doesn't support variable length arrays inside a struct so we could
either make our life complicated or just assume no-one is using more than 256
slots and hard-code that. Let's go for the easy solution until someone
notices.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:24:21 +10:00
Peter Hutterer
e9ecb5cabc test: add missing check for tripletap
We don't actually expect to get this one, hence the assert a few lines later.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:11:02 +10:00
Peter Hutterer
4c0eddfc74 test: fix a few scan-build errors about dead storage
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 13:06:18 +10:00
Peter Hutterer
d6c2b3d0de Update the BTN_TOOL bits correctly during SYN_DROPPED handling
Where at least one touch ends during SYN_DROPPED, we send out two event
frames: one with all applicable touch sequences ending (tracking id -1) and
the second one with the whole device state *and* the applicable touch
sequences starting (tracking id != -1).

This requires us to also update the BTN_TOOL_ bits correctly so that they are
correct after the first frame. For that we count the number of previously
known touches and send a 0 event for the matching BTN_TOOL_ bit, together with
a 1 event for the currently known touches.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 11:09:31 +10:00
Peter Hutterer
41de1b0e1a Terminate all stopped/changed touches during SYN_DROPPED in the first frame
The previous event processing had subtle issues with touches stopping during
SYN_DROPPED. All of the device state was processed in the same frame, but if
any touch changed tracking ID during SYN_DROPPED, an inserted SYN_REPORT
resulted in a weird split of events:
- the first frame had all key/sw/abs updates including those slots that
  changed tracking ID, but not the ones that were fully terminated.
- the second frame had only the slots states for newly started touches **and**
  the slot state for touches terminated during SYN_DROPPED but not restarted.

In other words, where three fingers were on the touchpad and slot 0 was lifted
and put down again and slot 1 was lifted but *not* put down again, our frames
contained:
- frame 1: terminate slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
- frame 2: start slot 0, terminate slot 1

Where there was no touch changing tracking ID, only one frame was generated.
The BTN_TOOL updates were buggy, they may not match the number of fingers down
as seen on a frame-by-frame basis. This triggered libinput bug
https://gitlab.freedesktop.org/libinput/libinput/issues/422

This patch changes the above example to
- frame 1: terminate slot 0, terminate slot 1
- frame 2: start slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1

Notably, the first frame no longer contains the BTN_TOOL bits. This patch is
one of two, the BTN_TOOL sync bits are part of a follow-up patch.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 11:06:28 +10:00
Peter Hutterer
2056da9517 Invert an if condition
Go from:
  if (a != b)
     continue;
  foo;

to:
  if (a == b) {
      foo;
  }

Basically just an indentation change after the condition inversion, makes the
follow-up patch easier to review.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 10:37:46 +10:00
Peter Hutterer
507bd1ee28 Push terminating the slots into a helper function
No functional changes.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 10:37:24 +10:00
Peter Hutterer
e38e3ae7c8 Split the MT state syncing and event generation into two functions
In the near future, we will need to handle slot termination *before* any other
state synchronization. So let's start splitting things up.

This is functionally equivalent though dropping the need_tracking_id_changes
variable means we run through all slots now to check if we need to terminate
one of them. Given the normal number of slots on a device and that this should
only ever run very rarely anyway... meh.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 10:35:59 +10:00
Peter Hutterer
b64f94f9c4 Expand the touch state handling during SYN_DROPPED
Keep a better state of each touch before/after the SYN_DROPPED. Most of this
is currently unused, it's functionally the same as before but the new code
serves to increase readability and it can be passed around easier this way.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 10:31:53 +10:00
Peter Hutterer
b2ec3cb7d4 Make the code for handling before/after SYN_DROPPED slot values more readable
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 09:05:22 +10:00
Peter Hutterer
ada38025a2 gitlab CI: hook up qemu
This is mostly copied from libinput's qemu setup with a few minor renames.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 08:49:02 +10:00
Peter Hutterer
f795694b2e gitlab CI: replace the hardcoded meson builddir with a variable
Bonus: we test for spaces in the directory name now too

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 08:34:55 +10:00
Peter Hutterer
d7098601c8 meson.build: hook up the static symbols leak test
And because bash on F31 is leaking, we need an extra valgrind suppression.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 08:34:55 +10:00
Peter Hutterer
d654a8edf8 test: change the static symbol leak test to a shell script
Easier to call from meson this way

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-19 08:34:55 +10:00
Peter Hutterer
cd9fd458a5 test: always ship with the helper files
The tarball shouldn't be dependent on whatever options were passed to
configure.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-18 19:39:40 +10:00
Peter Hutterer
ae0effd5ee meson.build: fix some whitespace, put reminder comment in
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-18 19:21:35 +10:00
Peter Hutterer
88701829e7 gitlab CI: add a job to make sure the soname is correct for both build systems
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-18 19:11:40 +10:00
Peter Hutterer
e67826060b gitlab CI: rename the custom build jobs
We don't really care that they're F31, that's an implementation detail. So
let's rename them so we can easily pick which job is which on the pipeline
overview.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-18 19:01:50 +10:00
Peter Hutterer
9fe2dfc8ef gitlab CI: run the test suite through valgrind
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 19:46:23 +10:00
Peter Hutterer
596ebd7acc gitlab CI: add targets to build from each others tarballs
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
2f9c40b5fb gitlab CI: add more targets for custom meson builds
Notable: the meson builds don't have a "nm is missing" target because meson
needs it for itself.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
f2d4ef6cc4 gitlab CI: rename few targets for autotools
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
12f9ec84d9 meson/configure: put a comment in that we don't want to bump the soname
We use symbol versioning anyway, so we don't need to bump the soname every
time.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
caf63dca41 gitlab CI: hook up the meson build
Centos doesn't run meson because it's too hard to install the package with dnf
and I can't be bothered going through pip.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
6c88d8c1cf Add support for the meson build system
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
223909ed0b tools: fix the include path for local includes
Make sure we use the local include files, and correct the path accordingly.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 17:42:32 +10:00
Peter Hutterer
d209b66930 gitlab CI: rename the default build jobs to autotools
Prep the path for adding meson

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 14:49:25 +10:00
Peter Hutterer
67b6e447e7 Auto-generate the gitlab CI script
There is so much duplication between the various jobs that it's hard to keep
track of it manually. Let's employ a python script to generate those bits,
reducing the actual gitlab-ci.yml to the hand-written parts only.

The new script takes the .gitlab-ci/gitlab-ci.yml.in and simply appends the
generated parts to it. Most of it is straightforward, only centos needs some
custom parts because of missing doxygen.

The diff is a bit hard to review, thanks to the python script we now group
based on distribution, not based on name (i.e. all fedoras in one group
instead of all container-preps in one group).
And since we're generating anyway, some of the in-between stages were removed
(e.g. $DISTRO-build@template).

A new CI job is added to run a diff against the .gitlab-ci.yml that's checked
in and the one generated by this script. If they differ, we fail.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 14:23:18 +10:00
Peter Hutterer
3e0a9e084d gitlab CI: move a few sections around
Move the centos builds to after the ubuntu builds and swap the two fedora
builds. Just we have the same order for things here as in the container
prep/clean phases and to make a future patch easier to review.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 11:15:10 +10:00
Peter Hutterer
0dbcfed117 gitlab CI: visually align the container images
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-17 10:50:30 +10:00
Peter Hutterer
388644b22b Compress an if statement
No functional changes, just making the code slightly more compressed

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:44 +00:00
Peter Hutterer
50ebda0263 Localize two variables
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:44 +00:00
Peter Hutterer
6430694715 Uncomplicate the setting of axis during slot sync
A few bytes get wasted, but no magic handling of offsets etc are required.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:44 +00:00
Peter Hutterer
c04f5bcec0 Push the tracking id change bits on the stack
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:44 +00:00
Peter Hutterer
5501973320 Push the slot_update bits on the stack
Much simpler code this way

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:44 +00:00
Peter Hutterer
757f2d4900 Drop the mt_sync_state in our device struct
Replace it with a stack-allocated one. This saves us a bunch of confusing
allocations and size calculations.

And in the process use uint32_t/int32_t to ensure the struct is actually the
expected size.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-16 22:02:43 +00:00
Peter Hutterer
487d80a7fe gitlab CI: align the image tags a bit nicer
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 15:55:35 +10:00
Peter Hutterer
c001fe50b0 gitlab CI: rename the default_build to autotools_build
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:50:16 +10:00
Peter Hutterer
977891bd88 flake8 fixes for make-event-names.py
Mostly whitespace changes, two semicolon removals and one change to "foo is
None".

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:50:16 +10:00
Peter Hutterer
4d4873d101 Change the python script to generate event names to Python3
It's well past time. If you need this to run on python2, patch it out locally.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:50:16 +10:00
Peter Hutterer
21ca8dba06 test: silence warnings about missing field initializers
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
8666e6958d test: fix two signed vs unsigned warnings
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
939076efc9 uinput: drop an unused function argument
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
3d03038d78 tools: drop explicit GNU_SOURCE define
It's defined globally through AC_USE_SYSTEM_EXTENSIONS

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
4c8a7a265d config.h is a local include path
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
0a66de813e tools: drop use of HAVE_CONFIG_H
There's no case where we don't have a config.h

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 12:03:23 +10:00
Peter Hutterer
201dfc38f9 gitlab CI: separate builddir from srcdir
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 11:49:37 +10:00
Peter Hutterer
ee2d35a90a gitlab CI: use extends over yaml anchors
This also gets rid of some superfluous inclusions - all those are inherited
now anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 09:03:11 +10:00
Peter Hutterer
6292354b44 gitlab CI: remove a reference to libinput
That's what you get for copy/paste...

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 08:38:32 +10:00
Peter Hutterer
90ff5a0cae gitlab CI: add a check-commit stage
Taken from libinput, checks for signed-off-by and other things.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-14 08:30:29 +10:00
Peter Hutterer
9fec3228fb configure.ac: add a toggle to enable the special coverity options
Coverity tries to supply system headers and fails badly at it. A bunch of
_Float... sizes are pulled in by math.h but not provided anywhere. So as a
workaround, let's add an option to explicitly enable coverity support that
simply #defines those types to ones we do know about and let's go on hoping
it'll eventually work.

See the equivalent addition to libinput in commit 8178339b5baa717.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-12 22:12:03 +00:00
Peter Hutterer
25cddcecd3 Add queue_push_event as shortcut for the two-liner we use everywhere
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-12 21:41:15 +10:00
Peter Hutterer
0af21e0e74 Simplify some error handling by assuming a >=3.4 kernel
v3.4 was released in 2012, every kernel since has that ioctl. So instead of
assuming you're running new libevdev on an 8 year old kernel, let's assume
that any error from the ioctl() is an actual error and handle it accordingly.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 21:07:06 +10:00
Peter Hutterer
4fc12638d2 test: slightly modernize some of the tests
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 20:57:42 +10:00
Peter Hutterer
58559d9fec test: provide a function to print an event
Easy to copy/paste into a test that needs a bit of debugging, otherwise unused.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 20:57:42 +10:00
Peter Hutterer
1014acedfc test: split the tests into one test case each
For debugging it's more important to be able to quickly run a single test
rather than grouping them together, we don't have thousands of tests here
anyway. So let's add a macro to put every test func into its own TCase,
allowing for test selection via the environment variable CK_RUN_CASE.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 20:57:42 +10:00
Peter Hutterer
2af0b94623 test: wrap the event checks into a macro
One-liner to check an event rather than three separate statements in every
test.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 20:57:42 +10:00
Peter Hutterer
28dbb3399a doc: add markdown for monospace rendering of defines
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-11 20:46:14 +10:00
Michael Forney
1f1bd4e2ce Only use GCC pragma on GCC
Signed-off-by: Michael Forney <mforney@mforney.org>
2020-02-05 20:31:30 -08:00
Michael Forney
2f300eb6b5 Avoid initializer index range
This is a GNU C extension, and is not available in ISO C.

Instead, just explicitly initialize other indices to -1.

Signed-off-by: Michael Forney <mforney@mforney.org>
2020-02-05 20:31:30 -08:00
Michael Forney
06ef34c86b Add fallback min/max for compilers that don't have statement expressions
Statement expressions are a GNU C extension and are not available
in ISO C.

On compilers that don't have them, define these macros as plain
conditional expressions, since they are only ever used with expressions
that have no side-effects.

The statement-expression version is still retained as an added
safety measure on GNU-compatible compilers.

Signed-off-by: Michael Forney <mforney@mforney.org>
2020-02-05 20:30:39 -08:00
Peter Hutterer
e74ba891f7 test: add mangle_path to the excluded symbols leak list
Don't 100% know where it comes from but it's not ours, so...

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-06 10:36:17 +10:00
Peter Hutterer
6668e0fe21 gitlab CI: some more centos deduplication
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-06 10:25:05 +10:00
Peter Hutterer
5b97b970c0 gitlab CI: don't run distcheck on centos 7 anymore
With b65be7aa79 the centos 7 RPMs don't include doxygen anymore, so let's drop
the distcheck job. Centos 7 is old enough at this point that we don't need to
care too much.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-06 10:22:48 +10:00
Peter Hutterer
5b3659d468 gitlab CI: force a rebuild of all the docker containers
To make sure the current pipeline is correct

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-03 20:40:40 +10:00
Peter Hutterer
ff8a5b065c gitlab CI: switch the custom builds to Fedora 31
With b65be7aa79 the centos 7 RPMs don't include doxygen anymore, causing a CI
pipeline failure (but only where the centos image is being rebuilt).

Fedora is a better early-warning system about possible breakages than Centos -
which was originally chosen precisely because it doesn't update much and was
faster to run in the CI (this was before custom docker images).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-03 20:40:40 +10:00
Peter Hutterer
925b2aa26d test: replace the SW_LID tests with SW_HEADPHONE_INSERT
We're only testing EV_SW event delivery here and SW_LID has the tendency to
suspend the host when we don't specifically inhibit it. So let's just swap for
the next one.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-11-18 13:45:18 +10:00
Peter Hutterer
b65be7aa79 CI: add a Centos 8 container build
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-11-15 14:47:50 +10:00
Peter Hutterer
864f0c6829 CI: deduplicate distcheck by making it a variable
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-11-15 14:47:50 +10:00
Peter Hutterer
74d4a3d11d CI: move the configure flags into a variable
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-11-15 14:40:56 +10:00
Peter Hutterer
6c4981393e CI: extend the CI to work with containers
Mostly copy/paste from libinput but we do build on debian and centos as well.
The special builds are basically the same as before.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-10-25 00:17:46 +00:00
Peter Hutterer
9a5f44a605 make-event-names.py should take the files as argument
Don't rely on cat, just let our script read everything as required.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-10-23 03:13:50 +00:00
Alexander Dahl
2c6733fc67 doc: Fix function names in simple code example
That code did not compile because those functions were only renamed in
header and code back then, but not in the example.

Fixes: ab2f20bfd6 ("Revamp the API once again")
Signed-off-by: Alexander Dahl <ada@thorsis.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-09-13 15:30:57 +10:00
Peter Hutterer
779749b22c libevdev 1.8.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-08-26 14:35:54 +10:00
Peter Hutterer
fce16d51a8 include: sync event codes with kernel 5.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-08-26 14:33:19 +10:00
Nayan Deshmukh
a2bb53262f doc: add a note regarding truncation of id_* fields
The id_* fields are 16 bits in linux/input.h and we mirror
the kernel API here. Even though we accept an int for this
fields in ABI the value is truncated at 16 bits.

Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-08-05 08:26:15 +10:00
Peter Hutterer
da67db5f59 Initialize the slots correctly when enabling ABS_MT_SLOT
Previously, enabling or disabling ABS_MT_SLOT would not change the actual
slots, it was treated as a normal bitflag. This means we couldn't initialize a
libevdev context from scratch and have it behave like a correct MT context.

Fixes #4

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-18 09:31:41 +10:00
Peter Hutterer
4d745caab4 doc: fix a typo
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-12 08:55:42 +10:00
Peter Hutterer
1300c23792 libevdev 1.7.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-05 11:36:08 +10:00
Peter Hutterer
71bf23cdc4 doc: fix distcheck
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-05 11:15:15 +10:00
Peter Hutterer
49206a2aba doc: minor documentation updates
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-05 10:56:45 +10:00
Peter Hutterer
deb52eb52f doc: add libinput's doxygen styles
Minor modifications to the style, but at least this is readable now.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-05 10:56:45 +10:00
Peter Hutterer
d834a1f2b7 doc: drop the custom stylesheet
Revert back to the normal doxygen looks, even though they're pretty awful. But
at least they're consistent, the custom stylesheets had all sorts of weird
corner cases that didnt' render correctly and I don't have enough CSS
knowledge to fix this correctly.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-03 17:48:28 +10:00
Peter Hutterer
7ea9b09433 doc: a change of the CSS needs to trigger a doxygen rebuild
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-03 17:48:28 +10:00
Peter Hutterer
a68e91b172 doc: change @retval documentation to help doxygen with rendering
This causes some weird rendering, let's split it into a list (which also
happens to be more readable).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-03 17:48:28 +10:00
Peter Hutterer
c8be2b3260 doc: fix some doxygen layout
The linewrapped 1 caused doxygen to start a list

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-03 17:48:11 +10:00
Peter Hutterer
cf645672dc doc: fix some doxygen warnings
warning: explicit link request to 'defines' could not be resolved

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-06-03 17:47:41 +10:00
Peter Hutterer
ae7b6128a8 libevdev 1.7rc1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-05-24 10:55:02 +10:00
Peter Hutterer
55d7375972 include: sync event codes with kernel 5.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-05-07 10:30:40 +10:00
Peter Hutterer
9fe185dd3d Add a code-based name lookup function
Two new function pairs:
	libevdev_event_code_from_code_name()
	libevdev_event_type_from_code_name()

	libevdev_event_code_from_code_name_n()
	libevdev_event_type_from_code_name_n()

These functions look up event codes/types by the name of the event code only,
removing the need to figure out what event type an event code has. So if all
you have is "BTN_TOUCH", you can now look up the type and code for that,
without having to check the prefix yourself to guess at the type.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-03-21 00:55:32 +00:00
Peter Hutterer
76662deeff Don't read events unless required
With the previous approach, every libevdev_next_event() invocation triggered a
read() on the device fd. This is not efficient, the kernel provides whole
event frames at a time so we're guaranteed to have more events waiting unless
the current event is a SYN_REPORT.

Assuming a fast-enough client and e.g. a touchpad device with multiple axes
per frame, we'd thus trigger several unnecessary read() calls per event frame.

Drop this behavior, instead only trigger the read when our internal queue is
empty and we need more events.

Fallout:
- we don't have any warning about a too-slow sync, i.e. if a SYN_DROPPED
  arrives while we're syncing, we don't get a warning in the log anymore.
  the test for this was removed.
- the tests that required the specific behavior were rewritten accordingly
- a revoke on a kernel device doesn't return ENODEV until already-received
  events have been processed

The above shouldn't be an issue for existing real-world clients.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-03-19 01:02:52 +00:00
Peter Hutterer
951cd6a189 include: sync event codes with kernel 5.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-03-06 10:56:55 +10:00
Peter Hutterer
6852dadbca Replace ABS_MT_SLOT - 1 with the v4.20 ABS_RESERVED define
ABS_RESERVED was added to 4.20 for that reason, to keep that event code
reserved so we can't use it for anything else (and thus mess up the fake MT
detection).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2019-01-16 13:17:33 +10:00
Peter Hutterer
29628dc2c3 include: sync event codes with kernel 4.20 2019-01-16 13:15:05 +10:00
Peter Hutterer
f293c11fec libevdev 1.6.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-10-26 09:50:23 +10:00
Peter Hutterer
41e47b7043 include: sync event codes with kernel 4.19
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-10-22 18:55:57 +10:00
Peter Hutterer
1e605f6282 Add libevdev_event_value_get_name() to resolve ABS_MT_TOOL_TYPE values
ABS_MT_TOOL_TYPE values are an enum, not a numerical value like all other
axes. So let's allow converting those values to string.

Fixes https://gitlab.freedesktop.org/libevdev/libevdev/issues/1

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-07-09 11:57:57 +10:00
Peter Hutterer
d9cfd143d0 Resolve the names "SW_MAX" and friends
Some of the *_MAX names are duplicates and have a real define. These were not
resolved until now.

Fixes https://gitlab.freedesktop.org/libevdev/libevdev/issues/3

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-07-09 11:57:57 +10:00
Peter Hutterer
812fc7096d make-event-names: minor cleanups for readability
Two variable renames for less ambiguity
Two changes from an long if condition to a "if foo in [...]"

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-07-09 11:57:57 +10:00
Peter Hutterer
35d6ce09d8 test: add a test timeout multiplier for valgrind
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-09 11:57:57 +10:00
Peter Hutterer
6a1f2e2ed2 GitLab CI: actually reference the default artifacts
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-09 11:14:14 +10:00
Peter Hutterer
a2ac0f0889 GitLab CI: build with the various options
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-29 12:07:14 +10:00
Peter Hutterer
ad5142a1b3 Add GitLab CI
A simple version of it, we just pull down a few popular distros, build on them
and make sure distcheck passes.

https://gitlab.freedesktop.org/libevdev/libevdev/issues/2

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-29 12:07:10 +10:00
Peter Hutterer
c16d85b8b6 configure.ac: remove --disable-test-run
This flag was used to disable test runs during make distcheck. Now that we
have more checks and the environment variable, we can drop this flag.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-29 11:50:38 +10:00
Peter Hutterer
6345c1cca2 configure.ac: fix the gcov linker flags
Presumably this worked, but it certainly doesn't work anymore (neither on
RHEL7 nor on Fedora 28)

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-29 11:50:37 +10:00
Peter Hutterer
e4c3a8ee7a test: add LIBEVDEV_SKIP_ROOT_TESTS environment variable check
Depending on the container, or other checks don't always work. Add an extra
environment variable instead.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-29 11:15:41 +10:00
Peter Hutterer
c4cfd7668a test: move the kernel test to the same infrastructure
We previously had this separate because it tested separate things. Now the
setup is generic enough that we should just re-use it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 15:19:05 +10:00
Peter Hutterer
1f9e087dac test: check for the device nodes to exist before testing
Even if we're root we may be running in a container without input device
nodes. In which case we should skip the test, not fail.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 15:19:05 +10:00
Peter Hutterer
805706a816 test: split some non-root tests into separate binaries
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 15:01:59 +10:00
Peter Hutterer
b642eddc31 test: sort-of autodetect whether we need root privileges
It's not really autodetection, we just declare the test suites that need root
privs. But this way we can generically check for it from the main() that we
re-use across tests.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 15:01:19 +10:00
Peter Hutterer
83ce8eb5be test: automate test suite handling
Move all tests to a special section, then loop through that section
to fetch all test suite. The result is that new tests only need to add the
source files without having to update everything else as well.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 15:00:24 +10:00
Peter Hutterer
bc5c72571d test: rename some tests for less ambiguity
"key" usually refers to one of KEY_ of EV_KEY in general, but here we're
testing event codes.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-15 14:16:29 +10:00
Peter Hutterer
c3953e1bb8 Change all URLs to gitlab.fdo
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-06-06 18:20:11 +10:00
Deepa Dinamani
3c6766c862 Update struct input_event
The struct input_event is not y2038 safe.
Update the struct according to the kernel patch:
https://lkml.org/lkml/2018/1/6/324

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-04-12 15:23:22 +10:00
Peter Hutterer
501f739564 include: sync event codes with kernel 4.16
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-04-04 10:54:43 +10:00
Peter Hutterer
7ae667ee89 libevdev 1.5.9
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-08 15:25:28 +10:00
Peter Hutterer
fbeeef9cde test: skip tests when we're not root
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-02-26 17:12:08 +10:00
Peter Hutterer
6ff816163e Blacklist SW_MAX so it doesn't shadow SW_PEN_INSERTED
They have the same value, so the _MAX code would shadow the real code, causing
issues in any client that needs to get all event names from libevdev.
Specifically, the loop of:
  for each code in 0 to max-for-type:
      print(name)
would not show up the code (but the _MAX) code instead. This causes issues
with clients that rely on name resolution that works. And the _MAX values are
special values anyway.

Blacklist it in the script here, causing it to resolve from name to code, but
not from code to name (like other duplicated codes).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-02-26 17:12:08 +10:00
Peter Hutterer
a67d1964ff Blacklist REP_MAX so it doesn't shadow REP_PERIOD
They have the same value, so the _MAX code would shadow the real code, causing
issues in any client that needs to get all event names from libevdev.
Specifically, the loop of:
  for each code in 0 to max-for-type:
      print(name)
would not show up the code (but the _MAX) code instead. This causes issues
with clients that rely on name resolution that works. And the _MAX values are
special values anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-02-26 17:12:08 +10:00
Peter Hutterer
3799acd49e Drop the python map printing
leftover from when this was part of evemu

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-02-26 16:53:55 +10:00
Peter Hutterer
0f40ad8888 libevdev 1.5.8
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-01-29 14:17:50 +10:00
Peter Hutterer
8df02686d3 Sync with kernel 4.15 (BTN_STYLUS3)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-01-29 14:13:58 +10:00
Peter Hutterer
e84897f29a test: add --no-install flag to be able to debug directly
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-12-13 10:01:58 +10:00
Peter Hutterer
0637d0237a When changing the fd, reset our grab state to ungrabbed
Previously, calling grabbing a device after changing the fd was a no-op
because libevdev's grab state didn't match the fd:

libevdev_grab(LIBEVDEV_GRAB);
  .. fd is grabbed
  .. internal state is 'grabbed'
libevdev_change_fd();
  .. new fd is ungrabbed
  .. internal state is 'grabbed'
libevdev_grab(LIBEVDEV_GRAB);
  .. argument matches internal state and we exit without grabbing the device

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-12-13 10:01:58 +10:00
Peter Hutterer
022b2bc3b0 include: sync with kernel 4.13
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-09-04 12:44:14 +10:00
Peter Hutterer
eefaca6f9f tools: add a script to sync the kernel header files
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-03 10:13:40 +10:00
Peter Hutterer
7ae59b1e9f include: sync with kernel v4.12
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-03 10:13:40 +10:00
Peter Hutterer
c6e11a0a80 uinput: make a note that the syspath we return is the input node
And not the syspath for the /dev/input/eventX node

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-03 09:55:29 +10:00
Peter Hutterer
b08a3c70e5 test: remove test for ULONG_MAX queue allocation
Fixes the warning:
../libevdev/libevdev-int.h:231:15: warning: argument 1 value
‘18446744073709551615’ exceeds maximum object size 9223372036854775807
[-Walloc-size-larger-than=]

That's now part of gcc's -Wall, so let's rely on that for code. Arguably, the
queue code is simple enough that we don't need a test for ENOMEM anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-05-09 13:43:05 +10:00
Peter Hutterer
7295576980 test: drop unused parameters from test's main()
Not needed, so let's get rid of the compiler warning.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-05-09 13:42:56 +10:00
Peter Hutterer
a9b3deb60f test: disable coredumps during test suite runs
It's a test suite, it shouldn't fill up the file system or the journal with
coredumps.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-05-09 08:12:43 +10:00
Peter Hutterer
78322a9b45 libevdev 1.5.7
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-05-04 10:35:01 +10:00
Peter Hutterer
abfb307e18 Fix an indentation issues
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-25 09:27:16 +10:00
Peter Hutterer
0b482b5f11 doc: add links to git repositories on the main page
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-03-24 14:42:00 +10:00
Mihail Konev
e7955544fe autogen: add default patch prefix
Signed-off-by: Mihail Konev <k.mvc@ya.ru>
2017-01-26 14:25:02 +10:00
Peter Hutterer
b13d67af9b autogen.sh: use exec for configure
No point in waiting around until it finishes

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-01-26 14:23:18 +10:00
Peter Hutterer
a072277ba9 autogen.sh: escape $srcdir before configure
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-01-26 14:22:34 +10:00
Peter Hutterer
1ec01b1310 tools: print an error if we don't have any matching events in the dpi tool
Beats crashing by dereferencing a null-pointer (when we access
m->frequencies[idx])

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-01-17 14:50:29 +10:00
Peter Hutterer
a155a977b7 tools: move udev printf into the print_summary() helper
No functional changes

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-01-17 14:42:13 +10:00
Peter Hutterer
24dafff909 configure.ac: enable subdir-objects
The main thing holding us back here was our gcov hacks. We used to rebuild the
libevdev sources locally inside test/ with the gcov flags so that we could
leave the main libevdev sources untouched. This doesn't work well with
subdir-objects - we have to link to libevdev.la instead.

To enable gcov, we now have to apply the gcov flags to the main library
object. But this also means that when running, the notes files will be
somewhere within the libevdev/ directory, not the test/ directory. Working
around this in automake gets nasty quickly, so just add a script that knows
how to search for things.

No functional changes unless --enable-gcov is given at configure time - then
don't install the library.

The gcov reports are now in test/gcov-reports/

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-01-09 09:40:28 +10:00
Peter Hutterer
1ee17e18ac test: fix a Makefile.am comment
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-01-06 11:28:58 +10:00
Peter Hutterer
d447a75e9e libevdev 1.5.6
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-01-04 13:04:58 +10:00
Nayan Deshmukh
f7188aabc9 Fix typos in Documentation
Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-01-03 07:43:41 +10:00
Peter Hutterer
8a47a03044 include: update to v4.9 linux/input.h headers
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-12-12 10:07:07 +10:00
Peter Hutterer
452847a314 libevdev 1.5.5
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-12-01 07:55:25 +10:00
Peter Hutterer
b261868b0a Disable test runs on make distcheck
The tests all need root, but running distcheck as root is not ideal. Disable
the test runs (but not the build) to make it easier to verify distcheck works
as intended.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-11-30 20:34:46 +10:00
Nathan Baker
e938e0b959 Fix minor error in doxygen example code
The incorrect variable was checked as a return code in an example, and
that can be confusing for people trying to learn or use the example code
as a starting point.
2016-11-14 07:10:02 +10:00
Peter Hutterer
61f0a0f9ad tools: print the mean frequency together with the max frequency
And if they're 30% out, print a warning. On the ThinkPad X1 Wireless Touch
Mouse (when connected via bluetooth) we get a bunch of events at the start of
the movement, all less than 1ms apart. Best guess is that the device goes to
low-power, then notices the movement and buffers the event until the BT
connection is back up. Then it sends all events at once. Usually they're less
than 1ms apart, but at one recording showed a 37ms delay before we go back to
the normal 70ms (~15Hz) the mouse has otherwise.

This is unpredictable enough that we can't just work around it so instead
print a warning to the user so they can go investigate.

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

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-09-21 16:57:29 +10:00
Peter Hutterer
55c43b19cf tools: rename frequency to max_frequency in the dpi tool
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-09-19 10:55:51 +10:00
Peter Hutterer
94385480ff tools: use uint64_t, not doubles for the µs parameters
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-09-16 07:26:42 +10:00
Peter Hutterer
2a612997ab tools: fix kernel-announced width/height
Side-effect of 240ba34ebd was that "touchpad size as listed by the kernel"
was now dependent on the values we got. This one is a static one based on the
axis info.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-09-15 11:57:52 +10:00
Peter Hutterer
d05736765c doc: drop the HTML_TIMESTAMP
Allows for reproducible builds. Debian carries a patch for this, and the
timestamp doesn't really add much since the doc is either in sync with master
or represents the release tag. Might as well drop it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-08-29 08:00:49 +10:00
Peter Hutterer
0f346f3090 libevdev 1.5.4
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-08-26 12:01:34 +10:00
Peter Hutterer
240ba34ebd tools: fix the touchpad resolution calculation
Previous ones used the absinfo from the kernel but since we never updated that
from within the tool, the output was always the same.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-08-26 11:43:54 +10:00
Peter Hutterer
0a5f884c58 libevdev 1.5.3
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-08-22 07:36:13 +10:00
Peter Hutterer
df5ca55609 Don't bother sanitizing disabled event codes
Filter them immediately instead of passing them on and relying on the actual
event handling code to filter them.

Reproducer: if EV_ABS is disabled on an Apple MagicMouse we still get events
passed into sanitize_event(). But the code handling EV_ABS events doesn't
update the state, so we end up complaining about double tracking IDs, even
though that is not actually correct.

https://bugzilla.redhat.com/show_bug.cgi?id=1361325

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-08-17 17:43:32 +10:00
Peter Hutterer
761687e995 tools: require a minimum size for touchpads
This mostly aims to catch users trying to specify the size in inches.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-08-01 07:47:46 +10:00
Peter Hutterer
911106230a tools: change touchpad-edge-detector to require physical size
Almost no-one does the calculations for me to update the udev rules (and some
rules were submitted with the <x resolution> placeholders left in).
Require the user to specify the physical size so we just copy/paste the actual
udev rule.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-08-01 06:48:04 +10:00
Peter Hutterer
4dd93f0108 libevdev 1.5.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-06-15 16:11:41 +10:00
Peter Hutterer
7f2fffc0d9 include: update to v4.6 linux/input.h header
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-05-16 09:51:55 +10:00
Peter Hutterer
98fd794693 libevdev 1.5.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-05-16 09:01:35 +10:00
Armin K
e628bb938b libevdev: Properly distribute uinput.h
Signed-off-by: Armin K <krejzi@email.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-05-16 08:12:05 +10:00
76 changed files with 16744 additions and 3144 deletions

21
.editorconfig Normal file
View file

@ -0,0 +1,21 @@
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{c,h}]
indent_style = tab
tab_width = 8
[*.py]
indent_style = space
indent_size = 4
charset = utf-8
[*.{yaml,tmpl}]
indent_style = space
indent_size = 2
charset = utf-8

2
.gitignore vendored
View file

@ -31,8 +31,6 @@ mkinstalldirs
stamp-h?
# Edit Compile Debug Document Distribute
*~
*.[0-9]
*.[0-9]x
*.bak
*.bin
core

692
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,692 @@
########################################
# #
# THIS FILE IS GENERATED, DO NOT EDIT #
# #
########################################
.templates_sha: &template_sha e195d80f35b45cc73668be3767b923fd76c70ed5 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
- project: 'freedesktop/ci-templates'
ref: *template_sha
file:
- '/templates/alpine.yml'
- '/templates/arch.yml'
- '/templates/debian.yml'
- '/templates/fedora.yml'
- '/templates/ubuntu.yml'
- '/templates/ci-fairy.yml'
stages:
- prep # rebuild the container images if there is a change
- build # for actually building and testing things in a container
- VM # for running the test suite in a VM
- autotools # distribution builds with autotools
- meson # distribution builds with meson
- tarballs # tarball builds
- container_clean # clean up unused container images
- merge-check # check for a merge request
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
variables:
# The upstrem repository we will check for images
FDO_UPSTREAM_REPO: libevdev/libevdev
GIT_DEPTH: 1
MESON_BUILDDIR: 'build dir'
.default_artifacts:
artifacts:
paths:
- _build/test/test-suite.log
- $MESON_BUILDDIR/meson-logs/
expire_in: 1 week
when: always
reports:
junit: $MESON_BUILDDIR/*junit*.xml
.autotools_build:
extends:
- .default_artifacts
script:
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules $CONFIGURE_FLAGS
- make
- make check
- if ! [[ -z "$MAKE_ARGS" ]]; then make $MAKE_ARGS; fi
- popd > /dev/null
variables:
LIBEVDEV_SKIP_ROOT_TESTS: 1
.meson_build:
extends:
- .default_artifacts
script:
- .gitlab-ci/meson-build.sh --run-test
variables:
MESON_TEST_ARGS: '--no-suite=needs-uinput'
.fedora:40:
extends: .fdo.distribution-image@fedora
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: '40'
.fedora:41:
extends: .fdo.distribution-image@fedora
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: '41'
.ubuntu:24.10:
extends: .fdo.distribution-image@ubuntu
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: '24.10'
.debian:stable:
extends: .fdo.distribution-image@debian
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: 'stable'
.debian:sid:
extends: .fdo.distribution-image@debian
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: 'sid'
.arch:rolling:
extends: .fdo.distribution-image@arch
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: 'rolling'
.alpine:latest:
extends: .fdo.distribution-image@alpine
variables:
FDO_DISTRIBUTION_TAG: '2024-11-25.0'
FDO_DISTRIBUTION_VERSION: 'latest'
#################################################################
# #
# prep stage #
# #
#################################################################
# Re-generate the CI script and make sure it's the one currently checked in
# If this job fails, re-generate the gitlab-ci.yml script, see
# $SRCDIR/.gitlab-ci/generate-gitlab-ci.py
#
check-ci-script:
extends:
- .fdo.ci-fairy
stage: prep
script:
- ci-fairy generate-template --verify && exit 0 || true
- echo "Committed gitlab-ci.yml differs from generated gitlab-ci.yml. Please verify"
- exit 1
#
# Verify that commit messages are as expected, signed-off, etc.
#
check-commit:
extends:
- .fdo.ci-fairy
stage: prep
script:
- ci-fairy -vv check-commits --junit-xml=results.xml && exit 0 || true
- echo "Error checking the commit message format. Please verify"
- exit 1
except:
- master@libevdev/libevdev
variables:
GIT_DEPTH: 100
artifacts:
reports:
junit: results.xml
#
# Verify that the merge request has the allow-collaboration checkbox ticked
#
check-merge-request:
extends:
- .fdo.ci-fairy
stage: merge-check
script:
- ci-fairy check-merge-request --require-allow-collaboration --junit-xml=results.xml
artifacts:
when: on_failure
reports:
junit: results.xml
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
.fedora.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: 'git gcc gcc-c++ meson automake autoconf libtool make pkgconfig python3 check-devel valgrind binutils doxygen xz clang-analyzer systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich'
.ubuntu.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: 'git gcc g++ meson automake autoconf libtool make pkg-config python3 check valgrind binutils doxygen xz-utils'
.debian.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: 'git gcc g++ meson automake autoconf libtool make pkg-config python3 check valgrind binutils doxygen xz-utils'
.arch.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: 'git gc meson automake autoconf libtool make pkgconfig python3 check valgrind binutils doxygen'
.alpine.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: 'git gcc g++ meson automake autoconf libtool make pkgconfig python3 check-dev valgrind binutils doxygen xz linux-headers'
# Pulls in the container from upstream or rebuilds it if missing
fedora:40@container-prep:
extends:
- .fedora:40
- .fedora.packages
- .fdo.container-build@fedora
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
fedora:41@container-prep:
extends:
- .fedora:41
- .fedora.packages
- .fdo.container-build@fedora
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
ubuntu:24.10@container-prep:
extends:
- .ubuntu:24.10
- .ubuntu.packages
- .fdo.container-build@ubuntu
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
debian:stable@container-prep:
extends:
- .debian:stable
- .debian.packages
- .fdo.container-build@debian
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
debian:sid@container-prep:
extends:
- .debian:sid
- .debian.packages
- .fdo.container-build@debian
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
arch:rolling@container-prep:
extends:
- .arch:rolling
- .arch.packages
- .fdo.container-build@arch
stage: prep
variables:
GIT_STRATEGY: none
# Pulls in the container from upstream or rebuilds it if missing
alpine:latest@container-prep:
extends:
- .alpine:latest
- .alpine.packages
- .fdo.container-build@alpine
stage: prep
variables:
GIT_STRATEGY: none
#################################################################
# #
# container clean stage #
# run during the clean stage #
# #
#################################################################
#
# This stage will look for the container images we currently have in
# the registry and will remove any that are not tagged with the provided
# $container_image:$tag
.container-clean:
extends:
- .fdo.ci-fairy
stage: container_clean
script:
# Go to your Profile, Settings, Access Tokens
# Create a personal token with 'api' scope, copy the value.
# Go to CI/CD, Schedules, schedule a new monthly job (or edit the existing one)
# Define a variable of type File named AUTHFILE. Content is that token
# value.
- ci-fairy -v --authfile $AUTHFILE delete-image
--repository $FDO_DISTRIBUTION_NAME/$FDO_DISTRIBUTION_VERSION
--exclude-tag $FDO_DISTRIBUTION_TAG
dependencies: []
allow_failure: true
only:
- schedules
### fedora 40
fedora:40@container-clean:
extends:
- .fedora:40
- .container-clean
needs: ["fedora:40@container-prep"]
### fedora 41
fedora:41@container-clean:
extends:
- .fedora:41
- .container-clean
needs: ["fedora:41@container-prep"]
### ubuntu 24.10
ubuntu:24.10@container-clean:
extends:
- .ubuntu:24.10
- .container-clean
needs: ["ubuntu:24.10@container-prep"]
### debian stable
debian:stable@container-clean:
extends:
- .debian:stable
- .container-clean
needs: ["debian:stable@container-prep"]
### debian sid
debian:sid@container-clean:
extends:
- .debian:sid
- .container-clean
needs: ["debian:sid@container-prep"]
### arch rolling
arch:rolling@container-clean:
extends:
- .arch:rolling
- .container-clean
needs: ["arch:rolling@container-prep"]
### alpine latest
alpine:latest@container-clean:
extends:
- .alpine:latest
- .container-clean
needs: ["alpine:latest@container-prep"]
#################################################################
# #
# build stage #
# #
#################################################################
.autotools-build@template:
extends:
- .autotools_build
stage: build
dependencies: []
variables:
MAKE_ARGS: "distcheck"
.meson-build@template:
extends:
- .meson_build
stage: build
dependencies: []
fedora:40@autotools-build:
extends:
- .fedora:40
- .autotools-build@template
stage: autotools
needs: ['fedora:40@container-prep']
fedora:40@meson-build:
extends:
- .fedora:40
- .meson-build@template
stage: meson
needs: ['fedora:40@container-prep']
fedora:41@autotools-build:
extends:
- .fedora:41
- .autotools-build@template
stage: autotools
needs: ['fedora:41@container-prep']
fedora:41@meson-build:
extends:
- .fedora:41
- .meson-build@template
stage: meson
needs: ['fedora:41@container-prep']
ubuntu:24.10@autotools-build:
extends:
- .ubuntu:24.10
- .autotools-build@template
stage: autotools
needs: ['ubuntu:24.10@container-prep']
ubuntu:24.10@meson-build:
extends:
- .ubuntu:24.10
- .meson-build@template
stage: meson
needs: ['ubuntu:24.10@container-prep']
debian:stable@autotools-build:
extends:
- .debian:stable
- .autotools-build@template
stage: autotools
needs: ['debian:stable@container-prep']
debian:stable@meson-build:
extends:
- .debian:stable
- .meson-build@template
stage: meson
needs: ['debian:stable@container-prep']
debian:sid@autotools-build:
extends:
- .debian:sid
- .autotools-build@template
stage: autotools
needs: ['debian:sid@container-prep']
debian:sid@meson-build:
extends:
- .debian:sid
- .meson-build@template
stage: meson
needs: ['debian:sid@container-prep']
arch:rolling@autotools-build:
extends:
- .arch:rolling
- .autotools-build@template
stage: autotools
needs: ['arch:rolling@container-prep']
arch:rolling@meson-build:
extends:
- .arch:rolling
- .meson-build@template
stage: meson
needs: ['arch:rolling@container-prep']
alpine:latest@autotools-build:
extends:
- .alpine:latest
- .autotools-build@template
stage: autotools
needs: ['alpine:latest@container-prep']
alpine:latest@meson-build:
extends:
- .alpine:latest
- .meson-build@template
stage: meson
needs: ['alpine:latest@container-prep']
# Build argument tests
#
# We only run the build option combinations on one image
# because they're supposed to fail equally on all
.fedora-custom-build@autotools-template:
extends:
- .fedora:40
- .autotools-build@template
stage: build
needs: ['fedora:40@container-prep']
no-valgrind:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y valgrind
no-check:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y check check-devel
no-doxygen:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y doxygen
variables:
MAKE_ARGS: '' # disable distcheck, requires doxygen
# doxygen is required for distcheck
no-doxygen-check-valgrind:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y doxygen valgrind check check-devel
variables:
MAKE_ARGS: '' # disable distcheck, requires doxygen
no-nm:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- mv /usr/bin/nm /usr/bin/nm.moved
enable-gcov:autotools:
extends: .fedora-custom-build@autotools-template
variables:
CONFIGURE_FLAGS: "--enable-gcov"
.fedora-custom-build@meson-template:
extends:
- .fedora:40
- .meson-build@template
stage: build
needs: ['fedora:40@container-prep']
no-valgrind:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y valgrind
no-check:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y check check-devel
variables:
MESON_ARGS: -Dtests=disabled
# doxygen is required for dist
no-doxygen:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y doxygen
variables:
MESON_ARGS: -Ddocumentation=disabled
NINJA_ARGS: ''
# doxygen is required for dist
no-doxygen-check-valgrind:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y doxygen valgrind check check-devel
variables:
MESON_ARGS: -Dtests=disabled -Ddocumentation=disabled
NINJA_ARGS: ''
enable-gcov:meson:
extends: .fedora-custom-build@meson-template
variables:
MESON_ARGS: '-Dcoverity=true'
scan-build:meson:
extends: .fedora-custom-build@meson-template
variables:
NINJA_ARGS: 'scan-build'
static-build:meson:
extends: .fedora-custom-build@meson-template
script:
- meson "$MESON_BUILDDIR" --default-library=static --prefix=$PWD/prefix-meson/
- ninja -C "$MESON_BUILDDIR" install
- ls -l $PWD/prefix-meson/lib64/libevdev.a
soname:
extends:
- .fedora:40
stage: build
script:
- ./autogen.sh --prefix=$PWD/prefix-autotools/
- make install
- ls -l $PWD/prefix-autotools/lib/libevdev.so.2.3.0
- meson "$MESON_BUILDDIR" --prefix=$PWD/prefix-meson/
- ninja -C "$MESON_BUILDDIR" install
- ls -l $PWD/prefix-meson/lib64/libevdev.so.2.3.0
needs: ['fedora:40@container-prep']
#################################################################
# #
# VM stage #
# #
#################################################################
.check_tainted: &check_tainted |
# make sure the kernel is not tainted
if [[ "$(/app/vmctl exec cat /proc/sys/kernel/tainted)" -gt 0 ]];
then
echo tainted kernel ;
exit 1 ;
fi
# build on the host, then run a systemd service to execute the test suite
# inside the qemu VM handled by b2c
.build-in-b2c@template:
extends:
- .default_artifacts
tags:
- kvm
variables:
MESON_BUILDDIR: build_dir
B2C_KERNEL: https://gitlab.freedesktop.org/api/v4/projects/libevdev%2Fhid-tools/packages/generic/kernel-x86_64/v6.5/bzImage
B2C_IMAGE: $FDO_DISTRIBUTION_IMAGE
B2C_COMMAND: .gitlab-ci/start-in-systemd.sh
script:
# first build in the host container
- .gitlab-ci/meson-build.sh --skip-test
# pull b2c
- curl -L -o /app/boot2container https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/2ff65156ba67fa8a0c309a4fc16c5df1a88a3844/vm2c.py
- chmod +x /app/boot2container
# runs the test suite only
- /app/boot2container
qemu:meson:
stage: VM
extends:
- .fdo.distribution-image@fedora
- .fedora:41
- .build-in-b2c@template
needs:
- "fedora:41@container-prep"
qemu:meson:valgrind:
extends:
- qemu:meson
variables:
MESON_TEST_ARGS: '--setup=valgrind'
meson-from-tarball:
extends:
- .fedora:41
stage: tarballs
script:
- export INSTALLDIR="$PWD/_inst"
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules $CONFIGURE_FLAGS
- make
- make dist
- popd > /dev/null
- mkdir -p _tarball_dir
- tar xf _build/libevdev-*.tar.xz -C _tarball_dir
- pushd _tarball_dir/libevdev-*/ > /dev/null
- meson "$MESON_BUILDDIR" --prefix="$INSTALLDIR"
- meson test -C "$MESON_BUILDDIR" --no-suite="needs-uinput"
- ninja -C "$MESON_BUILDDIR" install
- popd > /dev/null
- ls -lR $INSTALLDIR
needs: ['fedora:41@container-prep']
autotools-from-tarball:
extends:
- .fedora:41
stage: tarballs
script:
- export INSTALLDIR="$PWD/_inst"
- meson "$MESON_BUILDDIR"
- meson dist -C "$MESON_BUILDDIR" --no-tests
- mkdir -p _tarball_dir
- tar xf "$MESON_BUILDDIR"/meson-dist/libevdev-*.xz -C _tarball_dir
- pushd _tarball_dir/libevdev-*/ > /dev/null
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules --prefix="$INSTALLDIR" $CONFIGURE_FLAGS
- make
- make install
- make distcheck
- popd > /dev/null
- popd > /dev/null
- ls -lR $INSTALLDIR
variables:
LIBEVDEV_SKIP_ROOT_TESTS: 1
needs: ['fedora:41@container-prep']

486
.gitlab-ci/ci.template Normal file
View file

@ -0,0 +1,486 @@
{# You're looking at the template here, so you can ignore the below
warning. This is the right file to edit #}
########################################
# #
# THIS FILE IS GENERATED, DO NOT EDIT #
# #
########################################
.templates_sha: &template_sha e195d80f35b45cc73668be3767b923fd76c70ed5 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
- project: 'freedesktop/ci-templates'
ref: *template_sha
file:
{% for distribution in distributions|map(attribute='name')|unique()|sort() %}
- '/templates/{{distribution}}.yml'
{% endfor %}
- '/templates/ci-fairy.yml'
stages:
- prep # rebuild the container images if there is a change
- build # for actually building and testing things in a container
- VM # for running the test suite in a VM
- autotools # distribution builds with autotools
- meson # distribution builds with meson
- tarballs # tarball builds
- container_clean # clean up unused container images
- merge-check # check for a merge request
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
variables:
# The upstrem repository we will check for images
FDO_UPSTREAM_REPO: libevdev/libevdev
GIT_DEPTH: 1
MESON_BUILDDIR: 'build dir'
.default_artifacts:
artifacts:
paths:
- _build/test/test-suite.log
- $MESON_BUILDDIR/meson-logs/
expire_in: 1 week
when: always
reports:
junit: $MESON_BUILDDIR/*junit*.xml
.autotools_build:
extends:
- .default_artifacts
script:
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules $CONFIGURE_FLAGS
- make
- make check
- if ! [[ -z "$MAKE_ARGS" ]]; then make $MAKE_ARGS; fi
- popd > /dev/null
variables:
LIBEVDEV_SKIP_ROOT_TESTS: 1
.meson_build:
extends:
- .default_artifacts
script:
- .gitlab-ci/meson-build.sh --run-test
variables:
MESON_TEST_ARGS: '--no-suite=needs-uinput'
{# Generate templates for every distribution/version combination we want, any
job can then just extends: .name:version and the images will sort
themselves out. #}
{% for distro in distributions %}
{% for version in distro.versions %}
.{{distro.name}}:{{version}}:
extends: .fdo.distribution-image@{{distro.name}}
variables:
FDO_DISTRIBUTION_TAG: '{{distro.tag}}'
FDO_DISTRIBUTION_VERSION: '{{version}}'
{% endfor %}
{% endfor %}
#################################################################
# #
# prep stage #
# #
#################################################################
# Re-generate the CI script and make sure it's the one currently checked in
# If this job fails, re-generate the gitlab-ci.yml script, see
# $SRCDIR/.gitlab-ci/generate-gitlab-ci.py
#
check-ci-script:
extends:
- .fdo.ci-fairy
stage: prep
script:
- ci-fairy generate-template --verify && exit 0 || true
- echo "Committed gitlab-ci.yml differs from generated gitlab-ci.yml. Please verify"
- exit 1
#
# Verify that commit messages are as expected, signed-off, etc.
#
check-commit:
extends:
- .fdo.ci-fairy
stage: prep
script:
- ci-fairy -vv check-commits --junit-xml=results.xml && exit 0 || true
- echo "Error checking the commit message format. Please verify"
- exit 1
except:
- master@libevdev/libevdev
variables:
GIT_DEPTH: 100
artifacts:
reports:
junit: results.xml
#
# Verify that the merge request has the allow-collaboration checkbox ticked
#
check-merge-request:
extends:
- .fdo.ci-fairy
stage: merge-check
script:
- ci-fairy check-merge-request --require-allow-collaboration --junit-xml=results.xml
artifacts:
when: on_failure
reports:
junit: results.xml
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
{% for distro in distributions %}
.{{ distro.name }}.packages:
variables:
FDO_DISTRIBUTION_PACKAGES: '{{ ' '.join(distro.packages)}}'
{% endfor %}
{% for distro in distributions %}
{% for version in distro.versions %}
# Pulls in the container from upstream or rebuilds it if missing
{{ distro.name }}:{{ version }}@container-prep:
extends:
- .{{ distro.name }}:{{ version }}
- .{{ distro.name}}.packages
- .fdo.container-build@{{ distro.name }}
stage: prep
variables:
GIT_STRATEGY: none
{% endfor %}
{% endfor %}
#################################################################
# #
# container clean stage #
# run during the clean stage #
# #
#################################################################
#
# This stage will look for the container images we currently have in
# the registry and will remove any that are not tagged with the provided
# $container_image:$tag
.container-clean:
extends:
- .fdo.ci-fairy
stage: container_clean
script:
# Go to your Profile, Settings, Access Tokens
# Create a personal token with 'api' scope, copy the value.
# Go to CI/CD, Schedules, schedule a new monthly job (or edit the existing one)
# Define a variable of type File named AUTHFILE. Content is that token
# value.
- ci-fairy -v --authfile $AUTHFILE delete-image
--repository $FDO_DISTRIBUTION_NAME/$FDO_DISTRIBUTION_VERSION
--exclude-tag $FDO_DISTRIBUTION_TAG
dependencies: []
allow_failure: true
only:
- schedules
{% for distro in distributions %}
{% for version in distro.versions %}
### {{ distro.name }} {{ version }}
{{ distro.name }}:{{ version }}@container-clean:
extends:
- .{{ distro.name }}:{{ version }}
- .container-clean
needs: ["{{distro.name}}:{{version}}@container-prep"]
{% endfor %}
{% endfor %}
#################################################################
# #
# build stage #
# #
#################################################################
.autotools-build@template:
extends:
- .autotools_build
stage: build
dependencies: []
variables:
MAKE_ARGS: "distcheck"
.meson-build@template:
extends:
- .meson_build
stage: build
dependencies: []
{% for distro in distributions %}
{% for version in distro.versions %}
{{ distro.name }}:{{ version }}@autotools-build:
extends:
- .{{ distro.name }}:{{ version }}
- .autotools-build@template
stage: autotools
{# Where we have extra_variables defined, add them to the list #}
{% if distro.build is defined and distro.build.extra_variables is defined %}
variables:
{% for key, value in distro.build.extra_variables.items() %}
{{ key }}: {{ value }}
{% endfor %}
{% endif %}
needs: ['{{ distro.name }}:{{ version }}@container-prep']
{% if not distro.build is defined or distro.build.meson|default(True) %}
{{ distro.name }}:{{ version }}@meson-build:
extends:
- .{{ distro.name }}:{{ version }}
- .meson-build@template
stage: meson
{# Where we have extra_variables defined, add them to the list #}
{% if distro.build is defined and distro.build.extra_variables is defined %}
variables:
{% for key, value in distro.build.extra_variables.items() %}
{{ key }}: {{ value }}
{% endfor %}
{% endif %}
needs: ['{{ distro.name }}:{{ version }}@container-prep']
{% endif %}
{% endfor %}
{% endfor %}
# Build argument tests
#
# We only run the build option combinations on one image
# because they're supposed to fail equally on all
{% set custom_build_distro = distributions|selectattr("name", "equalto", "fedora")|first() %}
.fedora-custom-build@autotools-template:
extends:
- .{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}
- .autotools-build@template
stage: build
needs: ['{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}@container-prep']
no-valgrind:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y valgrind
no-check:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y check check-devel
no-doxygen:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y doxygen
variables:
MAKE_ARGS: '' # disable distcheck, requires doxygen
# doxygen is required for distcheck
no-doxygen-check-valgrind:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- dnf remove -y doxygen valgrind check check-devel
variables:
MAKE_ARGS: '' # disable distcheck, requires doxygen
no-nm:autotools:
extends: .fedora-custom-build@autotools-template
before_script:
- mv /usr/bin/nm /usr/bin/nm.moved
enable-gcov:autotools:
extends: .fedora-custom-build@autotools-template
variables:
CONFIGURE_FLAGS: "--enable-gcov"
.fedora-custom-build@meson-template:
extends:
- .{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}
- .meson-build@template
stage: build
needs: ['{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}@container-prep']
no-valgrind:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y valgrind
no-check:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y check check-devel
variables:
MESON_ARGS: -Dtests=disabled
# doxygen is required for dist
no-doxygen:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y doxygen
variables:
MESON_ARGS: -Ddocumentation=disabled
NINJA_ARGS: ''
# doxygen is required for dist
no-doxygen-check-valgrind:meson:
extends: .fedora-custom-build@meson-template
before_script:
- dnf remove -y doxygen valgrind check check-devel
variables:
MESON_ARGS: -Dtests=disabled -Ddocumentation=disabled
NINJA_ARGS: ''
enable-gcov:meson:
extends: .fedora-custom-build@meson-template
variables:
MESON_ARGS: '-Dcoverity=true'
scan-build:meson:
extends: .fedora-custom-build@meson-template
variables:
NINJA_ARGS: 'scan-build'
static-build:meson:
extends: .fedora-custom-build@meson-template
script:
- meson "$MESON_BUILDDIR" --default-library=static --prefix=$PWD/prefix-meson/
- ninja -C "$MESON_BUILDDIR" install
- ls -l $PWD/prefix-meson/lib64/libevdev.a
soname:
extends:
- .{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}
stage: build
script:
- ./autogen.sh --prefix=$PWD/prefix-autotools/
- make install
- ls -l $PWD/prefix-autotools/lib/libevdev.so.2.3.0
- meson "$MESON_BUILDDIR" --prefix=$PWD/prefix-meson/
- ninja -C "$MESON_BUILDDIR" install
- ls -l $PWD/prefix-meson/lib64/libevdev.so.2.3.0
needs: ['{{custom_build_distro.name}}:{{custom_build_distro.versions|first()}}@container-prep']
#################################################################
# #
# VM stage #
# #
#################################################################
.check_tainted: &check_tainted |
# make sure the kernel is not tainted
if [[ "$(/app/vmctl exec cat /proc/sys/kernel/tainted)" -gt 0 ]];
then
echo tainted kernel ;
exit 1 ;
fi
# build on the host, then run a systemd service to execute the test suite
# inside the qemu VM handled by b2c
.build-in-b2c@template:
extends:
- .default_artifacts
tags:
- kvm
variables:
MESON_BUILDDIR: build_dir
B2C_KERNEL: {{ b2c.kernel }}
B2C_IMAGE: $FDO_DISTRIBUTION_IMAGE
B2C_COMMAND: .gitlab-ci/start-in-systemd.sh
script:
# first build in the host container
- .gitlab-ci/meson-build.sh --skip-test
# pull b2c
- curl -L -o /app/boot2container https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/{{b2c.version}}/vm2c.py
- chmod +x /app/boot2container
# runs the test suite only
- /app/boot2container
{% for distro in distributions if distro.use_for_qemu_tests %}
{% set version = "{}".format(distro.versions|last()) %}
qemu:meson:
stage: VM
extends:
- .fdo.distribution-image@{{distro.name}}
- .{{distro.name}}:{{version}}
- .build-in-b2c@template
needs:
- "{{distro.name}}:{{version}}@container-prep"
qemu:meson:valgrind:
extends:
- qemu:meson
variables:
MESON_TEST_ARGS: '--setup=valgrind'
{% endfor %}
{% for distro in distributions if distro.use_for_tarball_tests %}
{% set version = "{}".format(distro.versions|last()) %}
meson-from-tarball:
extends:
- .{{distro.name}}:{{version}}
stage: tarballs
script:
- export INSTALLDIR="$PWD/_inst"
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules $CONFIGURE_FLAGS
- make
- make dist
- popd > /dev/null
- mkdir -p _tarball_dir
- tar xf _build/libevdev-*.tar.xz -C _tarball_dir
- pushd _tarball_dir/libevdev-*/ > /dev/null
- meson "$MESON_BUILDDIR" --prefix="$INSTALLDIR"
- meson test -C "$MESON_BUILDDIR" --no-suite="needs-uinput"
- ninja -C "$MESON_BUILDDIR" install
- popd > /dev/null
- ls -lR $INSTALLDIR
needs: ['{{distro.name}}:{{version}}@container-prep']
autotools-from-tarball:
extends:
- .{{distro.name}}:{{version}}
stage: tarballs
script:
- export INSTALLDIR="$PWD/_inst"
- meson "$MESON_BUILDDIR"
- meson dist -C "$MESON_BUILDDIR" --no-tests
- mkdir -p _tarball_dir
- tar xf "$MESON_BUILDDIR"/meson-dist/libevdev-*.xz -C _tarball_dir
- pushd _tarball_dir/libevdev-*/ > /dev/null
- mkdir _build
- pushd _build > /dev/null
- ../autogen.sh --disable-silent-rules --prefix="$INSTALLDIR" $CONFIGURE_FLAGS
- make
- make install
- make distcheck
- popd > /dev/null
- popd > /dev/null
- ls -lR $INSTALLDIR
variables:
LIBEVDEV_SKIP_ROOT_TESTS: 1
needs: ['{{distro.name}}:{{version}}@container-prep']
{% endfor %}

125
.gitlab-ci/config.yml Normal file
View file

@ -0,0 +1,125 @@
# This file contains the configuration for the gitlab ci.
# See the .gitlab-ci/generate-gitlab-ci.py file for more info
#
# We're happy to rebuild all containers when one changes.
.default_tag: &default_tag '2024-11-25.0'
distributions:
- name: fedora
tag: *default_tag
use_for_tarball_tests: true
# only one distro for qemu tests
use_for_qemu_tests: true
versions:
- '40'
- '41'
packages:
- git
- gcc
- gcc-c++
- meson
- automake
- autoconf
- libtool
- make
- pkgconfig
- python3
- check-devel
- valgrind
- binutils
- doxygen
- xz
- clang-analyzer
# below packages are for the qemu runs, so optional
- systemd-udev
- qemu-img
- qemu-system-x86-core
- qemu-system-aarch64-core
- jq
- python3-click
- python3-rich
- name: ubuntu
tag: *default_tag
versions:
- '24.10'
packages:
- git
- gcc
- g++
- meson
- automake
- autoconf
- libtool
- make
- pkg-config
- python3
- check
- valgrind
- binutils
- doxygen
- xz-utils
- name: debian
tag: *default_tag
versions:
- 'stable'
- 'sid'
packages:
- git
- gcc
- g++
- meson
- automake
- autoconf
- libtool
- make
- pkg-config
- python3
- check
- valgrind
- binutils
- doxygen
- xz-utils
- name: arch
tag: *default_tag
versions:
- 'rolling'
packages:
- git
- gc
- meson
- automake
- autoconf
- libtool
- make
- pkgconfig
- python3
- check
- valgrind
- binutils
- doxygen
- name: alpine
tag: *default_tag
versions:
- 'latest'
packages:
- git
- gcc
- g++
- meson
- automake
- autoconf
- libtool
- make
- pkgconfig
- python3
- check-dev
- valgrind
- binutils
- doxygen
- xz
- linux-headers
b2c:
version: 2ff65156ba67fa8a0c309a4fc16c5df1a88a3844
kernel: https://gitlab.freedesktop.org/api/v4/projects/libevdev%2Fhid-tools/packages/generic/kernel-x86_64/v6.5/bzImage

88
.gitlab-ci/meson-build.sh Executable file
View file

@ -0,0 +1,88 @@
#!/usr/bin/env bash
#
# This script is sourced from here:
# https://gitlab.freedesktop.org/whot/meson-helper
#
# SPDX-License-Identifier: MIT
set -x
if [[ -f .meson_environment ]]; then
. .meson_environment
fi
# If test args are set, we assume we want to run the tests
MESON_RUN_TEST="$MESON_TEST_ARGS"
while [[ $# -gt 0 ]]; do
case $1 in
--skip-setup)
shift
MESON_SKIP_SETUP="1"
;;
--skip-build)
shift
MESON_SKIP_BUILD="1"
;;
--skip-test)
shift
MESON_RUN_TEST=""
;;
--run-test)
shift
MESON_RUN_TEST="1"
;;
*)
echo "Unknow commandline argument $1"
exit 1
;;
esac
done
if [[ -z "$MESON_BUILDDIR" ]]; then
echo "\$MESON_BUILDDIR undefined."
exit 1
fi
# emulate a few gitlab variables to make it easier to
# run and debug locally.
if [[ -z "$CI_JOB_ID" ]] || [[ -z "$CI_JOB_NAME" ]]; then
echo "Missing \$CI_JOB_ID or \$CI_JOB_NAME".
CI_PROJECT_NAME=$(basename "$PWD")
CI_JOB_ID=$(date +%s)
CI_JOB_NAME="$CI_PROJECT_NAME-job-local"
echo "Simulating gitlab environment: "
echo " CI_JOB_ID=$CI_JOB_ID"
echo " CI_JOB_NAME=$CI_JOB_NAME"
fi
if [[ -n "$FDO_CI_CONCURRENT" ]]; then
jobcount="-j$FDO_CI_CONCURRENT"
export MESON_TESTTHREADS="$FDO_CI_CONCURRENT"
fi
echo "*************************************************"
echo "builddir: $MESON_BUILDDIR"
echo "meson args: $MESON_ARGS"
echo "ninja args: $NINJA_ARGS"
echo "meson test args: $MESON_TEST_ARGS"
echo "job count: ${jobcount-0}"
echo "*************************************************"
set -e
if [[ -z "$MESON_SKIP_SETUP" ]]; then
rm -rf "$MESON_BUILDDIR"
meson setup "$MESON_BUILDDIR" $MESON_ARGS
fi
meson configure "$MESON_BUILDDIR"
if [[ -z "$MESON_SKIP_BUILD" ]]; then
if [[ -n "$NINJA_ARGS" ]]; then
ninja_args="--ninja-args $NINJA_ARGS"
fi
meson compile -v -C "$MESON_BUILDDIR" $jobcount $ninja_args
fi
if [[ -n "$MESON_RUN_TEST" ]]; then
meson test -C "$MESON_BUILDDIR" $MESON_TEST_ARGS --print-errorlogs
fi

69
.gitlab-ci/start-in-systemd.sh Executable file
View file

@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -x
systemd_target=basic.target
post_command="/usr/bin/systemctl exit \$EXIT_STATUS"
while [[ $# -gt 0 ]]; do
case $1 in
--debug-mode)
shift
systemd_target=multi-user.target
post_command="echo you can now log in as root (no password) and then turn off by running \'/usr/bin/systemctl exit \$EXIT_STATUS\'"
;;
*)
echo "Unknow commandline argument $1"
exit 1
;;
esac
done
WORKDIR=${FDO_DISTRIBUTION_WORKINGDIR:-$PWD}
B2C_WORKDIR=${FDO_B2C_WORKDIR:-/app}
# remove root password for debugging
sed -i 's/root:!locked::/root:::/' /etc/shadow
# create a libevdev test suite service
cat <<EOF > /etc/systemd/system/libevdev-testsuite.service
[Unit]
Description=libevdev test suite
After=$systemd_target
[Service]
Type=simple
StandardOutput=journal+console
EnvironmentFile=$B2C_WORKDIR/.b2c_env
WorkingDirectory=$WORKDIR
ExecStart=$WORKDIR/.gitlab-ci/meson-build.sh --skip-setup --skip-build --run-test
# exit the container on termination
ExecStopPost=$post_command
[Install]
WantedBy=default.target
EOF
cat /etc/systemd/system/libevdev-testsuite.service
# enable the service
systemctl enable libevdev-testsuite.service
# disable some services we don't need in the CI
systemctl mask network-online.target
systemctl mask network-pre.target
systemctl mask timers.target
systemctl mask dnf-makecache.timer
systemctl mask systemd-logind.service
systemctl mask rpmdb-migrate.service
systemctl mask systemd-network-generator.service
systemctl mask cryptsetup-pre.target
systemctl mask cryptsetup.target
#change default target
systemctl set-default $systemd_target
# start the system
exec /usr/sbin/init

222
CODING_STYLE.md Normal file
View file

@ -0,0 +1,222 @@
# Coding style
- Indentation in tabs, 8 characters wide, spaces after the tabs where
vertical alignment is required (see below)
**Note: this file uses spaces due to markdown rendering issues for tabs.
Code must be implemented using tabs.**
- Max line width 80ch, do not break up printed strings though
- Break up long lines at logical groupings, one line for each logical group
```c
int a = somelongname() +
someotherlongname();
if (a < 0 &&
(b > 20 & d < 10) &&
d != 0.0)
somelongfunctioncall(arg1, arg2,
otherarg);
```
- Function declarations: return type on separate line, {} on separate line,
arguments broken up as above.
```c
static inline int
foobar(int a, int b)
{
}
void
somenamethatiswaytoolong(int a, int b,
int other)
{
}
```
- `/* comments only */`, no `// comments`
- `variable_name`, not `VariableName` or `variableName`. same for functions.
- no typedefs of structs, enums, unions
- if it generates a compiler warning, it needs to be fixed
- if it generates a static checker warning, it needs to be fixed or
commented
- declare variables at the top, try to keep them as local as possible.
Exception: if the same variable is re-used in multiple blocks, declare it
at the top.
Exception: basic loop variables, e.g. for (int i = 0; ...)
```c
int a;
int c;
if (foo) {
int b;
c = get_value();
usevalue(c);
}
if (bar) {
c = get_value();
useit(c);
}
```
- do not mix function invocations and variable definitions.
wrong:
```c
{
int a = foo();
int b = 7;
}
```
right:
```c
{
int a;
int b = 7;
a = foo();
}
```
- if/else: { on the same line, no curly braces if both blocks are a single
statement. If either if or else block are multiple statements, both must
have curly braces.
```c
if (foo) {
blah();
bar();
} else {
a = 10;
}
```
- public functions MUST be doxygen-commented, use doxygen's `@foo` rather than
`\foo` notation
- `#include "config.h"` comes first, followed by system headers, followed by
external library headers, followed by internal headers.
sort alphabetically where it makes sense (specifically system headers)
```c
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <libevdev/libevdev.h>
#include "libevdev-int.h"
```
- goto jumps only to the end of the function, and only for good reasons
(usually cleanup). goto never jumps backwards
- Use stdbool.h's bool for booleans within the library (instead of `int`).
Exception: the public API uses int, not bool.
# Git commit message requirements
Our CI will check the commit messages for a few requirements. Below is the
list of what we expect from a git commit.
## Commit message content
A [good commit message](http://who-t.blogspot.com/2009/12/on-commit-messages.html) needs to
answer three questions:
- Why is it necessary? It may fix a bug, it may add a feature, it may
improve performance, reliability, stability, or just be a change for the
sake of correctness.
- How does it address the issue? For short obvious patches this part can be
omitted, but it should be a high level description of what the approach
was.
- What effects does the patch have? (In addition to the obvious ones, this
may include benchmarks, side effects, etc.)
These three questions establish the context for the actual code changes, put
reviewers and others into the frame of mind to look at the diff and check if
the approach chosen was correct. A good commit message also helps
maintainers to decide if a given patch is suitable for stable branches or
inclusion in a distribution.
## Developer Certificate of Origin
Your commit **must** be signed off with a line:
```
Signed-off-by: <your name> <your email address>
```
By signing off, you indicate the [developer certificate of origin](https://developercertificate.org/).
> By making a contribution to this project, I certify that:
>
> (a) The contribution was created in whole or in part by me and I
> have the right to submit it under the open source license
> indicated in the file; or
>
> (b) The contribution is based upon previous work that, to the best
> of my knowledge, is covered under an appropriate open source
> license and I have the right under that license to submit that
> work with modifications, whether created in whole or in part
> by me, under the same open source license (unless I am
> permitted to submit under a different license), as indicated
> in the file; or
>
> (c) The contribution was provided directly to me by some other
> person who certified (a), (b) or (c) and I have not modified
> it.
>
> (d) I understand and agree that this project and the contribution
> are public and that a record of the contribution (including all
> personal information I submit with it, including my sign-off) is
> maintained indefinitely and may be redistributed consistent with
> this project or the open source license(s) involved.
## Commit message format
The canonical git commit message format is:
```
one line as the subject line with a high-level note
full explanation of the patch follows after an empty line. This explanation
can be multiple paragraphs and is largely free-form. Markdown is not
supported.
You can include extra data where required like:
- benchmark one says 10s
- benchmark two says 12s
Signed-off-by: <your name> <your email>
```
The subject line is the first thing everyone sees about this commit, so make
sure it's on point.
## Commit message technical requirements
- The commit message should use present tense (not past tense). Do write
"change foo to bar", not "changed foo to bar".
- The text width of the commit should be 78 chars or less, especially the
subject line.
- The author and signed-off-by must be your real name and email address. We
do not accept the default `@users.noreply` gitlab addresses.
```
git config --global user.name Your Name
git config --global user.email your@email
```

35
COPYING
View file

@ -1,23 +1,26 @@
SPDX-License-Identifier: MIT
Copyright © 2013 Red Hat, Inc.
Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
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 the copyright holders not be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no representations
about the suitability of this software for any purpose. It is provided "as
is" without express or implied warranty.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL THE COPYRIGHT HOLDERS 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.
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
The following license is from a Linux kernel header file and there is no GPL
code this package links to.

View file

@ -8,4 +8,4 @@ SUBDIRS = doc libevdev tools test
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libevdev.pc
EXTRA_DIST = libevdev.pc.in
EXTRA_DIST = libevdev.pc.in meson.build meson_options.txt

View file

@ -5,18 +5,17 @@ libevdev is a wrapper library for evdev devices. it moves the common
tasks when dealing with evdev devices into a library and provides a library
interface to the callers, thus avoiding erroneous ioctls, etc.
git://git.freedesktop.org/git/libevdev
http://cgit.freedesktop.org/libevdev/
The eventual goal is that libevdev wraps all ioctls available to evdev
devices, thus making direct access unnecessary.
https://gitlab.freedesktop.org/libevdev/libevdev.git
Go here for the API documentation:
http://www.freedesktop.org/software/libevdev/doc/latest/
File bugs in the freedesktop.org bugzilla:
https://bugs.freedesktop.org/enter_bug.cgi?product=libevdev
File bugs in the freedesktop.org GitLab instance:
https://gitlab.freedesktop.org/libevdev/libevdev/issues/
Patches, questions and general comments should be submitted to the input-tools@lists.freedesktop.org
mailing list:
Patches should be submitted as merge requests in the GitLab instance:
https://gitlab.freedesktop.org/libevdev/libevdev/merge_requests/
Questions and general comments should be submitted to the
input-tools@lists.freedesktop.org mailing list:
http://lists.freedesktop.org/mailman/listinfo/input-tools

View file

@ -9,4 +9,8 @@ cd "$srcdir"
autoreconf -fvi || exit $?
cd "$olddir"
test -n "$NOCONFIGURE" || $srcdir/configure "$@"
git config --local --get format.subjectPrefix >/dev/null 2>&1 ||
git config --local format.subjectPrefix "PATCH libevdev"
test -n "$NOCONFIGURE" || exec "$srcdir"/configure "$@"

View file

@ -1,28 +1,14 @@
# SPDX-License-Identifier: MIT
#
# Copyright © 2013 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 the copyright holders not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. The copyright holders make no representations
# about the suitability of this software for any purpose. It is provided "as
# is" without express or implied warranty.
#
# THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
# EVENT SHALL THE COPYRIGHT HOLDERS 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.
AC_PREREQ([2.62])
# change meson version too
AC_INIT([libevdev],
[1.5.0],
[https://bugs.freedesktop.org/enter_bug.cgi?product=libevdev],
[1.13.6],
[https://gitlab.freedesktop.org/libevdev/libevdev/issues/],
[libevdev],
[http://freedesktop.org/wiki/Software/libevdev/])
@ -32,17 +18,11 @@ AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
# Before making a release, the LIBEVDEV_LT_VERSION string should be
# modified.
# The string is of the form C:R:A.
# - If interfaces have been changed or added, but binary compatibility has
# been preserved, change to C+1:0:A+1
# - If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1:0:0
# - If the interface is the same as the previous version, change to C:R+1:A
LIBEVDEV_LT_VERSION=3:12:1
# DO NOT MODIFY THIS
# Use symbol versioning instead.
LIBEVDEV_LT_VERSION=5:0:3
AC_SUBST(LIBEVDEV_LT_VERSION)
@ -66,14 +46,22 @@ if test "x$lt_cv_prog_gnu_ld" = "xyes"; then
fi
AC_SUBST([GNU_LD_FLAGS], $with_ldflags)
case "${host_os}" in
freebsd*)
AC_SUBST([OS], [freebsd])
;;
*)
AC_SUBST([OS], [linux])
;;
esac
AC_CHECK_LIB([m], [round])
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(CHECK, [check >= 0.9.9], [HAVE_CHECK="yes"], [HAVE_CHECK="no"])
if test "x$HAVE_CHECK" = "xyes"; then
AC_PATH_PROG(VALGRIND, [valgrind])
else
if test "x$HAVE_CHECK" != "xyes"; then
AC_MSG_WARN([check not found - skipping building unit tests])
fi
AM_CONDITIONAL(HAVE_VALGRIND, [test "x$VALGRIND" != "x"])
AM_CONDITIONAL(ENABLE_RUNTIME_TESTS, [test "x$HAVE_CHECK" = "xyes"])
AM_CONDITIONAL(ENABLE_STATIC_LINK_TEST, [test "x$enable_static" = "xyes"])
@ -115,7 +103,7 @@ AC_ARG_ENABLE([gcov],
AS_IF([test "x$enable_gcov" != "xno"],
[
GCOV_CFLAGS="-fprofile-arcs -ftest-coverage"
GCOV_LDFLAGS="-fprofile-arcs -ftest-coverage"
GCOV_LDFLAGS="-lgcov"
enable_gcov=yes
],
)
@ -124,8 +112,27 @@ AC_SUBST([GCOV_CFLAGS])
AC_SUBST([GCOV_LDFLAGS])
AC_MSG_RESULT([$enable_gcov])
AC_MSG_CHECKING([whether to build with coverity support])
AC_ARG_ENABLE([coverity],
[AS_HELP_STRING([--enable-coverity],
[Whether to build with coverity support (default: disabled)])],
[],
[enable_coverity=no],
)
AS_IF([test "x$enable_coverity" != "xno"],
[
AC_DEFINE([_Float128], [__uint128_t], [Override for coverity])
AC_DEFINE([_Float32], [int], [Override for coverity])
AC_DEFINE([_Float32x], [int], [Override for coverity])
AC_DEFINE([_Float64], [long], [Override for coverity])
AC_DEFINE([_Float64x], [long], [Override for coverity])
enable_coverity=yes
],
)
AC_MSG_RESULT([$enable_coverity])
AM_PATH_PYTHON([2.6])
AC_PATH_PROG(CAT, [cat])
# nm to check for leaking symbols in the static library
AC_PATH_PROG(NM, [nm])
@ -162,5 +169,6 @@ AC_MSG_RESULT([
Build documentation ${have_doxygen}
Enable unit-tests ${HAVE_CHECK}
Enable profiling ${enable_gcov}
Enable coverity support ${enable_coverity}
Static library symbol check ${static_symbol_leaks_test}
])

View file

@ -8,14 +8,27 @@ header_files = \
$(top_srcdir)/libevdev/libevdev.h \
$(top_srcdir)/libevdev/libevdev-uinput.h
html/index.html: libevdev.doxygen $(header_files)
html/index.html: libevdev.doxygen style/libevdevdoxygen.css $(header_files)
$(AM_V_GEN)$(DOXYGEN) $<
clean-local:
$(AM_V_at)rm -rf html
doc_src= $(shell find html -type f -printf "html/%P\n" 2>/dev/null)
EXTRA_DIST = html/index.html $(doc_src) libevdev.css
style_src = \
style/bootstrap.css \
style/customdoxygen.css \
style/doxy-boot.js \
style/dynsections.js \
style/footer.html \
style/header.html \
style/layout.xml \
style/libevdevdoxygen.css \
style/LICENSE \
style/README.md \
style/style.css
EXTRA_DIST = html/index.html $(doc_src) $(style_src)
endif

View file

@ -1,227 +0,0 @@
h1 {
font-size: 150%;
color: #354C7B;
border-bottom: 1px solid #879ECB;
font-weight: normal;
padding-bottom: 4px;
padding-bottom: 8px;
}
#titlearea {
width: 30%;
margin-left: auto;
margin-right: auto;
padding: 0px 10px 15px 10px;
border: none;
border-bottom: 1px solid #879ECB;
}
#projectname {
text-align: center;
font-weight: bold;
font-size: 300%;
margin-top: 5px;
padding: 2px 0 0 0;
margin-left: auto;
margin-right: auto;
color: #354C7B;
}
#projectnumber {
font-size: 100%;
color: #354C7B;
}
#projectbrief {
text-align: center;
margin-left: 20px;
margin-top: 5px;
padding: 2px 0 0 0;
margin-left: auto;
margin-right: auto;
color: #354C7B;
}
#MSearchBox {
display: none;
}
#titlearea table {
margin-left: auto;
margin-right: auto;
}
#navrow1, #navrow2, #navrow3, #navrow4, #navpath {
width: 600px;
width: -moz-max-content;
margin-left: auto;
margin-right: auto;
}
/* in file list, appears under the nav bars */
.navpath ul, .navpath li {
width: 600px;
width: -moz-max-content;
margin-left: auto;
margin-right: auto;
background-image: none;
border: none;
border-bottom: 1px solid;
}
.navpath li.navelem a {
text-shadow: none;
outline: none;
}
.tabs, .tabs2, .tabs3 {
background-image: none;
}
/* main page/modules/files tabs */
.tablist li {
background-image: none;
}
/* main page/modules/files link text */
.tablist a {
background-image: none;
background-repeat: none;
}
/* main page/modules/files link text when hovering */
.tablist a:hover {
background-image: none;
background-repeat: none;
text-shadow: none;
color: black;
}
/* main page/modules/files currently selected */
.tablist li.current a {
background-image: none;
text-shadow: none;
color: black;
border-bottom: 1px solid;
}
.navpath {
background-image: none;
}
/* libevdev documentation/modules/file list ... superfluous header */
div.header {
display: none;
width: -moz-max-content;
margin-left: auto;
margin-right: auto;
background-image: none;
background-color: inherit;
font-size: 300%;
}
/* general text blocks */
.textblock {
width: 600px;
margin-left: auto;
margin-right: auto;
}
/* code fragments should expand to what's needed */
.fragment {
width: -moz-max-content;
}
/* list of modules container */
div .directory{
margin-left: auto;
margin-right: auto;
width: 600px;
border: none;
}
.directory td.entry {
width: 40%;
white-space: normal;
padding-left: 5px;
}
.directory td.desc {
width: 60%;
}
.directory td.entry img {
display: none;
}
h2.groupheader {
width: -moz-max-content;
}
/* table for list of functions */
table.memberdecls {
width: -moz-max-content;
}
div.memitem {
width: -moz-max-content;
border-bottom: 1px solid;
}
/* function prototype */
div.memproto {
background-image: none;
width: 600px;
border: none;
box-shadow: none;
}
/* function documentation */
div.memdoc {
background-image: none;
width: -moz-max-content;
box-shadow: none;
border: none;
}
div.contents {
margin-left: auto;
margin-right: auto;
width: 600px;
width: -moz-max-content;
}
p {
width: 580px;
}
dl.return {
width: 480px;
}
code {
background-color: #F9FAFC;
}
.footer {
width: 600px;
margin-left: auto;
margin-right: auto;
}
img.footer {
width: auto;
}
/* note, see also, returns */
dl.section {
width: 560px;
}
table.params {
width: 560px;
}

View file

@ -11,9 +11,12 @@ INPUT = @top_srcdir@/libevdev/libevdev.h \
@top_srcdir@/libevdev/libevdev-uinput.h
EXAMPLE_PATH = @top_srcdir@/include
GENERATE_HTML = YES
HTML_EXTRA_STYLESHEET = @srcdir@/libevdev.css
HTML_TIMESTAMP = YES
GENERATE_LATEX = NO
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = LIBEVDEV_ATTRIBUTE_PRINTF(f,a)=
HTML_HEADER = "@srcdir@/style/header.html"
HTML_FOOTER = "@srcdir@/style/footer.html"
HTML_EXTRA_STYLESHEET = "@srcdir@/style/bootstrap.css" \
"@srcdir@/style/customdoxygen.css" \
"@srcdir@/style/libevdevdoxygen.css"

229
doc/style/LICENSE Normal file
View file

@ -0,0 +1,229 @@
These licenses apply to the doxygen documentation HTML style only. They do
not apply or affect libinput itself.
Apache: https://github.com/Velron/doxygen-bootstrapped/
MIT: https://bootswatch.com/paper/bootstrap.css
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The MIT License (MIT)
Copyright (c) 2011-2015 Twitter, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

6
doc/style/README.md Normal file
View file

@ -0,0 +1,6 @@
# Doxygen-Bootstrap
This is a small project for integrating Doxygen output with Twitter Bootstrap.
See the Stratify Documentation for an example: https://stratifylabs.co/StratifyAPI/html/
The header.html and footer.html files in this repo are designed to be used with Jekyll and Github pages (specifically it is based on https://github.com/plusjade/jekyll-bootstrap/). Be sure to modify the header/footer html files so that they fit your needs. You can look at the source of https://stratifylabs.co/StratifyAPI/html/ to see what css and js files are used in the header.

7500
doc/style/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load diff

254
doc/style/customdoxygen.css Normal file
View file

@ -0,0 +1,254 @@
h1, .h1, h2, .h2, h3, .h3{
font-weight: 200 !important;
}
#navrow1, #navrow2, #navrow3, #navrow4, #navrow5{
border-bottom: 1px solid #EEEEEE;
}
.adjust-right {
margin-left: 30px !important;
font-size: 1.15em !important;
}
.navbar{
border: 0px solid #222 !important;
}
/* Sticky footer styles
-------------------------------------------------- */
html,
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
}
/* Wrapper for page content to push down footer */
#wrap {
min-height: 100%;
height: auto;
/* Negative indent footer by its height */
margin: 0 auto -60px;
/* Pad bottom by footer height */
padding: 0 0 60px;
}
/* Set the fixed height of the footer here */
#footer {
font-size: 0.9em;
padding: 8px 0px;
background-color: #f5f5f5;
}
.footer-row {
line-height: 44px;
}
#footer > .container {
padding-left: 15px;
padding-right: 15px;
}
.footer-follow-icon {
margin-left: 3px;
text-decoration: none !important;
}
.footer-follow-icon img {
width: 20px;
}
.footer-link {
padding-top: 5px;
display: inline-block;
color: #999999;
text-decoration: none;
}
.footer-copyright {
text-align: center;
}
@media (min-width: 992px) {
.footer-row {
text-align: left;
}
.footer-icons {
text-align: right;
}
}
@media (max-width: 991px) {
.footer-row {
text-align: center;
}
.footer-icons {
text-align: center;
}
}
/* DOXYGEN Code Styles
----------------------------------- */
a.qindex {
font-weight: bold;
}
a.qindexHL {
font-weight: bold;
background-color: #9CAFD4;
color: #ffffff;
border: 1px double #869DCA;
}
.contents a.qindexHL:visited {
color: #ffffff;
}
a.code, a.code:visited, a.line, a.line:visited {
color: #4665A2;
}
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
color: #4665A2;
}
/* @end */
dl.el {
margin-left: -1cm;
}
pre.fragment {
border: 1px solid #C4CFE5;
background-color: #FBFCFD;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
font-family: monospace, fixed;
font-size: 105%;
}
div.fragment {
padding: 4px 6px;
margin: 4px 8px 4px 2px;
border: 1px solid #C4CFE5;
}
div.line {
font-family: monospace, fixed;
font-size: 13px;
min-height: 13px;
line-height: 1.0;
text-wrap: unrestricted;
white-space: -moz-pre-wrap; /* Moz */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* IE 5.5+ */
text-indent: -53px;
padding-left: 53px;
padding-bottom: 0px;
margin: 0px;
-webkit-transition-property: background-color, box-shadow;
-webkit-transition-duration: 0.5s;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.5s;
-ms-transition-property: background-color, box-shadow;
-ms-transition-duration: 0.5s;
-o-transition-property: background-color, box-shadow;
-o-transition-duration: 0.5s;
transition-property: background-color, box-shadow;
transition-duration: 0.5s;
}
div.line.glow {
background-color: cyan;
box-shadow: 0 0 10px cyan;
}
span.lineno {
padding-right: 4px;
text-align: right;
border-right: 2px solid #0F0;
background-color: #E8E8E8;
white-space: pre;
}
span.lineno a {
background-color: #D8D8D8;
}
span.lineno a:hover {
background-color: #C8C8C8;
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
font-weight: bold;
}
div.groupText {
margin-left: 16px;
font-style: italic;
}
/* @group Code Colorization */
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
span.vhdldigit {
color: #ff00ff
}
span.vhdlchar {
color: #000000
}
span.vhdlkeyword {
color: #700070
}
span.vhdllogic {
color: #ff0000
}
blockquote {
background-color: #F7F8FB;
border-left: 2px solid #9CAFD4;
margin: 0 24px 0 4px;
padding: 0 12px 0 16px;
}

98
doc/style/doxy-boot.js Normal file
View file

@ -0,0 +1,98 @@
/*
Copyright (c) 2013-2016, Tyler Gilbert
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$( document ).ready(function() {
$("div.headertitle").addClass("page-header");
$("div.title").addClass("h1");
$('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> ");
$('li > a[href="index.html"] > span').text("Stratify Labs");
$('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> ");
$('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> ");
$('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> ");
$('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> ");
$('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> ");
$('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> ");
$('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> ");
$('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> ");
$('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> ");
$('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> ");
$(".icona .icon").addClass("label label-danger");
$(".icona .icon").after(" ");
$('img[src="closed.png"]').before("<i class='fa fa-chevron-right'></i> ");
$('img[src="closed.png"]').hide();
$("div.qindex").css("margin-bottom", "3em");
$("div.textblock").css("margin-bottom", "3em");
$("table.memberdecls").css("margin-bottom", "3em");
$("table.memberdecls").css("margin-top", "3em");
$("span.arrow").replaceWith("<i class='fa fa-chevron-right'></i> ");
$("ul.tablist").addClass("nav nav-pills");
$("ul.tablist").css("margin-top", "0.5em");
$("ul.tablist").css("margin-bottom", "0.5em");
$("li.current").addClass("active");
$("iframe").attr("scrolling", "yes");
$("#nav-path > ul").addClass("breadcrumb");
$("table.params").addClass("table");
$("div.ingroups").wrapInner("<small></small>");
$("div.levels").css("margin", "0.5em");
$("div.levels > span").addClass("btn btn-default btn-xs");
$("div.levels > span").css("margin-right", "0.25em");
$("table.directory").addClass("table table-striped table-bordered");
$("[class^=separator]").remove();
$("div.summary > a").addClass("btn btn-default btn-xs");
$("table.fieldtable").addClass("table");
$(".fragment").addClass("well");
$(".memitem").addClass("panel panel-default");
$(".memproto").addClass("panel-heading");
$(".memdoc").addClass("panel-body");
$("span.mlabel").addClass("label label-info");
$("table.memberdecls").addClass("table table-bordered");
//$("[class^=memitem]").addClass("active");
$("div.ah").addClass("btn btn-default");
$("span.mlabels").addClass("pull-right");
$("table.mlabels").css("width", "100%")
$("td.mlabels-right").addClass("pull-right");
$("div.ttc").addClass("panel panel-info");
$("div.ttname").addClass("panel-heading");
$("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
});

12
doc/style/dynsections.js Normal file
View file

@ -0,0 +1,12 @@
function toggleVisibility(linkObj)
{var base=$(linkObj).attr('id');var summary=$('#'+base+'-summary');var content=$('#'+base+'-content');var trigger=$('#'+base+'-trigger');var src=$(trigger).attr('src');if(content.is(':visible')===true){content.hide();summary.show();$(linkObj).addClass('closed').removeClass('opened');$(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');}else{content.show();summary.hide();$(linkObj).removeClass('closed').addClass('opened');$(trigger).attr('src',src.substring(0,src.length-10)+'open.png');}
return false;}
function updateStripes()
{$('table.directory tr').removeClass('even').filter(':visible:even').addClass('even');}
function toggleLevel(level)
{$('table.directory tr').each(function(){var l=this.id.split('_').length-1;var i=$('#img'+this.id.substring(3));var a=$('#arr'+this.id.substring(3));if(l<level+1){i.removeClass('iconfopen iconfclosed').addClass('iconfopen');a.html('&#9660;');$(this).show();}else if(l==level+1){i.removeClass('iconfclosed iconfopen').addClass('iconfclosed');a.html('&#9658;');$(this).show();}else{$(this).hide();}});updateStripes();}
function toggleFolder(id)
{var currentRow=$('#row_'+id);var rows=currentRow.nextAll("tr");var re=new RegExp('^row_'+id+'\\d+_$',"i");var childRows=rows.filter(function(){return this.id.match(re);});if(childRows.filter(':first').is(':visible')===true){var currentRowSpans=currentRow.find("span");currentRowSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");currentRowSpans.filter(".arrow").html('&#9658;');rows.filter("[id^=row_"+id+"]").hide();}else{var currentRowSpans=currentRow.find("span");currentRowSpans.filter(".iconfclosed").removeClass("iconfclosed").addClass("iconfopen");currentRowSpans.filter(".arrow").html('&#9660;');var childRowsSpans=childRows.find("span");childRowsSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");childRowsSpans.filter(".arrow").html('&#9658;');childRows.show();}
updateStripes();}
function toggleInherit(id)
{var rows=$('tr.inherit.'+id);var img=$('tr.inherit_header.'+id+' img');var src=$(img).attr('src');if(rows.filter(':first').is(':visible')===true){rows.css('display','none');$(img).attr('src',src.substring(0,src.length-8)+'closed.png');}else{rows.css('display','table-row');$(img).attr('src',src.substring(0,src.length-10)+'open.png');}}

26
doc/style/footer.html Normal file
View file

@ -0,0 +1,26 @@
<!-- HTML footer for doxygen 1.8.8-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
</div>
</div>
</div>
</div>
</div>
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
</a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

40
doc/style/header.html Normal file
View file

@ -0,0 +1,40 @@
<!-- HTML header for doxygen 1.8.8-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- For Mobile Devices -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>-->
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="doxy-boot.js"></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand">$projectname $projectnumber</a>
</div>
</div>
</nav>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div class="content" id="content">
<div class="container">
<div class="row">
<div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
<div style="margin-bottom: 15px;">
<!-- end header part -->

183
doc/style/layout.xml Normal file
View file

@ -0,0 +1,183 @@
<doxygenlayout version="1.0">
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="no" title="" intro=""/>
<tab type="modules" visible="yes" title="" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespaces" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
</tab>
<tab type="files" visible="no" title="">
<tab type="filelist" visible="no" title="" intro=""/>
<tab type="globals" visible="no" title="" intro=""/>
</tab>
<tab type="examples" visible="no" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="no"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<allmemberslink visible="yes"/>
<detaileddescription title="Documentation"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="no"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title="Documentation"/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<groupgraph visible="$GROUP_GRAPHS"/>
<briefdescription visible="yes"/>
<detaileddescription title="Documentation"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<dirs visible="yes" title=""/>
<nestedgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title="Documentation"/>
</directory>
</doxygenlayout>

View file

@ -0,0 +1,111 @@
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono");
dd {
margin-left: 30px;
}
.title {
font-size: 200%;
font-weight: bold;
}
.title .ingroups {
font-size: 50%;
}
h1 {
font-size: 150%;
color: #354C7B;
background: none;
border-bottom: 1px solid #879ECB;
font-size: 150%;
font-weight: normal;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 0px;
width: 100%;
}
h2 {
font-size: 150%;
}
.sm-dox li {
float:left;
border-top: 0;
padding-right: 20px;
}
.sm li, .sm a {
position: relative;
}
.sm, .sm ul, .sm li {
list-style: none;
display: block;
line-height: normal;
direction: ltr;
text-align: left;
}
.sm, .sm *, .sm *::before, .sm *::after {
box-sizing: border-box;
}
#main-nav {
padding: 30px;
}
/* Main menu sub-items like file-list, etc */
#main-menu li ul {
display: none;
}
.paramname {
padding-right: 10px;
}
.memtitle {
background-image: none;
background-color: #F0F0F0;
}
.memproto {
background-color: #F0F0F0;
}
.headertitle {
background-image: none;
background-color: #F0F0F0;
}
div.header {
border: none;
}
td.fieldname {
font-family: 'Roboto Mono', monospace;
}
.fieldtable th {
background-image: none;
background-color: #F0F0F0;
}
body {
letter-spacing: 0px;
}
.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams {
background-color: #F0F0F0;
}
a {
color: #2873b0;
}
.navpath ul {
background-image: none;
background-color: #F0F0F0;
}

173
doc/style/style.css Normal file
View file

@ -0,0 +1,173 @@
/* The standard CSS for doxygen */
pre.fragment {
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 12pt;
line-height: 125%;
font-family: monospace, fixed;
font-size: 110%;
}
div.fragment {
padding: 4px;
margin: 4px;
}
div.line {
font-family: monospace, fixed;
font-size: 16px;
min-height: 13px;
line-height: 1.0;
text-wrap: unrestricted;
white-space: -moz-pre-wrap; /* Moz */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* IE 5.5+ */
text-indent: -53px;
padding-left: 53px;
padding-bottom: 0px;
margin: 0px;
-webkit-transition-property: background-color, box-shadow;
-webkit-transition-duration: 0.5s;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.5s;
-ms-transition-property: background-color, box-shadow;
-ms-transition-duration: 0.5s;
-o-transition-property: background-color, box-shadow;
-o-transition-duration: 0.5s;
transition-property: background-color, box-shadow;
transition-duration: 0.5s;
}
div.line.glow {
background-color: cyan;
box-shadow: 0 0 10px cyan;
}
span.lineno {
padding-right: 4px;
text-align: right;
border-right: 2px solid #0F0;
white-space: pre;
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
font-weight: bold;
}
div.groupText {
margin-left: 16px;
font-style: italic;
}
td.indexkey {
background-color: #EBEFF6;
font-weight: bold;
border: 1px solid #C4CFE5;
margin: 2px 0px 2px 0;
padding: 2px 10px;
white-space: nowrap;
vertical-align: top;
}
td.indexvalue {
background-color: #EBEFF6;
border: 1px solid #C4CFE5;
padding: 2px 10px;
margin: 2px 0px;
}
tr.memlist {
background-color: #EEF1F7;
}
p.formulaDsp {
text-align: center;
}
img.formulaDsp {
}
img.formulaInl {
vertical-align: middle;
}
div.center {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 0px;
}
div.center img {
border: 0px;
}
address.footer {
text-align: right;
padding-right: 12px;
}
img.footer {
border: 0px;
vertical-align: middle;
}
/* @group Code Colorization */
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
span.vhdldigit {
color: #ff00ff
}
span.vhdlchar {
color: #000000
}
span.vhdlkeyword {
color: #700070
}
span.vhdllogic {
color: #ff0000
}
/* @end */

View file

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Input event codes
*
@ -26,6 +27,7 @@
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
#define INPUT_PROP_PRESSUREPAD 0x07 /* pressure triggers clicks */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
@ -277,7 +279,8 @@
#define KEY_PAUSECD 201
#define KEY_PROG3 202
#define KEY_PROG4 203
#define KEY_DASHBOARD 204 /* AL Dashboard */
#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */
#define KEY_DASHBOARD KEY_ALL_APPLICATIONS
#define KEY_SUSPEND 205
#define KEY_CLOSE 206 /* AC Close */
#define KEY_PLAY 207
@ -406,6 +409,7 @@
#define BTN_TOOL_MOUSE 0x146
#define BTN_TOOL_LENS 0x147
#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
#define BTN_STYLUS3 0x149
#define BTN_TOUCH 0x14a
#define BTN_STYLUS 0x14b
#define BTN_STYLUS2 0x14c
@ -437,10 +441,12 @@
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */
#define KEY_ZOOM KEY_FULL_SCREEN
#define KEY_MODE 0x175
#define KEY_KEYBOARD 0x176
#define KEY_SCREEN 0x177
#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */
#define KEY_SCREEN KEY_ASPECT_RATIO
#define KEY_PC 0x178 /* Media Select Computer */
#define KEY_TV 0x179 /* Media Select TV */
#define KEY_TV2 0x17a /* Media Select Cable */
@ -511,6 +517,10 @@
#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */
#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */
#define KEY_IMAGES 0x1ba /* AL Image Browser */
#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */
#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */
#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */
#define KEY_LINK_PHONE 0x1bf /* AL Phone Syncing */
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
@ -538,6 +548,7 @@
#define KEY_FN_F 0x1e2
#define KEY_FN_S 0x1e3
#define KEY_FN_B 0x1e4
#define KEY_FN_RIGHT_SHIFT 0x1e5
#define KEY_BRL_DOT1 0x1f1
#define KEY_BRL_DOT2 0x1f2
@ -591,7 +602,14 @@
#define BTN_DPAD_LEFT 0x222
#define BTN_DPAD_RIGHT 0x223
#define BTN_GRIPL 0x224
#define BTN_GRIPR 0x225
#define BTN_GRIPL2 0x226
#define BTN_GRIPR2 0x227
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
#define KEY_REFRESH_RATE_TOGGLE 0x232 /* Display refresh rate toggle */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
@ -600,10 +618,31 @@
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */
#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */
#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */
#define KEY_CAMERA_ACCESS_ENABLE 0x24b /* Enables programmatic access to camera devices. (HUTRR72) */
#define KEY_CAMERA_ACCESS_DISABLE 0x24c /* Disables programmatic access to camera devices. (HUTRR72) */
#define KEY_CAMERA_ACCESS_TOGGLE 0x24d /* Toggles the current state of the camera access control. (HUTRR72) */
#define KEY_ACCESSIBILITY 0x24e /* Toggles the system bound accessibility UI/command (HUTRR116) */
#define KEY_DO_NOT_DISTURB 0x24f /* Toggles the system-wide "Do Not Disturb" control (HUTRR94)*/
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
/*
* Keycodes for hotkeys toggling the electronic privacy screen found on some
* laptops on/off. Note when the embedded-controller turns on/off the eprivacy
* screen itself then the state should be reported through drm connecter props:
* https://www.kernel.org/doc/html/latest/gpu/drm-kms.html#standard-connector-properties
* Except when implementing the drm connecter properties API is not possible
* because e.g. the firmware does not allow querying the presence and/or status
* of the eprivacy screen at boot.
*/
#define KEY_EPRIVACY_SCREEN_ON 0x252
#define KEY_EPRIVACY_SCREEN_OFF 0x253
#define KEY_KBDINPUTASSIST_PREV 0x260
#define KEY_KBDINPUTASSIST_NEXT 0x261
#define KEY_KBDINPUTASSIST_PREVGROUP 0x262
@ -611,6 +650,142 @@
#define KEY_KBDINPUTASSIST_ACCEPT 0x264
#define KEY_KBDINPUTASSIST_CANCEL 0x265
/* Diagonal movement keys */
#define KEY_RIGHT_UP 0x266
#define KEY_RIGHT_DOWN 0x267
#define KEY_LEFT_UP 0x268
#define KEY_LEFT_DOWN 0x269
#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */
/* Show Top Menu of the Media (e.g. DVD) */
#define KEY_MEDIA_TOP_MENU 0x26b
#define KEY_NUMERIC_11 0x26c
#define KEY_NUMERIC_12 0x26d
/*
* Toggle Audio Description: refers to an audio service that helps blind and
* visually impaired consumers understand the action in a program. Note: in
* some countries this is referred to as "Video Description".
*/
#define KEY_AUDIO_DESC 0x26e
#define KEY_3D_MODE 0x26f
#define KEY_NEXT_FAVORITE 0x270
#define KEY_STOP_RECORD 0x271
#define KEY_PAUSE_RECORD 0x272
#define KEY_VOD 0x273 /* Video on Demand */
#define KEY_UNMUTE 0x274
#define KEY_FASTREVERSE 0x275
#define KEY_SLOWREVERSE 0x276
/*
* Control a data application associated with the currently viewed channel,
* e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
*/
#define KEY_DATA 0x277
#define KEY_ONSCREEN_KEYBOARD 0x278
/* Electronic privacy screen control */
#define KEY_PRIVACY_SCREEN_TOGGLE 0x279
/* Select an area of screen to be copied */
#define KEY_SELECTIVE_SCREENSHOT 0x27a
/* Move the focus to the next or previous user controllable element within a UI container */
#define KEY_NEXT_ELEMENT 0x27b
#define KEY_PREVIOUS_ELEMENT 0x27c
/* Toggle Autopilot engagement */
#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d
/* Shortcut Keys */
#define KEY_MARK_WAYPOINT 0x27e
#define KEY_SOS 0x27f
#define KEY_NAV_CHART 0x280
#define KEY_FISHING_CHART 0x281
#define KEY_SINGLE_RANGE_RADAR 0x282
#define KEY_DUAL_RANGE_RADAR 0x283
#define KEY_RADAR_OVERLAY 0x284
#define KEY_TRADITIONAL_SONAR 0x285
#define KEY_CLEARVU_SONAR 0x286
#define KEY_SIDEVU_SONAR 0x287
#define KEY_NAV_INFO 0x288
#define KEY_BRIGHTNESS_MENU 0x289
/*
* Some keyboards have keys which do not have a defined meaning, these keys
* are intended to be programmed / bound to macros by the user. For most
* keyboards with these macro-keys the key-sequence to inject, or action to
* take, is all handled by software on the host side. So from the kernel's
* point of view these are just normal keys.
*
* The KEY_MACRO# codes below are intended for such keys, which may be labeled
* e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys
* where the marking on the key does indicate a defined meaning / purpose.
*
* The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing
* KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO
* define MUST be added.
*/
#define KEY_MACRO1 0x290
#define KEY_MACRO2 0x291
#define KEY_MACRO3 0x292
#define KEY_MACRO4 0x293
#define KEY_MACRO5 0x294
#define KEY_MACRO6 0x295
#define KEY_MACRO7 0x296
#define KEY_MACRO8 0x297
#define KEY_MACRO9 0x298
#define KEY_MACRO10 0x299
#define KEY_MACRO11 0x29a
#define KEY_MACRO12 0x29b
#define KEY_MACRO13 0x29c
#define KEY_MACRO14 0x29d
#define KEY_MACRO15 0x29e
#define KEY_MACRO16 0x29f
#define KEY_MACRO17 0x2a0
#define KEY_MACRO18 0x2a1
#define KEY_MACRO19 0x2a2
#define KEY_MACRO20 0x2a3
#define KEY_MACRO21 0x2a4
#define KEY_MACRO22 0x2a5
#define KEY_MACRO23 0x2a6
#define KEY_MACRO24 0x2a7
#define KEY_MACRO25 0x2a8
#define KEY_MACRO26 0x2a9
#define KEY_MACRO27 0x2aa
#define KEY_MACRO28 0x2ab
#define KEY_MACRO29 0x2ac
#define KEY_MACRO30 0x2ad
/*
* Some keyboards with the macro-keys described above have some extra keys
* for controlling the host-side software responsible for the macro handling:
* -A macro recording start/stop key. Note that not all keyboards which emit
* KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if
* KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START
* should be interpreted as a recording start/stop toggle;
* -Keys for switching between different macro (pre)sets, either a key for
* cycling through the configured presets or keys to directly select a preset.
*/
#define KEY_MACRO_RECORD_START 0x2b0
#define KEY_MACRO_RECORD_STOP 0x2b1
#define KEY_MACRO_PRESET_CYCLE 0x2b2
#define KEY_MACRO_PRESET1 0x2b3
#define KEY_MACRO_PRESET2 0x2b4
#define KEY_MACRO_PRESET3 0x2b5
/*
* Some keyboards have a buildin LCD panel where the contents are controlled
* by the host. Often these have a number of keys directly below the LCD
* intended for controlling a menu shown on the LCD. These keys often don't
* have any labeling so we just name them KEY_KBD_LCD_MENU#
*/
#define KEY_KBD_LCD_MENU1 0x2b8
#define KEY_KBD_LCD_MENU2 0x2b9
#define KEY_KBD_LCD_MENU3 0x2ba
#define KEY_KBD_LCD_MENU4 0x2bb
#define KEY_KBD_LCD_MENU5 0x2bc
/* Performance Boost key (Alienware)/G-Mode key (Dell) */
#define KEY_PERFORMANCE 0x2bd
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
@ -672,6 +847,16 @@
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
/*
* 0x0a is reserved and should not be used in input drivers.
* It was used by HID as REL_MISC+1 and userspace needs to detect if
* the next REL_* event is correct or is just REL_MISC + n.
* We define here REL_RESERVED so userspace can rely on it and detect
* the situation described above.
*/
#define REL_RESERVED 0x0a
#define REL_WHEEL_HI_RES 0x0b
#define REL_HWHEEL_HI_RES 0x0c
#define REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
@ -705,9 +890,19 @@
#define ABS_TOOL_WIDTH 0x1c
#define ABS_VOLUME 0x20
#define ABS_PROFILE 0x21
#define ABS_MISC 0x28
/*
* 0x2e is reserved and should not be used in input drivers.
* It was used by HID as ABS_MISC+6 and userspace needs to detect if
* the next ABS_* event is correct or is just ABS_MISC + n.
* We define here ABS_RESERVED so userspace can rely on it and detect
* the situation described above.
*/
#define ABS_RESERVED 0x2e
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
@ -724,6 +919,7 @@
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
@ -748,7 +944,10 @@
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
#define SW_LINEIN_INSERT 0x0d /* set = inserted */
#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
#define SW_MAX 0x0f
#define SW_PEN_INSERTED 0x0f /* set = pen inserted */
#define SW_MACHINE_COVER 0x10 /* set = cover closed */
#define SW_USB_INSERT 0x11 /* set = USB audio device connected */
#define SW_MAX 0x11
#define SW_CNT (SW_MAX+1)
/*

View file

@ -0,0 +1,513 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _UAPI_INPUT_H
#define _UAPI_INPUT_H
#ifndef __KERNEL__
#include <sys/time.h>
#include <sys/ioccom.h>
#include <sys/types.h>
#endif
#include "input-event-codes.h"
/*
* The event structure itself
* Note that __USE_TIME_BITS64 is defined by libc based on
* application's request to use 64 bit time_t.
*/
struct input_event {
#if 1 /* (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__) */
struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
__kernel_ulong_t __sec;
#if defined(__sparc__) && defined(__arch64__)
unsigned int __usec;
unsigned int __pad;
#else
__kernel_ulong_t __usec;
#endif
#define input_event_sec __sec
#define input_event_usec __usec
#endif
uint16_t type;
uint16_t code;
int32_t value;
};
/*
* Protocol version.
*/
#define EV_VERSION 0x010001
/*
* IOCTLs (0x00 - 0x7f)
*/
struct input_id {
uint16_t bustype;
uint16_t vendor;
uint16_t product;
uint16_t version;
};
/**
* struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
* @value: latest reported value for the axis.
* @minimum: specifies minimum value for the axis.
* @maximum: specifies maximum value for the axis.
* @fuzz: specifies fuzz value that is used to filter noise from
* the event stream.
* @flat: values that are within this value will be discarded by
* joydev interface and reported as 0 instead.
* @resolution: specifies resolution for the values reported for
* the axis.
*
* Note that input core does not clamp reported values to the
* [minimum, maximum] limits, such task is left to userspace.
*
* The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
* is reported in units per millimeter (units/mm), resolution
* for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
* in units per radian.
* When INPUT_PROP_ACCELEROMETER is set the resolution changes.
* The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
* in units per g (units/g) and in units per degree per second
* (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ).
*/
struct input_absinfo {
int32_t value;
int32_t minimum;
int32_t maximum;
int32_t fuzz;
int32_t flat;
int32_t resolution;
};
/**
* struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
* @scancode: scancode represented in machine-endian form.
* @len: length of the scancode that resides in @scancode buffer.
* @index: index in the keymap, may be used instead of scancode
* @flags: allows to specify how kernel should handle the request. For
* example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
* should perform lookup in keymap by @index instead of @scancode
* @keycode: key code assigned to this scancode
*
* The structure is used to retrieve and modify keymap data. Users have
* option of performing lookup either by @scancode itself or by @index
* in keymap entry. EVIOCGKEYCODE will also return scancode or index
* (depending on which element was used to perform lookup).
*/
struct input_keymap_entry {
#define INPUT_KEYMAP_BY_INDEX (1 << 0)
uint8_t flags;
uint8_t len;
uint16_t index;
uint32_t keycode;
uint8_t scancode[32];
};
struct input_mask {
uint32_t type;
uint32_t codes_size;
uint64_t codes_ptr;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOWR('E', 0x04, unsigned int[2]) /* get keycode */
#define EVIOCGKEYCODE_V2 _IOWR('E', 0x04, struct input_keymap_entry)
#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */
#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry)
#define EVIOCGNAME(len) _IOC(IOC_OUT, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(IOC_OUT, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(IOC_OUT, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGPROP(len) _IOC(IOC_OUT, 'E', 0x09, len) /* get device properties */
/**
* EVIOCGMTSLOTS(len) - get MT slot values
* @len: size of the data buffer in bytes
*
* The ioctl buffer argument should be binary equivalent to
*
* struct input_mt_request_layout {
* uint32_t code;
* int32_t values[num_slots];
* };
*
* where num_slots is the (arbitrary) number of MT slots to extract.
*
* The ioctl size argument (len) is the size of the buffer, which
* should satisfy len = (num_slots + 1) * sizeof(int32_t). If len is
* too small to fit all available slots, the first num_slots are
* returned.
*
* Before the call, code is set to the wanted ABS_MT event type. On
* return, values[] is filled with the slot values for the specified
* ABS_MT code.
*
* If the request code is not an ABS_MT value, -EINVAL is returned.
*/
#define EVIOCGMTSLOTS(len) _IOC(IOC_INOUT, 'E', 0x0a, len)
#define EVIOCGKEY(len) _IOC(IOC_OUT, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(IOC_OUT, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(IOC_OUT, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(IOC_OUT, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(IOC_OUT, 'E', 0x20 + (ev), len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOWINT('E', 0x81) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOWINT('E', 0x90) /* Grab/Release device */
#define EVIOCREVOKE _IOWINT('E', 0x91) /* Revoke device access */
/**
* EVIOCGMASK - Retrieve current event mask
*
* This ioctl allows user to retrieve the current event mask for specific
* event type. The argument must be of type "struct input_mask" and
* specifies the event type to query, the address of the receive buffer and
* the size of the receive buffer.
*
* The event mask is a per-client mask that specifies which events are
* forwarded to the client. Each event code is represented by a single bit
* in the event mask. If the bit is set, the event is passed to the client
* normally. Otherwise, the event is filtered and will never be queued on
* the client's receive buffer.
*
* Event masks do not affect global state of the input device. They only
* affect the file descriptor they are applied to.
*
* The default event mask for a client has all bits set, i.e. all events
* are forwarded to the client. If the kernel is queried for an unknown
* event type or if the receive buffer is larger than the number of
* event codes known to the kernel, the kernel returns all zeroes for those
* codes.
*
* At maximum, codes_size bytes are copied.
*
* This ioctl may fail with ENODEV in case the file is revoked, EFAULT
* if the receive-buffer points to invalid memory, or EINVAL if the kernel
* does not implement the ioctl.
*/
#define EVIOCGMASK _IOW('E', 0x92, struct input_mask) /* Get event-masks */
/**
* EVIOCSMASK - Set event mask
*
* This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the
* current event mask, this changes the client's event mask for a specific
* type. See EVIOCGMASK for a description of event-masks and the
* argument-type.
*
* This ioctl provides full forward compatibility. If the passed event type
* is unknown to the kernel, or if the number of event codes specified in
* the mask is bigger than what is known to the kernel, the ioctl is still
* accepted and applied. However, any unknown codes are left untouched and
* stay cleared. That means, the kernel always filters unknown codes
* regardless of what the client requests. If the new mask doesn't cover
* all known event-codes, all remaining codes are automatically cleared and
* thus filtered.
*
* This ioctl may fail with ENODEV in case the file is revoked. EFAULT is
* returned if the receive-buffer points to invalid memory. EINVAL is returned
* if the kernel does not implement the ioctl.
*/
#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */
#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */
/*
* IDs.
*/
#define ID_BUS 0
#define ID_VENDOR 1
#define ID_PRODUCT 2
#define ID_VERSION 3
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
#define BUS_RMI 0x1D
#define BUS_CEC 0x1E
#define BUS_INTEL_ISHTP 0x1F
/*
* MT_TOOL types
*/
#define MT_TOOL_FINGER 0x00
#define MT_TOOL_PEN 0x01
#define MT_TOOL_PALM 0x02
#define MT_TOOL_DIAL 0x0a
#define MT_TOOL_MAX 0x0f
/*
* Values describing the status of a force-feedback effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
#define FF_STATUS_MAX 0x01
/*
* Structures used in ioctls to upload effects to a device
* They are pieces of a bigger structure (called ff_effect)
*/
/*
* All duration values are expressed in ms. Values above 32767 ms (0x7fff)
* should not be used and have unspecified results.
*/
/**
* struct ff_replay - defines scheduling of the force-feedback effect
* @length: duration of the effect
* @delay: delay before effect should start playing
*/
struct ff_replay {
uint16_t length;
uint16_t delay;
};
/**
* struct ff_trigger - defines what triggers the force-feedback effect
* @button: number of the button triggering the effect
* @interval: controls how soon the effect can be re-triggered
*/
struct ff_trigger {
uint16_t button;
uint16_t interval;
};
/**
* struct ff_envelope - generic force-feedback effect envelope
* @attack_length: duration of the attack (ms)
* @attack_level: level at the beginning of the attack
* @fade_length: duration of fade (ms)
* @fade_level: level at the end of fade
*
* The @attack_level and @fade_level are absolute values; when applying
* envelope force-feedback core will convert to positive/negative
* value based on polarity of the default level of the effect.
* Valid range for the attack and fade levels is 0x0000 - 0x7fff
*/
struct ff_envelope {
uint16_t attack_length;
uint16_t attack_level;
uint16_t fade_length;
uint16_t fade_level;
};
/**
* struct ff_constant_effect - defines parameters of a constant force-feedback effect
* @level: strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_constant_effect {
int16_t level;
struct ff_envelope envelope;
};
/**
* struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
* @start_level: beginning strength of the effect; may be negative
* @end_level: final strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_ramp_effect {
int16_t start_level;
int16_t end_level;
struct ff_envelope envelope;
};
/**
* struct ff_condition_effect - defines a spring or friction force-feedback effect
* @right_saturation: maximum level when joystick moved all way to the right
* @left_saturation: same for the left side
* @right_coeff: controls how fast the force grows when the joystick moves
* to the right
* @left_coeff: same for the left side
* @deadband: size of the dead zone, where no force is produced
* @center: position of the dead zone
*/
struct ff_condition_effect {
uint16_t right_saturation;
uint16_t left_saturation;
int16_t right_coeff;
int16_t left_coeff;
uint16_t deadband;
int16_t center;
};
/**
* struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
* @waveform: kind of the effect (wave)
* @period: period of the wave (ms)
* @magnitude: peak value
* @offset: mean value of the wave (roughly)
* @phase: 'horizontal' shift
* @envelope: envelope data
* @custom_len: number of samples (FF_CUSTOM only)
* @custom_data: buffer of samples (FF_CUSTOM only)
*
* Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
* FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
* for the time being as no driver supports it yet.
*
* Note: the data pointed by custom_data is copied by the driver.
* You can therefore dispose of the memory after the upload/update.
*/
struct ff_periodic_effect {
uint16_t waveform;
uint16_t period;
int16_t magnitude;
int16_t offset;
uint16_t phase;
struct ff_envelope envelope;
uint32_t custom_len;
int16_t *custom_data;
};
/**
* struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
* @strong_magnitude: magnitude of the heavy motor
* @weak_magnitude: magnitude of the light one
*
* Some rumble pads have two motors of different weight. Strong_magnitude
* represents the magnitude of the vibration generated by the heavy one.
*/
struct ff_rumble_effect {
uint16_t strong_magnitude;
uint16_t weak_magnitude;
};
/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
* @id: an unique id assigned to an effect
* @direction: direction of the effect
* @trigger: trigger conditions (struct ff_trigger)
* @replay: scheduling of the effect (struct ff_replay)
* @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
* ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
* defining effect parameters
*
* This structure is sent through ioctl from the application to the driver.
* To create a new effect application should set its @id to -1; the kernel
* will return assigned @id which can later be used to update or delete
* this effect.
*
* Direction of the effect is encoded as follows:
* 0 deg -> 0x0000 (down)
* 90 deg -> 0x4000 (left)
* 180 deg -> 0x8000 (up)
* 270 deg -> 0xC000 (right)
*/
struct ff_effect {
uint16_t type;
int16_t id;
uint16_t direction;
struct ff_trigger trigger;
struct ff_replay replay;
union {
struct ff_constant_effect constant;
struct ff_ramp_effect ramp;
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
} u;
};
/*
* Force feedback effect types
*/
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
#define FF_SPRING 0x53
#define FF_FRICTION 0x54
#define FF_DAMPER 0x55
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
#define FF_EFFECT_MIN FF_RUMBLE
#define FF_EFFECT_MAX FF_RAMP
/*
* Force feedback periodic effect types
*/
#define FF_SQUARE 0x58
#define FF_TRIANGLE 0x59
#define FF_SINE 0x5a
#define FF_SAW_UP 0x5b
#define FF_SAW_DOWN 0x5c
#define FF_CUSTOM 0x5d
#define FF_WAVEFORM_MIN FF_SQUARE
#define FF_WAVEFORM_MAX FF_CUSTOM
/*
* Set ff device properties
*/
#define FF_GAIN 0x60
#define FF_AUTOCENTER 0x61
/*
* ff->playback(effect_id = FF_GAIN) is the first effect_id to
* cause a collision with another ff method, in this case ff->set_gain().
* Therefore the greatest safe value for effect_id is FF_GAIN - 1,
* and thus the total number of effects should never exceed FF_GAIN.
*/
#define FF_MAX_EFFECTS FF_GAIN
#define FF_MAX 0x7f
#define FF_CNT (FF_MAX+1)
#endif /* _UAPI_INPUT_H */

View file

@ -0,0 +1,232 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_DEV_SETUP ioctl
* - add UI_ABS_SETUP ioctl
* - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
* - update ff support for the changes in kernel interface
* - add UINPUT_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support
* - added UI_SET_PHYS
* 0.1 20/06/2002
* - first public version
*/
#ifndef _UAPI__UINPUT_H_
#define _UAPI__UINPUT_H_
#include <sys/types.h>
#include <linux/input.h>
#define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload {
uint32_t request_id;
int32_t retval;
struct ff_effect effect;
struct ff_effect old;
};
struct uinput_ff_erase {
uint32_t request_id;
int32_t retval;
uint32_t effect_id;
};
/* ioctl */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
struct uinput_setup {
struct input_id id;
char name[UINPUT_MAX_NAME_SIZE];
uint32_t ff_effects_max;
};
/**
* UI_DEV_SETUP - Set device parameters for setup
*
* This ioctl sets parameters for the input device to be created. It
* supersedes the old "struct uinput_user_dev" method, which wrote this data
* via write(). To actually set the absolute axes UI_ABS_SETUP should be
* used.
*
* The ioctl takes a "struct uinput_setup" object as argument. The fields of
* this object are as follows:
* id: See the description of "struct input_id". This field is
* copied unchanged into the new device.
* name: This is used unchanged as name for the new device.
* ff_effects_max: This limits the maximum numbers of force-feedback effects.
* See below for a description of FF with uinput.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
struct uinput_abs_setup {
uint16_t code; /* axis code */
/* uint16_t filler; */
struct input_absinfo absinfo;
};
/**
* UI_ABS_SETUP - Set absolute axis information for the device to setup
*
* This ioctl sets one absolute axis information for the input device to be
* created. It supersedes the old "struct uinput_user_dev" method, which wrote
* part of this data and the content of UI_DEV_SETUP via write().
*
* The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
* of this object are as follows:
* code: The corresponding input code associated with this axis
* (ABS_X, ABS_Y, etc...)
* absinfo: See "struct input_absinfo" for a description of this field.
* This field is copied unchanged into the kernel for the
* specified axis. If the axis is not enabled via
* UI_SET_ABSBIT, this ioctl will enable it.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
#define UI_SET_EVBIT _IOWINT(UINPUT_IOCTL_BASE, 100)
#define UI_SET_KEYBIT _IOWINT(UINPUT_IOCTL_BASE, 101)
#define UI_SET_RELBIT _IOWINT(UINPUT_IOCTL_BASE, 102)
#define UI_SET_ABSBIT _IOWINT(UINPUT_IOCTL_BASE, 103)
#define UI_SET_MSCBIT _IOWINT(UINPUT_IOCTL_BASE, 104)
#define UI_SET_LEDBIT _IOWINT(UINPUT_IOCTL_BASE, 105)
#define UI_SET_SNDBIT _IOWINT(UINPUT_IOCTL_BASE, 106)
#define UI_SET_FFBIT _IOWINT(UINPUT_IOCTL_BASE, 107)
#define UI_SET_PHYS _IO(UINPUT_IOCTL_BASE, 108)
#define UI_SET_SWBIT _IOWINT(UINPUT_IOCTL_BASE, 109)
#define UI_SET_PROPBIT _IOWINT(UINPUT_IOCTL_BASE, 110)
#define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
#define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
/**
* UI_GET_SYSNAME - get the sysfs name of the created uinput device
*
* @return the sysfs name of the created virtual input device.
* The complete sysfs path is then /sys/devices/virtual/input/--NAME--
* Usually, it is in the form "inputN"
*/
#define UI_GET_SYSNAME(len) _IOC(IOC_OUT, UINPUT_IOCTL_BASE, 44, len)
/**
* UI_GET_VERSION - Return version of uinput protocol
*
* This writes uinput protocol version implemented by the kernel into
* the integer pointed to by the ioctl argument. The protocol version
* is hard-coded in the kernel and is independent of the uinput device.
*/
#define UI_GET_VERSION _IOR(UINPUT_IOCTL_BASE, 45, unsigned int)
/*
* To write a force-feedback-capable driver, the upload_effect
* and erase_effect callbacks in input_dev must be implemented.
* The uinput driver will generate a fake input event when one of
* these callbacks are invoked. The userspace code then uses
* ioctls to retrieve additional parameters and send the return code.
* The callback blocks until this return code is sent.
*
* The described callback mechanism is only used if ff_effects_max
* is set.
*
* To implement upload_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_upload struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
* uinput_ff_upload struct. It will be filled in with the
* ff_effects passed to upload_effect().
* 4. Perform the effect upload, and place a return code back into
the uinput_ff_upload struct.
* 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
* uinput_ff_upload_effect struct. This will complete execution
* of our upload_effect() handler.
*
* To implement erase_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_erase struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the
* uinput_ff_erase struct. It will be filled in with the
* effect ID passed to erase_effect().
* 4. Perform the effect erasure, and place a return code back
* into the uinput_ff_erase struct.
* 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
* uinput_ff_erase_effect struct. This will complete execution
* of our erase_effect() handler.
*/
/*
* This is the new event type, used only by uinput.
* 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
* is the unique request ID. This number was picked
* arbitrarily, above EV_MAX (since the input system
* never sees it) but in the range of a 16-bit int.
*/
#define EV_UINPUT 0x0101
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct input_id id;
uint32_t ff_effects_max;
int32_t absmax[ABS_CNT];
int32_t absmin[ABS_CNT];
int32_t absfuzz[ABS_CNT];
int32_t absflat[ABS_CNT];
};
#endif /* _UAPI__UINPUT_H_ */

View file

@ -1,486 +1,5 @@
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _INPUT_H
#define _INPUT_H
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/types.h>
#include "input-event-codes.h"
/*
* The event structure itself
*/
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
/*
* Protocol version.
*/
#define EV_VERSION 0x010001
/*
* IOCTLs (0x00 - 0x7f)
*/
struct input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};
/**
* struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
* @value: latest reported value for the axis.
* @minimum: specifies minimum value for the axis.
* @maximum: specifies maximum value for the axis.
* @fuzz: specifies fuzz value that is used to filter noise from
* the event stream.
* @flat: values that are within this value will be discarded by
* joydev interface and reported as 0 instead.
* @resolution: specifies resolution for the values reported for
* the axis.
*
* Note that input core does not clamp reported values to the
* [minimum, maximum] limits, such task is left to userspace.
*
* Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
* units per millimeter (units/mm), resolution for rotational axes
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
*/
struct input_absinfo {
__s32 value;
__s32 minimum;
__s32 maximum;
__s32 fuzz;
__s32 flat;
__s32 resolution;
};
/**
* struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
* @scancode: scancode represented in machine-endian form.
* @len: length of the scancode that resides in @scancode buffer.
* @index: index in the keymap, may be used instead of scancode
* @flags: allows to specify how kernel should handle the request. For
* example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
* should perform lookup in keymap by @index instead of @scancode
* @keycode: key code assigned to this scancode
*
* The structure is used to retrieve and modify keymap data. Users have
* option of performing lookup either by @scancode itself or by @index
* in keymap entry. EVIOCGKEYCODE will also return scancode or index
* (depending on which element was used to perform lookup).
*/
struct input_keymap_entry {
#define INPUT_KEYMAP_BY_INDEX (1 << 0)
__u8 flags;
__u8 len;
__u16 index;
__u32 keycode;
__u8 scancode[32];
};
struct input_mask {
__u32 type;
__u32 codes_size;
__u64 codes_ptr;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */
#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry)
#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */
#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry)
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */
/**
* EVIOCGMTSLOTS(len) - get MT slot values
* @len: size of the data buffer in bytes
*
* The ioctl buffer argument should be binary equivalent to
*
* struct input_mt_request_layout {
* __u32 code;
* __s32 values[num_slots];
* };
*
* where num_slots is the (arbitrary) number of MT slots to extract.
*
* The ioctl size argument (len) is the size of the buffer, which
* should satisfy len = (num_slots + 1) * sizeof(__s32). If len is
* too small to fit all available slots, the first num_slots are
* returned.
*
* Before the call, code is set to the wanted ABS_MT event type. On
* return, values[] is filled with the slot values for the specified
* ABS_MT code.
*
* If the request code is not an ABS_MT value, -EINVAL is returned.
*/
#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
#define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */
/**
* EVIOCGMASK - Retrieve current event mask
*
* This ioctl allows user to retrieve the current event mask for specific
* event type. The argument must be of type "struct input_mask" and
* specifies the event type to query, the address of the receive buffer and
* the size of the receive buffer.
*
* The event mask is a per-client mask that specifies which events are
* forwarded to the client. Each event code is represented by a single bit
* in the event mask. If the bit is set, the event is passed to the client
* normally. Otherwise, the event is filtered and will never be queued on
* the client's receive buffer.
*
* Event masks do not affect global state of the input device. They only
* affect the file descriptor they are applied to.
*
* The default event mask for a client has all bits set, i.e. all events
* are forwarded to the client. If the kernel is queried for an unknown
* event type or if the receive buffer is larger than the number of
* event codes known to the kernel, the kernel returns all zeroes for those
* codes.
*
* At maximum, codes_size bytes are copied.
*
* This ioctl may fail with ENODEV in case the file is revoked, EFAULT
* if the receive-buffer points to invalid memory, or EINVAL if the kernel
* does not implement the ioctl.
*/
#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */
/**
* EVIOCSMASK - Set event mask
*
* This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the
* current event mask, this changes the client's event mask for a specific
* type. See EVIOCGMASK for a description of event-masks and the
* argument-type.
*
* This ioctl provides full forward compatibility. If the passed event type
* is unknown to the kernel, or if the number of event codes specified in
* the mask is bigger than what is known to the kernel, the ioctl is still
* accepted and applied. However, any unknown codes are left untouched and
* stay cleared. That means, the kernel always filters unknown codes
* regardless of what the client requests. If the new mask doesn't cover
* all known event-codes, all remaining codes are automatically cleared and
* thus filtered.
*
* This ioctl may fail with ENODEV in case the file is revoked. EFAULT is
* returned if the receive-buffer points to invalid memory. EINVAL is returned
* if the kernel does not implement the ioctl.
*/
#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */
#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */
/*
* IDs.
*/
#define ID_BUS 0
#define ID_VENDOR 1
#define ID_PRODUCT 2
#define ID_VERSION 3
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
/*
* MT_TOOL types
*/
#define MT_TOOL_FINGER 0
#define MT_TOOL_PEN 1
#define MT_TOOL_PALM 2
#define MT_TOOL_MAX 2
/*
* Values describing the status of a force-feedback effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
#define FF_STATUS_MAX 0x01
/*
* Structures used in ioctls to upload effects to a device
* They are pieces of a bigger structure (called ff_effect)
*/
/*
* All duration values are expressed in ms. Values above 32767 ms (0x7fff)
* should not be used and have unspecified results.
*/
/**
* struct ff_replay - defines scheduling of the force-feedback effect
* @length: duration of the effect
* @delay: delay before effect should start playing
*/
struct ff_replay {
__u16 length;
__u16 delay;
};
/**
* struct ff_trigger - defines what triggers the force-feedback effect
* @button: number of the button triggering the effect
* @interval: controls how soon the effect can be re-triggered
*/
struct ff_trigger {
__u16 button;
__u16 interval;
};
/**
* struct ff_envelope - generic force-feedback effect envelope
* @attack_length: duration of the attack (ms)
* @attack_level: level at the beginning of the attack
* @fade_length: duration of fade (ms)
* @fade_level: level at the end of fade
*
* The @attack_level and @fade_level are absolute values; when applying
* envelope force-feedback core will convert to positive/negative
* value based on polarity of the default level of the effect.
* Valid range for the attack and fade levels is 0x0000 - 0x7fff
*/
struct ff_envelope {
__u16 attack_length;
__u16 attack_level;
__u16 fade_length;
__u16 fade_level;
};
/**
* struct ff_constant_effect - defines parameters of a constant force-feedback effect
* @level: strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_constant_effect {
__s16 level;
struct ff_envelope envelope;
};
/**
* struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
* @start_level: beginning strength of the effect; may be negative
* @end_level: final strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_ramp_effect {
__s16 start_level;
__s16 end_level;
struct ff_envelope envelope;
};
/**
* struct ff_condition_effect - defines a spring or friction force-feedback effect
* @right_saturation: maximum level when joystick moved all way to the right
* @left_saturation: same for the left side
* @right_coeff: controls how fast the force grows when the joystick moves
* to the right
* @left_coeff: same for the left side
* @deadband: size of the dead zone, where no force is produced
* @center: position of the dead zone
*/
struct ff_condition_effect {
__u16 right_saturation;
__u16 left_saturation;
__s16 right_coeff;
__s16 left_coeff;
__u16 deadband;
__s16 center;
};
/**
* struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
* @waveform: kind of the effect (wave)
* @period: period of the wave (ms)
* @magnitude: peak value
* @offset: mean value of the wave (roughly)
* @phase: 'horizontal' shift
* @envelope: envelope data
* @custom_len: number of samples (FF_CUSTOM only)
* @custom_data: buffer of samples (FF_CUSTOM only)
*
* Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
* FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
* for the time being as no driver supports it yet.
*
* Note: the data pointed by custom_data is copied by the driver.
* You can therefore dispose of the memory after the upload/update.
*/
struct ff_periodic_effect {
__u16 waveform;
__u16 period;
__s16 magnitude;
__s16 offset;
__u16 phase;
struct ff_envelope envelope;
__u32 custom_len;
__s16 *custom_data;
};
/**
* struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
* @strong_magnitude: magnitude of the heavy motor
* @weak_magnitude: magnitude of the light one
*
* Some rumble pads have two motors of different weight. Strong_magnitude
* represents the magnitude of the vibration generated by the heavy one.
*/
struct ff_rumble_effect {
__u16 strong_magnitude;
__u16 weak_magnitude;
};
/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
* @id: an unique id assigned to an effect
* @direction: direction of the effect
* @trigger: trigger conditions (struct ff_trigger)
* @replay: scheduling of the effect (struct ff_replay)
* @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
* ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
* defining effect parameters
*
* This structure is sent through ioctl from the application to the driver.
* To create a new effect application should set its @id to -1; the kernel
* will return assigned @id which can later be used to update or delete
* this effect.
*
* Direction of the effect is encoded as follows:
* 0 deg -> 0x0000 (down)
* 90 deg -> 0x4000 (left)
* 180 deg -> 0x8000 (up)
* 270 deg -> 0xC000 (right)
*/
struct ff_effect {
__u16 type;
__s16 id;
__u16 direction;
struct ff_trigger trigger;
struct ff_replay replay;
union {
struct ff_constant_effect constant;
struct ff_ramp_effect ramp;
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
} u;
};
/*
* Force feedback effect types
*/
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
#define FF_SPRING 0x53
#define FF_FRICTION 0x54
#define FF_DAMPER 0x55
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
#define FF_EFFECT_MIN FF_RUMBLE
#define FF_EFFECT_MAX FF_RAMP
/*
* Force feedback periodic effect types
*/
#define FF_SQUARE 0x58
#define FF_TRIANGLE 0x59
#define FF_SINE 0x5a
#define FF_SAW_UP 0x5b
#define FF_SAW_DOWN 0x5c
#define FF_CUSTOM 0x5d
#define FF_WAVEFORM_MIN FF_SQUARE
#define FF_WAVEFORM_MAX FF_CUSTOM
/*
* Set ff device properties
*/
#define FF_GAIN 0x60
#define FF_AUTOCENTER 0x61
/*
* ff->playback(effect_id = FF_GAIN) is the first effect_id to
* cause a collision with another ff method, in this case ff->set_gain().
* Therefore the greatest safe value for effect_id is FF_GAIN - 1,
* and thus the total number of effects should never exceed FF_GAIN.
*/
#define FF_MAX_EFFECTS FF_GAIN
#define FF_MAX 0x7f
#define FF_CNT (FF_MAX+1)
#endif /* _INPUT_H */
#ifdef __linux__
#include "linux/input.h"
#elif __FreeBSD__
#include "freebsd/input.h"
#endif

File diff suppressed because it is too large Load diff

539
include/linux/linux/input.h Normal file
View file

@ -0,0 +1,539 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _UAPI_INPUT_H
#define _UAPI_INPUT_H
#ifndef __KERNEL__
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/types.h>
#endif
#include "input-event-codes.h"
/*
* The event structure itself
* Note that __USE_TIME_BITS64 is defined by libc based on
* application's request to use 64 bit time_t.
*/
struct input_event {
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
__kernel_ulong_t __sec;
#if defined(__sparc__) && defined(__arch64__)
unsigned int __usec;
unsigned int __pad;
#else
__kernel_ulong_t __usec;
#endif
#define input_event_sec __sec
#define input_event_usec __usec
#endif
__u16 type;
__u16 code;
__s32 value;
};
/*
* Protocol version.
*/
#define EV_VERSION 0x010001
/*
* IOCTLs (0x00 - 0x7f)
*/
struct input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};
/**
* struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
* @value: latest reported value for the axis.
* @minimum: specifies minimum value for the axis.
* @maximum: specifies maximum value for the axis.
* @fuzz: specifies fuzz value that is used to filter noise from
* the event stream.
* @flat: values that are within this value will be discarded by
* joydev interface and reported as 0 instead.
* @resolution: specifies resolution for the values reported for
* the axis.
*
* Note that input core does not clamp reported values to the
* [minimum, maximum] limits, such task is left to userspace.
*
* The default resolution for main axes (ABS_X, ABS_Y, ABS_Z,
* ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units
* per millimeter (units/mm), resolution for rotational axes
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
* The resolution for the size axes (ABS_MT_TOUCH_MAJOR,
* ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR)
* is reported in units per millimeter (units/mm).
* When INPUT_PROP_ACCELEROMETER is set the resolution changes.
* The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
* units per g (units/g) and in units per degree per second
* (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ).
*/
struct input_absinfo {
__s32 value;
__s32 minimum;
__s32 maximum;
__s32 fuzz;
__s32 flat;
__s32 resolution;
};
/**
* struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
* @scancode: scancode represented in machine-endian form.
* @len: length of the scancode that resides in @scancode buffer.
* @index: index in the keymap, may be used instead of scancode
* @flags: allows to specify how kernel should handle the request. For
* example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
* should perform lookup in keymap by @index instead of @scancode
* @keycode: key code assigned to this scancode
*
* The structure is used to retrieve and modify keymap data. Users have
* option of performing lookup either by @scancode itself or by @index
* in keymap entry. EVIOCGKEYCODE will also return scancode or index
* (depending on which element was used to perform lookup).
*/
struct input_keymap_entry {
#define INPUT_KEYMAP_BY_INDEX (1 << 0)
__u8 flags;
__u8 len;
__u16 index;
__u32 keycode;
__u8 scancode[32];
};
struct input_mask {
__u32 type;
__u32 codes_size;
__u64 codes_ptr;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */
#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry)
#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */
#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry)
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */
/**
* EVIOCGMTSLOTS(len) - get MT slot values
* @len: size of the data buffer in bytes
*
* The ioctl buffer argument should be binary equivalent to
*
* struct input_mt_request_layout {
* __u32 code;
* __s32 values[num_slots];
* };
*
* where num_slots is the (arbitrary) number of MT slots to extract.
*
* The ioctl size argument (len) is the size of the buffer, which
* should satisfy len = (num_slots + 1) * sizeof(__s32). If len is
* too small to fit all available slots, the first num_slots are
* returned.
*
* Before the call, code is set to the wanted ABS_MT event type. On
* return, values[] is filled with the slot values for the specified
* ABS_MT code.
*
* If the request code is not an ABS_MT value, -EINVAL is returned.
*/
#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
#define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */
/**
* EVIOCGMASK - Retrieve current event mask
*
* This ioctl allows user to retrieve the current event mask for specific
* event type. The argument must be of type "struct input_mask" and
* specifies the event type to query, the address of the receive buffer and
* the size of the receive buffer.
*
* The event mask is a per-client mask that specifies which events are
* forwarded to the client. Each event code is represented by a single bit
* in the event mask. If the bit is set, the event is passed to the client
* normally. Otherwise, the event is filtered and will never be queued on
* the client's receive buffer.
*
* Event masks do not affect global state of the input device. They only
* affect the file descriptor they are applied to.
*
* The default event mask for a client has all bits set, i.e. all events
* are forwarded to the client. If the kernel is queried for an unknown
* event type or if the receive buffer is larger than the number of
* event codes known to the kernel, the kernel returns all zeroes for those
* codes.
*
* At maximum, codes_size bytes are copied.
*
* This ioctl may fail with ENODEV in case the file is revoked, EFAULT
* if the receive-buffer points to invalid memory, or EINVAL if the kernel
* does not implement the ioctl.
*/
#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */
/**
* EVIOCSMASK - Set event mask
*
* This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the
* current event mask, this changes the client's event mask for a specific
* type. See EVIOCGMASK for a description of event-masks and the
* argument-type.
*
* This ioctl provides full forward compatibility. If the passed event type
* is unknown to the kernel, or if the number of event codes specified in
* the mask is bigger than what is known to the kernel, the ioctl is still
* accepted and applied. However, any unknown codes are left untouched and
* stay cleared. That means, the kernel always filters unknown codes
* regardless of what the client requests. If the new mask doesn't cover
* all known event-codes, all remaining codes are automatically cleared and
* thus filtered.
*
* This ioctl may fail with ENODEV in case the file is revoked. EFAULT is
* returned if the receive-buffer points to invalid memory. EINVAL is returned
* if the kernel does not implement the ioctl.
*/
#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */
#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */
/*
* IDs.
*/
#define ID_BUS 0
#define ID_VENDOR 1
#define ID_PRODUCT 2
#define ID_VERSION 3
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
#define BUS_RMI 0x1D
#define BUS_CEC 0x1E
#define BUS_INTEL_ISHTP 0x1F
#define BUS_AMD_SFH 0x20
#define BUS_SDW 0x21
/*
* MT_TOOL types
*/
#define MT_TOOL_FINGER 0x00
#define MT_TOOL_PEN 0x01
#define MT_TOOL_PALM 0x02
#define MT_TOOL_DIAL 0x0a
#define MT_TOOL_MAX 0x0f
/*
* Values describing the status of a force-feedback effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
#define FF_STATUS_MAX 0x01
/*
* Structures used in ioctls to upload effects to a device
* They are pieces of a bigger structure (called ff_effect)
*/
/*
* All duration values are expressed in ms. Values above 32767 ms (0x7fff)
* should not be used and have unspecified results.
*/
/**
* struct ff_replay - defines scheduling of the force-feedback effect
* @length: duration of the effect
* @delay: delay before effect should start playing
*/
struct ff_replay {
__u16 length;
__u16 delay;
};
/**
* struct ff_trigger - defines what triggers the force-feedback effect
* @button: number of the button triggering the effect
* @interval: controls how soon the effect can be re-triggered
*/
struct ff_trigger {
__u16 button;
__u16 interval;
};
/**
* struct ff_envelope - generic force-feedback effect envelope
* @attack_length: duration of the attack (ms)
* @attack_level: level at the beginning of the attack
* @fade_length: duration of fade (ms)
* @fade_level: level at the end of fade
*
* The @attack_level and @fade_level are absolute values; when applying
* envelope force-feedback core will convert to positive/negative
* value based on polarity of the default level of the effect.
* Valid range for the attack and fade levels is 0x0000 - 0x7fff
*/
struct ff_envelope {
__u16 attack_length;
__u16 attack_level;
__u16 fade_length;
__u16 fade_level;
};
/**
* struct ff_constant_effect - defines parameters of a constant force-feedback effect
* @level: strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_constant_effect {
__s16 level;
struct ff_envelope envelope;
};
/**
* struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
* @start_level: beginning strength of the effect; may be negative
* @end_level: final strength of the effect; may be negative
* @envelope: envelope data
*/
struct ff_ramp_effect {
__s16 start_level;
__s16 end_level;
struct ff_envelope envelope;
};
/**
* struct ff_condition_effect - defines a spring or friction force-feedback effect
* @right_saturation: maximum level when joystick moved all way to the right
* @left_saturation: same for the left side
* @right_coeff: controls how fast the force grows when the joystick moves
* to the right
* @left_coeff: same for the left side
* @deadband: size of the dead zone, where no force is produced
* @center: position of the dead zone
*/
struct ff_condition_effect {
__u16 right_saturation;
__u16 left_saturation;
__s16 right_coeff;
__s16 left_coeff;
__u16 deadband;
__s16 center;
};
/**
* struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
* @waveform: kind of the effect (wave)
* @period: period of the wave (ms)
* @magnitude: peak value
* @offset: mean value of the wave (roughly)
* @phase: 'horizontal' shift
* @envelope: envelope data
* @custom_len: number of samples (FF_CUSTOM only)
* @custom_data: buffer of samples (FF_CUSTOM only)
*
* Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
* FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
* for the time being as no driver supports it yet.
*
* Note: the data pointed by custom_data is copied by the driver.
* You can therefore dispose of the memory after the upload/update.
*/
struct ff_periodic_effect {
__u16 waveform;
__u16 period;
__s16 magnitude;
__s16 offset;
__u16 phase;
struct ff_envelope envelope;
__u32 custom_len;
__s16 *custom_data;
};
/**
* struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
* @strong_magnitude: magnitude of the heavy motor
* @weak_magnitude: magnitude of the light one
*
* Some rumble pads have two motors of different weight. Strong_magnitude
* represents the magnitude of the vibration generated by the heavy one.
*/
struct ff_rumble_effect {
__u16 strong_magnitude;
__u16 weak_magnitude;
};
/**
* struct ff_haptic_effect
* @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.)
* @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined range
* @vendor_waveform_page: the vendor waveform page if hid_usage is in the vendor-defined range
* @intensity: strength of the effect as percentage
* @repeat_count: number of times to retrigger effect
* @retrigger_period: time before effect is retriggered (in ms)
*/
struct ff_haptic_effect {
__u16 hid_usage;
__u16 vendor_id;
__u8 vendor_waveform_page;
__u16 intensity;
__u16 repeat_count;
__u16 retrigger_period;
};
/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
* @id: an unique id assigned to an effect
* @direction: direction of the effect
* @trigger: trigger conditions (struct ff_trigger)
* @replay: scheduling of the effect (struct ff_replay)
* @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
* ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
* defining effect parameters
*
* This structure is sent through ioctl from the application to the driver.
* To create a new effect application should set its @id to -1; the kernel
* will return assigned @id which can later be used to update or delete
* this effect.
*
* Direction of the effect is encoded as follows:
* 0 deg -> 0x0000 (down)
* 90 deg -> 0x4000 (left)
* 180 deg -> 0x8000 (up)
* 270 deg -> 0xC000 (right)
*/
struct ff_effect {
__u16 type;
__s16 id;
__u16 direction;
struct ff_trigger trigger;
struct ff_replay replay;
union {
struct ff_constant_effect constant;
struct ff_ramp_effect ramp;
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
struct ff_haptic_effect haptic;
} u;
};
/*
* Force feedback effect types
*/
#define FF_HAPTIC 0x4f
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
#define FF_SPRING 0x53
#define FF_FRICTION 0x54
#define FF_DAMPER 0x55
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
#define FF_EFFECT_MIN FF_HAPTIC
#define FF_EFFECT_MAX FF_RAMP
/*
* Force feedback periodic effect types
*/
#define FF_SQUARE 0x58
#define FF_TRIANGLE 0x59
#define FF_SINE 0x5a
#define FF_SAW_UP 0x5b
#define FF_SAW_DOWN 0x5c
#define FF_CUSTOM 0x5d
#define FF_WAVEFORM_MIN FF_SQUARE
#define FF_WAVEFORM_MAX FF_CUSTOM
/*
* Set ff device properties
*/
#define FF_GAIN 0x60
#define FF_AUTOCENTER 0x61
/*
* ff->playback(effect_id = FF_GAIN) is the first effect_id to
* cause a collision with another ff method, in this case ff->set_gain().
* Therefore the greatest safe value for effect_id is FF_GAIN - 1,
* and thus the total number of effects should never exceed FF_GAIN.
*/
#define FF_MAX_EFFECTS FF_GAIN
#define FF_MAX 0x7f
#define FF_CNT (FF_MAX+1)
#endif /* _UAPI_INPUT_H */

View file

@ -0,0 +1,231 @@
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_DEV_SETUP ioctl
* - add UI_ABS_SETUP ioctl
* - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
* - update ff support for the changes in kernel interface
* - add UINPUT_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support
* - added UI_SET_PHYS
* 0.1 20/06/2002
* - first public version
*/
#ifndef __UINPUT_H_
#define __UINPUT_H_
#include <linux/types.h>
#include <linux/input.h>
#define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload {
__u32 request_id;
__s32 retval;
struct ff_effect effect;
struct ff_effect old;
};
struct uinput_ff_erase {
__u32 request_id;
__s32 retval;
__u32 effect_id;
};
/* ioctl */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
struct uinput_setup {
struct input_id id;
char name[UINPUT_MAX_NAME_SIZE];
__u32 ff_effects_max;
};
/**
* UI_DEV_SETUP - Set device parameters for setup
*
* This ioctl sets parameters for the input device to be created. It
* supersedes the old "struct uinput_user_dev" method, which wrote this data
* via write(). To actually set the absolute axes UI_ABS_SETUP should be
* used.
*
* The ioctl takes a "struct uinput_setup" object as argument. The fields of
* this object are as follows:
* id: See the description of "struct input_id". This field is
* copied unchanged into the new device.
* name: This is used unchanged as name for the new device.
* ff_effects_max: This limits the maximum numbers of force-feedback effects.
* See below for a description of FF with uinput.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
struct uinput_abs_setup {
__u16 code; /* axis code */
/* __u16 filler; */
struct input_absinfo absinfo;
};
/**
* UI_ABS_SETUP - Set absolute axis information for the device to setup
*
* This ioctl sets one absolute axis information for the input device to be
* created. It supersedes the old "struct uinput_user_dev" method, which wrote
* part of this data and the content of UI_DEV_SETUP via write().
*
* The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
* of this object are as follows:
* code: The corresponding input code associated with this axis
* (ABS_X, ABS_Y, etc...)
* absinfo: See "struct input_absinfo" for a description of this field.
* This field is copied unchanged into the kernel for the
* specified axis. If the axis is not enabled via
* UI_SET_ABSBIT, this ioctl will enable it.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
#define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
#define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
#define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
/**
* UI_GET_SYSNAME - get the sysfs name of the created uinput device
*
* @return the sysfs name of the created virtual input device.
* The complete sysfs path is then /sys/devices/virtual/input/--NAME--
* Usually, it is in the form "inputN"
*/
#define UI_GET_SYSNAME(len) _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len)
/**
* UI_GET_VERSION - Return version of uinput protocol
*
* This writes uinput protocol version implemented by the kernel into
* the integer pointed to by the ioctl argument. The protocol version
* is hard-coded in the kernel and is independent of the uinput device.
*/
#define UI_GET_VERSION _IOR(UINPUT_IOCTL_BASE, 45, unsigned int)
/*
* To write a force-feedback-capable driver, the upload_effect
* and erase_effect callbacks in input_dev must be implemented.
* The uinput driver will generate a fake input event when one of
* these callbacks are invoked. The userspace code then uses
* ioctls to retrieve additional parameters and send the return code.
* The callback blocks until this return code is sent.
*
* The described callback mechanism is only used if ff_effects_max
* is set.
*
* To implement upload_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_upload struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
* uinput_ff_upload struct. It will be filled in with the
* ff_effects passed to upload_effect().
* 4. Perform the effect upload, and place a return code back into
the uinput_ff_upload struct.
* 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
* uinput_ff_upload_effect struct. This will complete execution
* of our upload_effect() handler.
*
* To implement erase_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_erase struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the
* uinput_ff_erase struct. It will be filled in with the
* effect ID passed to erase_effect().
* 4. Perform the effect erasure, and place a return code back
* into the uinput_ff_erase struct.
* 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
* uinput_ff_erase_effect struct. This will complete execution
* of our erase_effect() handler.
*/
/*
* This is the new event type, used only by uinput.
* 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
* is the unique request ID. This number was picked
* arbitrarily, above EV_MAX (since the input system
* never sees it) but in the range of a 16-bit int.
*/
#define EV_UINPUT 0x0101
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct input_id id;
__u32 ff_effects_max;
__s32 absmax[ABS_CNT];
__s32 absmin[ABS_CNT];
__s32 absfuzz[ABS_CNT];
__s32 absflat[ABS_CNT];
};
#endif /* __UINPUT_H_ */

View file

@ -1,231 +1,5 @@
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_DEV_SETUP ioctl
* - add UI_ABS_SETUP ioctl
* - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
* - update ff support for the changes in kernel interface
* - add UINPUT_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support
* - added UI_SET_PHYS
* 0.1 20/06/2002
* - first public version
*/
#ifndef __UINPUT_H_
#define __UINPUT_H_
#include <linux/types.h>
#include <linux/input.h>
#define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload {
__u32 request_id;
__s32 retval;
struct ff_effect effect;
struct ff_effect old;
};
struct uinput_ff_erase {
__u32 request_id;
__s32 retval;
__u32 effect_id;
};
/* ioctl */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
struct uinput_setup {
struct input_id id;
char name[UINPUT_MAX_NAME_SIZE];
__u32 ff_effects_max;
};
/**
* UI_DEV_SETUP - Set device parameters for setup
*
* This ioctl sets parameters for the input device to be created. It
* supersedes the old "struct uinput_user_dev" method, which wrote this data
* via write(). To actually set the absolute axes UI_ABS_SETUP should be
* used.
*
* The ioctl takes a "struct uinput_setup" object as argument. The fields of
* this object are as follows:
* id: See the description of "struct input_id". This field is
* copied unchanged into the new device.
* name: This is used unchanged as name for the new device.
* ff_effects_max: This limits the maximum numbers of force-feedback effects.
* See below for a description of FF with uinput.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
struct uinput_abs_setup {
__u16 code; /* axis code */
/* __u16 filler; */
struct input_absinfo absinfo;
};
/**
* UI_ABS_SETUP - Set absolute axis information for the device to setup
*
* This ioctl sets one absolute axis information for the input device to be
* created. It supersedes the old "struct uinput_user_dev" method, which wrote
* part of this data and the content of UI_DEV_SETUP via write().
*
* The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
* of this object are as follows:
* code: The corresponding input code associated with this axis
* (ABS_X, ABS_Y, etc...)
* absinfo: See "struct input_absinfo" for a description of this field.
* This field is copied unchanged into the kernel for the
* specified axis. If the axis is not enabled via
* UI_SET_ABSBIT, this ioctl will enable it.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
#define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
#define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
#define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
/**
* UI_GET_SYSNAME - get the sysfs name of the created uinput device
*
* @return the sysfs name of the created virtual input device.
* The complete sysfs path is then /sys/devices/virtual/input/--NAME--
* Usually, it is in the form "inputN"
*/
#define UI_GET_SYSNAME(len) _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len)
/**
* UI_GET_VERSION - Return version of uinput protocol
*
* This writes uinput protocol version implemented by the kernel into
* the integer pointed to by the ioctl argument. The protocol version
* is hard-coded in the kernel and is independent of the uinput device.
*/
#define UI_GET_VERSION _IOR(UINPUT_IOCTL_BASE, 45, unsigned int)
/*
* To write a force-feedback-capable driver, the upload_effect
* and erase_effect callbacks in input_dev must be implemented.
* The uinput driver will generate a fake input event when one of
* these callbacks are invoked. The userspace code then uses
* ioctls to retrieve additional parameters and send the return code.
* The callback blocks until this return code is sent.
*
* The described callback mechanism is only used if ff_effects_max
* is set.
*
* To implement upload_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_upload struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
* uinput_ff_upload struct. It will be filled in with the
* ff_effects passed to upload_effect().
* 4. Perform the effect upload, and place a return code back into
the uinput_ff_upload struct.
* 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
* uinput_ff_upload_effect struct. This will complete execution
* of our upload_effect() handler.
*
* To implement erase_effect():
* 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_erase struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the
* uinput_ff_erase struct. It will be filled in with the
* effect ID passed to erase_effect().
* 4. Perform the effect erasure, and place a return code back
* into the uinput_ff_erase struct.
* 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
* uinput_ff_erase_effect struct. This will complete execution
* of our erase_effect() handler.
*/
/*
* This is the new event type, used only by uinput.
* 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
* is the unique request ID. This number was picked
* arbitrarily, above EV_MAX (since the input system
* never sees it) but in the range of a 16-bit int.
*/
#define EV_UINPUT 0x0101
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct input_id id;
__u32 ff_effects_max;
__s32 absmax[ABS_CNT];
__s32 absmin[ABS_CNT];
__s32 absfuzz[ABS_CNT];
__s32 absflat[ABS_CNT];
};
#endif /* __UINPUT_H_ */
#ifdef __linux__
#include "linux/uinput.h"
#elif __FreeBSD__
#include "freebsd/uinput.h"
#endif

View file

@ -1,6 +1,7 @@
lib_LTLIBRARIES=libevdev.la
AM_CPPFLAGS = $(GCC_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)
AM_CPPFLAGS = $(GCC_CFLAGS) $(GCOV_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)
AM_LDFLAGS = $(GCOV_LDFLAGS)
libevdev_la_SOURCES = \
libevdev.h \
@ -11,11 +12,14 @@ libevdev_la_SOURCES = \
libevdev-uinput-int.h \
libevdev.c \
libevdev-names.c \
../include/linux/input-event-codes.h \
../include/linux/input.h
../include/linux/uinput.h
../include/linux/input.h \
../include/linux/uinput.h \
../include/linux/@OS@/input-event-codes.h \
../include/linux/@OS@/input.h \
../include/linux/@OS@/uinput.h
libevdev_la_LDFLAGS = \
$(AM_LDFLAGS) \
-version-info $(LIBEVDEV_LT_VERSION) \
-Wl,--version-script="$(srcdir)/libevdev.sym" \
$(GNU_LD_FLAGS)
@ -26,10 +30,13 @@ libevdevincludedir = $(includedir)/libevdev-1.0/libevdev
libevdevinclude_HEADERS = libevdev.h libevdev-uinput.h
event-names.h: Makefile make-event-names.py
$(CAT) $(top_srcdir)/include/linux/input.h $(top_srcdir)/include/linux/input-event-codes.h | $(PYTHON) $(srcdir)/make-event-names.py > $@
$(PYTHON) $(srcdir)/make-event-names.py $(top_srcdir)/include/linux/@OS@/input.h $(top_srcdir)/include/linux/@OS@/input-event-codes.h > $@
EXTRA_DIST = make-event-names.py libevdev.sym
EXTRA_DIST = make-event-names.py libevdev.sym ../include
CLEANFILES = event-names.h
BUILT_SOURCES = event-names.h
if GCOV_ENABLED
CLEANFILES += *.gcno
endif

View file

@ -1,29 +1,12 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
#ifndef LIBEVDEV_INT_H
#define LIBEVDEV_INT_H
#include <config.h>
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -55,11 +38,6 @@ enum SyncState {
SYNC_IN_PROGRESS,
};
struct mt_sync_state {
int code;
int val[];
};
/**
* Internal only: log data used to send messages to the respective log
* handler. We re-use the same struct for a global and inside
@ -112,15 +90,6 @@ struct libevdev {
struct timeval last_event_time;
struct {
struct mt_sync_state *mt_state;
size_t mt_state_sz; /* in bytes */
unsigned long *slot_update;
size_t slot_update_sz; /* in bytes */
unsigned long *tracking_id_changes;
size_t tracking_id_changes_sz; /* in bytes */
} mt_sync;
struct logdata log;
};
@ -143,6 +112,16 @@ _libevdev_log_msg(const struct libevdev *dev,
extern enum libevdev_log_priority
_libevdev_log_priority(const struct libevdev *dev);
static inline void
init_event(struct libevdev *dev, struct input_event *ev, int type, int code, int value)
{
ev->input_event_sec = dev->last_event_time.tv_sec;
ev->input_event_usec = dev->last_event_time.tv_usec;
ev->type = type;
ev->code = code;
ev->value = value;
}
/**
* @return a pointer to the next element in the queue, or NULL if the queue
* is full.
@ -156,6 +135,18 @@ queue_push(struct libevdev *dev)
return &dev->queue[dev->queue_next++];
}
static inline bool
queue_push_event(struct libevdev *dev, unsigned int type,
unsigned int code, int value)
{
struct input_event *ev = queue_push(dev);
if (ev)
init_event(dev, ev, type, code, value);
return ev != NULL;
}
/**
* Set ev to the last element in the queue, removing it from the queue.
*

View file

@ -1,34 +1,18 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
*
* 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "libevdev.h"
#include "libevdev-int.h"
#include "libevdev-util.h"
#include "libevdev.h"
#include "event-names.h"
struct name_lookup {
@ -142,6 +126,29 @@ libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len)
return entry ? (int)entry->value : -1;
}
LIBEVDEV_EXPORT int
libevdev_event_value_from_name(unsigned int type, unsigned int code, const char *name)
{
return libevdev_event_value_from_name_n(type, code, name, strlen(name));
}
LIBEVDEV_EXPORT int
libevdev_event_value_from_name_n(unsigned int type, unsigned int code, const char *name, size_t len)
{
struct name_lookup lookup;
const struct name_entry *entry;
if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
return -1;
lookup.name = name;
lookup.len = len;
entry = lookup_name(tool_type_names, ARRAY_LENGTH(tool_type_names), &lookup);
return entry ? (int)entry->value : -1;
}
LIBEVDEV_EXPORT int
libevdev_property_from_name(const char *name)
{
@ -161,3 +168,46 @@ libevdev_property_from_name_n(const char *name, size_t len)
return entry ? (int)entry->value : -1;
}
LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name(const char *name)
{
return libevdev_event_code_from_code_name_n(name, strlen(name));
}
LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name_n(const char *name, size_t len)
{
const struct name_entry *entry;
struct name_lookup lookup;
/* now look up the name @name and return the constant */
lookup.name = name;
lookup.len = len;
entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
return entry ? (int)entry->value : -1;
}
LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name(const char *name)
{
return libevdev_event_type_from_code_name_n(name, strlen(name));
}
LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name_n(const char *name, size_t len)
{
const struct name_entry *entry;
struct name_lookup lookup;
/* First look up if the name exists, we dont' want to return a valid
* type for an invalid code name */
lookup.name = name;
lookup.len = len;
entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
return entry ? type_from_prefix(name, len) : -1;
}

View file

@ -1,23 +1,6 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
struct libevdev_uinput {

View file

@ -1,44 +1,25 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <linux/uinput.h>
#include <unistd.h>
#include "libevdev.h"
#include "libevdev-int.h"
#include "libevdev-uinput.h"
#include "libevdev-uinput-int.h"
#include "libevdev-uinput.h"
#include "libevdev-util.h"
#define SYS_INPUT_DIR "/sys/devices/virtual/input/"
#include "libevdev.h"
#ifndef UINPUT_IOCTL_BASE
#define UINPUT_IOCTL_BASE 'U'
@ -182,6 +163,35 @@ libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev)
return uinput_dev->fd;
}
#ifdef __FreeBSD__
/*
* FreeBSD does not have anything similar to sysfs.
* Set libevdev_uinput->syspath to NULL unconditionally.
* Look up the device nodes directly instead of via sysfs, as this matches what
* is returned by the UI_GET_SYSNAME ioctl() on FreeBSD.
*/
static int
fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
{
#define DEV_INPUT_DIR "/dev/input/"
int rc;
char buf[sizeof(DEV_INPUT_DIR) + 64] = DEV_INPUT_DIR;
rc = ioctl(uinput_dev->fd,
UI_GET_SYSNAME(sizeof(buf) - strlen(DEV_INPUT_DIR)),
&buf[strlen(DEV_INPUT_DIR)]);
if (rc == -1)
return -1;
uinput_dev->syspath = NULL;
uinput_dev->devnode = strdup(buf);
return 0;
#undef DEV_INPUT_DIR
}
#else /* !__FreeBSD__ */
static int is_event_device(const struct dirent *dent) {
return strncmp("event", dent->d_name, 5) == 0;
}
@ -217,6 +227,7 @@ static int is_input_device(const struct dirent *dent) {
static int
fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
{
#define SYS_INPUT_DIR "/sys/devices/virtual/input/"
struct dirent **namelist;
int ndev, i;
int rc;
@ -270,18 +281,19 @@ fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
/* FIXME: could descend into bit comparison here */
log_info(NULL, "multiple identical devices found. syspath is unreliable\n");
break;
} else {
rc = snprintf(buf, sizeof(buf), "%s%s",
SYS_INPUT_DIR,
namelist[i]->d_name);
if (rc < 0 || (size_t)rc >= sizeof(buf)) {
log_error(NULL, "Invalid syspath, syspath is unreliable\n");
break;
}
uinput_dev->syspath = strdup(buf);
uinput_dev->devnode = fetch_device_node(buf);
}
rc = snprintf(buf, sizeof(buf), "%s%s",
SYS_INPUT_DIR,
namelist[i]->d_name);
if (rc < 0 || (size_t)rc >= sizeof(buf)) {
log_error(NULL, "Invalid syspath, syspath is unreliable\n");
break;
}
uinput_dev->syspath = strdup(buf);
uinput_dev->devnode = fetch_device_node(buf);
}
}
@ -290,11 +302,12 @@ fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
free(namelist);
return uinput_dev->devnode ? 0 : -1;
#undef SYS_INPUT_DIR
}
#endif /* __FreeBSD__*/
static int
uinput_create_write(const struct libevdev *dev, int fd,
struct libevdev_uinput *new_device)
uinput_create_write(const struct libevdev *dev, int fd)
{
int rc;
struct uinput_user_dev uidev;
@ -313,9 +326,9 @@ uinput_create_write(const struct libevdev *dev, int fd,
goto error;
rc = write(fd, &uidev, sizeof(uidev));
if (rc < 0)
if (rc < 0) {
goto error;
else if ((size_t)rc < sizeof(uidev)) {
} else if ((size_t)rc < sizeof(uidev)) {
errno = EINVAL;
goto error;
}
@ -381,7 +394,7 @@ libevdev_uinput_create_from_device(const struct libevdev *dev, int fd, struct li
uinput_version >= 5)
rc = uinput_create_DEV_SETUP(dev, fd, new_device);
else
rc = uinput_create_write(dev, fd, new_device);
rc = uinput_create_write(dev, fd);
if (rc != 0)
goto error;
@ -455,7 +468,13 @@ libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev,
unsigned int code,
int value)
{
struct input_event ev = { {0,0}, type, code, value };
struct input_event ev = {
.input_event_sec = 0,
.input_event_usec = 0,
.type = type,
.code = code,
.value = value
};
int fd = libevdev_uinput_get_fd(uinput_dev);
int rc, max;

View file

@ -1,23 +1,25 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef LIBEVDEV_UINPUT_H
@ -40,21 +42,20 @@ struct libevdev_uinput;
*
* @code
* int err;
* int fd, new_fd, uifd;
* int fd, uifd;
* struct libevdev *dev;
* struct libevdev_uinput *uidev;
* struct input_event ev[2];
*
* fd = open("/dev/input/event0", O_RDONLY);
* if (fd < 0)
* return err;
* return -errno;
*
* err = libevdev_new_from_fd(fd, &dev);
* if (err != 0)
* return err;
*
* uifd = open("/dev/uinput", O_RDWR);
* if (uidev < 0)
* if (uifd < 0)
* return -errno;
*
* err = libevdev_uinput_create_from_device(dev, uifd, &uidev);
@ -65,7 +66,7 @@ struct libevdev_uinput;
* err = libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1);
* if (err != 0)
* return err;
* libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
* err = libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
* if (err != 0)
* return err;
*
@ -107,7 +108,7 @@ struct libevdev_uinput;
*/
enum libevdev_uinput_open_mode {
/* intentionally -2 to avoid to avoid code like the below from accidentally working:
/* intentionally -2 to avoid code like below from accidentally working:
fd = open("/dev/uinput", O_RDWR); // fails, fd is -1
libevdev_uinput_create_from_device(dev, fd, &uidev); // may hide the error */
LIBEVDEV_UINPUT_OPEN_MANAGED = -2 /**< let libevdev open and close @c /dev/uinput */
@ -138,6 +139,9 @@ enum libevdev_uinput_open_mode {
* REP_PERIOD will default to the kernel defaults, not to the ones set in the
* source device.
*
* @note On FreeBSD, if the UI_GET_SYSNAME ioctl() fails, there is no other way
* to get a device, and the function call will fail.
*
* @param dev The device to duplicate
* @param uinput_fd @ref LIBEVDEV_UINPUT_OPEN_MANAGED or a file descriptor to @c /dev/uinput,
* @param[out] uinput_dev The newly created libevdev device.
@ -183,13 +187,21 @@ int libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev);
* @ingroup uinput
*
* Return the syspath representing this uinput device. If the UI_GET_SYSNAME
* ioctl not available, libevdev makes an educated guess.
* ioctl is not available, libevdev makes an educated guess.
* The UI_GET_SYSNAME ioctl is available since Linux 3.15.
*
* The syspath returned is the one of the input node itself
* (e.g. /sys/devices/virtual/input/input123), not the syspath of the device
* node returned with libevdev_uinput_get_devnode().
*
* @note This function may return NULL if UI_GET_SYSNAME is not available.
* In that case, libevdev uses ctime and the device name to guess devices.
* To avoid false positives, wait at least wait at least 1.5s between
* creating devices that have the same name.
* To avoid false positives, wait at least 1.5s between creating devices that
* have the same name.
*
* @note FreeBSD does not have sysfs, on FreeBSD this function always returns
* NULL.
*
* @param uinput_dev A previously created uinput device.
* @return The syspath for this device, including the preceding /sys
*
@ -207,6 +219,11 @@ const char* libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev);
*
* @note This function may return NULL. libevdev may have to guess the
* syspath and the device node. See libevdev_uinput_get_syspath() for details.
*
* @note On FreeBSD, this function can not return NULL. libudev uses the
* UI_GET_SYSNAME ioctl to get the device node on this platform and if that
* fails, the call to libevdev_uinput_create_from_device() fails.
*
* @param uinput_dev A previously created uinput device.
* @return The device node for this device, in the form of /dev/input/eventN
*

View file

@ -1,29 +1,12 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
#ifndef _UTIL_H_
#define _UTIL_H_
#include <config.h>
#include "config.h"
#include <stdbool.h>
#include <string.h>
@ -34,6 +17,7 @@
#undef min
#undef max
#ifdef __GNUC__
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
@ -44,6 +28,10 @@
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; \
})
#else
#define min(a,b) ((a) > (b) ? (b) : (a))
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
static inline bool
startswith(const char *str, size_t len, const char *prefix, size_t plen)
@ -54,19 +42,19 @@ startswith(const char *str, size_t len, const char *prefix, size_t plen)
static inline int
bit_is_set(const unsigned long *array, int bit)
{
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
return !!(array[bit / LONG_BITS] & (1ULL << (bit % LONG_BITS)));
}
static inline void
set_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS));
array[bit / LONG_BITS] |= (1ULL << (bit % LONG_BITS));
}
static inline void
clear_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS));
array[bit / LONG_BITS] &= ~(1ULL << (bit % LONG_BITS));
}
static inline void

View file

@ -1,38 +1,23 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <errno.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <poll.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libevdev.h"
#include "libevdev-int.h"
#include "libevdev-util.h"
#include "libevdev.h"
#include "event-names.h"
#define MAXEVENTS 64
@ -43,7 +28,26 @@ enum event_filter_status {
EVENT_FILTER_DISCARD, /**< Discard current event */
};
static int sync_mt_state(struct libevdev *dev, int create_events);
/* Keeps a record of touches during SYN_DROPPED */
enum touch_state {
TOUCH_OFF,
TOUCH_STARTED, /* Started during SYN_DROPPED */
TOUCH_STOPPED, /* Stopped during SYN_DROPPED */
TOUCH_ONGOING, /* Existed before, still have same tracking ID */
TOUCH_CHANGED, /* Existed before but have new tracking ID now, so
stopped + started in that slot */
};
struct slot_change_state {
enum touch_state state;
unsigned long axes[NLONGS(ABS_CNT)]; /* bitmask for updated axes */
};
static int sync_mt_state(struct libevdev *dev,
struct slot_change_state changes_out[dev->num_slots]);
static int
update_key_state(struct libevdev *dev, const struct input_event *e);
static inline int*
slot_value(const struct libevdev *dev, int slot, int axis)
@ -176,10 +180,11 @@ _libevdev_log_msg(const struct libevdev *dev,
if (priority > dev->log.priority)
return;
} else if (!log_data.global_handler || priority > log_data.priority)
} else if (!log_data.global_handler || priority > log_data.priority) {
return;
else if (unlikely(log_data.device_handler))
} else if (unlikely(log_data.device_handler)) {
abort(); /* Seppuku, see above */
}
va_start(args, format);
if (dev && dev->log.device_handler)
@ -199,9 +204,6 @@ libevdev_reset(struct libevdev *dev)
free(dev->phys);
free(dev->uniq);
free(dev->mt_slot_vals);
free(dev->mt_sync.mt_state);
free(dev->mt_sync.tracking_id_changes);
free(dev->mt_sync.slot_update);
memset(dev, 0, sizeof(*dev));
dev->fd = -1;
dev->initialized = false;
@ -299,8 +301,7 @@ _libevdev_log_priority(const struct libevdev *dev)
{
if (dev && dev->log.device_handler)
return dev->log.priority;
else
return libevdev_get_log_priority();
return libevdev_get_log_priority();
}
LIBEVDEV_EXPORT int
@ -311,9 +312,65 @@ libevdev_change_fd(struct libevdev *dev, int fd)
return -1;
}
dev->fd = fd;
dev->grabbed = LIBEVDEV_UNGRAB;
return 0;
}
static void
reset_tracking_ids(struct libevdev *dev)
{
if (dev->num_slots == -1 ||
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_TRACKING_ID))
return;
for (int slot = 0; slot < dev->num_slots; slot++)
libevdev_set_slot_value(dev, slot, ABS_MT_TRACKING_ID, -1);
}
static inline void
free_slots(struct libevdev *dev)
{
dev->num_slots = -1;
free(dev->mt_slot_vals);
dev->mt_slot_vals = NULL;
}
static int
init_slots(struct libevdev *dev)
{
const struct input_absinfo *abs_info;
int rc = 0;
free(dev->mt_slot_vals);
dev->mt_slot_vals = NULL;
/* devices with ABS_RESERVED aren't MT devices,
see the documentation for multitouch-related
functions for more details */
if (libevdev_has_event_code(dev, EV_ABS, ABS_RESERVED) ||
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
if (dev->num_slots != -1) {
free_slots(dev);
}
return rc;
}
abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT);
free_slots(dev);
dev->num_slots = abs_info->maximum + 1;
dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int));
if (!dev->mt_slot_vals) {
rc = -ENOMEM;
goto out;
}
dev->current_slot = abs_info->value;
reset_tracking_ids(dev);
out:
return rc;
}
LIBEVDEV_EXPORT int
libevdev_set_fd(struct libevdev* dev, int fd)
{
@ -324,8 +381,11 @@ libevdev_set_fd(struct libevdev* dev, int fd)
if (dev->initialized) {
log_bug(dev, "device already initialized.\n");
return -EBADF;
} else if (fd < 0)
}
if (fd < 0) {
return -EBADF;
}
libevdev_reset(dev);
@ -460,41 +520,13 @@ libevdev_set_fd(struct libevdev* dev, int fd)
dev->fd = fd;
/* devices with ABS_MT_SLOT - 1 aren't MT devices,
see the documentation for multitouch-related
functions for more details */
if (!libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT - 1) &&
libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
const struct input_absinfo *abs_info;
rc = init_slots(dev);
if (rc != 0)
goto out;
abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT);
dev->num_slots = abs_info->maximum + 1;
dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int));
if (!dev->mt_slot_vals) {
rc = -ENOMEM;
goto out;
}
dev->current_slot = abs_info->value;
dev->mt_sync.mt_state_sz = sizeof(*dev->mt_sync.mt_state) +
(dev->num_slots) * sizeof(int);
dev->mt_sync.mt_state = calloc(1, dev->mt_sync.mt_state_sz);
dev->mt_sync.tracking_id_changes_sz = NLONGS(dev->num_slots) * sizeof(long);
dev->mt_sync.tracking_id_changes = malloc(dev->mt_sync.tracking_id_changes_sz);
dev->mt_sync.slot_update_sz = NLONGS(dev->num_slots * ABS_MT_CNT) * sizeof(long);
dev->mt_sync.slot_update = malloc(dev->mt_sync.slot_update_sz);
if (!dev->mt_sync.tracking_id_changes ||
!dev->mt_sync.slot_update ||
!dev->mt_sync.mt_state) {
rc = -ENOMEM;
goto out;
}
sync_mt_state(dev, 0);
if (dev->num_slots != -1) {
struct slot_change_state unused[dev->num_slots];
sync_mt_state(dev, unused);
}
rc = init_event_queue(dev);
@ -521,15 +553,6 @@ libevdev_get_fd(const struct libevdev* dev)
return dev->fd;
}
static inline void
init_event(struct libevdev *dev, struct input_event *ev, int type, int code, int value)
{
ev->time = dev->last_event_time;
ev->type = type;
ev->code = code;
ev->value = value;
}
static int
sync_key_state(struct libevdev *dev)
{
@ -545,10 +568,8 @@ sync_key_state(struct libevdev *dev)
int old, new;
old = bit_is_set(dev->key_values, i);
new = bit_is_set(keystate, i);
if (old ^ new) {
struct input_event *ev = queue_push(dev);
init_event(dev, ev, EV_KEY, i, new ? 1 : 0);
}
if (old ^ new)
queue_push_event(dev, EV_KEY, i, new ? 1 : 0);
}
memcpy(dev->key_values, keystate, rc);
@ -573,10 +594,8 @@ sync_sw_state(struct libevdev *dev)
int old, new;
old = bit_is_set(dev->sw_values, i);
new = bit_is_set(swstate, i);
if (old ^ new) {
struct input_event *ev = queue_push(dev);
init_event(dev, ev, EV_SW, i, new ? 1 : 0);
}
if (old ^ new)
queue_push_event(dev, EV_SW, i, new ? 1 : 0);
}
memcpy(dev->sw_values, swstate, rc);
@ -602,8 +621,7 @@ sync_led_state(struct libevdev *dev)
old = bit_is_set(dev->led_values, i);
new = bit_is_set(ledstate, i);
if (old ^ new) {
struct input_event *ev = queue_push(dev);
init_event(dev, ev, EV_LED, i, new ? 1 : 0);
queue_push_event(dev, EV_LED, i, new ? 1 : 0);
}
}
@ -633,9 +651,7 @@ sync_abs_state(struct libevdev *dev)
goto out;
if (dev->abs_info[i].value != abs_info.value) {
struct input_event *ev = queue_push(dev);
init_event(dev, ev, EV_ABS, i, abs_info.value);
queue_push_event(dev, EV_ABS, i, abs_info.value);
dev->abs_info[i].value = abs_info.value;
}
}
@ -646,105 +662,176 @@ out:
}
static int
sync_mt_state(struct libevdev *dev, int create_events)
sync_mt_state(struct libevdev *dev,
struct slot_change_state changes_out[dev->num_slots])
{
struct input_event *ev;
struct input_absinfo abs_info;
int rc;
int axis, slot;
int ioctl_success = 0;
int last_reported_slot = 0;
struct mt_sync_state *mt_state = dev->mt_sync.mt_state;
unsigned long *slot_update = dev->mt_sync.slot_update;
unsigned long *tracking_id_changes = dev->mt_sync.tracking_id_changes;
int need_tracking_id_changes = 0;
#define MAX_SLOTS 256
int rc = 0;
struct slot_change_state changes[MAX_SLOTS] = {0};
unsigned int nslots = min(MAX_SLOTS, dev->num_slots);
memset(dev->mt_sync.slot_update, 0, dev->mt_sync.slot_update_sz);
memset(dev->mt_sync.tracking_id_changes, 0,
dev->mt_sync.tracking_id_changes_sz);
for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
/* EVIOCGMTSLOTS required format */
struct mt_sync_state {
uint32_t code;
int32_t val[MAX_SLOTS];
} mt_state;
#define AXISBIT(_slot, _axis) (_slot * ABS_MT_CNT + _axis - ABS_MT_MIN)
for (axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
if (axis == ABS_MT_SLOT)
if (axis == ABS_MT_SLOT ||
!libevdev_has_event_code(dev, EV_ABS, axis))
continue;
if (!libevdev_has_event_code(dev, EV_ABS, axis))
continue;
mt_state.code = axis;
rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(mt_state)), &mt_state);
if (rc < 0)
goto out;
mt_state->code = axis;
rc = ioctl(dev->fd, EVIOCGMTSLOTS(dev->mt_sync.mt_state_sz), mt_state);
if (rc < 0) {
/* if the first ioctl fails with -EINVAL, chances are the kernel
doesn't support the ioctl. Simply continue */
if (errno == -EINVAL && !ioctl_success) {
rc = 0;
} else /* if the second, ... ioctl fails, really fail */
goto out;
} else {
if (ioctl_success == 0)
ioctl_success = 1;
for (unsigned int slot = 0; slot < nslots; slot++) {
int val_before = *slot_value(dev, slot, axis),
val_after = mt_state.val[slot];
for (slot = 0; slot < dev->num_slots; slot++) {
if (*slot_value(dev, slot, axis) == mt_state->val[slot])
continue;
if (axis == ABS_MT_TRACKING_ID &&
*slot_value(dev, slot, axis) != -1 &&
mt_state->val[slot] != -1) {
set_bit(tracking_id_changes, slot);
need_tracking_id_changes = 1;
if (axis == ABS_MT_TRACKING_ID) {
if (val_before == -1 && val_after != -1) {
changes[slot].state = TOUCH_STARTED;
} else if (val_before != -1 && val_after == -1) {
changes[slot].state = TOUCH_STOPPED;
} else if (val_before != -1 && val_after != -1 &&
val_before == val_after) {
changes[slot].state = TOUCH_ONGOING;
} else if (val_before != -1 && val_after != -1 &&
val_before != val_after) {
changes[slot].state = TOUCH_CHANGED;
} else {
changes[slot].state = TOUCH_OFF;
}
*slot_value(dev, slot, axis) = mt_state->val[slot];
set_bit(slot_update, AXISBIT(slot, axis));
/* note that this slot has updates */
set_bit(slot_update, AXISBIT(slot, ABS_MT_SLOT));
}
}
}
if (!create_events) {
rc = 0;
goto out;
}
if (need_tracking_id_changes) {
for (slot = 0; slot < dev->num_slots; slot++) {
if (!bit_is_set(tracking_id_changes, slot))
if (val_before == val_after)
continue;
ev = queue_push(dev);
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, slot);
ev = queue_push(dev);
init_event(dev, ev, EV_ABS, ABS_MT_TRACKING_ID, -1);
*slot_value(dev, slot, axis) = val_after;
last_reported_slot = slot;
set_bit(changes[slot].axes, axis);
/* note that this slot has updates */
set_bit(changes[slot].axes, ABS_MT_SLOT);
}
ev = queue_push(dev);
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
}
for (slot = 0; slot < dev->num_slots; slot++) {
if (!bit_is_set(slot_update, AXISBIT(slot, ABS_MT_SLOT)))
if (dev->num_slots > MAX_SLOTS)
memset(changes_out, 0, sizeof(*changes) * dev->num_slots);
memcpy(changes_out, changes, sizeof(*changes) * nslots);
out:
return rc;
}
static void
terminate_slots(struct libevdev *dev,
const struct slot_change_state changes[dev->num_slots],
int *last_reported_slot)
{
const unsigned int map[] = {BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP,
BTN_TOOL_QUINTTAP};
bool touches_stopped = false;
int ntouches_before = 0, ntouches_after = 0;
/* For BTN_TOOL_* emulation, we need to know how many touches we had
* before and how many we have left once we terminate all the ones
* that changed and all the ones that stopped.
*/
for (int slot = 0; slot < dev->num_slots; slot++) {
switch(changes[slot].state) {
case TOUCH_OFF:
break;
case TOUCH_CHANGED:
case TOUCH_STOPPED:
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot);
queue_push_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
*last_reported_slot = slot;
touches_stopped = true;
ntouches_before++;
break;
case TOUCH_ONGOING:
ntouches_before++;
ntouches_after++;
break;
case TOUCH_STARTED:
break;
}
}
/* If any of the touches stopped, we need to split the sync state
into two frames - one with all the stopped touches, one with the
new touches starting (if any) */
if (touches_stopped) {
/* Send through the required BTN_TOOL_ 0 and 1 events for
* the previous and current number of fingers. And update
* our own key state accordingly, so that during the second
* sync event frame sync_key_state() sets everything correctly
* for the *real* number of touches.
*/
if (ntouches_before > 0 && ntouches_before <= 5) {
struct input_event ev = {
.type = EV_KEY,
.code = map[ntouches_before - 1],
.value = 0,
};
queue_push_event(dev, ev.type, ev.code, ev.value);
update_key_state(dev, &ev);
}
if (ntouches_after > 0 && ntouches_after <= 5) {
struct input_event ev = {
.type = EV_KEY,
.code = map[ntouches_after - 1],
.value = 1,
};
queue_push_event(dev, ev.type, ev.code, ev.value);
update_key_state(dev, &ev);
}
queue_push_event(dev, EV_SYN, SYN_REPORT, 0);
}
}
static int
push_mt_sync_events(struct libevdev *dev,
const struct slot_change_state changes[dev->num_slots],
int last_reported_slot)
{
struct input_absinfo abs_info;
int rc;
for (int slot = 0; slot < dev->num_slots; slot++) {
bool have_slot_event = false;
if (!bit_is_set(changes[slot].axes, ABS_MT_SLOT))
continue;
ev = queue_push(dev);
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, slot);
last_reported_slot = slot;
for (axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
if (axis == ABS_MT_SLOT ||
!libevdev_has_event_code(dev, EV_ABS, axis))
continue;
if (bit_is_set(slot_update, AXISBIT(slot, axis))) {
ev = queue_push(dev);
init_event(dev, ev, EV_ABS, axis, *slot_value(dev, slot, axis));
if (bit_is_set(changes[slot].axes, axis)) {
/* We already sent the tracking id -1 in
* terminate_slots so don't do that again. There
* may be other axes like ABS_MT_TOOL_TYPE that
* need to be synced despite no touch being active */
if (axis == ABS_MT_TRACKING_ID &&
*slot_value(dev, slot, axis) == -1)
continue;
if (!have_slot_event) {
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot);
last_reported_slot = slot;
have_slot_event = true;
}
queue_push_event(dev, EV_ABS, axis,
*slot_value(dev, slot, axis));
}
}
}
@ -758,12 +845,8 @@ sync_mt_state(struct libevdev *dev, int create_events)
dev->current_slot = abs_info.value;
if (dev->current_slot != last_reported_slot) {
ev = queue_push(dev);
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, dev->current_slot);
}
#undef AXISBIT
if (dev->current_slot != last_reported_slot)
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, dev->current_slot);
rc = 0;
out:
@ -783,11 +866,13 @@ read_more_events(struct libevdev *dev)
next = queue_next_element(dev);
len = read(dev->fd, next, free_elem * sizeof(struct input_event));
if (len < 0) {
if (len < 0)
return -errno;
} else if (len > 0 && len % sizeof(struct input_event) != 0)
if (len > 0 && len % sizeof(struct input_event) != 0)
return -EINVAL;
else if (len > 0) {
if (len > 0) {
int nev = len/sizeof(struct input_event);
queue_set_num_elements(dev, queue_num_elements(dev) + nev);
}
@ -834,12 +919,35 @@ static int
sync_state(struct libevdev *dev)
{
int rc = 0;
struct input_event *ev;
bool want_mt_sync = false;
int last_reported_slot = 0;
struct slot_change_state changes[dev->num_slots > 0 ? dev->num_slots : 1];
memset(changes, 0, sizeof(changes));
/* see section "Discarding events before synchronizing" in
* libevdev/libevdev.h */
drain_events(dev);
/* We generate one or two event frames during sync.
* The first one (if it exists) terminates all slots that have
* either terminated during SYN_DROPPED or changed their tracking
* ID.
*
* The second frame syncs everything up to the current state of the
* device - including re-starting those slots that have a changed
* tracking id.
*/
if (dev->num_slots > -1 &&
libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
want_mt_sync = true;
rc = sync_mt_state(dev, changes);
if (rc == 0)
terminate_slots(dev, changes, &last_reported_slot);
else
want_mt_sync = false;
}
if (libevdev_has_event_type(dev, EV_KEY))
rc = sync_key_state(dev);
if (libevdev_has_event_type(dev, EV_LED))
@ -848,15 +956,13 @@ sync_state(struct libevdev *dev)
rc = sync_sw_state(dev);
if (rc == 0 && libevdev_has_event_type(dev, EV_ABS))
rc = sync_abs_state(dev);
if (rc == 0 && dev->num_slots > -1 &&
libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT))
rc = sync_mt_state(dev, 1);
if (rc == 0 && want_mt_sync)
push_mt_sync_events(dev, changes, last_reported_slot);
dev->queue_nsync = queue_num_elements(dev);
if (dev->queue_nsync > 0) {
ev = queue_push(dev);
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
queue_push_event(dev, EV_SYN, SYN_REPORT, 0);
dev->queue_nsync++;
}
@ -890,7 +996,9 @@ update_mt_state(struct libevdev *dev, const struct input_event *e)
}
return 0;
} else if (dev->current_slot == -1)
}
if (dev->current_slot == -1)
return 1;
*slot_value(dev, dev->current_slot, e->code) = e->value;
@ -966,7 +1074,8 @@ update_state(struct libevdev *dev, const struct input_event *e)
break;
}
dev->last_event_time = e->time;
dev->last_event_time.tv_sec = e->input_event_sec;
dev->last_event_time.tv_usec = e->input_event_usec;
return rc;
}
@ -979,6 +1088,9 @@ sanitize_event(const struct libevdev *dev,
struct input_event *ev,
enum SyncState sync_state)
{
if (!libevdev_has_event_code(dev, ev->type, ev->code))
return EVENT_FILTER_DISCARD;
if (unlikely(dev->num_slots > -1 &&
libevdev_event_is_code(ev, EV_ABS, ABS_MT_SLOT) &&
(ev->value < 0 || ev->value >= dev->num_slots))) {
@ -992,7 +1104,9 @@ sanitize_event(const struct libevdev *dev,
N to -1 or from -1 to N. Never from -1 to -1, or N to M. Very
unlikely to ever happen from a real device.
*/
} else if (unlikely(sync_state == SYNC_NONE &&
}
if (unlikely(sync_state == SYNC_NONE &&
dev->num_slots > -1 &&
libevdev_event_is_code(ev, EV_ABS, ABS_MT_TRACKING_ID) &&
((ev->value == -1 &&
@ -1020,7 +1134,9 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
if ((flags & valid_flags) == 0) {
@ -1062,8 +1178,7 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
read in any more.
*/
do {
if (!(flags & LIBEVDEV_READ_FLAG_BLOCKING) ||
queue_num_elements(dev) == 0) {
if (queue_num_elements(dev) == 0) {
rc = read_more_events(dev);
if (rc < 0 && rc != -EAGAIN)
goto out;
@ -1095,15 +1210,8 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
if (flags & LIBEVDEV_READ_FLAG_SYNC && dev->queue_nsync > 0) {
dev->queue_nsync--;
rc = LIBEVDEV_READ_STATUS_SYNC;
if (dev->queue_nsync == 0) {
struct input_event next;
if (dev->queue_nsync == 0)
dev->sync_state = SYNC_NONE;
if (queue_peek(dev, 0, &next) == 0 &&
next.type == EV_SYN && next.code == SYN_DROPPED)
log_info(dev, "SYN_DROPPED received after finished "
"sync - you're not keeping up\n");
}
}
out:
@ -1119,7 +1227,9 @@ libevdev_has_event_pending(struct libevdev *dev)
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
if (queue_num_elements(dev) != 0)
@ -1204,6 +1314,16 @@ libevdev_enable_property(struct libevdev *dev, unsigned int prop)
return 0;
}
LIBEVDEV_EXPORT int
libevdev_disable_property(struct libevdev *dev, unsigned int prop)
{
if (prop > INPUT_PROP_MAX)
return -1;
clear_bit(dev->props, prop);
return 0;
}
LIBEVDEV_EXPORT int
libevdev_has_event_type(const struct libevdev *dev, unsigned int type)
{
@ -1300,8 +1420,9 @@ libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsign
libevdev_has_event_code(dev, type, code)) {
*value = libevdev_get_event_value(dev, type, code);
return 1;
} else
return 0;
}
return 0;
}
LIBEVDEV_EXPORT int
@ -1351,8 +1472,9 @@ libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigne
slot < (unsigned int)dev->num_slots) {
*value = libevdev_get_slot_value(dev, slot, code);
return 1;
} else
return 0;
}
return 0;
}
LIBEVDEV_EXPORT int
@ -1489,6 +1611,12 @@ libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
if (type == EV_ABS) {
const struct input_absinfo *abs = data;
dev->abs_info[code] = *abs;
if (code == ABS_MT_SLOT) {
if (init_slots(dev) != 0)
return -1;
} else if (code == ABS_MT_TRACKING_ID) {
reset_tracking_ids(dev);
}
} else if (type == EV_REP) {
const int *value = data;
dev->rep_values[code] = *value;
@ -1513,6 +1641,15 @@ libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned in
clear_bit(mask, code);
if (type == EV_ABS) {
if (code == ABS_MT_SLOT) {
if (init_slots(dev) != 0)
return -1;
} else if (code == ABS_MT_TRACKING_ID) {
reset_tracking_ids(dev);
}
}
return 0;
}
@ -1524,7 +1661,9 @@ libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const stru
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
if (code > ABS_MAX)
@ -1547,7 +1686,9 @@ libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab)
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB) {
@ -1607,6 +1748,23 @@ libevdev_event_code_get_name(unsigned int type, unsigned int code)
return event_type_map[type][code];
}
LIBEVDEV_EXPORT const char *
libevdev_event_value_get_name(unsigned int type,
unsigned int code,
int value)
{
/* This is a simplified version because nothing else
is an enum like ABS_MT_TOOL_TYPE so we don't need
a generic lookup */
if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
return NULL;
if (value < 0 || value > MT_TOOL_MAX)
return NULL;
return mt_tool_map[value];
}
LIBEVDEV_EXPORT const char*
libevdev_property_get_name(unsigned int prop)
{
@ -1658,7 +1816,9 @@ libevdev_kernel_set_led_values(struct libevdev *dev, ...)
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
memset(ev, 0, sizeof(ev));
@ -1714,7 +1874,9 @@ libevdev_set_clock_id(struct libevdev *dev, int clockid)
if (!dev->initialized) {
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
return -EBADF;
} else if (dev->fd < 0)
}
if (dev->fd < 0)
return -EBADF;
return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0;

View file

@ -1,23 +1,26 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
#ifndef LIBEVDEV_H
@ -39,23 +42,29 @@ extern "C" {
* the \ref ioctls through type-safe interfaces and provides functions to change
* the appearance of the device.
*
* Development
* ===========
* The git repository is available here:
*
* - https://gitlab.freedesktop.org/libevdev/libevdev
*
* Development of libevdev is discussed on
* [input-tools@lists.freedesktop.org](http://lists.freedesktop.org/mailman/listinfo/input-tools)
* [input-tools@lists.freedesktop.org](http://lists.freedesktop.org/mailman/listinfo/input-tools).
* Please submit patches, questions or general comments there.
*
* Handling events and SYN_DROPPED
* ===============================
*
* libevdev provides an interface for handling events, including most notably
* SYN_DROPPED events. SYN_DROPPED events are sent by the kernel when the
* `SYN_DROPPED` events. `SYN_DROPPED` events are sent by the kernel when the
* process does not read events fast enough and the kernel is forced to drop
* some events. This causes the device to get out of sync with the process'
* view of it. libevdev handles this by telling the caller that a SYN_DROPPED
* view of it. libevdev handles this by telling the caller that a * `SYN_DROPPED`
* has been received and that the state of the device is different to what is
* to be expected. It then provides the delta between the previous state and
* the actual state of the device as a set of events. See
* libevdev_next_event() and @ref syn_dropped for more information on how
* SYN_DROPPED is handled.
* `SYN_DROPPED` is handled.
*
* Signal safety
* =============
@ -78,7 +87,7 @@ extern "C" {
*
* libevdev does not handle the file descriptors directly, it merely uses
* them. The caller is responsible for opening the file descriptors, setting
* them to O_NONBLOCK and handling permissions. A caller should drain any
* them to `O_NONBLOCK` and handling permissions. A caller should drain any
* events pending on the file descriptor before passing it to libevdev.
*
* Where does libevdev sit?
@ -95,9 +104,10 @@ extern "C" {
*
* kernel libevdev xf86-input-evdev X server X client
*
* For Weston/Wayland, the stack would look like this:
* For anything using libinput (e.g. most Wayland compositors), the stack
* the stack would look like this:
*
* kernel libevdev Weston Wayland client
* kernel libevdev libinput Compositor Wayland client
*
* libevdev does **not** have knowledge of X clients or Wayland clients, it is
* too low in the stack.
@ -135,14 +145,14 @@ extern "C" {
* rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
* if (rc == 0)
* printf("Event: %s %s %d\n",
* libevdev_get_event_type_name(ev.type),
* libevdev_get_event_code_name(ev.type, ev.code),
* libevdev_event_type_get_name(ev.type),
* libevdev_event_code_get_name(ev.type, ev.code),
* ev.value);
* } while (rc == 1 || rc == 0 || rc == -EAGAIN);
* @endcode
*
* A more complete example is available with the libevdev-events tool here:
* http://cgit.freedesktop.org/libevdev/tree/tools/libevdev-events.c
* https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c
*
* Backwards compatibility with older kernel
* =========================================
@ -153,25 +163,31 @@ extern "C" {
* License information
* ===================
* libevdev is licensed under the
* [X11 license](http://cgit.freedesktop.org/libevdev/tree/COPYING).
* [MIT license](http://cgit.freedesktop.org/libevdev/tree/COPYING).
*
* Bindings
* ===================
* - Python: https://gitlab.freedesktop.org/libevdev/python-libevdev
* - Haskell: http://hackage.haskell.org/package/evdev
* - Rust: https://crates.io/crates/evdev-rs
*
* Reporting bugs
* ==============
* Please report bugs in the freedesktop.org bugzilla under the libevdev product:
* https://bugs.freedesktop.org/enter_bug.cgi?product=libevdev
* Please report bugs in the freedesktop.org GitLab instance:
* https://gitlab.freedesktop.org/libevdev/libevdev/issues/
*/
/**
* @page syn_dropped SYN_DROPPED handling
*
* This page describes how libevdev handles SYN_DROPPED events.
* This page describes how libevdev handles `SYN_DROPPED` events.
*
* Receiving SYN_DROPPED events
* ============================
* Receiving `SYN_DROPPED` events
* ==============================
*
* The kernel sends evdev events separated by an event of type EV_SYN and
* code SYN_REPORT. Such an event marks the end of a frame of hardware
* events. The number of events between SYN_REPORT events is arbitrary and
* The kernel sends evdev events separated by an event of type `EV_SYN` and
* code `SYN_REPORT`. Such an event marks the end of a frame of hardware
* events. The number of events between `SYN_REPORT` events is arbitrary and
* depends on the hardware. An example event sequence may look like this:
* @code
* EV_ABS ABS_X 9
@ -191,7 +207,7 @@ extern "C" {
* the buffer size to handle at least one full event. In the normal case,
* the client reads the event and the kernel can place the next event in the
* buffer. If the client is not fast enough, the kernel places an event of
* type EV_SYN and code SYN_DROPPED into the buffer, effectively notifying
* type `EV_SYN` and code `SYN_DROPPED` into the buffer, effectively notifying
* the client that some events were lost. The above example event sequence
* may look like this (note the missing/repeated events):
* @code
@ -210,19 +226,19 @@ extern "C" {
* EV_SYN SYN_REPORT 0
* @endcode
*
* A SYN_DROPPED event may be recieved at any time in the event sequence.
* When a SYN_DROPPED event is received, the client must:
* * discard all events since the last SYN_REPORT
* * discard all events until including the next SYN_REPORT
* A `SYN_DROPPED` event may be recieved at any time in the event sequence.
* When a `SYN_DROPPED` event is received, the client must:
* * discard all events since the last `SYN_REPORT`
* * discard all events until including the next `SYN_REPORT`
* These event are part of incomplete event frames.
*
* Synchronizing the state of the device
* =====================================
*
* The handling of the device after a SYN_DROPPED depends on the available
* event codes. For all event codes of type EV_REL, no handling is
* The handling of the device after a `SYN_DROPPED` depends on the available
* event codes. For all event codes of type `EV_REL`, no handling is
* necessary, there is no state attached. For all event codes of type
* EV_KEY, EV_SW, EV_LED and EV_SND, the matching @ref ioctls retrieve the
* `EV_KEY`, `EV_SW`, `EV_LED` and `EV_SND`, the matching @ref ioctls retrieve the
* current state. The caller must then compare the last-known state to the
* retrieved state and handle the deltas accordingly.
* libevdev simplifies this approach: if the state of the device has
@ -230,12 +246,12 @@ extern "C" {
* passes it to the caller during libevdev_next_event() if
* @ref LIBEVDEV_READ_FLAG_SYNC is set.
*
* For events of type EV_ABS and an event code less than ABS_MT_SLOT, the
* For events of type `EV_ABS` and an event code less than `ABS_MT_SLOT`, the
* handling of state changes is as described above. For events between
* ABS_MT_SLOT and ABS_MAX, the event handling differs.
* `ABS_MT_SLOT` and `ABS_MAX`, the event handling differs.
* Slots are the vehicles to transport information for multiple simultaneous
* touchpoints on a device. Slots are re-used once a touchpoint has ended.
* The kernel sends an ABS_MT_SLOT event whenever the current slot
* The kernel sends an `ABS_MT_SLOT` event whenever the current slot
* changes; any event in the above axis range applies only to the currently
* active slot.
* Thus, an event sequence from a slot-capable device may look like this:
@ -246,24 +262,24 @@ extern "C" {
* EV_ABS ABS_MT_POSITION_Y 80
* EV_SYN SYN_REPORT 0
* @endcode
* Note the lack of ABS_MT_SLOT: the first ABS_MT_POSITION_Y applies to
* Note the lack of `ABS_MT_SLOT`: the first `ABS_MT_POSITION_Y` applies to
* a slot opened previously, and is the only axis that changed for that
* slot. The touchpoint in slot 1 now has position 100/80.
* slot. The touchpoint in slot 1 now has position `100/80`.
* The kernel does not provide events if a value does not change, and does
* not send ABS_MT_SLOT events if the slot does not change, or none of the
* not send `ABS_MT_SLOT` events if the slot does not change, or none of the
* values within a slot changes. A client must thus keep the state for each
* slot.
*
* If a SYN_DROPPED is received, the client must sync all slots
* If a `SYN_DROPPED` is received, the client must sync all slots
* individually and update its internal state. libevdev simplifies this by
* generating multiple events:
* * for each slot on the device, libevdev generates an
* ABS_MT_SLOT event with the value set to the slot number
* * for each event code between ABS_MT_SLOT + 1 and ABS_MAX that changed
* `ABS_MT_SLOT` event with the value set to the slot number
* * for each event code between `ABS_MT_SLOT + 1` and `ABS_MAX` that changed
* state for this slot, libevdev generates an event for the new state
* * libevdev sends a final ABS_MT_SLOT event for the current slot as
* * libevdev sends a final `ABS_MT_SLOT` event for the current slot as
* seen by the kernel
* * libevdev terminates this sequence with an EV_SYN SYN_REPORT event
* * libevdev terminates this sequence with an `EV_SYN SYN_REPORT` event
*
* An example event sequence for such a sync may look like this:
* @code
@ -278,26 +294,26 @@ extern "C" {
* EV_ABS ABS_MT_SLOT 1
* EV_SYN SYN_REPORT 0
* @endcode
* Note the terminating ABS_MT_SLOT event, this indicates that the kernel
* Note the terminating `ABS_MT_SLOT` event, this indicates that the kernel
* currently has slot 1 active.
*
* Synchronizing ABS_MT_TRACKING_ID
* ================================
*
* The event code ABS_MT_TRACKING_ID is used to denote the start and end of
* a touch point within a slot. An ABS_MT_TRACKING_ID of zero or greater
* denotes the start of a touchpoint, an ABS_MT_TRACKING_ID of -1 denotes
* the end of a touchpoint within this slot. During SYN_DROPPED, a touch
* The event code `ABS_MT_TRACKING_ID` is used to denote the start and end of
* a touch point within a slot. An `ABS_MT_TRACKING_ID` of zero or greater
* denotes the start of a touchpoint, an `ABS_MT_TRACKING_ID` of -1 denotes
* the end of a touchpoint within this slot. During `SYN_DROPPED`, a touch
* point may have ended and re-started within a slot - a client must check
* the ABS_MT_TRACKING_ID. libevdev simplifies this by emulating extra
* events if the ABS_MT_TRACKING_ID has changed:
* * if the ABS_MT_TRACKING_ID was valid and is -1, libevdev enqueues an
* ABS_MT_TRACKING_ID event with value -1.
* * if the ABS_MT_TRACKING_ID was -1 and is now a valid ID, libevdev
* enqueues an ABS_MT_TRACKING_ID event with the current value.
* * if the ABS_MT_TRACKING_ID was a valid ID and is now a different valid
* ID, libevev enqueues an ABS_MT_TRACKING_ID event with value -1 and
* another ABS_MT_TRACKING_ID event with the new value.
* the `ABS_MT_TRACKING_ID`. libevdev simplifies this by emulating extra
* events if the `ABS_MT_TRACKING_ID` has changed:
* * if the `ABS_MT_TRACKING_ID` was valid and is -1, libevdev enqueues an
* `ABS_MT_TRACKING_ID` event with value -1.
* * if the `ABS_MT_TRACKING_ID` was -1 and is now a valid ID, libevdev
* enqueues an `ABS_MT_TRACKING_ID` event with the current value.
* * if the `ABS_MT_TRACKING_ID` was a valid ID and is now a different valid
* ID, libevev enqueues an `ABS_MT_TRACKING_ID` event with value -1 and
* another `ABS_MT_TRACKING_ID` event with the new value.
*
* An example event sequence for such a sync may look like this:
* @code
@ -318,14 +334,14 @@ extern "C" {
* EV_SYN SYN_REPORT 0
* @endcode
* Note how the touchpoint in slot 0 was terminated, the touchpoint in slot
* 2 was terminated and then started with a new ABS_MT_TRACKING_ID. The touchpoint
* in slot 1 maintained the same ABS_MT_TRACKING_ID and only updated the
* 2 was terminated and then started with a new `ABS_MT_TRACKING_ID`. The touchpoint
* in slot 1 maintained the same `ABS_MT_TRACKING_ID` and only updated the
* coordinates. Slot 1 is the currently active slot.
*
* In the case of a SYN_DROPPED event, a touch point may be invisible to a
* client if it started after SYN_DROPPED and finished before the client
* In the case of a `SYN_DROPPED` event, a touch point may be invisible to a
* client if it started after `SYN_DROPPED` and finished before the client
* handles events again. The below example shows an example event sequence
* and what libevdev sees in the case of a SYN_DROPPED event:
* and what libevdev sees in the case of a `SYN_DROPPED` event:
* @code
*
* kernel | userspace
@ -349,7 +365,7 @@ extern "C" {
* @endcode
* If such an event sequence occurs, libevdev will send all updated axes
* during the sync process. Axis events may thus be generated for devices
* without a currently valid ABS_MT_TRACKING_ID. Specifically for the above
* without a currently valid `ABS_MT_TRACKING_ID`. Specifically for the above
* example, the client would receive the following event sequence:
* @code
* EV_ABS ABS_MT_SLOT 0 LIBEVDEV_READ_FLAG_NORMAL
@ -375,15 +391,15 @@ extern "C" {
* Discarding events before synchronizing
* =====================================
*
* The kernel implements the client buffer as a ring buffer. SYN_DROPPED
* The kernel implements the client buffer as a ring buffer. `SYN_DROPPED`
* events are handled when the buffer is full and a new event is received
* from a device. All existing events are discarded, a SYN_DROPPED is added
* from a device. All existing events are discarded, a `SYN_DROPPED` is added
* to the buffer followed by the actual device event. Further events will be
* appended to the buffer until it is either read by the client, or filled
* again, at which point the sequence repeats.
*
* When the client reads the buffer, the buffer will thus always consist of
* exactly one SYN_DROPPED event followed by an unspecified number of real
* exactly one `SYN_DROPPED` event followed by an unspecified number of real
* events. The data the ioctls return is the current state of the device,
* i.e. the state after all these events have been processed. For example,
* assume the buffer contains the following sequence:
@ -405,10 +421,10 @@ extern "C" {
* @endcode
* An ioctl at any time in this sequence will return a value of 6 for ABS_X.
*
* libevdev discards all events after a SYN_DROPPED to ensure the events
* libevdev discards all events after a `SYN_DROPPED` to ensure the events
* during @ref LIBEVDEV_READ_FLAG_SYNC represent the last known state of the
* device. This loses some granularity of the events especially as the time
* between the SYN_DROPPED and the sync process increases. It does however
* between the `SYN_DROPPED` and the sync process increases. It does however
* avoid spurious cursor movements. In the above example, the event sequence
* by libevdev is:
* @code
@ -433,7 +449,7 @@ extern "C" {
* Minimum requirements
* ====================
* libevdev requires a 2.6.36 kernel as minimum. Specifically, it requires
* kernel-support for ABS_MT_SLOT.
* kernel-support for `ABS_MT_SLOT`.
*
* Event and input property names
* ==============================
@ -442,28 +458,28 @@ extern "C" {
* The list of event names is compiled at build-time, any events not defined
* at build time will not resolve. Specifically,
* libevdev_event_code_get_name() for an undefined type or code will
* always return NULL. Likewise, libevdev_property_get_name() will return NULL
* always return `NULL`. Likewise, libevdev_property_get_name() will return NULL
* for properties undefined at build-time.
*
* Input properties
* ================
* If the kernel does not support input properties, specifically the
* EVIOCGPROPS ioctl, libevdev does not expose input properties to the caller.
* `EVIOCGPROPS` ioctl, libevdev does not expose input properties to the caller.
* Specifically, libevdev_has_property() will always return 0 unless the
* property has been manually set with libevdev_enable_property().
*
* This also applies to the libevdev-uinput code. If uinput does not honor
* UI_SET_PROPBIT, libevdev will continue without setting the properties on
* `UI_SET_PROPBIT`, libevdev will continue without setting the properties on
* the device.
*
* MT slot behavior
* =================
* If the kernel does not support the EVIOCGMTSLOTS ioctl, libevdev
* If the kernel does not support the `EVIOCGMTSLOTS` ioctl, libevdev
* assumes all values in all slots are 0 and continues without an error.
*
* SYN_DROPPED behavior
* ====================
* A kernel without SYN_DROPPED won't send such an event. libevdev_next_event()
* A kernel without `SYN_DROPPED` won't send such an event. libevdev_next_event()
* will never require the switch to sync mode.
*/
@ -484,11 +500,11 @@ extern "C" {
* <dd>supported, see libevdev_enable_event_code()</dd>
* <dt>EVIOCGKEYCODE:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCGKEYCODE:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCSKEYCODE:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCSKEYCODE:</dt>
* <dt>EVIOCGKEYCODE_V2:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCSKEYCODE_V2:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCGNAME:</dt>
* <dd>supported, see libevdev_get_name()</dd>
@ -528,6 +544,10 @@ extern "C" {
* <dt>EVIOCREVOKE:</dt>
* <dd>currently not supported, see
* http://lists.freedesktop.org/archives/input-tools/2014-January/000688.html</dd>
* <dt>EVIOCGMASK:</dt>
* <dd>currently not supported</dd>
* <dt>EVIOCSMASK:</dt>
* <dd>currently not supported</dd>
* </dl>
*
*/
@ -562,7 +582,7 @@ extern "C" {
* [Check unit testing framework](http://check.sourceforge.net/). Tests are
* divided into test suites and test cases. Most tests create a uinput device,
* so you'll need to run as root, and your kernel must have
* CONFIG_INPUT_UINPUT enabled.
* `CONFIG_INPUT_UINPUT` enabled.
*
* To run a specific suite only:
*
@ -618,7 +638,7 @@ extern "C" {
* return ENOMEM;
*
* err = libevdev_set_fd(dev, fd);
* if (err < 0) {
* if (err < 0)
* printf("Failed (errno %d): %s\n", -err, strerror(-err));
*
* libevdev_free(dev);
@ -655,9 +675,9 @@ extern "C" {
/**
* @defgroup bits Querying device capabilities
*
* Abstraction functions to handle device capabilities, specificially
* Abstraction functions to handle device capabilities, specifically
* device properties such as the name of the device and the bits
* representing the events suppported by this device.
* representing the events supported by this device.
*
* The logical state returned may lag behind the physical state of the device.
* libevdev queries the device state on libevdev_set_fd() and then relies on
@ -669,11 +689,11 @@ extern "C" {
/**
* @defgroup mt Multi-touch related functions
* Functions for querying multi-touch-related capabilities. MT devices
* following the kernel protocol B (using ABS_MT_SLOT) provide multiple touch
* following the kernel protocol B (using `ABS_MT_SLOT`) provide multiple touch
* points through so-called slots on the same axis. The slots are enumerated,
* a client reading from the device will first get an ABS_MT_SLOT event, then
* the values of axes changed in this slot. Multiple slots may be provided in
* before an EV_SYN event.
* before an `EV_SYN` event.
*
* As with @ref bits, the logical state of the device as seen by the library
* depends on the caller using libevdev_next_event().
@ -681,17 +701,17 @@ extern "C" {
* The Linux kernel requires all axes on a device to have a semantic
* meaning, matching the axis names in linux/input.h. Some devices merely
* export a number of axes beyond the available axis list. For those
* devices, the multitouch information is invalid. Specfically, if a device
* provides the ABS_MT_SLOT axis AND also the (ABS_MT_SLOT - 1) axis, the
* devices, the multitouch information is invalid. Specifically, if a device
* provides the `ABS_MT_SLOT` axis AND also the `ABS_RESERVED` axis, the
* device is not treated as multitouch device. No slot information is
* available and the ABS_MT axis range for these devices is treated as all
* other EV_ABS axes.
* available and the `ABS_MT` axis range for these devices is treated as all
* other `EV_ABS` axes.
*
* Note that because of limitations in the kernel API, such fake multitouch
* devices can not be reliably synched after a SYN_DROPPED event. libevdev
* ignores all ABS_MT axis values during the sync process and instead
* devices can not be reliably synced after a `SYN_DROPPED` event. libevdev
* ignores all `ABS_MT` axis values during the sync process and instead
* relies on the device to send the current axis value with the first event
* after SYN_DROPPED.
* after `SYN_DROPPED`.
*/
/**
@ -796,7 +816,7 @@ int libevdev_new_from_fd(int fd, struct libevdev **dev);
* libevdev</code> is invalid and must not be used.
*
* Note that calling libevdev_free() does not close the file descriptor
* currently asssociated with this instance.
* currently associated with this instance.
*
* @param dev The evdev device
*
@ -956,10 +976,14 @@ enum libevdev_grab_mode {
* Grabbing an already grabbed device, or ungrabbing an ungrabbed device is
* a noop and always succeeds.
*
* A grab is an operation tied to a file descriptor, not a device. If a
* client changes the file descriptor with libevdev_change_fd(), it must
* also re-issue a grab with libevdev_grab().
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param grab If true, grab the device. Otherwise ungrab the device.
*
* @return 0 if the device was successfull grabbed or ungrabbed, or a
* @return 0 if the device was successfully grabbed or ungrabbed, or a
* negative errno in case of failure.
*/
int libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab);
@ -985,7 +1009,7 @@ int libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab);
* events like EV_REL.
*
* Unless otherwise specified, libevdev function behavior is undefined until
* a successfull call to libevdev_set_fd().
* a successful call to libevdev_set_fd().
*
* @param dev The evdev device
* @param fd The file descriptor for the device
@ -1024,6 +1048,9 @@ int libevdev_set_fd(struct libevdev* dev, int fd);
*
* The fd may be open in O_RDONLY or O_RDWR.
*
* After changing the fd, the device is assumed ungrabbed and a caller must
* call libevdev_grab() again.
*
* It is an error to call this function before calling libevdev_set_fd().
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
@ -1254,7 +1281,9 @@ int libevdev_get_id_product(const struct libevdev *dev);
* @param product_id The product ID to assign to this device
*
* @note This function may be called before libevdev_set_fd(). A call to
* libevdev_set_fd() will overwrite any previously set value.
* libevdev_set_fd() will overwrite any previously set value. Even though
* the function accepts an int for product_id the value is truncated at 16
* bits.
*/
void libevdev_set_id_product(struct libevdev *dev, int product_id);
@ -1276,7 +1305,9 @@ int libevdev_get_id_vendor(const struct libevdev *dev);
* @param vendor_id The vendor ID to assign to this device
*
* @note This function may be called before libevdev_set_fd(). A call to
* libevdev_set_fd() will overwrite any previously set value.
* libevdev_set_fd() will overwrite any previously set value. Even though
* the function accepts an int for vendor_id the value is truncated at 16
* bits.
*/
void libevdev_set_id_vendor(struct libevdev *dev, int vendor_id);
@ -1298,7 +1329,9 @@ int libevdev_get_id_bustype(const struct libevdev *dev);
* @param bustype The bustype to assign to this device
*
* @note This function may be called before libevdev_set_fd(). A call to
* libevdev_set_fd() will overwrite any previously set value.
* libevdev_set_fd() will overwrite any previously set value. Even though
* the function accepts an int for bustype the value is truncated at 16
* bits.
*/
void libevdev_set_id_bustype(struct libevdev *dev, int bustype);
@ -1320,7 +1353,9 @@ int libevdev_get_id_version(const struct libevdev *dev);
* @param version The version to assign to this device
*
* @note This function may be called before libevdev_set_fd(). A call to
* libevdev_set_fd() will overwrite any previously set value.
* libevdev_set_fd() will overwrite any previously set value. Even though
* the function accepts an int for version the value is truncated at 16
* bits.
*/
void libevdev_set_id_version(struct libevdev *dev, int version);
@ -1360,6 +1395,16 @@ int libevdev_has_property(const struct libevdev *dev, unsigned int prop);
*/
int libevdev_enable_property(struct libevdev *dev, unsigned int prop);
/**
* @ingroup kernel
*
* @param dev The evdev device
* @param prop The input property to disable, one of INPUT_PROP_...
*
* @return 0 on success or -1 on failure
*/
int libevdev_disable_property(struct libevdev *dev, unsigned int prop);
/**
* @ingroup bits
*
@ -1477,8 +1522,7 @@ const struct input_absinfo* libevdev_get_abs_info(const struct libevdev *dev, un
* the event.
*
* If the device supports ABS_MT_SLOT, the value returned for any ABS_MT_*
* event code is the value of the currently active slot. You should use
* libevdev_get_slot_value() instead.
* event code is undefined. Use libevdev_get_slot_value() instead.
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param type The event type for the code to query (EV_SYN, EV_REL, etc.)
@ -1518,9 +1562,11 @@ int libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsi
* @param value The new value to set
*
* @return 0 on success, or -1 on failure.
* @retval -1 the device does not have the event type or code enabled, or the code is outside the
* allowed limits for the given type, or the type cannot be set, or the
* value is not permitted for the given code.
* @retval -1
* - the device does not have the event type or code enabled, or
* - the code is outside the allowed limits for the given type, or
* - the type cannot be set, or
* - the value is not permitted for the given code.
*
* @see libevdev_set_slot_value
* @see libevdev_get_event_value
@ -1595,9 +1641,11 @@ int libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsig
* @param value The new value to set
*
* @return 0 on success, or -1 on failure.
* @retval -1 the device does not have the event code enabled, or the code is
* outside the allowed limits for multitouch events, or the slot number is outside
* the limits for this device, or the device does not support multitouch events.
* @retval -1
* - the device does not have the event code enabled, or
* - the code is outside the allowed limits for multitouch events, or
* - the slot number is outside the limits for this device, or
* - the device does not support multitouch events.
*
* @see libevdev_set_event_value
* @see libevdev_get_slot_value
@ -1672,9 +1720,9 @@ int libevdev_get_current_slot(const struct libevdev *dev);
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param code One of ABS_X, ABS_Y, ...
* @param min The new minimum for this axis
* @param val The new minimum for this axis
*/
void libevdev_set_abs_minimum(struct libevdev *dev, unsigned int code, int min);
void libevdev_set_abs_minimum(struct libevdev *dev, unsigned int code, int val);
/**
* @ingroup kernel
@ -1685,9 +1733,9 @@ void libevdev_set_abs_minimum(struct libevdev *dev, unsigned int code, int min);
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param code One of ABS_X, ABS_Y, ...
* @param max The new maxium for this axis
* @param val The new maxium for this axis
*/
void libevdev_set_abs_maximum(struct libevdev *dev, unsigned int code, int max);
void libevdev_set_abs_maximum(struct libevdev *dev, unsigned int code, int val);
/**
* @ingroup kernel
@ -1698,9 +1746,9 @@ void libevdev_set_abs_maximum(struct libevdev *dev, unsigned int code, int max);
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param code One of ABS_X, ABS_Y, ...
* @param fuzz The new fuzz for this axis
* @param val The new fuzz for this axis
*/
void libevdev_set_abs_fuzz(struct libevdev *dev, unsigned int code, int fuzz);
void libevdev_set_abs_fuzz(struct libevdev *dev, unsigned int code, int val);
/**
* @ingroup kernel
@ -1711,9 +1759,9 @@ void libevdev_set_abs_fuzz(struct libevdev *dev, unsigned int code, int fuzz);
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param code One of ABS_X, ABS_Y, ...
* @param flat The new flat for this axis
* @param val The new flat for this axis
*/
void libevdev_set_abs_flat(struct libevdev *dev, unsigned int code, int flat);
void libevdev_set_abs_flat(struct libevdev *dev, unsigned int code, int val);
/**
* @ingroup kernel
@ -1724,9 +1772,9 @@ void libevdev_set_abs_flat(struct libevdev *dev, unsigned int code, int flat);
*
* @param dev The evdev device, already initialized with libevdev_set_fd()
* @param code One of ABS_X, ABS_Y, ...
* @param resolution The new axis resolution
* @param val The new axis resolution
*/
void libevdev_set_abs_resolution(struct libevdev *dev, unsigned int code, int resolution);
void libevdev_set_abs_resolution(struct libevdev *dev, unsigned int code, int val);
/**
* @ingroup kernel
@ -2006,6 +2054,29 @@ const char * libevdev_event_type_get_name(unsigned int type);
*/
const char * libevdev_event_code_get_name(unsigned int type, unsigned int code);
/**
* @ingroup misc
*
* This function resolves the event value for a code.
*
* For almost all event codes this will return NULL as the value is just a
* numerical value. As of kernel 4.17, the only event code that will return
* a non-NULL value is EV_ABS/ABS_MT_TOOL_TYPE.
*
* @param type The event type for the value to query (EV_ABS, etc.)
* @param code The event code for the value to query (e.g. ABS_MT_TOOL_TYPE)
* @param value The event value to return the name for (e.g. MT_TOOL_PALM)
*
* @return The name of the given event value (e.g. MT_TOOL_PALM) or NULL for
* an invalid type or code or NULL for an axis that has numerical values
* only.
*
* @note The list of names is compiled into libevdev. If the kernel adds new
* defines for new event values, libevdev will not automatically pick these up.
*/
const char * libevdev_event_value_get_name(unsigned int type,
unsigned int code,
int value);
/**
* @ingroup misc
*
@ -2114,6 +2185,136 @@ int libevdev_event_code_from_name(unsigned int type, const char *name);
int libevdev_event_code_from_name_n(unsigned int type, const char *name,
size_t len);
/**
* @ingroup misc
*
* Look up an event value by its type, code and name. Event values start
* with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The
* prefix must be included in the name. It returns the constant assigned
* to the event code or -1 if not found.
*
* You have to pass the event type and code where to look for the name. For
* instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type,
* ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string.
*
* As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution.
*
* @param type The event type (EV_* constant) where to look for the name.
* @param code The event code (ABS_* constant) where to look for the name.
* @param name A non-NULL string describing an input-event value
* ("MT_TOOL_TYPE", ...)
*
* @return The given value constant for the name or -1 if not found.
*/
int libevdev_event_value_from_name(unsigned int type, unsigned int code,
const char *name);
/**
* @ingroup misc
*
* Look up an event type for a event code name. For example, the name
* "ABS_Y" returns EV_ABS. For the lookup to succeed, the name must be
* unique, which is the case for all defines as of kernel 5.0 and likely to
* be the case in the future.
*
* This is equivalent to libevdev_event_type_from_name() but takes the code
* name instead of the type name.
*
* @param name A non-NULL string describing an input-event value
* ("ABS_X", "REL_Y", "KEY_A", ...)
*
* @return The given event code for the name or -1 if not found.
*/
int
libevdev_event_type_from_code_name(const char *name);
/**
* @ingroup misc
*
* Look up an event type for a event code name. For example, the name
* "ABS_Y" returns EV_ABS. For the lookup to succeed, the name must be
* unique, which is the case for all defines as of kernel 5.0 and likely to
* be the case in the future.
*
* This is equivalent to libevdev_event_type_from_name_n() but takes the code
* name instead of the type name.
*
* @param name A non-NULL string describing an input-event value
* ("ABS_X", "REL_Y", "KEY_A", ...)
* @param len The length of the passed string excluding any terminating 0
* character.
*
* @return The given event code for the name or -1 if not found.
*/
int
libevdev_event_type_from_code_name_n(const char *name, size_t len);
/**
* @ingroup misc
*
* Look up an event code by its name. For example, the name "ABS_Y"
* returns 1. For the lookup to succeed, the name must be unique, which is
* the case for all defines as of kernel 5.0 and likely to be the case in
* the future.
*
* This is equivalent to libevdev_event_code_from_name() without the need
* for knowing the event type.
*
* @param name A non-NULL string describing an input-event value
* ("ABS_X", "REL_Y", "KEY_A", ...)
*
* @return The given event code for the name or -1 if not found.
*/
int
libevdev_event_code_from_code_name(const char *name);
/**
* @ingroup misc
*
* Look up an event code by its name. For example, the name "ABS_Y"
* returns 1. For the lookup to succeed, the name must be unique, which is
* the case for all defines as of kernel 5.0 and likely to be the case in
* the future.
*
* This is equivalent to libevdev_event_code_from_name_n() without the need
* for knowing the event type.
*
* @param name A non-NULL string describing an input-event value
* ("ABS_X", "REL_Y", "KEY_A", ...)
* @param len The length of the passed string excluding any terminating 0
* character.
*
* @return The given event code for the name or -1 if not found.
*/
int
libevdev_event_code_from_code_name_n(const char *name, size_t len);
/**
* @ingroup misc
*
* Look up an event value by its type, code and name. Event values start
* with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The
* prefix must be included in the name. It returns the constant assigned
* to the event code or -1 if not found.
*
* You have to pass the event type and code where to look for the name. For
* instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type,
* ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string.
*
* As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution.
*
* @param type The event type (EV_* constant) where to look for the name.
* @param code The event code (ABS_* constant) where to look for the name.
* @param name A non-NULL string describing an input-event value
* ("MT_TOOL_TYPE", ...)
* @param len The length of the string in @p name excluding any terminating 0
* character.
*
* @return The given value constant for the name or -1 if not found.
*/
int libevdev_event_value_from_name_n(unsigned int type, unsigned int code,
const char *name, size_t len);
/**
* @ingroup misc
*

View file

@ -1,23 +1,6 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2013 David Herrmann <dh.herrmann@gmail.com>
*
* 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
LIBEVDEV_1 {
@ -112,3 +95,29 @@ global:
local:
*;
} LIBEVDEV_1;
LIBEVDEV_1_6 {
global:
libevdev_event_value_get_name;
libevdev_event_value_from_name;
libevdev_event_value_from_name_n;
local:
*;
} LIBEVDEV_1_3;
LIBEVDEV_1_7 {
global:
libevdev_event_code_from_code_name;
libevdev_event_code_from_code_name_n;
libevdev_event_type_from_code_name;
libevdev_event_type_from_code_name_n;
local:
*;
} LIBEVDEV_1_6;
LIBEVDEV_1_10 {
global:
libevdev_disable_property;
local:
*;
} LIBEVDEV_1_7;

View file

@ -1,213 +1,231 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Parses linux/input.h scanning for #define KEY_FOO 134
# Prints C header files or Python files that can be used as
# mapping and lookup tables.
#
from __future__ import print_function
import re
import sys
class Bits(object):
pass
def __init__(self):
self.max_codes = {}
prefixes = [
"EV_",
"REL_",
"ABS_",
"KEY_",
"BTN_",
"LED_",
"SND_",
"MSC_",
"SW_",
"FF_",
"SYN_",
"REP_",
"INPUT_PROP_",
"EV_",
"REL_",
"ABS_",
"KEY_",
"BTN_",
"LED_",
"SND_",
"MSC_",
"SW_",
"FF_",
"SYN_",
"REP_",
"INPUT_PROP_",
"MT_TOOL_",
]
blacklist = [
"EV_VERSION",
"BTN_MISC",
"BTN_MOUSE",
"BTN_JOYSTICK",
"BTN_GAMEPAD",
"BTN_DIGI",
"BTN_WHEEL",
"BTN_TRIGGER_HAPPY"
duplicates = [
"EV_VERSION",
"BTN_MISC",
"BTN_MOUSE",
"BTN_JOYSTICK",
"BTN_GAMEPAD",
"BTN_DIGI",
"BTN_WHEEL",
"BTN_TRIGGER_HAPPY",
"SW_MAX",
"REP_MAX",
]
btn_additional = [
[0, "BTN_A"],
[0, "BTN_B"],
[0, "BTN_X"],
[0, "BTN_Y"],
[0, "BTN_A"],
[0, "BTN_B"],
[0, "BTN_X"],
[0, "BTN_Y"],
]
names = [
"REL_",
"ABS_",
"KEY_",
"BTN_",
"LED_",
"SND_",
"MSC_",
"SW_",
"FF_",
"SYN_",
"REP_",
code_prefixes = [
"REL_",
"ABS_",
"KEY_",
"BTN_",
"LED_",
"SND_",
"MSC_",
"SW_",
"FF_",
"SYN_",
"REP_",
]
def print_bits(bits, prefix):
if not hasattr(bits, prefix):
return
print("static const char * const %s_map[%s_MAX + 1] = {" % (prefix, prefix.upper()))
for val, name in list(getattr(bits, prefix).items()):
print(" [%s] = \"%s\"," % (name, name))
if prefix == "key":
for val, name in list(getattr(bits, "btn").items()):
print(" [%s] = \"%s\"," % (name, name))
print("};")
print("")
if not hasattr(bits, prefix):
return
print("static const char * const %s_map[%s_MAX + 1] = {" % (prefix, prefix.upper()))
for val, name in sorted(list(getattr(bits, prefix).items())):
print(" [%s] = \"%s\"," % (name, name))
if prefix == "key":
for val, name in sorted(list(getattr(bits, "btn").items())):
print(" [%s] = \"%s\"," % (name, name))
print("};")
print("")
def print_map(bits):
print("static const char * const * const event_type_map[EV_MAX + 1] = {")
print("static const char * const * const event_type_map[EV_MAX + 1] = {")
for prefix in prefixes:
if prefix == "BTN_" or prefix == "EV_" or prefix == "INPUT_PROP_":
continue
print(" [EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower()))
for prefix in prefixes:
if prefix in ["BTN_", "EV_", "INPUT_PROP_", "MT_TOOL_"]:
continue
print(" [EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower()))
print("};")
print("")
print("};")
print("")
print("#if __clang__")
print("#pragma clang diagnostic push")
print("#pragma clang diagnostic ignored \"-Winitializer-overrides\"")
print("#else")
print("#pragma GCC diagnostic push")
print("#pragma GCC diagnostic ignored \"-Woverride-init\"")
print("#endif")
print("static const int ev_max[EV_MAX + 1] = {")
print(" [0 ... EV_MAX] = -1,")
for prefix in prefixes:
if prefix == "BTN_" or prefix == "EV_" or prefix == "INPUT_PROP_":
continue
print(" [EV_%s] = %s_MAX," % (prefix[:-1], prefix[:-1]))
print("};")
print("#if __clang__")
print("#pragma clang diagnostic pop /* \"-Winitializer-overrides\" */")
print("#else")
print("#pragma GCC diagnostic pop /* \"-Woverride-init\" */")
print("#endif");
print("")
print("#if __clang__")
print("#pragma clang diagnostic push")
print("#pragma clang diagnostic ignored \"-Winitializer-overrides\"")
print("#elif __GNUC__")
print("#pragma GCC diagnostic push")
print("#pragma GCC diagnostic ignored \"-Woverride-init\"")
print("#endif")
print("static const int ev_max[EV_MAX + 1] = {")
for val in range(bits.max_codes["EV_MAX"] + 1):
if val in bits.ev:
prefix = bits.ev[val][3:]
if prefix + "_" in prefixes:
print(" %s_MAX," % prefix)
continue
print(" -1,")
print("};")
print("#if __clang__")
print("#pragma clang diagnostic pop /* \"-Winitializer-overrides\" */")
print("#elif __GNUC__")
print("#pragma GCC diagnostic pop /* \"-Woverride-init\" */")
print("#endif")
print("")
def print_python_map(bits):
print("map = {")
for val, name in list(getattr(bits, "ev").items()):
name = name[3:]
if name == "REP" or name == "PWR" or name == "FF_STATUS" or name == "MAX":
continue
print(" %d : %s_map," % (val, name.lower()))
print("}")
print("")
def print_lookup(bits, prefix):
if not hasattr(bits, prefix):
return
if not hasattr(bits, prefix):
return
names = list(getattr(bits, prefix).items())
if prefix == "btn":
names = names + btn_additional;
names = sorted(list(getattr(bits, prefix).items()))
if prefix == "btn":
names = names + btn_additional
# We need to manually add the _MAX codes because some are
# duplicates
maxname = "%s_MAX" % (prefix.upper())
if maxname in duplicates:
names.append((bits.max_codes[maxname], maxname))
for val, name in sorted(names, key=lambda e: e[1]):
print(" { .name = \"%s\", .value = %s }," % (name, name))
for val, name in sorted(names, key=lambda e: e[1]):
print(" { .name = \"%s\", .value = %s }," % (name, name))
def print_lookup_table(bits):
print("struct name_entry {")
print(" const char *name;")
print(" unsigned int value;")
print("};")
print("")
print("static const struct name_entry ev_names[] = {")
print_lookup(bits, "ev")
print("};")
print("")
print("struct name_entry {")
print(" const char *name;")
print(" unsigned int value;")
print("};")
print("")
print("static const struct name_entry tool_type_names[] = {")
print_lookup(bits, "mt_tool")
print("};")
print("")
print("static const struct name_entry ev_names[] = {")
print_lookup(bits, "ev")
print("};")
print("")
print("static const struct name_entry code_names[] = {")
for prefix in sorted(code_prefixes, key=lambda e: e):
print_lookup(bits, prefix[:-1].lower())
print("};")
print("")
print("static const struct name_entry prop_names[] = {")
print_lookup(bits, "input_prop")
print("};")
print("")
print("static const struct name_entry code_names[] = {")
for prefix in sorted(names, key=lambda e: e):
print_lookup(bits, prefix[:-1].lower())
print("};")
print("")
print("static const struct name_entry prop_names[] = {")
print_lookup(bits, "input_prop")
print("};")
print("")
def print_mapping_table(bits):
print("/* THIS FILE IS GENERATED, DO NOT EDIT */")
print("")
print("#ifndef EVENT_NAMES_H")
print("#define EVENT_NAMES_H")
print("")
print("/* THIS FILE IS GENERATED, DO NOT EDIT */")
print("")
print("#ifndef EVENT_NAMES_H")
print("#define EVENT_NAMES_H")
print("")
for prefix in prefixes:
if prefix == "BTN_":
continue
print_bits(bits, prefix[:-1].lower())
for prefix in prefixes:
if prefix == "BTN_":
continue
print_bits(bits, prefix[:-1].lower())
print_map(bits)
print_lookup_table(bits)
print_map(bits)
print_lookup_table(bits)
print("#endif /* EVENT_NAMES_H */")
print("#endif /* EVENT_NAMES_H */")
def parse_define(bits, line):
m = re.match(r"^#define\s+(\w+)\s+(\w+)", line)
if m == None:
return
m = re.match(r"^#define\s+(\w+)\s+(\w+)", line)
if m is None:
return
name = m.group(1)
name = m.group(1)
if name in blacklist:
return
try:
value = int(m.group(2), 0)
except ValueError:
return
try:
value = int(m.group(2), 0)
except ValueError:
return
for prefix in prefixes:
if not name.startswith(prefix):
continue
for prefix in prefixes:
if not name.startswith(prefix):
continue
if name.endswith("_MAX"):
bits.max_codes[name] = value
attrname = prefix[:-1].lower()
if name in duplicates:
return
if not hasattr(bits, attrname):
setattr(bits, attrname, {})
b = getattr(bits, attrname)
b[value] = name
attrname = prefix[:-1].lower()
def parse(fp):
bits = Bits()
if not hasattr(bits, attrname):
setattr(bits, attrname, {})
b = getattr(bits, attrname)
b[value] = name
lines = fp.readlines()
for line in lines:
if not line.startswith("#define"):
continue
parse_define(bits, line)
return bits
def parse(lines):
bits = Bits()
for line in lines:
if not line.startswith("#define"):
continue
parse_define(bits, line)
return bits
def usage(prog):
print("Usage: cat <files> | %s" % prog)
print("Usage: %s <files>".format(prog))
if __name__ == "__main__":
if len(sys.argv) != 1:
usage(sys.argv[0])
sys.exit(2)
if len(sys.argv) <= 1:
usage(sys.argv[0])
sys.exit(2)
bits = parse(sys.stdin)
print_mapping_table(bits)
from itertools import chain
lines = chain(*[open(f).readlines() for f in sys.argv[1:]])
bits = parse(lines)
print_mapping_table(bits)

299
meson.build Normal file
View file

@ -0,0 +1,299 @@
project('libevdev', 'c',
version: '1.13.6', # change autotools version too
license: 'MIT/Expat',
default_options: [ 'c_std=gnu99', 'warning_level=2' ],
meson_version: '>= 0.56.0')
libevdev_version = meson.project_version().split('.')
dir_root = meson.project_source_root()
dir_src = dir_root / 'libevdev'
dir_src_test = dir_root / 'test'
# Include directories
includes_include = include_directories('include')
# DO NOT MODIFY THIS
# Use symbol versioning instead.
libevdev_lt_c=5
libevdev_lt_r=0
libevdev_lt_a=3
# convert to soname
libevdev_so_version = '@0@.@1@.@2@'.format((libevdev_lt_c - libevdev_lt_a),
libevdev_lt_a, libevdev_lt_r)
# Compiler setup
cc = meson.get_compiler('c')
cppflags = ['-Wno-unused-parameter', '-fvisibility=hidden']
cflags = cppflags + ['-Wmissing-prototypes', '-Wstrict-prototypes']
add_project_arguments(cflags, language: 'c')
add_project_arguments(cppflags, language: 'cpp')
# config.h
config_h = configuration_data()
config_h.set('_GNU_SOURCE', '1')
# Dependencies
pkgconfig = import('pkgconfig')
dep_lm = cc.find_library('m')
dep_rt = cc.find_library('rt')
input_h = dir_root / 'include' / 'linux' / host_machine.system() / 'input.h'
input_event_codes_h = dir_root / 'include' / 'linux' / host_machine.system() / 'input-event-codes.h'
# event-names.h
make_event_names = find_program('libevdev/make-event-names.py')
event_names_h = configure_file(input: 'libevdev/libevdev.h',
output: 'event-names.h',
command: [make_event_names, input_h, input_event_codes_h],
capture: true)
# libevdev.so
install_headers('libevdev/libevdev.h',
'libevdev/libevdev-uinput.h',
subdir: 'libevdev-1.0/libevdev')
src_libevdev = [event_names_h] + files(
'libevdev/libevdev.h',
'libevdev/libevdev-int.h',
'libevdev/libevdev-util.h',
'libevdev/libevdev-uinput.c',
'libevdev/libevdev-uinput.h',
'libevdev/libevdev-uinput-int.h',
'libevdev/libevdev.c',
'libevdev/libevdev-names.c',
'include/linux/input.h',
'include/linux/uinput.h',
)
mapfile = dir_src / 'libevdev.sym'
version_flag = '-Wl,--version-script,@0@'.format(mapfile)
lib_libevdev = library('evdev',
src_libevdev,
include_directories: [includes_include],
dependencies: [dep_rt],
version: libevdev_so_version,
link_args: version_flag,
link_depends: mapfile,
install: true
)
inc_libevdev = include_directories('.')
dep_libevdev = declare_dependency(link_with: lib_libevdev,
include_directories: [inc_libevdev])
pkgconfig.generate(
filebase: 'libevdev',
name: 'libevdev',
description: 'Handler library for evdev events',
version: meson.project_version(),
libraries: lib_libevdev,
subdirs: 'libevdev-1.0',
)
man_config = configuration_data()
man_config.set('PACKAGE_VERSION', meson.project_version())
manpage = configure_file(input: 'doc/libevdev.man.in',
output: 'libevdev.3',
configuration: man_config)
install_man(manpage)
# tools
if not get_option('tools').disabled()
executable('libevdev-events',
sources: ['tools/libevdev-events.c'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: false)
executable('libevdev-list-codes',
sources: ['tools/libevdev-list-codes.c'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: false)
executable('touchpad-edge-detector',
sources: ['tools/touchpad-edge-detector.c'],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_lm],
install: true)
executable('mouse-dpi-tool',
sources: ['tools/mouse-dpi-tool.c'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: true)
executable('libevdev-tweak-device',
sources: ['tools/libevdev-tweak-device.c'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: true)
install_man('tools/libevdev-tweak-device.1',
'tools/touchpad-edge-detector.1',
'tools/mouse-dpi-tool.1')
endif
# tests
dep_check = dependency('check', version: '>= 0.9.9',
required: get_option('tests'))
if dep_check.found()
executable('test-link',
sources: ['test/test-link.c'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: false)
executable('test-compile-pedantic',
sources: ['test/test-compile-pedantic.c'],
c_args: ['-pedantic', '-Werror', '-std=c89'],
include_directories: [includes_include],
dependencies: dep_libevdev,
install: false)
src_common = [
'test/test-common-uinput.c',
'test/test-common-uinput.h',
'test/test-common.c',
'test/test-common.h',
'test/test-main.c',
]
test_event_codes = executable('test-event-codes',
sources: src_common + [
'test/test-event-codes.c',
'test/test-event-names.c',
'test/test-context.c',
],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_check],
install: false)
test('test-event-codes', test_event_codes, suite: ['library', 'needs-uinput'])
test_internals = executable('test-internals',
sources: src_common + [
'test/test-int-queue.c',
],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_check],
install: false)
test('test-internals', test_internals, suite: ['library', 'needs-uinput'])
test_uinput = executable('test-uinput',
sources: src_common + [
'test/test-uinput.c',
],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_check],
install: false)
test('test-uinput', test_uinput, suite: ['library', 'needs-uinput'])
test_libevdev = executable('test-libevdev',
sources: src_common + [
'test/test-libevdev-init.c',
'test/test-libevdev-has-event.c',
'test/test-libevdev-events.c',
],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_check],
install: false)
test('test-libevdev', test_libevdev, suite: ['library', 'needs-uinput'], env: ['CK_DEFAULT_TIMEOUT=10'])
test_kernel = executable('test-kernel',
sources: src_common + [
'test/test-kernel.c',
],
include_directories: [includes_include],
dependencies: [dep_libevdev, dep_check],
install: false)
test('test-kernel', test_kernel, suite: ['kernel', 'needs-uinput'])
valgrind = find_program('valgrind', required: false)
if valgrind.found()
valgrind_env = environment()
valgrind_env.set('CK_TIMEOUT_MULTIPLIER', '10')
valgrind_env.set('CK_FORK', 'no')
valgrind_env.set('RUNNING_ON_VALGRIND', '1')
valgrind_suppressions_file = dir_src_test / 'valgrind.suppressions'
add_test_setup('valgrind',
exe_wrapper: [ valgrind,
'--leak-check=full',
'--gen-suppressions=all',
'--error-exitcode=3',
'--suppressions=' + valgrind_suppressions_file ],
env: valgrind_env,
timeout_multiplier: 100)
else
message('valgrind not found, disabling valgrind test suite')
endif
test_static_link = find_program('test/test-static-symbols-leak.sh')
test('static-symbols-leak', test_static_link,
args: [meson.current_build_dir()],
suite: 'static')
endif
doxygen = find_program('doxygen', required: get_option('documentation'))
if doxygen.found()
src_doxygen = files(
# source files
dir_src / 'libevdev.h',
dir_src / 'libevdev-uinput.h',
# style files
'doc/style/bootstrap.css',
'doc/style/customdoxygen.css',
'doc/style/doxy-boot.js',
'doc/style/dynsections.js',
'doc/style/footer.html',
'doc/style/header.html',
'doc/style/layout.xml',
'doc/style/libevdevdoxygen.css',
'doc/style/LICENSE',
'doc/style/README.md',
'doc/style/style.css',
)
doxyfiles = []
foreach f: src_doxygen
df = configure_file(input: f,
output: '@PLAINNAME@',
copy: true)
doxyfiles += [df]
endforeach
doc_config = configuration_data()
doc_config.set('PACKAGE_NAME', meson.project_name())
doc_config.set('PACKAGE_VERSION', meson.project_version())
doc_config.set('builddir', meson.current_build_dir())
doc_config.set('top_srcdir', dir_root)
doc_config.set('srcdir', dir_root / 'doc')
doxyfile = configure_file(input: 'doc/libevdev.doxygen.in',
output: 'libevdev.doxygen',
configuration: doc_config)
custom_target('doxygen',
input: [doxyfiles, doxyfile] + src_doxygen,
output: ['.'],
command: [doxygen, doxyfile],
install: false,
build_by_default: true)
endif
# Coverity breaks because it doesn't define _Float128 correctly, you'll end
# up with a bunch of messages in the form:
# "/usr/include/stdlib.h", line 133: error #20: identifier "_Float128" is
# undefined
# extern _Float128 strtof128 (const char *__restrict __nptr,
# ^
# We don't use float128 ourselves, it gets pulled in from math.h or
# something, so let's just define it as uint128 and move on.
# Unfortunately we can't detect the coverity build at meson configure
# time, we only know it fails at runtime. So make this an option instead, to
# be removed when coverity fixes this again.
if get_option('coverity')
config_h.set('_Float128', '__uint128_t')
config_h.set('_Float32', 'int')
config_h.set('_Float32x', 'int')
config_h.set('_Float64', 'long')
config_h.set('_Float64x', 'long')
endif
############ output files ############
configure_file(output: 'config.h', configuration: config_h)

16
meson_options.txt Normal file
View file

@ -0,0 +1,16 @@
option('tests',
type: 'feature',
value: 'enabled',
description: 'Build the tests')
option('tools',
type: 'feature',
value: 'enabled',
description: 'Build the tools')
option('documentation',
type: 'feature',
value: 'enabled',
description: 'Build the documentation')
option('coverity',
type: 'boolean',
value: false,
description: 'Enable coverity build fixes, see meson.build for details')

View file

@ -22,10 +22,15 @@ test_static_link_LDADD = $(top_builddir)/libevdev/libevdev.la
test_static_link_LDFLAGS = $(AM_LDFLAGS) -static
check_local_deps =
clean_local_deps =
if ENABLE_RUNTIME_TESTS
run_tests = test-libevdev test-kernel
run_tests = \
test-libevdev \
test-kernel \
test-uinput \
test-event-codes \
test-libevdev-internals \
$(NULL)
.NOTPARALLEL:
@ -33,15 +38,7 @@ noinst_PROGRAMS += $(run_tests)
TESTS = $(run_tests)
libevdev_sources = $(top_srcdir)/libevdev/libevdev.c \
$(top_srcdir)/libevdev/libevdev.h \
$(top_srcdir)/libevdev/libevdev-names.c \
$(top_srcdir)/libevdev/libevdev-uinput.h \
$(top_srcdir)/libevdev/libevdev-uinput.c \
$(top_srcdir)/libevdev/libevdev-uinput-int.h \
$(top_srcdir)/libevdev/libevdev-util.h \
$(top_srcdir)/libevdev/libevdev-int.h
common_sources = $(libevdev_sources) \
common_sources = \
test-common-uinput.c \
test-common-uinput.h \
test-common.c \
@ -51,67 +48,58 @@ common_sources = $(libevdev_sources) \
AM_CPPFLAGS += $(CHECK_CFLAGS) $(GCOV_CFLAGS)
AM_LDFLAGS += $(GCOV_LDFLAGS)
test_libevdev_SOURCES = \
test_event_codes_SOURCES = \
test-main.c \
test-event-names.c \
test-event-codes.c \
test-libevdev-init.c \
test-libevdev-has-event.c \
test-event-names.c \
test-context.c \
$(common_sources)
test_event_codes_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
test_event_codes_LDFLAGS = -no-install
test_libevdev_internals_SOURCES = \
test-main.c \
test-int-queue.c \
test-libevdev-events.c \
$(common_sources)
test_libevdev_internals_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
test_libevdev_internals_LDFLAGS = -no-install
test_uinput_SOURCES = \
test-main.c \
test-uinput.c \
$(common_sources)
test_uinput_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
test_uinput_LDFLAGS = -no-install
test_libevdev_LDADD = $(CHECK_LIBS)
test_libevdev_SOURCES = \
test-main.c \
test-libevdev-init.c \
test-libevdev-has-event.c \
test-libevdev-events.c \
$(common_sources)
test_libevdev_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
test_libevdev_LDFLAGS = -no-install
test_kernel_SOURCES = \
test-main.c \
test-kernel.c \
$(common_sources)
test_kernel_CFLAGS = -I$(top_srcdir)
test_kernel_LDADD = $(CHECK_LIBS)
if HAVE_VALGRIND
VALGRIND_FLAGS=--leak-check=full \
--quiet \
--error-exitcode=3 \
--suppressions=$(srcdir)/valgrind.suppressions
valgrind:
$(MAKE) check-TESTS LOG_COMPILER="$(VALGRIND)" LOG_FLAGS="$(VALGRIND_FLAGS)"
check_local_deps += valgrind
endif
EXTRA_DIST = valgrind.suppressions
test_kernel_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
if GCOV_ENABLED
CLEANFILES = gcov-report.txt
CLEANFILES = gcov-reports/*.gcov gcov-reports/summary.txt *.gcno *.gcda
gcov-clean:
@rm -f *.gcov
gcov-report: generate-gcov-report.sh
$(AM_V_GEN)$(srcdir)/generate-gcov-report.sh gcov-reports $(top_builddir)/libevdev $(builddir)
gcov-report.txt: gcov-clean check-TESTS
$(AM_V_GEN)(rm -rf $@; \
echo "========== coverage report ========" >> $@; \
for file in `find $(top_srcdir)/libevdev -name "*.c" -printf "%P\n"`; do \
gcov $$file > /dev/null; \
if test -f $$file.gcov; then \
total=`grep -v " -:" $$file.gcov | wc -l`; \
missing=`grep "#####" $$file.gcov | wc -l`; \
hit=$$((total - missing)); \
echo -e "$$file: total lines: $$total not tested: $$missing ($$((($$hit * 100)/$$total))%)"; \
fi \
done >> $@; \
echo "========== =============== ========" >> $@; \
)
gcov: gcov-report.txt
@cat gcov-report.txt
gcov: gcov-report
@cat gcov-reports/summary.txt
check_local_deps += gcov
clean_local_deps += gcov-clean
else
@ -121,37 +109,22 @@ gcov-report.txt:
gcov:
@true
gcov-clean:
@true
endif # HAVE_VALGRIND
endif # GCOV_ENABLED
.PHONY: gcov gcov-clean gcov-report.txt
.PHONY: gcov gcov-clean gcov-report
endif # ENABLE_RUNTIME_TESTS
if ENABLE_STATIC_SYMBOL_LEAKS_TEST
# Hack to check for leaking symbols in the static library.
# See https://bugs.freedesktop.org/show_bug.cgi?id=82785
# Note the spaces in the expressions! After the first grep, each line
# is " T symbol_name"
static-symbol-leaks: test-static-link
$(AM_V_GEN)(\
$(NM) --extern-only $(builddir)/test-static-link | \
grep -o -e " T .*" | \
grep -v -e " main$$" \
-e " atexit" \
-e " *gcov.*" \
-e " _.*" \
-e " libevdev_*" && \
echo "Leaking symbols found" && \
exit 1 || exit 0 \
)
static-symbol-leaks: test-static-link test-static-symbols-leak.sh
$(AM_V_GEN) $(srcdir)/test-static-symbols-leak.sh $(builddir)
check_local_deps += static-symbol-leaks
endif # HAVE_NM
EXTRA_DIST = valgrind.suppressions generate-gcov-report.sh test-static-symbols-leak.sh
check-local: $(check_local_deps)
clean-local: $(clean_local_deps)
rm -f *.gcno *.gcda

40
test/generate-gcov-report.sh Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -e
if [[ $# -lt 2 ]]; then
echo "Usage: ./generate-gcov-report.sh <rel-target-dir> <srcdir> [<srcdir> ... ]"
exit 1
fi
target_dir=$1
shift
source_dirs=$*
if [[ "${target_dir:0:1}" != '/' ]]; then
target_dir="$PWD/$target_dir"
fi
summary_file="$target_dir/summary.txt"
mkdir -p "$target_dir"
rm -f "$target_dir"/*.gcov
for dir in $source_dirs; do
pushd "$dir" > /dev/null
for file in *.c; do
find ./ -name "*${file/\.c/.gcda}" -exec gcov {} \; > /dev/null
done
find ./ -name "*.gcov" \! -path "*/`basename "$target_dir"`/*" -exec mv {} "$target_dir" \;
popd > /dev/null
done
echo "========== coverage report ========" > "$summary_file"
for file in "$target_dir"/*.gcov; do
total=`grep -v " -:" "$file" | wc -l`
missing=`grep "#####" "$file" | wc -l`
hit=$((total - missing));
percent=$((($hit * 100)/$total))
fname=`basename "$file"`
printf "%-32s total lines: %4s not tested: %4s (%3s%%)\n" "$fname" "$total" "$missing" "$percent">> "$summary_file"
done
echo "========== =============== ========" >> "$summary_file"

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <libevdev/libevdev.h>
#define DEFAULT_IDS NULL

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <check.h>
#include <errno.h>
#include <fcntl.h>
@ -89,6 +72,7 @@ void test_create_abs_device(struct uinput_device **uidev_return,
va_start(args, abs);
rc = uinput_device_set_event_bits_v(uidev, args);
ck_assert_msg(rc == 0, "Failed to set uinput bits");
va_end(args);
while (--nabs >= 0) {

View file

@ -1,37 +1,57 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <libevdev/libevdev.h>
#include <stdbool.h>
#include <stdio.h>
#include <check.h>
#ifndef _TEST_COMMON_H_
#define _TEST_COMMON_H_
struct libevdev_test {
const char *name;
Suite* (*setup)(void);
bool needs_root_privileges;
} __attribute__((aligned(16)));
#define _TEST_SUITE(name, root_privs) \
static Suite* (name##_setup)(void); \
static const struct libevdev_test _test \
__attribute__((used)) \
__attribute__((section ("test_section"))) = { \
#name, name##_setup, root_privs \
}; \
static Suite* (name##_setup)(void)
#define TEST_SUITE(name) \
_TEST_SUITE(name, false)
#define TEST_SUITE_ROOT_PRIVILEGES(name) \
_TEST_SUITE(name, true)
#define TEST_DEVICE_NAME "libevdev test device"
#define add_test(suite, func) do { \
TCase *tc = tcase_create(#func); \
tcase_add_test(tc, func); \
suite_add_tcase(suite, tc); \
} while(0)
#include "test-common-uinput.h"
#define assert_event(e_, t, c, v) \
do { \
const struct input_event *e = (e_); \
ck_assert_int_eq(e->type, (t)); \
ck_assert_int_eq(e->code, (c)); \
ck_assert_int_eq(e->value, (v)); \
} while(0)
void test_create_device(struct uinput_device **uidev,
struct libevdev **dev,
...);
@ -51,4 +71,23 @@ void test_logfunc_ignore_error(enum libevdev_log_priority priority,
const char *file, int line,
const char *func,
const char *format, va_list args);
static inline void
print_event(const struct input_event *ev)
{
if (ev->type == EV_SYN)
printf("Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n",
ev->input_event_sec,
ev->input_event_usec,
libevdev_event_type_get_name(ev->type));
else
printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
ev->input_event_sec,
ev->input_event_usec,
ev->type,
libevdev_event_type_get_name(ev->type),
ev->code,
libevdev_event_code_get_name(ev->type, ev->code),
ev->value);
}
#endif /* _TEST_COMMON_H_ */

161
test/test-context.c Normal file
View file

@ -0,0 +1,161 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2019 Red Hat, Inc.
*/
#include "config.h"
#include "test-common.h"
START_TEST(test_info)
{
struct libevdev *d = libevdev_new();
libevdev_set_name(d, "some name");
ck_assert_str_eq(libevdev_get_name(d), "some name");
libevdev_set_phys(d, "physical");
ck_assert_str_eq(libevdev_get_phys(d), "physical");
libevdev_set_uniq(d, "very unique");
ck_assert_str_eq(libevdev_get_uniq(d), "very unique");
libevdev_set_id_bustype(d, 1);
libevdev_set_id_vendor(d, 2);
libevdev_set_id_product(d, 3);
libevdev_set_id_version(d, 4);
ck_assert_int_eq(libevdev_get_id_bustype(d), 1);
ck_assert_int_eq(libevdev_get_id_vendor(d), 2);
ck_assert_int_eq(libevdev_get_id_product(d), 3);
ck_assert_int_eq(libevdev_get_id_version(d), 4);
libevdev_free(d);
}
END_TEST
START_TEST(test_properties)
{
for (unsigned prop = 0; prop < INPUT_PROP_CNT; prop++) {
struct libevdev *d = libevdev_new();
ck_assert(!libevdev_has_property(d, prop));
libevdev_enable_property(d, prop);
ck_assert(libevdev_has_property(d, prop));
libevdev_free(d);
}
}
END_TEST
START_TEST(test_bits)
{
for (unsigned type = 1; type < EV_CNT; type++) {
unsigned max = libevdev_event_type_get_max(type);
if((int)max == -1)
continue;
for (unsigned code = 0; code <= max; code++) {
struct libevdev *d = libevdev_new();
const struct input_absinfo abs = {
.minimum = 10,
.maximum = 20,
.fuzz = 30,
.flat = 40,
.resolution = 50,
};
const void *data = NULL;
if (type == EV_ABS || type == EV_REP)
data = &abs;
ck_assert(!libevdev_has_event_code(d, type, code));
libevdev_enable_event_code(d, type, code, data);
ck_assert(libevdev_has_event_code(d, type, code));
libevdev_free(d);
}
}
}
END_TEST
START_TEST(test_mt_slots_enable_disable)
{
struct libevdev *d = libevdev_new();
struct input_absinfo abs = {0};
abs.maximum = 5;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 6);
libevdev_disable_event_code(d, EV_ABS, ABS_MT_SLOT);
ck_assert(!libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), -1);
abs.maximum = 2;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 3);
libevdev_free(d);
}
END_TEST
START_TEST(test_mt_slots_increase_decrease)
{
struct libevdev *d = libevdev_new();
struct input_absinfo abs = {0};
abs.maximum = 5;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 6);
abs.maximum = 2;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 3);
abs.maximum = 6;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 7);
abs.maximum = 10;
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
ck_assert_int_eq(libevdev_get_num_slots(d), 11);
libevdev_free(d);
}
END_TEST
START_TEST(test_mt_tracking_id)
{
struct libevdev *d = libevdev_new();
struct input_absinfo abs = { .maximum = 5 };
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
/* Not yet enabled, so 0. This is technically undefined */
for (int slot = 0; slot < 5; slot++)
ck_assert_int_eq(libevdev_get_slot_value(d, 0, ABS_MT_TRACKING_ID), 0);
libevdev_enable_event_code(d, EV_ABS, ABS_MT_TRACKING_ID, &abs);
for (int slot = 0; slot < 5; slot++)
ck_assert_int_eq(libevdev_get_slot_value(d, 0, ABS_MT_TRACKING_ID), -1);
libevdev_free(d);
}
END_TEST
TEST_SUITE(event_name_suite)
{
Suite *s = suite_create("Context manipulation");
add_test(s, test_info);
add_test(s, test_properties);
add_test(s, test_bits);
add_test(s, test_mt_slots_enable_disable);
add_test(s, test_mt_slots_increase_decrease);
add_test(s, test_mt_tracking_id);
return s;
}

View file

@ -1,29 +1,12 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
*
* 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include "test-common.h"
START_TEST(test_type_codes)
START_TEST(test_type_names)
{
ck_assert_int_eq(libevdev_event_type_from_name("EV_SYN"), EV_SYN);
ck_assert_int_eq(libevdev_event_type_from_name("EV_KEY"), EV_KEY);
@ -43,7 +26,7 @@ START_TEST(test_type_codes)
}
END_TEST
START_TEST(test_type_invalid)
START_TEST(test_type_names_invalid)
{
ck_assert_int_eq(libevdev_event_type_from_name("EV_Syn"), -1);
ck_assert_int_eq(libevdev_event_type_from_name("ev_SYN"), -1);
@ -55,7 +38,42 @@ START_TEST(test_type_invalid)
}
END_TEST
START_TEST(test_key_codes)
START_TEST(test_type_name_lookup)
{
ck_assert_int_eq(libevdev_event_type_from_code_name("SYN_REPORT"), EV_SYN);
ck_assert_int_eq(libevdev_event_type_from_code_name("KEY_A"), EV_KEY);
ck_assert_int_eq(libevdev_event_type_from_code_name("REL_Z"), EV_REL);
ck_assert_int_eq(libevdev_event_type_from_code_name("ABS_Z"), EV_ABS);
ck_assert_int_eq(libevdev_event_type_from_code_name("MSC_SERIAL"), EV_MSC);
ck_assert_int_eq(libevdev_event_type_from_code_name("SND_TONE"), EV_SND);
ck_assert_int_eq(libevdev_event_type_from_code_name("SW_TABLET_MODE"), EV_SW);
ck_assert_int_eq(libevdev_event_type_from_code_name("LED_CHARGING"), EV_LED);
ck_assert_int_eq(libevdev_event_type_from_code_name("REP_PERIOD"), EV_REP);
ck_assert_int_eq(libevdev_event_type_from_code_name("FF_SPRING"), EV_FF);
ck_assert_int_eq(libevdev_event_type_from_code_name("FF_STATUS_STOPPED"), EV_FF_STATUS);
ck_assert_int_eq(libevdev_event_type_from_code_name_n("KEY_1zzzzz", 5), EV_KEY);
ck_assert_int_eq(libevdev_event_type_from_code_name_n("ABS_Zooom", 5), EV_ABS);
ck_assert_int_eq(libevdev_event_type_from_code_name("KEY_MAX"), EV_KEY);
ck_assert_int_eq(libevdev_event_type_from_code_name("REL_MAX"), EV_REL);
ck_assert_int_eq(libevdev_event_type_from_code_name("ABS_MAX"), EV_ABS);
}
END_TEST
START_TEST(test_type_name_lookup_invalid)
{
ck_assert_int_eq(libevdev_event_type_from_name("SYN_REPORTED"), -1);
ck_assert_int_eq(libevdev_event_type_from_name("syn_blah"), -1);
ck_assert_int_eq(libevdev_event_type_from_name("SYN_"), -1);
ck_assert_int_eq(libevdev_event_type_from_name("KEY_BANANA"), -1);
ck_assert_int_eq(libevdev_event_type_from_name_n("KEY_BA", 6), -1);
ck_assert_int_eq(libevdev_event_type_from_name_n("KEY_BLAH", 8), -1);
}
END_TEST
START_TEST(test_code_names)
{
ck_assert_int_eq(libevdev_event_code_from_name(EV_SYN, "SYN_REPORT"), SYN_REPORT);
ck_assert_int_eq(libevdev_event_code_from_name(EV_ABS, "ABS_X"), ABS_X);
@ -72,13 +90,37 @@ START_TEST(test_key_codes)
ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "KEY_0"), KEY_0);
ck_assert_int_eq(libevdev_event_code_from_name(EV_FF, "FF_GAIN"), FF_GAIN);
ck_assert_int_eq(libevdev_event_code_from_name(EV_FF_STATUS, "FF_STATUS_MAX"), FF_STATUS_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_SW, "SW_MAX"), SW_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_SW, "SW_PEN_INSERTED"), SW_PEN_INSERTED);
ck_assert_int_eq(libevdev_event_code_from_name_n(EV_ABS, "ABS_YXZ", 5), ABS_Y);
}
END_TEST
START_TEST(test_key_invalid)
START_TEST(test_code_name_lookup)
{
/* Same as test_code_names() but without the type */
ck_assert_int_eq(libevdev_event_code_from_code_name("SYN_REPORT"), SYN_REPORT);
ck_assert_int_eq(libevdev_event_code_from_code_name("ABS_X"), ABS_X);
ck_assert_int_eq(libevdev_event_code_from_code_name("BTN_A"), BTN_A);
ck_assert_int_eq(libevdev_event_code_from_code_name("KEY_A"), KEY_A);
ck_assert_int_eq(libevdev_event_code_from_code_name("REL_X"), REL_X);
ck_assert_int_eq(libevdev_event_code_from_code_name("MSC_RAW"), MSC_RAW);
ck_assert_int_eq(libevdev_event_code_from_code_name("LED_KANA"), LED_KANA);
ck_assert_int_eq(libevdev_event_code_from_code_name("SND_BELL"), SND_BELL);
ck_assert_int_eq(libevdev_event_code_from_code_name("REP_DELAY"), REP_DELAY);
ck_assert_int_eq(libevdev_event_code_from_code_name("SYN_DROPPED"), SYN_DROPPED);
ck_assert_int_eq(libevdev_event_code_from_code_name("KEY_RESERVED"), KEY_RESERVED);
ck_assert_int_eq(libevdev_event_code_from_code_name("BTN_0"), BTN_0);
ck_assert_int_eq(libevdev_event_code_from_code_name("KEY_0"), KEY_0);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_GAIN"), FF_GAIN);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_STATUS_MAX"), FF_STATUS_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("SW_PEN_INSERTED"), SW_PEN_INSERTED);
ck_assert_int_eq(libevdev_event_code_from_code_name_n("ABS_YXZ", 5), ABS_Y);
}
END_TEST
START_TEST(test_code_names_invalid)
{
ck_assert_int_eq(libevdev_event_code_from_name(EV_MAX, "MAX_FAKE"), -1);
ck_assert_int_eq(libevdev_event_code_from_name(EV_CNT, "CNT_FAKE"), -1);
@ -99,6 +141,76 @@ START_TEST(test_key_invalid)
}
END_TEST
START_TEST(test_code_name_lookup_invalid)
{
/* Same as test_code_names_invalid() but without the type */
ck_assert_int_eq(libevdev_event_code_from_code_name("MAX_FAKE"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("CNT_FAKE"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("PWR_SOMETHING"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("EV_ABS"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("ABS_XY"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("BTN_GAMEPAD"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("BUS_PCI"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_STATUS"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_STATUS_"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_STATUS"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_STATUS_"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("ID_BUS"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("SND_CNT"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name("SW_CNT"), -1);
ck_assert_int_eq(libevdev_event_code_from_code_name_n("ABS_X", 4), -1);
}
END_TEST
START_TEST(test_code_names_max)
{
ck_assert_int_eq(libevdev_event_code_from_name(EV_SYN, "SYN_MAX"), SYN_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "KEY_MAX"), KEY_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_REL, "REL_MAX"), REL_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_ABS, "ABS_MAX"), ABS_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_MSC, "MSC_MAX"), MSC_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_SW, "SW_MAX"), SW_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_LED, "LED_MAX"), LED_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_SND, "SND_MAX"), SND_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_REP, "REP_MAX"), REP_MAX);
ck_assert_int_eq(libevdev_event_code_from_name(EV_FF, "FF_MAX"), FF_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("SYN_MAX"), SYN_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("KEY_MAX"), KEY_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("REL_MAX"), REL_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("ABS_MAX"), ABS_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("MSC_MAX"), MSC_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("SW_MAX"), SW_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("LED_MAX"), LED_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("SND_MAX"), SND_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("REP_MAX"), REP_MAX);
ck_assert_int_eq(libevdev_event_code_from_code_name("FF_MAX"), FF_MAX);
}
END_TEST
START_TEST(test_value_names)
{
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PALM"), MT_TOOL_PALM);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_FINGER"), MT_TOOL_FINGER);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PEN"), MT_TOOL_PEN);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_MAX"), MT_TOOL_MAX);
}
END_TEST
START_TEST(test_value_names_invalid)
{
ck_assert_int_eq(libevdev_event_value_from_name(EV_SYN, REL_X, "MT_TOOL_PALM"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_REL, REL_X, "MT_TOOL_PALM"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_X, "MT_TOOL_PALM"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PALMA"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, ""), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "EV_ABS"), -1);
ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "ABS_X"), -1);
}
END_TEST
START_TEST(test_properties)
{
struct prop {
@ -131,25 +243,26 @@ START_TEST(test_properties_invalid)
}
END_TEST
Suite *
event_code_suite(void)
TEST_SUITE(event_code_suite)
{
Suite *s = suite_create("Event codes");
TCase *tc = tcase_create("type tests");
tcase_add_test(tc, test_type_codes);
tcase_add_test(tc, test_type_invalid);
suite_add_tcase(s, tc);
add_test(s, test_type_names);
add_test(s, test_type_names_invalid);
add_test(s, test_type_name_lookup);
add_test(s, test_type_name_lookup_invalid);
tc = tcase_create("key tests");
tcase_add_test(tc, test_key_codes);
tcase_add_test(tc, test_key_invalid);
suite_add_tcase(s, tc);
add_test(s, test_code_names);
add_test(s, test_code_name_lookup);
add_test(s, test_code_names_invalid);
add_test(s, test_code_name_lookup_invalid);
add_test(s, test_code_names_max);
tc = tcase_create("property tests");
tcase_add_test(tc, test_properties);
tcase_add_test(tc, test_properties_invalid);
suite_add_tcase(s, tc);
add_test(s, test_value_names);
add_test(s, test_value_names_invalid);
add_test(s, test_properties);
add_test(s, test_properties_invalid);
return s;
}

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include "test-common.h"
START_TEST(test_limits)
@ -36,6 +19,7 @@ START_TEST(test_limits)
ck_assert(libevdev_event_code_get_name(EV_REP, REP_MAX + 1) == NULL);
ck_assert(libevdev_event_code_get_name(EV_FF, FF_MAX + 1) == NULL);
ck_assert(libevdev_event_code_get_name(EV_MAX + 1, 0) == NULL);
ck_assert(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_MAX + 1) == NULL);
}
END_TEST
@ -143,6 +127,15 @@ START_TEST(test_code_snd_name)
}
END_TEST
START_TEST(test_code_rep_name)
{
ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_DELAY), "REP_DELAY");
ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_PERIOD), "REP_PERIOD");
ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_MAX), "REP_PERIOD");
}
END_TEST
START_TEST(test_code_msc_name)
{
/* pick out a few only */
@ -164,7 +157,8 @@ START_TEST(test_code_sw_name)
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_LID), "SW_LID");
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_RFKILL_ALL), "SW_RFKILL_ALL");
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_LINEIN_INSERT), "SW_LINEIN_INSERT");
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_MAX), "SW_MAX");
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_PEN_INSERTED), "SW_PEN_INSERTED");
ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_MAX), "SW_USB_INSERT");
}
END_TEST
@ -191,6 +185,35 @@ START_TEST(test_code_syn_name)
}
END_TEST
START_TEST(test_value_name)
{
unsigned int type, code;
int value;
for (type = 0; type < EV_MAX; type++) {
int max = libevdev_event_type_get_max(type);
if (max == -1)
continue;
for (code = 0; code < (unsigned int)max; code++) {
if (type == EV_ABS && code == ABS_MT_TOOL_TYPE)
continue;
for (value = 0; value < 0xff; value++) {
ck_assert(libevdev_event_value_get_name(type, code, value) == NULL);
}
}
}
ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER), "MT_TOOL_FINGER");
ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM), "MT_TOOL_PALM");
ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PEN), "MT_TOOL_PEN");
ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_MAX), "MT_TOOL_MAX");
ck_assert(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, -1) == NULL);
}
END_TEST
START_TEST(test_prop_name)
{
ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_POINTER), "INPUT_PROP_POINTER");
@ -261,40 +284,31 @@ START_TEST(test_event_code)
}
END_TEST
Suite *
event_name_suite(void)
TEST_SUITE(event_name_suite)
{
Suite *s = suite_create("Event names");
TCase *tc = tcase_create("type limits");
tcase_add_test(tc, test_limits);
tcase_add_test(tc, test_event_type_max);
suite_add_tcase(s, tc);
add_test(s, test_limits);
add_test(s, test_event_type_max);
tc = tcase_create("type names");
tcase_add_test(tc, test_type_name);
suite_add_tcase(s, tc);
add_test(s, test_type_name);
tc = tcase_create("code names");
tcase_add_test(tc, test_code_abs_name);
tcase_add_test(tc, test_code_rel_name);
tcase_add_test(tc, test_code_key_name);
tcase_add_test(tc, test_code_led_name);
tcase_add_test(tc, test_code_snd_name);
tcase_add_test(tc, test_code_msc_name);
tcase_add_test(tc, test_code_sw_name);
tcase_add_test(tc, test_code_ff_name);
tcase_add_test(tc, test_code_syn_name);
suite_add_tcase(s, tc);
add_test(s, test_code_abs_name);
add_test(s, test_code_rel_name);
add_test(s, test_code_key_name);
add_test(s, test_code_led_name);
add_test(s, test_code_snd_name);
add_test(s, test_code_rep_name);
add_test(s, test_code_msc_name);
add_test(s, test_code_sw_name);
add_test(s, test_code_ff_name);
add_test(s, test_code_syn_name);
tc = tcase_create("prop names");
tcase_add_test(tc, test_prop_name);
suite_add_tcase(s, tc);
add_test(s, test_value_name);
add_test(s, test_prop_name);
tc = tcase_create("event values");
tcase_add_test(tc, test_event_type);
tcase_add_test(tc, test_event_code);
suite_add_tcase(s, tc);
add_test(s, test_event_type);
add_test(s, test_event_code);
return s;
}

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <limits.h>
#include <libevdev/libevdev-int.h>
#include "test-common.h"
@ -33,9 +16,6 @@ START_TEST(test_queue_alloc)
rc = queue_alloc(&dev, 0);
ck_assert_int_eq(rc, -ENOMEM);
rc = queue_alloc(&dev, ULONG_MAX);
ck_assert_int_eq(rc, -ENOMEM);
rc = queue_alloc(&dev, 100);
ck_assert_int_eq(rc, 0);
@ -329,8 +309,7 @@ START_TEST(test_queue_set_num_elements)
}
END_TEST
Suite *
queue_suite(void)
TEST_SUITE(queue_suite)
{
Suite *s = suite_create("Event queue");

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2014 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
@ -61,15 +44,17 @@ START_TEST(test_revoke)
uinput_device_event(uidev, EV_REL, REL_X, 1);
uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
for (int i = 0; i < 2; i++) {
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
ck_assert_int_eq(ev1.type, ev2.type);
ck_assert_int_eq(ev1.code, ev2.code);
ck_assert_int_eq(ev1.value, ev2.value);
ck_assert_int_eq(ev1.type, ev2.type);
ck_assert_int_eq(ev1.code, ev2.code);
ck_assert_int_eq(ev1.value, ev2.value);
}
/* revoke first device, expect it closed, second device still open */
dev_fd = libevdev_get_fd(dev);
@ -81,6 +66,9 @@ START_TEST(test_revoke)
}
ck_assert_msg(rc == 0, "Failed to revoke device: %s", strerror(errno));
uinput_device_event(uidev, EV_REL, REL_X, 1);
uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
ck_assert_int_eq(rc, -ENODEV);
@ -160,26 +148,13 @@ out:
}
END_TEST
int main(int argc, char **argv)
TEST_SUITE_ROOT_PRIVILEGES(kernel)
{
SRunner *sr;
Suite *s;
TCase *tc;
int failed;
Suite *s = suite_create("kernel");
s = suite_create("kernel tests");
add_test(s, test_revoke);
add_test(s, test_revoke_invalid);
add_test(s, test_revoke_fail_after);
tc = tcase_create("EVIOCREVOKE");
tcase_add_test(tc, test_revoke);
tcase_add_test(tc, test_revoke_invalid);
tcase_add_test(tc, test_revoke_fail_after);
suite_add_tcase(s, tc);
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
failed = srunner_ntests_failed(sr);
srunner_free(sr);
return failed;
return s;
}

File diff suppressed because it is too large Load diff

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <linux/input.h>
#include <errno.h>
#include <unistd.h>
@ -117,6 +100,14 @@ START_TEST(test_event_codes)
continue;
}
#ifdef __FreeBSD__
/* Force feedback events are not supported by FreeBSD */
if (*evbit == EV_FF) {
evbit++;
continue;
}
#endif
max = libevdev_event_type_get_max(*evbit);
for (code = 1; code < max; code += 10) {
@ -125,10 +116,11 @@ START_TEST(test_event_codes)
test_create_abs_device(&uidev, &dev,
1, &abs,
-1);
} else
} else {
test_create_device(&uidev, &dev,
*evbit, code,
-1);
}
ck_assert_msg(libevdev_has_event_type(dev, *evbit), "for event type %d\n", *evbit);
ck_assert_msg(libevdev_has_event_code(dev, *evbit, code), "for type %d code %d", *evbit, code);
@ -249,7 +241,7 @@ START_TEST(test_input_props)
struct uinput_device* uidev;
struct libevdev *dev;
int rc, i;
struct input_absinfo abs = {0, 0, 2, 0, 0};
struct input_absinfo abs = { .value = 0, .minimum = 0, .maximum = 2};
uidev = uinput_device_new(TEST_DEVICE_NAME);
rc = uinput_device_set_abs_bit(uidev, ABS_X, &abs);
@ -282,7 +274,7 @@ START_TEST(test_set_input_props)
struct uinput_device* uidev;
struct libevdev *dev;
int rc, fd;
struct input_absinfo abs = {0, 0, 2, 0, 0};
struct input_absinfo abs = { .value = 0, .minimum = 0, .maximum = 2};
dev = libevdev_new();
ck_assert_int_eq(libevdev_enable_property(dev, INPUT_PROP_MAX + 1), -1);
@ -305,6 +297,13 @@ START_TEST(test_set_input_props)
ck_assert_int_eq(libevdev_has_property(dev, INPUT_PROP_DIRECT), 0);
ck_assert_int_eq(libevdev_has_property(dev, INPUT_PROP_BUTTONPAD), 1);
/* Test disabling the properties too */
ck_assert_int_eq(libevdev_disable_property(dev, INPUT_PROP_MAX + 1), -1);
ck_assert_int_eq(libevdev_disable_property(dev, INPUT_PROP_DIRECT), 0);
ck_assert_int_eq(libevdev_disable_property(dev, INPUT_PROP_BUTTONPAD), 0);
ck_assert_int_eq(libevdev_has_property(dev, INPUT_PROP_DIRECT), 0);
ck_assert_int_eq(libevdev_has_property(dev, INPUT_PROP_BUTTONPAD), 0);
uinput_device_free(uidev);
libevdev_free(dev);
}
@ -318,12 +317,14 @@ START_TEST(test_slot_init_value)
const int nabs = 6;
int i;
int fd;
struct input_absinfo abs[] = { { ABS_X, 0, 1000 },
{ ABS_Y, 0, 1000 },
{ ABS_MT_POSITION_X, 0, 1000 },
{ ABS_MT_POSITION_Y, 0, 1000 },
{ ABS_MT_TRACKING_ID, -1, 2 },
{ ABS_MT_SLOT, 0, 1 }};
struct input_absinfo abs[] = {
{ .value = ABS_X, .minimum = 0, .maximum = 1000 },
{ .value = ABS_Y, .minimum = 0, .maximum = 1000 },
{ .value = ABS_MT_POSITION_X, .minimum = 0, .maximum = 1000 },
{ .value = ABS_MT_POSITION_Y, .minimum = 0, .maximum = 1000 },
{ .value = ABS_MT_TRACKING_ID, .minimum = -1, .maximum = 2 },
{ .value = ABS_MT_SLOT, .minimum = 0, .maximum = 1 }
};
uidev = uinput_device_new(TEST_DEVICE_NAME);
@ -371,10 +372,12 @@ START_TEST(test_no_slots)
{
struct uinput_device* uidev;
struct libevdev *dev;
struct input_absinfo abs[] = { { ABS_X, 0, 2 },
{ ABS_Y, 0, 2 },
{ ABS_MT_POSITION_X, 0, 2 },
{ ABS_MT_POSITION_Y, 0, 2 }};
struct input_absinfo abs[] = {
{ .value = ABS_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_Y, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_Y, .minimum = 0, .maximum = 2 }
};
test_create_abs_device(&uidev, &dev, 4, abs,
-1);
@ -392,11 +395,13 @@ START_TEST(test_slot_number)
struct uinput_device* uidev;
struct libevdev *dev;
const int nslots = 4;
struct input_absinfo abs[] = { { ABS_X, 0, 2 },
{ ABS_Y, 0, 2 },
{ ABS_MT_POSITION_X, 0, 2 },
{ ABS_MT_POSITION_Y, 0, 2 },
{ ABS_MT_SLOT, 0, nslots - 1 }};
struct input_absinfo abs[] = {
{ .value = ABS_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_Y, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_Y, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_SLOT, .minimum = 0, .maximum = nslots - 1 }
};
test_create_abs_device(&uidev, &dev, 5, abs,
-1);
@ -415,12 +420,14 @@ START_TEST(test_invalid_mt_device)
struct libevdev *dev;
const int nslots = 4;
int value;
struct input_absinfo abs[] = { { ABS_X, 0, 2 },
{ ABS_Y, 0, 2 },
{ ABS_MT_POSITION_X, 0, 2 },
{ ABS_MT_POSITION_Y, 0, 2 },
{ ABS_MT_SLOT - 1, 0, 2 },
{ ABS_MT_SLOT, 0, nslots - 1 }};
struct input_absinfo abs[] = {
{ .value = ABS_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_Y, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_X, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_POSITION_Y, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_SLOT - 1, .minimum = 0, .maximum = 2 },
{ .value = ABS_MT_SLOT, .minimum = 0, .maximum = nslots - 1 }
};
test_create_abs_device(&uidev, &dev, 6, abs,
-1);
@ -732,7 +739,7 @@ START_TEST(test_device_enable_bit)
{
struct uinput_device* uidev;
struct libevdev *dev, *dev2;
struct input_absinfo abs = {ABS_X, 0, 2};
struct input_absinfo abs = { .value = ABS_X, .minimum = 0, .maximum = 2 };
int rc;
test_create_abs_device(&uidev, &dev, 1, &abs,
@ -776,7 +783,7 @@ START_TEST(test_device_enable_bit_invalid)
{
struct uinput_device* uidev;
struct libevdev *dev;
struct input_absinfo abs = {ABS_X, 0, 1};
struct input_absinfo abs = { .value = ABS_X, .minimum = 0, .maximum = 1 };
test_create_abs_device(&uidev, &dev, 1, &abs,
-1);
@ -802,7 +809,10 @@ START_TEST(test_device_disable_bit)
struct uinput_device* uidev;
struct libevdev *dev, *dev2;
int rc;
struct input_absinfo abs[2] = {{ABS_X, 0, 1}, {ABS_Y, 0, 1}};
struct input_absinfo abs[2] = {
{ .value = ABS_X, .minimum = 0, .maximum = 1 },
{ .value = ABS_Y, .minimum = 0, .maximum = 1 },
};
test_create_abs_device(&uidev, &dev,
2, abs,
@ -848,7 +858,7 @@ START_TEST(test_device_disable_bit_invalid)
{
struct uinput_device* uidev;
struct libevdev *dev;
struct input_absinfo abs = {ABS_X, 0, 1};
struct input_absinfo abs = { .value = ABS_X, .minimum = 0, .maximum = 1 };
test_create_abs_device(&uidev, &dev, 1, &abs, -1);
@ -1142,61 +1152,44 @@ START_TEST(test_led_same)
}
END_TEST
Suite *
libevdev_has_event_test(void)
TEST_SUITE_ROOT_PRIVILEGES(has_events)
{
Suite *s = suite_create("libevdev_has_event tests");
TCase *tc = tcase_create("event type");
tcase_add_test(tc, test_ev_bit_limits);
tcase_add_test(tc, test_has_ev_bit);
suite_add_tcase(s, tc);
add_test(s, test_ev_bit_limits);
add_test(s, test_has_ev_bit);
tc = tcase_create("event codes");
tcase_add_test(tc, test_event_codes);
tcase_add_test(tc, test_event_code_limits);
suite_add_tcase(s, tc);
add_test(s, test_event_codes);
add_test(s, test_event_code_limits);
tc = tcase_create("ev_rep");
tcase_add_test(tc, test_ev_rep);
tcase_add_test(tc, test_ev_rep_values);
suite_add_tcase(s, tc);
add_test(s, test_ev_rep);
add_test(s, test_ev_rep_values);
tc = tcase_create("input properties");
tcase_add_test(tc, test_input_props);
tcase_add_test(tc, test_set_input_props);
suite_add_tcase(s, tc);
add_test(s, test_input_props);
add_test(s, test_set_input_props);
tc = tcase_create("multitouch info");
tcase_add_test(tc, test_no_slots);
tcase_add_test(tc, test_slot_number);
tcase_add_test(tc, test_slot_init_value);
tcase_add_test(tc, test_invalid_mt_device);
suite_add_tcase(s, tc);
add_test(s, test_no_slots);
add_test(s, test_slot_number);
add_test(s, test_slot_init_value);
add_test(s, test_invalid_mt_device);
tc = tcase_create("device info");
tcase_add_test(tc, test_device_name);
tcase_add_test(tc, test_device_set_name);
tcase_add_test(tc, test_device_set_ids);
tcase_add_test(tc, test_device_get_abs_info);
suite_add_tcase(s, tc);
add_test(s, test_device_name);
add_test(s, test_device_set_name);
add_test(s, test_device_set_ids);
add_test(s, test_device_get_abs_info);
tc = tcase_create("device bit manipulation");
tcase_add_test(tc, test_device_set_abs);
tcase_add_test(tc, test_device_enable_bit);
tcase_add_test(tc, test_device_enable_bit_invalid);
tcase_add_test(tc, test_device_disable_bit);
tcase_add_test(tc, test_device_disable_bit_invalid);
tcase_add_test(tc, test_device_kernel_change_axis);
tcase_add_test(tc, test_device_kernel_change_axis_invalid);
tcase_add_test(tc, test_device_kernel_set_abs_invalid_fd);
suite_add_tcase(s, tc);
add_test(s, test_device_set_abs);
add_test(s, test_device_enable_bit);
add_test(s, test_device_enable_bit_invalid);
add_test(s, test_device_disable_bit);
add_test(s, test_device_disable_bit_invalid);
add_test(s, test_device_kernel_change_axis);
add_test(s, test_device_kernel_change_axis_invalid);
add_test(s, test_device_kernel_set_abs_invalid_fd);
tc = tcase_create("led manipulation");
tcase_add_test(tc, test_led_valid);
tcase_add_test(tc, test_led_invalid);
tcase_add_test(tc, test_led_same);
suite_add_tcase(s, tc);
add_test(s, test_led_valid);
add_test(s, test_led_invalid);
add_test(s, test_led_same);
return s;
}

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
@ -468,10 +451,98 @@ START_TEST(test_device_grab_invalid_fd)
}
END_TEST
START_TEST(test_device_grab_change_fd)
{
struct libevdev_uinput *uidev;
struct libevdev *dev, *other;
struct input_event e;
int rc;
int other_fd;
int dev_fd;
dev = libevdev_new();
libevdev_set_name(dev, "libevdev test device");
libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL);
rc = libevdev_uinput_create_from_device(dev,
LIBEVDEV_UINPUT_OPEN_MANAGED,
&uidev);
ck_assert_int_eq(rc, 0);
libevdev_free(dev);
dev_fd = open(libevdev_uinput_get_devnode(uidev),
O_RDONLY|O_NONBLOCK);
ck_assert_int_ne(dev_fd, -1);
rc = libevdev_new_from_fd(dev_fd, &dev);
ck_assert_int_eq(rc, 0);
other_fd = open(libevdev_uinput_get_devnode(uidev),
O_RDONLY|O_NONBLOCK);
ck_assert_int_ne(other_fd, -1);
rc = libevdev_new_from_fd(other_fd, &other);
ck_assert_int_eq(rc, 0);
/* check we're getting the events before the grab */
libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1);
libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, -EAGAIN);
/* no events after the grab */
rc = libevdev_grab(dev, LIBEVDEV_GRAB);
ck_assert_int_eq(rc, 0);
libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1);
libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_grab(dev, LIBEVDEV_GRAB);
ck_assert_int_eq(rc, 0);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, -EAGAIN);
/* swapping the fd removes the grab */
close(dev_fd);
dev_fd = open(libevdev_uinput_get_devnode(uidev),
O_RDONLY|O_NONBLOCK);
ck_assert_int_ne(dev_fd, -1);
rc = libevdev_change_fd(dev, dev_fd);
ck_assert_int_eq(rc, 0);
/* check we're getting the events again */
libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1);
libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, -EAGAIN);
/* no events after the grab */
rc = libevdev_grab(dev, LIBEVDEV_GRAB);
ck_assert_int_eq(rc, 0);
libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1);
libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e);
ck_assert_int_eq(rc, -EAGAIN);
libevdev_uinput_destroy(uidev);
libevdev_free(dev);
libevdev_free(other);
close(dev_fd);
close(other_fd);
}
END_TEST
START_TEST(test_set_clock_id)
{
struct uinput_device* uidev;
struct libevdev *dev;
int clockid;
int rc;
test_create_device(&uidev, &dev,
@ -490,7 +561,13 @@ START_TEST(test_set_clock_id)
rc = libevdev_set_clock_id(dev, CLOCK_MONOTONIC);
ck_assert_int_eq(rc, 0);
rc = libevdev_set_clock_id(dev, CLOCK_MONOTONIC_RAW);
#ifdef __FreeBSD__
clockid = CLOCK_MONOTONIC_FAST;
#else
clockid = CLOCK_MONOTONIC_RAW;
#endif
rc = libevdev_set_clock_id(dev, clockid);
ck_assert_int_eq(rc, -EINVAL);
uinput_device_free(uidev);
@ -575,19 +652,19 @@ START_TEST(test_clock_id_events)
ck_assert_int_eq(ev1.code, ev2.code);
ck_assert_int_eq(ev1.value, ev2.value);
t1 = ev1.time.tv_sec * 1000000LL + ev1.time.tv_usec;
t2 = ev2.time.tv_sec * 1000000LL + ev2.time.tv_usec;
t1 = ev1.input_event_sec * 1000000LL + ev1.input_event_usec;
t2 = ev2.input_event_sec * 1000000LL + ev2.input_event_usec;
ck_assert_int_ne(t1, t2);
ck_assert_int_ge(ev1.time.tv_sec, t1_real.tv_sec);
ck_assert_int_ge(ev1.time.tv_usec, t1_real.tv_nsec/1000);
ck_assert_int_le(ev1.time.tv_sec, t2_real.tv_sec);
ck_assert_int_le(ev1.time.tv_usec, t2_real.tv_nsec/1000);
ck_assert_int_ge(ev1.input_event_sec, t1_real.tv_sec);
ck_assert_int_ge(ev1.input_event_usec, t1_real.tv_nsec/1000);
ck_assert_int_le(ev1.input_event_sec, t2_real.tv_sec);
ck_assert_int_le(ev1.input_event_usec, t2_real.tv_nsec/1000);
ck_assert_int_ge(ev2.time.tv_sec, t1_mono.tv_sec);
ck_assert_int_ge(ev2.time.tv_usec, t1_mono.tv_nsec/1000);
ck_assert_int_le(ev2.time.tv_sec, t2_mono.tv_sec);
ck_assert_int_le(ev2.time.tv_usec, t2_mono.tv_nsec/1000);
ck_assert_int_ge(ev2.input_event_sec, t1_mono.tv_sec);
ck_assert_int_ge(ev2.input_event_usec, t1_mono.tv_nsec/1000);
ck_assert_int_le(ev2.input_event_sec, t2_mono.tv_sec);
ck_assert_int_le(ev2.input_event_usec, t2_mono.tv_nsec/1000);
uinput_device_free(uidev);
libevdev_free(dev);
@ -596,42 +673,32 @@ START_TEST(test_clock_id_events)
}
END_TEST
Suite *
libevdev_init_test(void)
TEST_SUITE_ROOT_PRIVILEGES(libevdev_init_test)
{
Suite *s = suite_create("libevdev init tests");
TCase *tc = tcase_create("device init");
tcase_add_test(tc, test_new_device);
tcase_add_test(tc, test_free_device);
tcase_add_test(tc, test_init_from_invalid_fd);
tcase_add_test(tc, test_init_and_change_fd);
suite_add_tcase(s, tc);
add_test(s, test_new_device);
add_test(s, test_free_device);
add_test(s, test_init_from_invalid_fd);
add_test(s, test_init_and_change_fd);
tc = tcase_create("log init");
tcase_add_test(tc, test_log_init);
tcase_add_test(tc, test_log_priority);
tcase_add_test(tc, test_log_set_get_priority);
tcase_add_test(tc, test_log_default_priority);
tcase_add_test(tc, test_log_data);
tcase_add_test(tc, test_device_log_init);
suite_add_tcase(s, tc);
add_test(s, test_log_init);
add_test(s, test_log_priority);
add_test(s, test_log_set_get_priority);
add_test(s, test_log_default_priority);
add_test(s, test_log_data);
add_test(s, test_device_log_init);
tc = tcase_create("device fd init");
tcase_add_test(tc, test_device_init);
tcase_add_test(tc, test_device_init_from_fd);
suite_add_tcase(s, tc);
add_test(s, test_device_init);
add_test(s, test_device_init_from_fd);
tc = tcase_create("device grab");
tcase_add_test(tc, test_device_grab);
tcase_add_test(tc, test_device_grab_invalid_fd);
suite_add_tcase(s, tc);
add_test(s, test_device_grab);
add_test(s, test_device_grab_invalid_fd);
add_test(s, test_device_grab_change_fd);
tc = tcase_create("clock id");
tcase_add_test(tc, test_set_clock_id);
tcase_add_test(tc, test_set_clock_id_invalid_fd);
tcase_add_test(tc, test_clock_id_events);
suite_add_tcase(s, tc);
add_test(s, test_set_clock_id);
add_test(s, test_set_clock_id_invalid_fd);
add_test(s, test_clock_id_events);
return s;
}

View file

@ -1,48 +1,33 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <check.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libevdev/libevdev.h>
#include "test-common.h"
extern Suite *event_name_suite(void);
extern Suite *event_code_suite(void);
extern Suite *libevdev_init_test(void);
extern Suite *queue_suite(void);
extern Suite *libevdev_has_event_test(void);
extern Suite *libevdev_events(void);
extern Suite *uinput_suite(void);
static int
is_debugger_attached(void)
{
int rc = 1;
/*
* FreeBSD does not support PTRACE_ATTACH, disable attaching a debugger
* on FreeBSD by skipping the rest of the function and just return 1.
*/
#ifndef __FreeBSD__
int status;
int rc;
int pid = fork();
if (pid == -1)
@ -55,35 +40,75 @@ is_debugger_attached(void)
ptrace(PTRACE_CONT, NULL, NULL);
ptrace(PTRACE_DETACH, ppid, NULL, NULL);
rc = 0;
} else
rc = 1;
}
_exit(rc);
} else {
waitpid(pid, &status, 0);
rc = WEXITSTATUS(status);
}
#endif /* !__FreeBSD__ */
return rc;
}
int main(int argc, char **argv)
static bool
device_nodes_exist(void)
{
struct stat st;
int rc;
rc = stat("/dev/uinput", &st);
if (rc == -1 && errno == ENOENT)
return false;
rc = stat("/dev/input", &st);
if (rc == -1 && errno == ENOENT)
return false;
/* Any issues but ENOENT we just let the test suite blow up later */
return true;
}
extern const struct libevdev_test __start_test_section, __stop_test_section;
int main(void)
{
const struct libevdev_test *t;
const struct rlimit corelimit = {0, 0};
int failed;
for (t = &__start_test_section; t < &__stop_test_section; t++) {
if (t->needs_root_privileges) {
if (getenv("LIBEVDEV_SKIP_ROOT_TESTS"))
return 77;
if (getuid() != 0) {
fprintf(stderr, "This test needs to run as root\n");
return 77;
}
if (!device_nodes_exist()) {
fprintf(stderr, "This test needs /dev/input and /dev/uinput to exist\n");
return 77;
}
break;
}
}
if (is_debugger_attached())
setenv("CK_FORK", "no", 0);
if (setrlimit(RLIMIT_CORE, &corelimit) != 0)
perror("WARNING: Core dumps not disabled. Reason");
libevdev_set_log_function(test_logfunc_abort_on_error, NULL);
Suite *s = libevdev_has_event_test();
SRunner *sr = srunner_create(s);
srunner_add_suite(sr, libevdev_events());
srunner_add_suite(sr, libevdev_init_test());
srunner_add_suite(sr, queue_suite());
srunner_add_suite(sr, event_name_suite());
srunner_add_suite(sr, event_code_suite());
srunner_add_suite(sr, uinput_suite());
srunner_run_all(sr, CK_NORMAL);
SRunner *sr = srunner_create(NULL);
for (t = &__start_test_section; t < &__stop_test_section; t++) {
srunner_add_suite(sr, t->setup());
}
srunner_run_all(sr, CK_ENV);
failed = srunner_ntests_failed(sr);
srunner_free(sr);

View file

@ -0,0 +1,21 @@
#!/usr/bin/env bash
#
# Hack to check for leaking symbols in the static library.
# See https://bugs.freedesktop.org/show_bug.cgi?id=82785
# Note the spaces in the expressions! After the first grep, each line
# is " T symbol_name"
test -z "$RUNNING_ON_VALGRIND" || exit 77
builddir="$1"
test -f "$builddir/test-static-link" || (echo "Unable to find test file" && exit 1)
nm --extern-only "$builddir/test-static-link" |
grep -o -e " T .*" | \
grep -v -e " main\$" \
-e " atexit" \
-e " mangle_path" \
-e " *gcov.*" \
-e " _.*" \
-e " libevdev_*" && \
echo "Leaking symbols found" && exit 1 || exit 0

View file

@ -1,26 +1,9 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <linux/input.h>
#include <errno.h>
#include <unistd.h>
@ -69,7 +52,7 @@ START_TEST(test_uinput_create_device)
if (max == -1)
continue;
for (code = 0; code < max; code++) {
for (code = 0; code < (unsigned int)max; code++) {
ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
libevdev_has_event_code(dev2, type, code));
}
@ -150,7 +133,7 @@ START_TEST(test_uinput_create_device_from_fd)
if (max == -1)
continue;
for (code = 0; code < max; code++) {
for (code = 0; code < (unsigned int)max; code++) {
ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
libevdev_has_event_code(dev2, type, code));
}
@ -164,6 +147,93 @@ START_TEST(test_uinput_create_device_from_fd)
}
END_TEST
#ifdef __FreeBSD__
START_TEST(test_uinput_check_devnode_bsd)
{
struct libevdev *dev;
struct libevdev_uinput *uidev, *uidev2;
const char *devnode, *devnode2;
int fd, fd2;
int rc;
dev = libevdev_new();
ck_assert(dev != NULL);
libevdev_set_name(dev, TEST_DEVICE_NAME);
libevdev_enable_event_type(dev, EV_SYN);
libevdev_enable_event_type(dev, EV_REL);
libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
fd = open(UINPUT_NODE, O_RDWR);
ck_assert_int_gt(fd, -1);
fd2 = open(UINPUT_NODE, O_RDWR);
ck_assert_int_gt(fd2, -1);
rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
ck_assert_int_eq(rc, 0);
/* create a second one */
libevdev_set_name(dev, TEST_DEVICE_NAME " 2");
rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
ck_assert_int_eq(rc, 0);
devnode = libevdev_uinput_get_devnode(uidev);
ck_assert(devnode != NULL);
/* get syspath twice returns same pointer */
devnode2 = libevdev_uinput_get_devnode(uidev);
ck_assert(devnode == devnode2);
/* second dev has different devnode */
devnode2 = libevdev_uinput_get_devnode(uidev2);
ck_assert(strcmp(devnode, devnode2) != 0);
libevdev_uinput_destroy(uidev2);
libevdev_uinput_destroy(uidev);
close(fd2);
close(fd);
libevdev_free(dev);
}
END_TEST
START_TEST(test_uinput_check_syspath_bsd)
{
struct libevdev *dev;
struct libevdev_uinput *uidev;
const char *syspath;
int fd;
int rc;
dev = libevdev_new();
ck_assert(dev != NULL);
libevdev_set_name(dev, TEST_DEVICE_NAME);
libevdev_enable_event_type(dev, EV_SYN);
libevdev_enable_event_type(dev, EV_REL);
libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
fd = open(UINPUT_NODE, O_RDWR);
ck_assert_int_gt(fd, -1);
rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
ck_assert_int_eq(rc, 0);
syspath = libevdev_uinput_get_syspath(uidev);
/* FreeBSD should always return NULL for libevdev_unput_get_syspath() */
ck_assert(syspath == NULL);
libevdev_uinput_destroy(uidev);
close(fd);
libevdev_free(dev);
}
END_TEST
#else /* !__FreeBSD__ */
START_TEST(test_uinput_check_syspath_time)
{
struct libevdev *dev;
@ -269,6 +339,8 @@ START_TEST(test_uinput_check_syspath_name)
}
END_TEST
#endif /* __FreeBSD __ */
START_TEST(test_uinput_events)
{
struct libevdev *dev;
@ -368,26 +440,24 @@ START_TEST(test_uinput_properties)
}
END_TEST
Suite *
uinput_suite(void)
TEST_SUITE_ROOT_PRIVILEGES(uinput_suite)
{
Suite *s = suite_create("libevdev uinput device tests");
TCase *tc = tcase_create("device creation");
tcase_add_test(tc, test_uinput_create_device);
tcase_add_test(tc, test_uinput_create_device_invalid);
tcase_add_test(tc, test_uinput_create_device_from_fd);
tcase_add_test(tc, test_uinput_check_syspath_time);
tcase_add_test(tc, test_uinput_check_syspath_name);
suite_add_tcase(s, tc);
add_test(s, test_uinput_create_device);
add_test(s, test_uinput_create_device_invalid);
add_test(s, test_uinput_create_device_from_fd);
#ifdef __FreeBSD__
add_test(s, test_uinput_check_devnode_bsd);
add_test(s, test_uinput_check_syspath_bsd);
#else
add_test(s, test_uinput_check_syspath_time);
add_test(s, test_uinput_check_syspath_name);
#endif
tc = tcase_create("device events");
tcase_add_test(tc, test_uinput_events);
suite_add_tcase(s, tc);
add_test(s, test_uinput_events);
tc = tcase_create("device properties");
tcase_add_test(tc, test_uinput_properties);
suite_add_tcase(s, tc);
add_test(s, test_uinput_properties);
return s;
}

View file

@ -18,3 +18,10 @@
fun:ioctl
fun:test_revoke*
}
{
<bash_memleak>
Memcheck:Leak
...
fun:reader_loop
fun:main
}

View file

@ -1,4 +1,4 @@
noinst_PROGRAMS = libevdev-events
noinst_PROGRAMS = libevdev-events libevdev-list-codes
bin_PROGRAMS = \
touchpad-edge-detector \
mouse-dpi-tool \
@ -10,6 +10,9 @@ libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la
libevdev_events_SOURCES = libevdev-events.c
libevdev_events_LDADD = $(libevdev_ldadd)
libevdev_list_codes_SOURCES = libevdev-list-codes.c
libevdev_list_codes_LDADD = $(libevdev_ldadd)
touchpad_edge_detector_SOURCES = touchpad-edge-detector.c
touchpad_edge_detector_LDADD = $(libevdev_ldadd)
@ -18,4 +21,9 @@ mouse_dpi_tool_LDADD = $(libevdev_ldadd)
libevdev_tweak_device_SOURCES = libevdev-tweak-device.c
libevdev_tweak_device_LDADD = $(libevdev_ldadd)
libevdev_tweak_device_MANS = libevdev-tweak-device.1
dist_man_MANS = \
libevdev-tweak-device.1 \
mouse-dpi-tool.1 \
touchpad-edge-detector.1 \
$(NULL)

View file

@ -1,37 +1,20 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2013 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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 <config.h>
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <linux/input.h>
#include <sys/types.h>
#include "libevdev.h"
#include "libevdev/libevdev.h"
static void
print_abs_bits(struct libevdev *dev, int axis)
@ -112,13 +95,13 @@ print_event(struct input_event *ev)
{
if (ev->type == EV_SYN)
printf("Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n",
ev->time.tv_sec,
ev->time.tv_usec,
ev->input_event_sec,
ev->input_event_usec,
libevdev_event_type_get_name(ev->type));
else
printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
ev->time.tv_sec,
ev->time.tv_usec,
ev->input_event_sec,
ev->input_event_usec,
ev->type,
libevdev_event_type_get_name(ev->type),
ev->code,

View file

@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Red Hat, Inc.
*/
/* Lists all event types and codes currently known by libevdev. */
#include "config.h"
#include <stdio.h>
#include <linux/input.h>
#include "libevdev/libevdev.h"
static void
list_event_codes(unsigned int type, unsigned int max)
{
const char *typestr = libevdev_event_type_get_name(type);
if (!typestr)
return;
printf("- %s:\n", typestr);
for (unsigned int code = 0; code <= max; code++) {
const char *str = libevdev_event_code_get_name(type, code);
if (!str)
continue;
printf(" %d: %s\n", code, str);
}
}
int
main (int argc, char **argv)
{
printf("codes:\n");
for (unsigned int type = 0; type <= EV_MAX; type++) {
int max = libevdev_event_type_get_max(type);
if (max == -1)
continue;
list_event_codes(type, (unsigned int)max);
}
return 0;
}

View file

@ -1,46 +1,29 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2014 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
#define _GNU_SOURCE
#include <config.h>
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <linux/input.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <linux/input.h>
#include <sys/types.h>
#include <unistd.h>
#include "libevdev.h"
#include "libevdev/libevdev.h"
static void
usage(void)
usage(const char *progname)
{
printf("%s --abs <axis> [--min min] [--max max] [--res res] [--fuzz fuzz] [--flat flat] /dev/input/eventXYZ\n"
"\tChange the absinfo struct for the named axis\n"
@ -48,9 +31,9 @@ usage(void)
"\tChange the x/y resolution on the given device\n"
"%s --led <led> --on|--off /dev/input/eventXYZ\n"
"\tEnable or disable the named LED\n",
program_invocation_short_name,
program_invocation_short_name,
program_invocation_short_name);
progname,
progname,
progname);
}
enum mode {
@ -416,7 +399,7 @@ main(int argc, char **argv)
rc = EXIT_SUCCESS;
/* fallthrough */
case MODE_NONE:
usage();
usage(basename(argv[0]));
goto out;
case MODE_ABS:
rc = parse_options_abs(argc, argv, &changes, &axis,
@ -440,7 +423,7 @@ main(int argc, char **argv)
if (optind >= argc) {
rc = EXIT_FAILURE;
usage();
usage(basename(argv[0]));
goto out;
}

18
tools/mouse-dpi-tool.1 Normal file
View file

@ -0,0 +1,18 @@
.TH MOUSE-DPI-TOOL "1"
.SH NAME
mouse-dpi-tool \- mouse resolution estimation tool
.SH SYNOPSIS
.BR mouse-dpi-tool " <\fIevdev device\fP>"
.SH DESCRIPTION
.B mouse-dpi-tool
reads relative events (mouse movement events) and calculates the
distance covered and maximum frequency of the incoming events.
Combined with a measurement of the actual distance physically covered,
this allows the mouse's resolution to be estimated.
.PP
Some mouse devices provide dynamic frequencies, it is
recommended to measure multiple times to obtain the highest value.
.PP
.SH OPTIONS
.B mouse-dpi-tool
accepts no options.

View file

@ -1,55 +1,41 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2014 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 <libevdev/libevdev.h>
#include <sys/signalfd.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libevdev/libevdev.h"
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
static int signalled = 0;
struct measurements {
int distance;
double frequency;
double max_frequency;
double *frequencies;
size_t frequencies_sz;
size_t nfrequencies;
uint64_t us;
};
static int
usage(void) {
printf("Usage: %s /dev/input/event0\n", program_invocation_short_name);
usage(const char *progname) {
printf("Usage: %s /dev/input/event0\n", progname);
printf("\n");
printf("This tool reads relative events from the kernel and calculates\n"
"the distance covered and maximum frequency of the incoming events.\n"
@ -58,18 +44,27 @@ usage(void) {
return 1;
}
static inline uint64_t
tv2us(const struct timeval *tv)
{
return tv->tv_sec * 1000000 + tv->tv_usec;
}
static inline double
get_frequency(double last, double current)
get_frequency(uint64_t last, uint64_t current)
{
return 1000000.0/(current - last);
}
static inline void
push_frequency(struct measurements *m, double freq)
{
if (m->nfrequencies == m->frequencies_sz) {
m->frequencies_sz += 100;
m->frequencies = realloc(m->frequencies,
m->frequencies_sz * sizeof *m->frequencies);
if (!m->frequencies)
abort();
}
m->frequencies[m->nfrequencies] = freq;
m->nfrequencies++;
}
static int
print_current_values(const struct measurements *m)
{
@ -89,7 +84,7 @@ print_current_values(const struct measurements *m)
progress = (progress + 1) % 4;
printf("\rCovered distance in device units: %8d at frequency %3.1fHz %c",
abs(m->distance), m->frequency, status);
abs(m->distance), m->max_frequency, status);
return 0;
}
@ -101,20 +96,23 @@ handle_event(struct measurements *m, const struct input_event *ev)
const int idle_reset = 3000000; /* us */
uint64_t last_us = m->us;
m->us = tv2us(&ev->time);
m->us = ev->input_event_sec * 1000000 + ev->input_event_usec;
/* reset after pause */
if (last_us + idle_reset < m->us) {
m->frequency = 0.0;
m->max_frequency = 0.0;
m->distance = 0;
} else {
double freq = get_frequency(last_us, m->us);
m->frequency = max(freq, m->frequency);
push_frequency(m, freq);
m->max_frequency = max(freq, m->max_frequency);
return print_current_values(m);
}
return 0;
} else if (ev->type != EV_REL)
}
if (ev->type != EV_REL)
return 0;
switch(ev->code) {
@ -126,26 +124,26 @@ handle_event(struct measurements *m, const struct input_event *ev)
return 0;
}
static void
signal_handler(__attribute__((__unused__)) int signal)
{
signalled++;
}
static int
mainloop(struct libevdev *dev, struct measurements *m) {
struct pollfd fds[2];
sigset_t mask;
struct pollfd fds;
fds[0].fd = libevdev_get_fd(dev);
fds[0].events = POLLIN;
fds.fd = libevdev_get_fd(dev);
fds.events = POLLIN;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK);
fds[1].events = POLLIN;
signal(SIGINT, signal_handler);
sigprocmask(SIG_BLOCK, &mask, NULL);
while (poll(fds, 2, -1)) {
while (poll(&fds, 1, -1)) {
struct input_event ev;
int rc;
if (fds[1].revents)
if (signalled)
break;
do {
@ -153,39 +151,28 @@ mainloop(struct libevdev *dev, struct measurements *m) {
if (rc == LIBEVDEV_READ_STATUS_SYNC) {
fprintf(stderr, "Error: cannot keep up\n");
return 1;
} else if (rc != -EAGAIN && rc < 0) {
}
if (rc != -EAGAIN && rc < 0) {
fprintf(stderr, "Error: %s\n", strerror(-rc));
return 1;
} else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
handle_event(m, &ev);
}
if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
handle_event(m, &ev);
} while (rc != -EAGAIN);
}
return 0;
}
static void
print_summary(struct measurements *m)
static inline double
mean_frequency(struct measurements *m)
{
int res;
int idx;
printf("Estimated sampling frequency: %dHz\n", (int)m->frequency);
printf("To calculate resolution, measure physical distance covered\n"
"and look up the matching resolution in the table below\n");
m->distance = abs(m->distance);
/* If the mouse has more than 2500dpi, the manufacturer usually
shows off on their website anyway */
for (res = 400; res <= 2500; res += 200) {
double inch = m->distance/(double)res;
printf("%8dmm %8.2fin %8ddpi\n",
(int)(inch * 25.4), inch, res);
}
printf("If your resolution is not in the list, calculate it with:\n"
"\tresolution=%d/inches, or\n"
"\tresolution=%d * 25.4/mm\n", m->distance, m->distance);
idx = m->nfrequencies/2;
return m->frequencies[idx];
}
static inline const char*
@ -206,20 +193,68 @@ bustype(int bustype)
return bus;
}
static void
print_summary(struct libevdev *dev, struct measurements *m)
{
int res;
int max_freq, mean_freq;
if (m->nfrequencies == 0) {
fprintf(stderr, "Error: no matching events received.\n");
return;
}
max_freq = (int)m->max_frequency;
mean_freq = (int)mean_frequency(m);
printf("Estimated sampling frequency: %dHz (mean %dHz)\n",
max_freq, mean_freq);
if (max_freq > mean_freq * 1.3)
printf("WARNING: Max frequency is more than 30%% higher "
"than mean frequency. Manual verification required!\n");
printf("To calculate resolution, measure physical distance covered\n"
"and look up the matching resolution in the table below\n");
m->distance = abs(m->distance);
/* If the mouse has more than 2500dpi, the manufacturer usually
shows off on their website anyway */
for (res = 400; res <= 2500; res += 200) {
double inch = m->distance/(double)res;
printf("%8dmm %8.2fin %8ddpi\n",
(int)(inch * 25.4), inch, res);
}
printf("If your resolution is not in the list, calculate it with:\n"
"\tresolution=%d/inches, or\n"
"\tresolution=%d * 25.4/mm\n", m->distance, m->distance);
printf("\n");
printf("Entry for hwdb match (replace XXX with the resolution in DPI):\n"
"mouse:%s:v%04xp%04x:name:%s:\n"
" MOUSE_DPI=XXX@%d\n",
bustype(libevdev_get_id_bustype(dev)),
libevdev_get_id_vendor(dev),
libevdev_get_id_product(dev),
libevdev_get_name(dev),
(int)m->max_frequency);
}
int
main (int argc, char **argv) {
int rc;
int fd;
const char *path;
struct libevdev *dev;
struct measurements measurements = {0, 0, 0};
struct measurements measurements = {0};
if (argc < 2)
return usage();
return usage(basename(argv[0]));
path = argv[1];
if (path[0] == '-')
return usage();
return usage(basename(argv[0]));
fd = open(path, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
@ -249,17 +284,7 @@ main (int argc, char **argv) {
printf("\n");
print_summary(&measurements);
printf("\n");
printf("Entry for hwdb match (replace XXX with the resolution in DPI):\n"
"mouse:%s:v%04xp%04x:name:%s:\n"
" MOUSE_DPI=XXX@%d\n",
bustype(libevdev_get_id_bustype(dev)),
libevdev_get_id_vendor(dev),
libevdev_get_id_product(dev),
libevdev_get_name(dev),
(int)measurements.frequency);
print_summary(dev, &measurements);
libevdev_free(dev);
close(fd);

View file

@ -1,7 +1,37 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
make
rsync --delete -avz doc/html/ freedesktop.org:/srv/www.freedesktop.org/www/software/libevdev/doc/latest
tag="$1"
case $tag in
-h|--help)
echo "Usage: $0 <tag>"
echo "Builds the libevdev documentation and rsyncs it to the freedesktop.org server."
echo ""
echo "Options:"
echo " tag ... the tag to build (default: master)"
exit 0
;;
1*)
# Helper so we can run it with the numerical tag only, tags
# are all prefixed with libevdev
tag="libevdev-$tag"
;;
**)
;;
esac
tag=${tag:-master}
dir=$(mktemp -d --tmpdir='' libevdev-doc.XXX)
git clone --depth 1 --branch "$tag" https://gitlab.freedesktop.org/libevdev/libevdev.git "$dir"
pushd $dir
builddir=_doc_build
rm -rf "$builddir"
meson setup "$builddir"
ninja -C "$builddir"
# Strip libevdev- prefix from the tag and replace master with latest, whichever applies
htmldir=${tag/#libevdev-/}
htmldir=${htmldir/master/latest}
rsync --delete -avz "$builddir/html/" freedesktop.org:/srv/www.freedesktop.org/www/software/libevdev/doc/${htmldir}
popd

View file

@ -0,0 +1,31 @@
#!/bin/sh
#
# Syncs the repository with the input.h and input-event-codes.h headers from
# a checked out source directory.
#
# Usage:
# sync-with-kernel-headers.sh path/to/kernel v4.12
KERNEL_TREE="$1"
GIT_DIR="$KERNEL_TREE/.git"
TAG="$2"
export GIT_DIR
if [ -z "$TAG" ] || ! [ -d "$GIT_DIR" ]; then
echo "Usage: `basename $0` path/to/kernel tag"
exit 1
fi
if ! [ -d .git ]; then
echo "Run me from the top-level git tree"
exit 1
fi
file="linux/input.h"
git cat-file -p "$TAG:include/uapi/$file" > "include/linux/linux/$(basename $file)"
file="linux/input-event-codes.h"
git cat-file -p "$TAG:include/uapi/$file" > "include/linux/linux/$(basename $file)"
git cat-file -p "$TAG:include/uapi/$file" > "include/linux/freebsd/$(basename $file)"

View file

@ -0,0 +1,44 @@
.TH TOUCHPAD-EDGE-DETECTOR "1"
.SH NAME
touchpad-edge-detector \- print the axis ranges for a touchpad device
.SH SYNOPSIS
.B touchpad-edge-detector [--help] \fIWxH /dev/input/eventX\fR
.SH DESCRIPTION
.PP
The
.B touchpad-edge-detector
tool reads touchpad events from the kernel and records the minimum and
maximum coordinates based on user input. This is an interactive tool, the
user must move a finger around the touchpad, attempting to trigger an
event at all edges of the touchpad.
.PP
To terminate the event collection and print a summary, press Ctrl+C. It is
recommended that the tool is run several times to guarantee a reliable
result.
.SH OPTIONS
.TP 8
.I WxH
The width and height of the touchpad in mm. For a touchpad 100mm wide and
75mm high, the argument is thus \fI100x75\fR. This is a required argument.
.TP 8
.I /dev/input/eventX
The event node of the touchpad to read events from. A list of possible event
nodes can be obtained with either one of the following commands: \fBlibinput
record\fR, \fBevemu-record\fR, or \fBevtest\fR. Alternatively the event node
for a device is listed in the \fBHandlers=\fR line \fI/proc/bus/input/devices\fR.
This is a required argument.
.TP 8
.B --help
Print a short help description
.SH NOTES
.PP
On completion, this tool prints a summary of the collected events and a
suggested udev rule. Due to rounding errors it is rare to get an exact match
for the touchpad's dimensions, but any discrepancy of more than 5mm should
be corrected with the suggested udev rule.
.PP
The udev rule should be simplified and submitted as a pull request to the
system repository at \fIhttps://github.com/systemd/systemd\fR. For further
guidance, see the file \fI/usr/lib/udev/hwdb.d/60-evdev.hwdb\fR.
.SH SEE ALSO
udev(7)

View file

@ -1,52 +1,37 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2014 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 <libevdev/libevdev.h>
#include <sys/signalfd.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <math.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libevdev/libevdev.h"
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
static int signalled = 0;
static int
usage(void) {
printf("Usage: %s /dev/input/event0\n", program_invocation_short_name);
usage(const char *progname) {
printf("Usage: %s 12x34 /dev/input/eventX\n", progname);
printf("\n");
printf("This tool reads the touchpad events from the kernel and calculates\n "
"the minimum and maximum for the x and y coordinates, respectively.\n");
"the minimum and maximum for the x and y coordinates, respectively.\n"
"The first argument is the physical size of the touchpad in mm (WIDTHxHEIGHT).\n");
return 1;
}
@ -54,6 +39,10 @@ struct dimensions {
int top, bottom, left, right;
};
struct size {
int w, h;
};
static int
print_current_values(const struct dimensions *d)
{
@ -76,9 +65,10 @@ print_current_values(const struct dimensions *d)
static int
handle_event(struct dimensions *d, const struct input_event *ev) {
if (ev->type == EV_SYN) {
if (ev->type == EV_SYN)
return print_current_values(d);
} else if (ev->type != EV_ABS)
if (ev->type != EV_ABS)
return 0;
switch(ev->code) {
@ -97,26 +87,26 @@ handle_event(struct dimensions *d, const struct input_event *ev) {
return 0;
}
static void
signal_handler(__attribute__((__unused__)) int signal)
{
signalled++;
}
static int
mainloop(struct libevdev *dev, struct dimensions *dim) {
struct pollfd fds[2];
sigset_t mask;
struct pollfd fds;
fds[0].fd = libevdev_get_fd(dev);
fds[0].events = POLLIN;
fds.fd = libevdev_get_fd(dev);
fds.events = POLLIN;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK);
fds[1].events = POLLIN;
signal(SIGINT, signal_handler);
sigprocmask(SIG_BLOCK, &mask, NULL);
while (poll(fds, 2, -1)) {
while (poll(&fds, 1, -1)) {
struct input_event ev;
int rc;
if (fds[1].revents)
if (signalled)
break;
do {
@ -124,12 +114,16 @@ mainloop(struct libevdev *dev, struct dimensions *dim) {
if (rc == LIBEVDEV_READ_STATUS_SYNC) {
fprintf(stderr, "Error: cannot keep up\n");
return 1;
} else if (rc != -EAGAIN && rc < 0) {
}
if (rc != -EAGAIN && rc < 0) {
fprintf(stderr, "Error: %s\n", strerror(-rc));
return 1;
} else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
handle_event(dim, &ev);
}
if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
handle_event(dim, &ev);
} while (rc != -EAGAIN);
}
@ -163,31 +157,35 @@ dmi_matchstr(struct libevdev *dev, char *match, size_t sz)
modalias[strlen(modalias) - 1] = '\0'; /* drop \n */
snprintf(match, sz, "name:%s:%s", libevdev_get_name(dev), modalias);
return;
}
static void
print_udev_override_rule(struct libevdev *dev, const struct dimensions *dim) {
print_udev_override_rule(struct libevdev *dev,
const struct dimensions *dim,
const struct size *size) {
const struct input_absinfo *x, *y;
char match[PATH_MAX];
int w, h;
int xres, yres;
x = libevdev_get_abs_info(dev, ABS_X);
y = libevdev_get_abs_info(dev, ABS_Y);
w = x->maximum - x->minimum;
h = y->maximum - y->minimum;
w = dim->right - dim->left;
h = dim->bottom - dim->top;
xres = round((double)w/size->w);
yres = round((double)h/size->h);
if (x->resolution && y->resolution) {
int width = x->maximum - x->minimum,
height = y->maximum - y->minimum;
printf("Touchpad size as listed by the kernel: %dx%dmm\n",
w/x->resolution, h/y->resolution);
width/x->resolution, height/y->resolution);
} else {
printf("Touchpad has no resolution, size unknown\n");
}
printf("Calculate resolution as:\n");
printf(" x axis: %d/<width in mm>\n", w);
printf(" y axis: %d/<height in mm>\n", h);
printf("User-specified touchpad size: %dx%dmm\n", size->w, size->h);
printf("Calculated ranges: %d/%d\n", w, h);
printf("\n");
printf("Suggested udev rule:\n");
@ -203,16 +201,16 @@ print_udev_override_rule(struct libevdev *dev, const struct dimensions *dim) {
printf("# <Laptop model description goes here>\n"
"evdev:%s*\n"
" EVDEV_ABS_00=%d:%d:<x resolution>\n"
" EVDEV_ABS_01=%d:%d:<y resolution>\n",
" EVDEV_ABS_00=%d:%d:%d\n"
" EVDEV_ABS_01=%d:%d:%d\n",
match,
dim->left, dim->right,
dim->top, dim->bottom);
dim->left, dim->right, xres,
dim->top, dim->bottom, yres);
if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_X))
printf(" EVDEV_ABS_35=%d:%d:<x resolution>\n"
" EVDEV_ABS_36=%d:%d:<y resolution>\n",
dim->left, dim->right,
dim->top, dim->bottom);
printf(" EVDEV_ABS_35=%d:%d:%d\n"
" EVDEV_ABS_36=%d:%d:%d\n",
dim->left, dim->right, xres,
dim->top, dim->bottom, yres);
}
int main (int argc, char **argv) {
@ -221,13 +219,26 @@ int main (int argc, char **argv) {
const char *path;
struct libevdev *dev;
struct dimensions dim;
struct size size;
if (argc < 2)
return usage();
if (argc < 3)
return usage(basename(argv[0]));
path = argv[1];
if (sscanf(argv[1], "%dx%d", &size.w, &size.h) != 2 ||
size.w <= 0 || size.h <= 0)
return usage(basename(argv[0]));
if (size.w < 30 || size.h < 30) {
fprintf(stderr,
"%dx%dmm is too small for a touchpad.\n"
"Please specify the touchpad size in mm.\n",
size.w, size.h);
return 1;
}
path = argv[2];
if (path[0] == '-')
return usage();
return usage(basename(argv[0]));
fd = open(path, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
@ -273,7 +284,7 @@ int main (int argc, char **argv) {
rc = mainloop(dev, &dim);
printf("\n\n");
print_udev_override_rule(dev, &dim);
print_udev_override_rule(dev, &dim, &size);
out:
libevdev_free(dev);