├── .gitignore ├── COPYING ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── doc ├── .gitignore ├── Makefile.am ├── libevdev.css ├── libevdev.doxygen.in └── libevdev.man.in ├── include └── linux │ ├── input-event-codes.h │ ├── input.h │ └── uinput.h ├── libevdev.pc.in ├── libevdev ├── .gitignore ├── Makefile.am ├── libevdev-int.h ├── libevdev-names.c ├── libevdev-uinput-int.h ├── libevdev-uinput.c ├── libevdev-uinput.h ├── libevdev-util.h ├── libevdev.c ├── libevdev.h ├── libevdev.sym └── make-event-names.py ├── m4 ├── .gitignore └── attributes.m4 ├── test ├── .gitignore ├── Makefile.am ├── generate-gcov-report.sh ├── test-common-uinput.c ├── test-common-uinput.h ├── test-common.c ├── test-common.h ├── test-compile-pedantic.c ├── test-event-codes.c ├── test-event-names.c ├── test-int-queue.c ├── test-kernel.c ├── test-libevdev-events.c ├── test-libevdev-has-event.c ├── test-libevdev-init.c ├── test-link.c ├── test-main.c ├── test-uinput.c └── valgrind.suppressions └── tools ├── .gitignore ├── Makefile.am ├── libevdev-events.c ├── libevdev-tweak-device.1 ├── libevdev-tweak-device.c ├── mouse-dpi-tool.c ├── publish-doc ├── sync-with-kernel-headers.sh └── touchpad-edge-detector.c /.gitignore: -------------------------------------------------------------------------------- 1 | # GNU Build System (Autotools) 2 | aclocal.m4 3 | *.announce 4 | autom4te.cache/ 5 | autoscan.log 6 | build-aux/ 7 | ChangeLog 8 | compile 9 | config.cache 10 | config.guess 11 | config.h 12 | config.h.in 13 | config.log 14 | config-ml.in 15 | config.py 16 | config.status 17 | config.status.lineno 18 | config.sub 19 | configure 20 | configure.scan 21 | depcomp 22 | .dirstamp 23 | install-sh 24 | libtool 25 | ltmain.sh 26 | Makefile 27 | Makefile.in 28 | mdate-sh 29 | missing 30 | mkinstalldirs 31 | stamp-h? 32 | # Edit Compile Debug Document Distribute 33 | *~ 34 | *.[0-9] 35 | *.[0-9]x 36 | *.bak 37 | *.bin 38 | core 39 | .deps/ 40 | *.dll 41 | *.exe 42 | *.gcda 43 | *.gcno 44 | *.gcov 45 | *.kld 46 | *.ko 47 | *.ko.cmd 48 | *.lai 49 | .libs/ 50 | *.l[oa] 51 | *.[oa] 52 | *.objq 53 | *.patch 54 | *.pc 55 | *.pdb 56 | *.pyc 57 | py-compile 58 | *.pyo 59 | *.so 60 | *.swo 61 | *.swp 62 | symlink-tree 63 | tags 64 | *.tar.bz2 65 | *.tar.gz 66 | *.tar.xz 67 | texinfo.tex 68 | .vimdir 69 | ylwrap 70 | # Application Specific Files 71 | *.trs 72 | *.log 73 | *.sig 74 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright © 2013 Red Hat, Inc. 2 | Copyright © 2013 David Herrmann 3 | 4 | Permission to use, copy, modify, distribute, and sell this software and its 5 | documentation for any purpose is hereby granted without fee, provided that 6 | the above copyright notice appear in all copies and that both that copyright 7 | notice and this permission notice appear in supporting documentation, and 8 | that the name of the copyright holders not be used in advertising or 9 | publicity pertaining to distribution of the software without specific, 10 | written prior permission. The copyright holders make no representations 11 | about the suitability of this software for any purpose. It is provided "as 12 | is" without express or implied warranty. 13 | 14 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | OF THIS SOFTWARE. 21 | 22 | The following license is from a Linux kernel header file and there is no GPL 23 | code this package links to. 24 | 25 | Copyright (c) 1999-2002 Vojtech Pavlik 26 | 27 | This program is free software; you can redistribute it and/or modify it 28 | under the terms of the GNU General Public License version 2 as published by 29 | the Free Software Foundation. 30 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} 2 | PRINT_DIRECTORY_FLAGS_1= 3 | PRINT_DIRECTORY_FLAGS_0=--no-print-directory 4 | PRINT_DIRECTORY_FLAGS_=$(PRINT_DIRECTORY_FLAGS_$(AM_DEFAULT_VERBOSITY)) 5 | AM_MAKEFLAGS = $(PRINT_DIRECTORY_FLAGS_$(V)) 6 | SUBDIRS = doc libevdev tools test 7 | 8 | pkgconfigdir = $(libdir)/pkgconfig 9 | pkgconfig_DATA = libevdev.pc 10 | 11 | EXTRA_DIST = libevdev.pc.in 12 | 13 | AM_DISTCHECK_CONFIGURE_FLAGS = --disable-test-run 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libevdev - wrapper library for evdev input devices 2 | ================================================== 3 | 4 | libevdev is a wrapper library for evdev devices. it moves the common 5 | tasks when dealing with evdev devices into a library and provides a library 6 | interface to the callers, thus avoiding erroneous ioctls, etc. 7 | 8 | git@gitlab.freedesktop.org:libevdev/libevdev.git 9 | https://gitlab.freedesktop.org/libevdev/libevdev.git 10 | 11 | The eventual goal is that libevdev wraps all ioctls available to evdev 12 | devices, thus making direct access unnecessary. 13 | 14 | Go here for the API documentation: 15 | http://www.freedesktop.org/software/libevdev/doc/latest/ 16 | 17 | File bugs in the freedesktop.org GitLab instance: 18 | https://gitlab.freedesktop.org/libevdev/libevdev/issues/ 19 | 20 | Patches, questions and general comments should be submitted to the input-tools@lists.freedesktop.org 21 | mailing list: 22 | http://lists.freedesktop.org/mailman/listinfo/input-tools 23 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -n "$srcdir" || srcdir=`dirname "$0"` 4 | test -n "$srcdir" || srcdir=. 5 | 6 | olddir=`pwd` 7 | 8 | cd "$srcdir" 9 | autoreconf -fvi || exit $? 10 | 11 | cd "$olddir" 12 | 13 | git config --local --get format.subjectPrefix >/dev/null 2>&1 || 14 | git config --local format.subjectPrefix "PATCH libevdev" 15 | 16 | test -n "$NOCONFIGURE" || exec "$srcdir"/configure "$@" 17 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Copyright © 2013 Red Hat, Inc. 2 | # 3 | # Permission to use, copy, modify, distribute, and sell this software and its 4 | # documentation for any purpose is hereby granted without fee, provided that 5 | # the above copyright notice appear in all copies and that both that copyright 6 | # notice and this permission notice appear in supporting documentation, and 7 | # that the name of the copyright holders not be used in advertising or 8 | # publicity pertaining to distribution of the software without specific, 9 | # written prior permission. The copyright holders make no representations 10 | # about the suitability of this software for any purpose. It is provided "as 11 | # is" without express or implied warranty. 12 | # 13 | # THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 14 | # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 15 | # EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 16 | # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 17 | # DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 18 | # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 19 | # OF THIS SOFTWARE. 20 | 21 | AC_PREREQ([2.62]) 22 | 23 | AC_INIT([libevdev], 24 | [1.5.9], 25 | [https://bugs.freedesktop.org/enter_bug.cgi?product=libevdev], 26 | [libevdev], 27 | [http://freedesktop.org/wiki/Software/libevdev/]) 28 | 29 | AC_CONFIG_SRCDIR([libevdev/libevdev.c]) 30 | AC_CONFIG_HEADERS([config.h]) 31 | AC_CONFIG_MACRO_DIR([m4]) 32 | AC_CONFIG_AUX_DIR([build-aux]) 33 | AC_USE_SYSTEM_EXTENSIONS 34 | 35 | AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects]) 36 | 37 | # Before making a release, the LIBEVDEV_LT_VERSION string should be 38 | # modified. 39 | # The string is of the form C:R:A. 40 | # - If interfaces have been changed or added, but binary compatibility has 41 | # been preserved, change to C+1:0:A+1 42 | # - If binary compatibility has been broken (eg removed or changed interfaces) 43 | # change to C+1:0:0 44 | # - If the interface is the same as the previous version, change to C:R+1:A 45 | LIBEVDEV_LT_VERSION=3:21:1 46 | AC_SUBST(LIBEVDEV_LT_VERSION) 47 | 48 | 49 | AM_SILENT_RULES([yes]) 50 | 51 | # Check for programs 52 | AC_PROG_CC_C99 53 | 54 | # Initialize libtool 55 | LT_PREREQ([2.2]) 56 | LT_INIT 57 | LT_PATH_LD 58 | 59 | with_ldflags="" 60 | if test "x$lt_cv_prog_gnu_ld" = "xyes"; then 61 | CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ 62 | -Wl,--as-needed \ 63 | -Wl,--gc-sections \ 64 | -Wl,-z,relro \ 65 | -Wl,-z,now]) 66 | fi 67 | AC_SUBST([GNU_LD_FLAGS], $with_ldflags) 68 | 69 | AC_CHECK_LIB([m], [round]) 70 | 71 | PKG_PROG_PKG_CONFIG() 72 | PKG_CHECK_MODULES(CHECK, [check >= 0.9.9], [HAVE_CHECK="yes"], [HAVE_CHECK="no"]) 73 | if test "x$HAVE_CHECK" = "xyes"; then 74 | AC_PATH_PROG(VALGRIND, [valgrind]) 75 | else 76 | AC_MSG_WARN([check not found - skipping building unit tests]) 77 | fi 78 | AM_CONDITIONAL(HAVE_VALGRIND, [test "x$VALGRIND" != "x"]) 79 | AM_CONDITIONAL(ENABLE_RUNTIME_TESTS, [test "x$HAVE_CHECK" = "xyes"]) 80 | AM_CONDITIONAL(ENABLE_STATIC_LINK_TEST, [test "x$enable_static" = "xyes"]) 81 | 82 | AC_ARG_ENABLE([test-run], 83 | AS_HELP_STRING([--enable-test-run], [For internal use only]), 84 | [run_tests="$enableval"], [run_tests="yes"]) 85 | AM_CONDITIONAL(RUN_TESTS, [test "x$run_tests" = "xyes"]) 86 | 87 | with_cflags="" 88 | if test "x$GCC" = "xyes"; then 89 | CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ 90 | -Wall \ 91 | -Wextra \ 92 | -Wno-unused-parameter \ 93 | -Wstrict-prototypes \ 94 | -Wmissing-prototypes \ 95 | -fvisibility=hidden \ 96 | -pipe \ 97 | -fno-strict-aliasing \ 98 | -ffunction-sections \ 99 | -fdata-sections \ 100 | -fno-strict-aliasing \ 101 | -fdiagnostics-show-option \ 102 | -fno-common]) 103 | fi 104 | AC_SUBST([GCC_CFLAGS], $with_cflags) 105 | 106 | AC_PATH_PROG(DOXYGEN, [doxygen]) 107 | if test "x$DOXYGEN" = "x"; then 108 | AC_MSG_WARN([doxygen not found - required for documentation]) 109 | have_doxygen="no" 110 | else 111 | have_doxygen="yes" 112 | fi 113 | AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$have_doxygen" = "xyes"]) 114 | 115 | AC_MSG_CHECKING([whether to build with gcov]) 116 | AC_ARG_ENABLE([gcov], 117 | [AS_HELP_STRING([--enable-gcov], 118 | [Whether to enable coverage testing (default:disabled)])], 119 | [], 120 | [enable_gcov=no], 121 | ) 122 | AS_IF([test "x$enable_gcov" != "xno"], 123 | [ 124 | GCOV_CFLAGS="-fprofile-arcs -ftest-coverage" 125 | GCOV_LDFLAGS="-fprofile-arcs -ftest-coverage" 126 | enable_gcov=yes 127 | ], 128 | ) 129 | AM_CONDITIONAL([GCOV_ENABLED], [test "x$enable_gcov" != "xno"]) 130 | AC_SUBST([GCOV_CFLAGS]) 131 | AC_SUBST([GCOV_LDFLAGS]) 132 | AC_MSG_RESULT([$enable_gcov]) 133 | 134 | AM_PATH_PYTHON([2.6]) 135 | AC_PATH_PROG(CAT, [cat]) 136 | 137 | # nm to check for leaking symbols in the static library 138 | AC_PATH_PROG(NM, [nm]) 139 | AM_CONDITIONAL(HAVE_NM, [test "x$NM" != "x"]) 140 | if test "x$enable_static" = "xno"; then 141 | static_symbol_leaks_test="no - static build disabled" 142 | else 143 | if test "x$NM" = "x"; then 144 | AC_MSG_WARN([nm not found - skipping symbol leak test]) 145 | have_nm="no" 146 | static_symbol_leaks_test="no - nm not found" 147 | else 148 | have_nm="yes" 149 | static_symbol_leaks_test="yes" 150 | fi 151 | fi 152 | 153 | AM_CONDITIONAL(ENABLE_STATIC_SYMBOL_LEAKS_TEST, [test "x$static_symbol_leaks_test" = "xyes"]) 154 | 155 | AC_CONFIG_FILES([Makefile 156 | libevdev/Makefile 157 | doc/Makefile 158 | doc/libevdev.doxygen 159 | doc/libevdev.man 160 | tools/Makefile 161 | test/Makefile 162 | libevdev.pc]) 163 | AC_OUTPUT 164 | 165 | AC_MSG_RESULT([ 166 | Prefix ${prefix} 167 | Libdir ${libdir} 168 | 169 | Build documentation ${have_doxygen} 170 | Enable unit-tests ${HAVE_CHECK} 171 | Run unit-tests ${run_tests} 172 | Enable profiling ${enable_gcov} 173 | Static library symbol check ${static_symbol_leaks_test} 174 | ]) 175 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | html/ 2 | libevdev.doxygen 3 | libevdev.man 4 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | man3_MANS = libevdev.man 2 | 3 | if HAVE_DOXYGEN 4 | 5 | noinst_DATA = html/index.html 6 | 7 | header_files = \ 8 | $(top_srcdir)/libevdev/libevdev.h \ 9 | $(top_srcdir)/libevdev/libevdev-uinput.h 10 | 11 | html/index.html: libevdev.doxygen $(header_files) 12 | $(AM_V_GEN)$(DOXYGEN) $< 13 | 14 | clean-local: 15 | $(AM_V_at)rm -rf html 16 | 17 | doc_src= $(shell find html -type f -printf "html/%P\n" 2>/dev/null) 18 | EXTRA_DIST = html/index.html $(doc_src) libevdev.css 19 | 20 | endif 21 | 22 | # make sure doc was built before running dist 23 | dist-hook: 24 | @test -f $(distdir)/html/index.html || (\ 25 | echo "******************************************************" && \ 26 | echo "Couldn't find documentation files, refusing make dist." && \ 27 | echo "Install doxygen to build documentation for tarball." && \ 28 | echo "******************************************************" && \ 29 | test ) 30 | -------------------------------------------------------------------------------- /doc/libevdev.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 150%; 3 | color: #354C7B; 4 | border-bottom: 1px solid #879ECB; 5 | font-weight: normal; 6 | padding-bottom: 4px; 7 | padding-bottom: 8px; 8 | } 9 | 10 | #titlearea { 11 | width: 30%; 12 | margin-left: auto; 13 | margin-right: auto; 14 | padding: 0px 10px 15px 10px; 15 | border: none; 16 | border-bottom: 1px solid #879ECB; 17 | } 18 | 19 | #projectname { 20 | text-align: center; 21 | font-weight: bold; 22 | font-size: 300%; 23 | margin-top: 5px; 24 | padding: 2px 0 0 0; 25 | margin-left: auto; 26 | margin-right: auto; 27 | color: #354C7B; 28 | } 29 | 30 | #projectnumber { 31 | font-size: 100%; 32 | color: #354C7B; 33 | } 34 | 35 | #projectbrief { 36 | text-align: center; 37 | margin-left: 20px; 38 | margin-top: 5px; 39 | padding: 2px 0 0 0; 40 | margin-left: auto; 41 | margin-right: auto; 42 | color: #354C7B; 43 | } 44 | 45 | #MSearchBox { 46 | display: none; 47 | } 48 | 49 | #titlearea table { 50 | margin-left: auto; 51 | margin-right: auto; 52 | } 53 | 54 | #navrow1, #navrow2, #navrow3, #navrow4, #navpath { 55 | width: 600px; 56 | width: -moz-max-content; 57 | margin-left: auto; 58 | margin-right: auto; 59 | } 60 | 61 | /* in file list, appears under the nav bars */ 62 | .navpath ul, .navpath li { 63 | width: 600px; 64 | width: -moz-max-content; 65 | margin-left: auto; 66 | margin-right: auto; 67 | background-image: none; 68 | border: none; 69 | border-bottom: 1px solid; 70 | } 71 | 72 | .navpath li.navelem a { 73 | text-shadow: none; 74 | outline: none; 75 | } 76 | 77 | .tabs, .tabs2, .tabs3 { 78 | background-image: none; 79 | } 80 | 81 | /* main page/modules/files tabs */ 82 | .tablist li { 83 | background-image: none; 84 | } 85 | 86 | /* main page/modules/files link text */ 87 | .tablist a { 88 | background-image: none; 89 | background-repeat: none; 90 | } 91 | 92 | /* main page/modules/files link text when hovering */ 93 | .tablist a:hover { 94 | background-image: none; 95 | background-repeat: none; 96 | text-shadow: none; 97 | color: black; 98 | } 99 | 100 | /* main page/modules/files currently selected */ 101 | .tablist li.current a { 102 | background-image: none; 103 | text-shadow: none; 104 | color: black; 105 | border-bottom: 1px solid; 106 | } 107 | 108 | .navpath { 109 | background-image: none; 110 | } 111 | 112 | /* libevdev documentation/modules/file list ... superfluous header */ 113 | div.header { 114 | display: none; 115 | width: -moz-max-content; 116 | margin-left: auto; 117 | margin-right: auto; 118 | background-image: none; 119 | background-color: inherit; 120 | font-size: 300%; 121 | } 122 | 123 | /* general text blocks */ 124 | .textblock { 125 | width: 600px; 126 | margin-left: auto; 127 | margin-right: auto; 128 | } 129 | 130 | /* code fragments should expand to what's needed */ 131 | .fragment { 132 | width: -moz-max-content; 133 | } 134 | 135 | /* list of modules container */ 136 | div .directory{ 137 | margin-left: auto; 138 | margin-right: auto; 139 | width: 600px; 140 | border: none; 141 | } 142 | 143 | 144 | .directory td.entry { 145 | width: 40%; 146 | white-space: normal; 147 | padding-left: 5px; 148 | 149 | } 150 | 151 | .directory td.desc { 152 | width: 60%; 153 | } 154 | 155 | .directory td.entry img { 156 | display: none; 157 | } 158 | 159 | h2.groupheader { 160 | width: -moz-max-content; 161 | } 162 | 163 | /* table for list of functions */ 164 | table.memberdecls { 165 | width: -moz-max-content; 166 | } 167 | 168 | div.memitem { 169 | width: -moz-max-content; 170 | border-bottom: 1px solid; 171 | } 172 | 173 | /* function prototype */ 174 | div.memproto { 175 | background-image: none; 176 | width: 600px; 177 | border: none; 178 | box-shadow: none; 179 | } 180 | 181 | /* function documentation */ 182 | div.memdoc { 183 | background-image: none; 184 | width: -moz-max-content; 185 | box-shadow: none; 186 | border: none; 187 | } 188 | 189 | div.contents { 190 | margin-left: auto; 191 | margin-right: auto; 192 | width: 600px; 193 | width: -moz-max-content; 194 | } 195 | 196 | p { 197 | width: 580px; 198 | } 199 | 200 | dl.return { 201 | width: 480px; 202 | } 203 | 204 | code { 205 | background-color: #F9FAFC; 206 | } 207 | 208 | 209 | 210 | .footer { 211 | width: 600px; 212 | margin-left: auto; 213 | margin-right: auto; 214 | } 215 | 216 | img.footer { 217 | width: auto; 218 | } 219 | 220 | /* note, see also, returns */ 221 | dl.section { 222 | width: 560px; 223 | } 224 | 225 | table.params { 226 | width: 560px; 227 | } 228 | -------------------------------------------------------------------------------- /doc/libevdev.doxygen.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = @PACKAGE_NAME@ 2 | PROJECT_NUMBER = @PACKAGE_VERSION@ 3 | PROJECT_BRIEF = "A wrapper library for evdev devices" 4 | JAVADOC_AUTOBRIEF = YES 5 | TAB_SIZE = 8 6 | OPTIMIZE_OUTPUT_FOR_C = YES 7 | EXTRACT_ALL = YES 8 | MAX_INITIALIZER_LINES = 0 9 | QUIET = YES 10 | INPUT = @top_srcdir@/libevdev/libevdev.h \ 11 | @top_srcdir@/libevdev/libevdev-uinput.h 12 | EXAMPLE_PATH = @top_srcdir@/include 13 | GENERATE_HTML = YES 14 | HTML_EXTRA_STYLESHEET = @srcdir@/libevdev.css 15 | GENERATE_LATEX = NO 16 | MACRO_EXPANSION = YES 17 | EXPAND_ONLY_PREDEF = YES 18 | PREDEFINED = LIBEVDEV_ATTRIBUTE_PRINTF(f,a)= 19 | -------------------------------------------------------------------------------- /doc/libevdev.man.in: -------------------------------------------------------------------------------- 1 | .TH LIBEVDEV 3 @PACKAGE_VERSION@ 2 | .SH NAME 3 | libevdev \- wrapper library for evdev devices 4 | .SH SYNOPSIS 5 | .HP 6 | #include 7 | .PP 8 | int 9 | .B libevdev_new_from_fd 10 | (int fd, struct libevdev **device) 11 | .PP 12 | void 13 | .B libevdev_free 14 | (struct libevdev *device) 15 | 16 | .SH DESCRIPTION 17 | .PP 18 | .B libevdev 19 | is a wrapper library for evdev devices. it moves the common 20 | tasks when dealing with evdev devices into a library and provides a library 21 | interface to the callers, thus avoiding erroneous ioctls, etc. 22 | .PP 23 | This man page is a placeholder only. The documentation for this version of 24 | .B libevdev 25 | is available at: 26 | .PP 27 | .B http://www.freedesktop.org/software/libevdev/doc/@PACKAGE_VERSION@/ 28 | .SH LICENSE 29 | .B libevdev 30 | is licensed under the MIT license. 31 | 32 | 33 | -------------------------------------------------------------------------------- /include/linux/input.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * Copyright (c) 1999-2002 Vojtech Pavlik 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 as published by 7 | * the Free Software Foundation. 8 | */ 9 | #ifndef _INPUT_H 10 | #define _INPUT_H 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "input-event-codes.h" 19 | 20 | /* 21 | * The event structure itself 22 | * Note that __USE_TIME_BITS64 is defined by libc based on 23 | * application's request to use 64 bit time_t. 24 | */ 25 | 26 | struct input_event { 27 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL) 28 | struct timeval time; 29 | #define input_event_sec time.tv_sec 30 | #define input_event_usec time.tv_usec 31 | #else 32 | __kernel_ulong_t __sec; 33 | __kernel_ulong_t __usec; 34 | #define input_event_sec __sec 35 | #define input_event_usec __usec 36 | #endif 37 | __u16 type; 38 | __u16 code; 39 | __s32 value; 40 | }; 41 | 42 | /* 43 | * Protocol version. 44 | */ 45 | 46 | #define EV_VERSION 0x010001 47 | 48 | /* 49 | * IOCTLs (0x00 - 0x7f) 50 | */ 51 | 52 | struct input_id { 53 | __u16 bustype; 54 | __u16 vendor; 55 | __u16 product; 56 | __u16 version; 57 | }; 58 | 59 | /** 60 | * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls 61 | * @value: latest reported value for the axis. 62 | * @minimum: specifies minimum value for the axis. 63 | * @maximum: specifies maximum value for the axis. 64 | * @fuzz: specifies fuzz value that is used to filter noise from 65 | * the event stream. 66 | * @flat: values that are within this value will be discarded by 67 | * joydev interface and reported as 0 instead. 68 | * @resolution: specifies resolution for the values reported for 69 | * the axis. 70 | * 71 | * Note that input core does not clamp reported values to the 72 | * [minimum, maximum] limits, such task is left to userspace. 73 | * 74 | * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z) 75 | * is reported in units per millimeter (units/mm), resolution 76 | * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported 77 | * in units per radian. 78 | * When INPUT_PROP_ACCELEROMETER is set the resolution changes. 79 | * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in 80 | * in units per g (units/g) and in units per degree per second 81 | * (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ). 82 | */ 83 | struct input_absinfo { 84 | __s32 value; 85 | __s32 minimum; 86 | __s32 maximum; 87 | __s32 fuzz; 88 | __s32 flat; 89 | __s32 resolution; 90 | }; 91 | 92 | /** 93 | * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls 94 | * @scancode: scancode represented in machine-endian form. 95 | * @len: length of the scancode that resides in @scancode buffer. 96 | * @index: index in the keymap, may be used instead of scancode 97 | * @flags: allows to specify how kernel should handle the request. For 98 | * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel 99 | * should perform lookup in keymap by @index instead of @scancode 100 | * @keycode: key code assigned to this scancode 101 | * 102 | * The structure is used to retrieve and modify keymap data. Users have 103 | * option of performing lookup either by @scancode itself or by @index 104 | * in keymap entry. EVIOCGKEYCODE will also return scancode or index 105 | * (depending on which element was used to perform lookup). 106 | */ 107 | struct input_keymap_entry { 108 | #define INPUT_KEYMAP_BY_INDEX (1 << 0) 109 | __u8 flags; 110 | __u8 len; 111 | __u16 index; 112 | __u32 keycode; 113 | __u8 scancode[32]; 114 | }; 115 | 116 | struct input_mask { 117 | __u32 type; 118 | __u32 codes_size; 119 | __u64 codes_ptr; 120 | }; 121 | 122 | #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ 123 | #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ 124 | #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ 125 | #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ 126 | 127 | #define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ 128 | #define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) 129 | #define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ 130 | #define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) 131 | 132 | #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ 133 | #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ 134 | #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ 135 | #define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */ 136 | 137 | /** 138 | * EVIOCGMTSLOTS(len) - get MT slot values 139 | * @len: size of the data buffer in bytes 140 | * 141 | * The ioctl buffer argument should be binary equivalent to 142 | * 143 | * struct input_mt_request_layout { 144 | * __u32 code; 145 | * __s32 values[num_slots]; 146 | * }; 147 | * 148 | * where num_slots is the (arbitrary) number of MT slots to extract. 149 | * 150 | * The ioctl size argument (len) is the size of the buffer, which 151 | * should satisfy len = (num_slots + 1) * sizeof(__s32). If len is 152 | * too small to fit all available slots, the first num_slots are 153 | * returned. 154 | * 155 | * Before the call, code is set to the wanted ABS_MT event type. On 156 | * return, values[] is filled with the slot values for the specified 157 | * ABS_MT code. 158 | * 159 | * If the request code is not an ABS_MT value, -EINVAL is returned. 160 | */ 161 | #define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) 162 | 163 | #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ 164 | #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ 165 | #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ 166 | #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ 167 | 168 | #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ 169 | #define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ 170 | #define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ 171 | 172 | #define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */ 173 | #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ 174 | #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ 175 | 176 | #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ 177 | #define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */ 178 | 179 | /** 180 | * EVIOCGMASK - Retrieve current event mask 181 | * 182 | * This ioctl allows user to retrieve the current event mask for specific 183 | * event type. The argument must be of type "struct input_mask" and 184 | * specifies the event type to query, the address of the receive buffer and 185 | * the size of the receive buffer. 186 | * 187 | * The event mask is a per-client mask that specifies which events are 188 | * forwarded to the client. Each event code is represented by a single bit 189 | * in the event mask. If the bit is set, the event is passed to the client 190 | * normally. Otherwise, the event is filtered and will never be queued on 191 | * the client's receive buffer. 192 | * 193 | * Event masks do not affect global state of the input device. They only 194 | * affect the file descriptor they are applied to. 195 | * 196 | * The default event mask for a client has all bits set, i.e. all events 197 | * are forwarded to the client. If the kernel is queried for an unknown 198 | * event type or if the receive buffer is larger than the number of 199 | * event codes known to the kernel, the kernel returns all zeroes for those 200 | * codes. 201 | * 202 | * At maximum, codes_size bytes are copied. 203 | * 204 | * This ioctl may fail with ENODEV in case the file is revoked, EFAULT 205 | * if the receive-buffer points to invalid memory, or EINVAL if the kernel 206 | * does not implement the ioctl. 207 | */ 208 | #define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */ 209 | 210 | /** 211 | * EVIOCSMASK - Set event mask 212 | * 213 | * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the 214 | * current event mask, this changes the client's event mask for a specific 215 | * type. See EVIOCGMASK for a description of event-masks and the 216 | * argument-type. 217 | * 218 | * This ioctl provides full forward compatibility. If the passed event type 219 | * is unknown to the kernel, or if the number of event codes specified in 220 | * the mask is bigger than what is known to the kernel, the ioctl is still 221 | * accepted and applied. However, any unknown codes are left untouched and 222 | * stay cleared. That means, the kernel always filters unknown codes 223 | * regardless of what the client requests. If the new mask doesn't cover 224 | * all known event-codes, all remaining codes are automatically cleared and 225 | * thus filtered. 226 | * 227 | * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is 228 | * returned if the receive-buffer points to invalid memory. EINVAL is returned 229 | * if the kernel does not implement the ioctl. 230 | */ 231 | #define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */ 232 | 233 | #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ 234 | 235 | /* 236 | * IDs. 237 | */ 238 | 239 | #define ID_BUS 0 240 | #define ID_VENDOR 1 241 | #define ID_PRODUCT 2 242 | #define ID_VERSION 3 243 | 244 | #define BUS_PCI 0x01 245 | #define BUS_ISAPNP 0x02 246 | #define BUS_USB 0x03 247 | #define BUS_HIL 0x04 248 | #define BUS_BLUETOOTH 0x05 249 | #define BUS_VIRTUAL 0x06 250 | 251 | #define BUS_ISA 0x10 252 | #define BUS_I8042 0x11 253 | #define BUS_XTKBD 0x12 254 | #define BUS_RS232 0x13 255 | #define BUS_GAMEPORT 0x14 256 | #define BUS_PARPORT 0x15 257 | #define BUS_AMIGA 0x16 258 | #define BUS_ADB 0x17 259 | #define BUS_I2C 0x18 260 | #define BUS_HOST 0x19 261 | #define BUS_GSC 0x1A 262 | #define BUS_ATARI 0x1B 263 | #define BUS_SPI 0x1C 264 | #define BUS_RMI 0x1D 265 | #define BUS_CEC 0x1E 266 | #define BUS_INTEL_ISHTP 0x1F 267 | 268 | /* 269 | * MT_TOOL types 270 | */ 271 | #define MT_TOOL_FINGER 0 272 | #define MT_TOOL_PEN 1 273 | #define MT_TOOL_PALM 2 274 | #define MT_TOOL_MAX 2 275 | 276 | /* 277 | * Values describing the status of a force-feedback effect 278 | */ 279 | #define FF_STATUS_STOPPED 0x00 280 | #define FF_STATUS_PLAYING 0x01 281 | #define FF_STATUS_MAX 0x01 282 | 283 | /* 284 | * Structures used in ioctls to upload effects to a device 285 | * They are pieces of a bigger structure (called ff_effect) 286 | */ 287 | 288 | /* 289 | * All duration values are expressed in ms. Values above 32767 ms (0x7fff) 290 | * should not be used and have unspecified results. 291 | */ 292 | 293 | /** 294 | * struct ff_replay - defines scheduling of the force-feedback effect 295 | * @length: duration of the effect 296 | * @delay: delay before effect should start playing 297 | */ 298 | struct ff_replay { 299 | __u16 length; 300 | __u16 delay; 301 | }; 302 | 303 | /** 304 | * struct ff_trigger - defines what triggers the force-feedback effect 305 | * @button: number of the button triggering the effect 306 | * @interval: controls how soon the effect can be re-triggered 307 | */ 308 | struct ff_trigger { 309 | __u16 button; 310 | __u16 interval; 311 | }; 312 | 313 | /** 314 | * struct ff_envelope - generic force-feedback effect envelope 315 | * @attack_length: duration of the attack (ms) 316 | * @attack_level: level at the beginning of the attack 317 | * @fade_length: duration of fade (ms) 318 | * @fade_level: level at the end of fade 319 | * 320 | * The @attack_level and @fade_level are absolute values; when applying 321 | * envelope force-feedback core will convert to positive/negative 322 | * value based on polarity of the default level of the effect. 323 | * Valid range for the attack and fade levels is 0x0000 - 0x7fff 324 | */ 325 | struct ff_envelope { 326 | __u16 attack_length; 327 | __u16 attack_level; 328 | __u16 fade_length; 329 | __u16 fade_level; 330 | }; 331 | 332 | /** 333 | * struct ff_constant_effect - defines parameters of a constant force-feedback effect 334 | * @level: strength of the effect; may be negative 335 | * @envelope: envelope data 336 | */ 337 | struct ff_constant_effect { 338 | __s16 level; 339 | struct ff_envelope envelope; 340 | }; 341 | 342 | /** 343 | * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect 344 | * @start_level: beginning strength of the effect; may be negative 345 | * @end_level: final strength of the effect; may be negative 346 | * @envelope: envelope data 347 | */ 348 | struct ff_ramp_effect { 349 | __s16 start_level; 350 | __s16 end_level; 351 | struct ff_envelope envelope; 352 | }; 353 | 354 | /** 355 | * struct ff_condition_effect - defines a spring or friction force-feedback effect 356 | * @right_saturation: maximum level when joystick moved all way to the right 357 | * @left_saturation: same for the left side 358 | * @right_coeff: controls how fast the force grows when the joystick moves 359 | * to the right 360 | * @left_coeff: same for the left side 361 | * @deadband: size of the dead zone, where no force is produced 362 | * @center: position of the dead zone 363 | */ 364 | struct ff_condition_effect { 365 | __u16 right_saturation; 366 | __u16 left_saturation; 367 | 368 | __s16 right_coeff; 369 | __s16 left_coeff; 370 | 371 | __u16 deadband; 372 | __s16 center; 373 | }; 374 | 375 | /** 376 | * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect 377 | * @waveform: kind of the effect (wave) 378 | * @period: period of the wave (ms) 379 | * @magnitude: peak value 380 | * @offset: mean value of the wave (roughly) 381 | * @phase: 'horizontal' shift 382 | * @envelope: envelope data 383 | * @custom_len: number of samples (FF_CUSTOM only) 384 | * @custom_data: buffer of samples (FF_CUSTOM only) 385 | * 386 | * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, 387 | * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined 388 | * for the time being as no driver supports it yet. 389 | * 390 | * Note: the data pointed by custom_data is copied by the driver. 391 | * You can therefore dispose of the memory after the upload/update. 392 | */ 393 | struct ff_periodic_effect { 394 | __u16 waveform; 395 | __u16 period; 396 | __s16 magnitude; 397 | __s16 offset; 398 | __u16 phase; 399 | 400 | struct ff_envelope envelope; 401 | 402 | __u32 custom_len; 403 | __s16 *custom_data; 404 | }; 405 | 406 | /** 407 | * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect 408 | * @strong_magnitude: magnitude of the heavy motor 409 | * @weak_magnitude: magnitude of the light one 410 | * 411 | * Some rumble pads have two motors of different weight. Strong_magnitude 412 | * represents the magnitude of the vibration generated by the heavy one. 413 | */ 414 | struct ff_rumble_effect { 415 | __u16 strong_magnitude; 416 | __u16 weak_magnitude; 417 | }; 418 | 419 | /** 420 | * struct ff_effect - defines force feedback effect 421 | * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, 422 | * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) 423 | * @id: an unique id assigned to an effect 424 | * @direction: direction of the effect 425 | * @trigger: trigger conditions (struct ff_trigger) 426 | * @replay: scheduling of the effect (struct ff_replay) 427 | * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, 428 | * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further 429 | * defining effect parameters 430 | * 431 | * This structure is sent through ioctl from the application to the driver. 432 | * To create a new effect application should set its @id to -1; the kernel 433 | * will return assigned @id which can later be used to update or delete 434 | * this effect. 435 | * 436 | * Direction of the effect is encoded as follows: 437 | * 0 deg -> 0x0000 (down) 438 | * 90 deg -> 0x4000 (left) 439 | * 180 deg -> 0x8000 (up) 440 | * 270 deg -> 0xC000 (right) 441 | */ 442 | struct ff_effect { 443 | __u16 type; 444 | __s16 id; 445 | __u16 direction; 446 | struct ff_trigger trigger; 447 | struct ff_replay replay; 448 | 449 | union { 450 | struct ff_constant_effect constant; 451 | struct ff_ramp_effect ramp; 452 | struct ff_periodic_effect periodic; 453 | struct ff_condition_effect condition[2]; /* One for each axis */ 454 | struct ff_rumble_effect rumble; 455 | } u; 456 | }; 457 | 458 | /* 459 | * Force feedback effect types 460 | */ 461 | 462 | #define FF_RUMBLE 0x50 463 | #define FF_PERIODIC 0x51 464 | #define FF_CONSTANT 0x52 465 | #define FF_SPRING 0x53 466 | #define FF_FRICTION 0x54 467 | #define FF_DAMPER 0x55 468 | #define FF_INERTIA 0x56 469 | #define FF_RAMP 0x57 470 | 471 | #define FF_EFFECT_MIN FF_RUMBLE 472 | #define FF_EFFECT_MAX FF_RAMP 473 | 474 | /* 475 | * Force feedback periodic effect types 476 | */ 477 | 478 | #define FF_SQUARE 0x58 479 | #define FF_TRIANGLE 0x59 480 | #define FF_SINE 0x5a 481 | #define FF_SAW_UP 0x5b 482 | #define FF_SAW_DOWN 0x5c 483 | #define FF_CUSTOM 0x5d 484 | 485 | #define FF_WAVEFORM_MIN FF_SQUARE 486 | #define FF_WAVEFORM_MAX FF_CUSTOM 487 | 488 | /* 489 | * Set ff device properties 490 | */ 491 | 492 | #define FF_GAIN 0x60 493 | #define FF_AUTOCENTER 0x61 494 | 495 | /* 496 | * ff->playback(effect_id = FF_GAIN) is the first effect_id to 497 | * cause a collision with another ff method, in this case ff->set_gain(). 498 | * Therefore the greatest safe value for effect_id is FF_GAIN - 1, 499 | * and thus the total number of effects should never exceed FF_GAIN. 500 | */ 501 | #define FF_MAX_EFFECTS FF_GAIN 502 | 503 | #define FF_MAX 0x7f 504 | #define FF_CNT (FF_MAX+1) 505 | 506 | #endif /* _INPUT_H */ 507 | -------------------------------------------------------------------------------- /include/linux/uinput.h: -------------------------------------------------------------------------------- 1 | /* 2 | * User level driver support for input subsystem 3 | * 4 | * Heavily based on evdev.c by Vojtech Pavlik 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | * 20 | * Author: Aristeu Sergio Rozanski Filho 21 | * 22 | * Changes/Revisions: 23 | * 0.5 08/13/2015 (David Herrmann & 24 | * Benjamin Tissoires ) 25 | * - add UI_DEV_SETUP ioctl 26 | * - add UI_ABS_SETUP ioctl 27 | * - add UI_GET_VERSION ioctl 28 | * 0.4 01/09/2014 (Benjamin Tissoires ) 29 | * - add UI_GET_SYSNAME ioctl 30 | * 0.3 24/05/2006 (Anssi Hannula ) 31 | * - update ff support for the changes in kernel interface 32 | * - add UINPUT_VERSION 33 | * 0.2 16/10/2004 (Micah Dowty ) 34 | * - added force feedback support 35 | * - added UI_SET_PHYS 36 | * 0.1 20/06/2002 37 | * - first public version 38 | */ 39 | #ifndef __UINPUT_H_ 40 | #define __UINPUT_H_ 41 | 42 | #include 43 | #include 44 | 45 | #define UINPUT_VERSION 5 46 | #define UINPUT_MAX_NAME_SIZE 80 47 | 48 | struct uinput_ff_upload { 49 | __u32 request_id; 50 | __s32 retval; 51 | struct ff_effect effect; 52 | struct ff_effect old; 53 | }; 54 | 55 | struct uinput_ff_erase { 56 | __u32 request_id; 57 | __s32 retval; 58 | __u32 effect_id; 59 | }; 60 | 61 | /* ioctl */ 62 | #define UINPUT_IOCTL_BASE 'U' 63 | #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) 64 | #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) 65 | 66 | struct uinput_setup { 67 | struct input_id id; 68 | char name[UINPUT_MAX_NAME_SIZE]; 69 | __u32 ff_effects_max; 70 | }; 71 | 72 | /** 73 | * UI_DEV_SETUP - Set device parameters for setup 74 | * 75 | * This ioctl sets parameters for the input device to be created. It 76 | * supersedes the old "struct uinput_user_dev" method, which wrote this data 77 | * via write(). To actually set the absolute axes UI_ABS_SETUP should be 78 | * used. 79 | * 80 | * The ioctl takes a "struct uinput_setup" object as argument. The fields of 81 | * this object are as follows: 82 | * id: See the description of "struct input_id". This field is 83 | * copied unchanged into the new device. 84 | * name: This is used unchanged as name for the new device. 85 | * ff_effects_max: This limits the maximum numbers of force-feedback effects. 86 | * See below for a description of FF with uinput. 87 | * 88 | * This ioctl can be called multiple times and will overwrite previous values. 89 | * If this ioctl fails with -EINVAL, it is recommended to use the old 90 | * "uinput_user_dev" method via write() as a fallback, in case you run on an 91 | * old kernel that does not support this ioctl. 92 | * 93 | * This ioctl may fail with -EINVAL if it is not supported or if you passed 94 | * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the 95 | * passed uinput_setup object cannot be read/written. 96 | * If this call fails, partial data may have already been applied to the 97 | * internal device. 98 | */ 99 | #define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup) 100 | 101 | struct uinput_abs_setup { 102 | __u16 code; /* axis code */ 103 | /* __u16 filler; */ 104 | struct input_absinfo absinfo; 105 | }; 106 | 107 | /** 108 | * UI_ABS_SETUP - Set absolute axis information for the device to setup 109 | * 110 | * This ioctl sets one absolute axis information for the input device to be 111 | * created. It supersedes the old "struct uinput_user_dev" method, which wrote 112 | * part of this data and the content of UI_DEV_SETUP via write(). 113 | * 114 | * The ioctl takes a "struct uinput_abs_setup" object as argument. The fields 115 | * of this object are as follows: 116 | * code: The corresponding input code associated with this axis 117 | * (ABS_X, ABS_Y, etc...) 118 | * absinfo: See "struct input_absinfo" for a description of this field. 119 | * This field is copied unchanged into the kernel for the 120 | * specified axis. If the axis is not enabled via 121 | * UI_SET_ABSBIT, this ioctl will enable it. 122 | * 123 | * This ioctl can be called multiple times and will overwrite previous values. 124 | * If this ioctl fails with -EINVAL, it is recommended to use the old 125 | * "uinput_user_dev" method via write() as a fallback, in case you run on an 126 | * old kernel that does not support this ioctl. 127 | * 128 | * This ioctl may fail with -EINVAL if it is not supported or if you passed 129 | * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the 130 | * passed uinput_setup object cannot be read/written. 131 | * If this call fails, partial data may have already been applied to the 132 | * internal device. 133 | */ 134 | #define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup) 135 | 136 | #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) 137 | #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) 138 | #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) 139 | #define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) 140 | #define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) 141 | #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) 142 | #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) 143 | #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) 144 | #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) 145 | #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) 146 | #define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int) 147 | 148 | #define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload) 149 | #define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload) 150 | #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) 151 | #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) 152 | 153 | /** 154 | * UI_GET_SYSNAME - get the sysfs name of the created uinput device 155 | * 156 | * @return the sysfs name of the created virtual input device. 157 | * The complete sysfs path is then /sys/devices/virtual/input/--NAME-- 158 | * Usually, it is in the form "inputN" 159 | */ 160 | #define UI_GET_SYSNAME(len) _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len) 161 | 162 | /** 163 | * UI_GET_VERSION - Return version of uinput protocol 164 | * 165 | * This writes uinput protocol version implemented by the kernel into 166 | * the integer pointed to by the ioctl argument. The protocol version 167 | * is hard-coded in the kernel and is independent of the uinput device. 168 | */ 169 | #define UI_GET_VERSION _IOR(UINPUT_IOCTL_BASE, 45, unsigned int) 170 | 171 | /* 172 | * To write a force-feedback-capable driver, the upload_effect 173 | * and erase_effect callbacks in input_dev must be implemented. 174 | * The uinput driver will generate a fake input event when one of 175 | * these callbacks are invoked. The userspace code then uses 176 | * ioctls to retrieve additional parameters and send the return code. 177 | * The callback blocks until this return code is sent. 178 | * 179 | * The described callback mechanism is only used if ff_effects_max 180 | * is set. 181 | * 182 | * To implement upload_effect(): 183 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. 184 | * A request ID will be given in 'value'. 185 | * 2. Allocate a uinput_ff_upload struct, fill in request_id with 186 | * the 'value' from the EV_UINPUT event. 187 | * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the 188 | * uinput_ff_upload struct. It will be filled in with the 189 | * ff_effects passed to upload_effect(). 190 | * 4. Perform the effect upload, and place a return code back into 191 | the uinput_ff_upload struct. 192 | * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the 193 | * uinput_ff_upload_effect struct. This will complete execution 194 | * of our upload_effect() handler. 195 | * 196 | * To implement erase_effect(): 197 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. 198 | * A request ID will be given in 'value'. 199 | * 2. Allocate a uinput_ff_erase struct, fill in request_id with 200 | * the 'value' from the EV_UINPUT event. 201 | * 3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the 202 | * uinput_ff_erase struct. It will be filled in with the 203 | * effect ID passed to erase_effect(). 204 | * 4. Perform the effect erasure, and place a return code back 205 | * into the uinput_ff_erase struct. 206 | * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the 207 | * uinput_ff_erase_effect struct. This will complete execution 208 | * of our erase_effect() handler. 209 | */ 210 | 211 | /* 212 | * This is the new event type, used only by uinput. 213 | * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' 214 | * is the unique request ID. This number was picked 215 | * arbitrarily, above EV_MAX (since the input system 216 | * never sees it) but in the range of a 16-bit int. 217 | */ 218 | #define EV_UINPUT 0x0101 219 | #define UI_FF_UPLOAD 1 220 | #define UI_FF_ERASE 2 221 | 222 | struct uinput_user_dev { 223 | char name[UINPUT_MAX_NAME_SIZE]; 224 | struct input_id id; 225 | __u32 ff_effects_max; 226 | __s32 absmax[ABS_CNT]; 227 | __s32 absmin[ABS_CNT]; 228 | __s32 absfuzz[ABS_CNT]; 229 | __s32 absflat[ABS_CNT]; 230 | }; 231 | #endif /* __UINPUT_H_ */ 232 | -------------------------------------------------------------------------------- /libevdev.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libevdev 7 | Description: Handler library for evdev events 8 | Version: @VERSION@ 9 | Cflags: -I${includedir}/libevdev-1.0/ 10 | Libs: -L${libdir} -levdev 11 | -------------------------------------------------------------------------------- /libevdev/.gitignore: -------------------------------------------------------------------------------- 1 | event-names.h 2 | -------------------------------------------------------------------------------- /libevdev/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES=libevdev.la 2 | 3 | AM_CPPFLAGS = $(GCC_CFLAGS) $(GCOV_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir) 4 | AM_LDFLAGS = $(GCOV_LDFLAGS) 5 | 6 | libevdev_la_SOURCES = \ 7 | libevdev.h \ 8 | libevdev-int.h \ 9 | libevdev-util.h \ 10 | libevdev-uinput.c \ 11 | libevdev-uinput.h \ 12 | libevdev-uinput-int.h \ 13 | libevdev.c \ 14 | libevdev-names.c \ 15 | ../include/linux/input-event-codes.h \ 16 | ../include/linux/input.h \ 17 | ../include/linux/uinput.h 18 | 19 | libevdev_la_LDFLAGS = \ 20 | $(AM_LDFLAGS) \ 21 | -version-info $(LIBEVDEV_LT_VERSION) \ 22 | -Wl,--version-script="$(srcdir)/libevdev.sym" \ 23 | $(GNU_LD_FLAGS) 24 | 25 | EXTRA_libevdev_la_DEPENDENCIES = $(srcdir)/libevdev.sym 26 | 27 | libevdevincludedir = $(includedir)/libevdev-1.0/libevdev 28 | libevdevinclude_HEADERS = libevdev.h libevdev-uinput.h 29 | 30 | event-names.h: Makefile make-event-names.py 31 | $(CAT) $(top_srcdir)/include/linux/input.h $(top_srcdir)/include/linux/input-event-codes.h | $(PYTHON) $(srcdir)/make-event-names.py > $@ 32 | 33 | 34 | EXTRA_DIST = make-event-names.py libevdev.sym 35 | CLEANFILES = event-names.h 36 | BUILT_SOURCES = event-names.h 37 | 38 | if GCOV_ENABLED 39 | CLEANFILES += *.gcno 40 | endif 41 | -------------------------------------------------------------------------------- /libevdev/libevdev-int.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #ifndef LIBEVDEV_INT_H 24 | #define LIBEVDEV_INT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "libevdev.h" 32 | #include "libevdev-util.h" 33 | 34 | #define MAX_NAME 256 35 | #define ABS_MT_MIN ABS_MT_SLOT 36 | #define ABS_MT_MAX ABS_MT_TOOL_Y 37 | #define ABS_MT_CNT (ABS_MT_MAX - ABS_MT_MIN + 1) 38 | #define LIBEVDEV_EXPORT __attribute__((visibility("default"))) 39 | #define ALIAS(_to) __attribute__((alias(#_to))) 40 | 41 | /** 42 | * Sync state machine: 43 | * default state: SYNC_NONE 44 | * 45 | * SYNC_NONE → SYN_DROPPED or forced sync → SYNC_NEEDED 46 | * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC) → SYNC_IN_PROGRESS 47 | * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE 48 | * SYNC_IN_PROGRESS → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE 49 | * SYNC_IN_PROGRESS → no sync events left → SYNC_NONE 50 | * 51 | */ 52 | enum SyncState { 53 | SYNC_NONE, 54 | SYNC_NEEDED, 55 | SYNC_IN_PROGRESS, 56 | }; 57 | 58 | struct mt_sync_state { 59 | int code; 60 | int val[]; 61 | }; 62 | 63 | /** 64 | * Internal only: log data used to send messages to the respective log 65 | * handler. We re-use the same struct for a global and inside 66 | * struct libevdev. 67 | * For the global, device_handler is NULL, for per-device instance 68 | * global_handler is NULL. 69 | */ 70 | struct logdata { 71 | enum libevdev_log_priority priority; /** minimum logging priority */ 72 | libevdev_log_func_t global_handler; /** global handler function */ 73 | libevdev_device_log_func_t device_handler; /** per-device handler function */ 74 | void *userdata; /** user-defined data pointer */ 75 | }; 76 | 77 | struct libevdev { 78 | int fd; 79 | bool initialized; 80 | char *name; 81 | char *phys; 82 | char *uniq; 83 | struct input_id ids; 84 | int driver_version; 85 | unsigned long bits[NLONGS(EV_CNT)]; 86 | unsigned long props[NLONGS(INPUT_PROP_CNT)]; 87 | unsigned long key_bits[NLONGS(KEY_CNT)]; 88 | unsigned long rel_bits[NLONGS(REL_CNT)]; 89 | unsigned long abs_bits[NLONGS(ABS_CNT)]; 90 | unsigned long led_bits[NLONGS(LED_CNT)]; 91 | unsigned long msc_bits[NLONGS(MSC_CNT)]; 92 | unsigned long sw_bits[NLONGS(SW_CNT)]; 93 | unsigned long rep_bits[NLONGS(REP_CNT)]; /* convenience, always 1 */ 94 | unsigned long ff_bits[NLONGS(FF_CNT)]; 95 | unsigned long snd_bits[NLONGS(SND_CNT)]; 96 | unsigned long key_values[NLONGS(KEY_CNT)]; 97 | unsigned long led_values[NLONGS(LED_CNT)]; 98 | unsigned long sw_values[NLONGS(SW_CNT)]; 99 | struct input_absinfo abs_info[ABS_CNT]; 100 | int *mt_slot_vals; /* [num_slots * ABS_MT_CNT] */ 101 | int num_slots; /**< valid slots in mt_slot_vals */ 102 | int current_slot; 103 | int rep_values[REP_CNT]; 104 | 105 | enum SyncState sync_state; 106 | enum libevdev_grab_mode grabbed; 107 | 108 | struct input_event *queue; 109 | size_t queue_size; /**< size of queue in elements */ 110 | size_t queue_next; /**< next event index */ 111 | size_t queue_nsync; /**< number of sync events */ 112 | 113 | struct timeval last_event_time; 114 | 115 | struct { 116 | struct mt_sync_state *mt_state; 117 | size_t mt_state_sz; /* in bytes */ 118 | unsigned long *slot_update; 119 | size_t slot_update_sz; /* in bytes */ 120 | unsigned long *tracking_id_changes; 121 | size_t tracking_id_changes_sz; /* in bytes */ 122 | } mt_sync; 123 | 124 | struct logdata log; 125 | }; 126 | 127 | #define log_msg_cond(dev, priority, ...) \ 128 | do { \ 129 | if (_libevdev_log_priority(dev) >= priority) \ 130 | _libevdev_log_msg(dev, priority, __FILE__, __LINE__, __func__, __VA_ARGS__); \ 131 | } while(0) 132 | 133 | #define log_error(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, __VA_ARGS__) 134 | #define log_info(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_INFO, __VA_ARGS__) 135 | #define log_dbg(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_DEBUG, __VA_ARGS__) 136 | #define log_bug(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, "BUG: "__VA_ARGS__) 137 | 138 | extern void 139 | _libevdev_log_msg(const struct libevdev *dev, 140 | enum libevdev_log_priority priority, 141 | const char *file, int line, const char *func, 142 | const char *format, ...) LIBEVDEV_ATTRIBUTE_PRINTF(6, 7); 143 | extern enum libevdev_log_priority 144 | _libevdev_log_priority(const struct libevdev *dev); 145 | 146 | /** 147 | * @return a pointer to the next element in the queue, or NULL if the queue 148 | * is full. 149 | */ 150 | static inline struct input_event* 151 | queue_push(struct libevdev *dev) 152 | { 153 | if (dev->queue_next >= dev->queue_size) 154 | return NULL; 155 | 156 | return &dev->queue[dev->queue_next++]; 157 | } 158 | 159 | /** 160 | * Set ev to the last element in the queue, removing it from the queue. 161 | * 162 | * @return 0 on success, 1 if the queue is empty. 163 | */ 164 | static inline int 165 | queue_pop(struct libevdev *dev, struct input_event *ev) 166 | { 167 | if (dev->queue_next == 0) 168 | return 1; 169 | 170 | *ev = dev->queue[--dev->queue_next]; 171 | 172 | return 0; 173 | } 174 | 175 | static inline int 176 | queue_peek(struct libevdev *dev, size_t idx, struct input_event *ev) 177 | { 178 | if (dev->queue_next == 0 || idx > dev->queue_next) 179 | return 1; 180 | *ev = dev->queue[idx]; 181 | return 0; 182 | } 183 | 184 | /** 185 | * Shift the first n elements into ev and return the number of elements 186 | * shifted. 187 | * ev must be large enough to store n elements. 188 | * 189 | * @param ev The buffer to copy into, or NULL 190 | * @return The number of elements in ev. 191 | */ 192 | static inline int 193 | queue_shift_multiple(struct libevdev *dev, size_t n, struct input_event *ev) 194 | { 195 | size_t remaining; 196 | 197 | if (dev->queue_next == 0) 198 | return 0; 199 | 200 | remaining = dev->queue_next; 201 | n = min(n, remaining); 202 | remaining -= n; 203 | 204 | if (ev) 205 | memcpy(ev, dev->queue, n * sizeof(*ev)); 206 | 207 | memmove(dev->queue, &dev->queue[n], remaining * sizeof(*dev->queue)); 208 | 209 | dev->queue_next = remaining; 210 | return n; 211 | } 212 | 213 | /** 214 | * Set ev to the first element in the queue, shifting everything else 215 | * forward by one. 216 | * 217 | * @return 0 on success, 1 if the queue is empty. 218 | */ 219 | static inline int 220 | queue_shift(struct libevdev *dev, struct input_event *ev) 221 | { 222 | return queue_shift_multiple(dev, 1, ev) == 1 ? 0 : 1; 223 | } 224 | 225 | static inline int 226 | queue_alloc(struct libevdev *dev, size_t size) 227 | { 228 | if (size == 0) 229 | return -ENOMEM; 230 | 231 | dev->queue = calloc(size, sizeof(struct input_event)); 232 | if (!dev->queue) 233 | return -ENOMEM; 234 | 235 | dev->queue_size = size; 236 | dev->queue_next = 0; 237 | return 0; 238 | } 239 | 240 | static inline void 241 | queue_free(struct libevdev *dev) 242 | { 243 | free(dev->queue); 244 | dev->queue_size = 0; 245 | dev->queue_next = 0; 246 | } 247 | 248 | static inline size_t 249 | queue_num_elements(struct libevdev *dev) 250 | { 251 | return dev->queue_next; 252 | } 253 | 254 | static inline size_t 255 | queue_size(struct libevdev *dev) 256 | { 257 | return dev->queue_size; 258 | } 259 | 260 | static inline size_t 261 | queue_num_free_elements(struct libevdev *dev) 262 | { 263 | if (dev->queue_size == 0) 264 | return 0; 265 | 266 | return dev->queue_size - dev->queue_next; 267 | } 268 | 269 | static inline struct input_event * 270 | queue_next_element(struct libevdev *dev) 271 | { 272 | if (dev->queue_next == dev->queue_size) 273 | return NULL; 274 | 275 | return &dev->queue[dev->queue_next]; 276 | } 277 | 278 | static inline int 279 | queue_set_num_elements(struct libevdev *dev, size_t nelem) 280 | { 281 | if (nelem > dev->queue_size) 282 | return 1; 283 | 284 | dev->queue_next = nelem; 285 | 286 | return 0; 287 | } 288 | 289 | #define max_mask(uc, lc) \ 290 | case EV_##uc: \ 291 | *mask = dev->lc##_bits; \ 292 | max = libevdev_event_type_get_max(type); \ 293 | break; 294 | 295 | static inline int 296 | type_to_mask_const(const struct libevdev *dev, unsigned int type, const unsigned long **mask) 297 | { 298 | int max; 299 | 300 | switch(type) { 301 | max_mask(ABS, abs); 302 | max_mask(REL, rel); 303 | max_mask(KEY, key); 304 | max_mask(LED, led); 305 | max_mask(MSC, msc); 306 | max_mask(SW, sw); 307 | max_mask(FF, ff); 308 | max_mask(REP, rep); 309 | max_mask(SND, snd); 310 | default: 311 | max = -1; 312 | break; 313 | } 314 | 315 | return max; 316 | } 317 | 318 | static inline int 319 | type_to_mask(struct libevdev *dev, unsigned int type, unsigned long **mask) 320 | { 321 | int max; 322 | 323 | switch(type) { 324 | max_mask(ABS, abs); 325 | max_mask(REL, rel); 326 | max_mask(KEY, key); 327 | max_mask(LED, led); 328 | max_mask(MSC, msc); 329 | max_mask(SW, sw); 330 | max_mask(FF, ff); 331 | max_mask(REP, rep); 332 | max_mask(SND, snd); 333 | default: 334 | max = -1; 335 | break; 336 | } 337 | 338 | return max; 339 | } 340 | 341 | #undef max_mask 342 | #endif 343 | -------------------------------------------------------------------------------- /libevdev/libevdev-names.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 David Herrmann 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "libevdev.h" 30 | #include "libevdev-int.h" 31 | #include "libevdev-util.h" 32 | #include "event-names.h" 33 | 34 | struct name_lookup { 35 | const char *name; 36 | size_t len; 37 | }; 38 | 39 | static int cmp_entry(const void *vlookup, const void *ventry) 40 | { 41 | const struct name_lookup *lookup = vlookup; 42 | const struct name_entry *entry = ventry; 43 | int r; 44 | 45 | r = strncmp(lookup->name, entry->name, lookup->len); 46 | if (!r) { 47 | if (entry->name[lookup->len]) 48 | r = -1; 49 | else 50 | r = 0; 51 | } 52 | 53 | return r; 54 | } 55 | 56 | static const struct name_entry* 57 | lookup_name(const struct name_entry *array, size_t asize, 58 | struct name_lookup *lookup) 59 | { 60 | const struct name_entry *entry; 61 | 62 | entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry); 63 | if (!entry) 64 | return NULL; 65 | 66 | return entry; 67 | } 68 | 69 | LIBEVDEV_EXPORT int 70 | libevdev_event_type_from_name(const char *name) 71 | { 72 | return libevdev_event_type_from_name_n(name, strlen(name)); 73 | } 74 | 75 | LIBEVDEV_EXPORT int 76 | libevdev_event_type_from_name_n(const char *name, size_t len) 77 | { 78 | struct name_lookup lookup; 79 | const struct name_entry *entry; 80 | 81 | lookup.name = name; 82 | lookup.len = len; 83 | 84 | entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup); 85 | 86 | return entry ? (int)entry->value : -1; 87 | } 88 | 89 | static int type_from_prefix(const char *name, ssize_t len) 90 | { 91 | const char *e; 92 | size_t i; 93 | ssize_t l; 94 | 95 | /* MAX_ is not allowed, even though EV_MAX exists */ 96 | if (startswith(name, len, "MAX_", 4)) 97 | return -1; 98 | /* BTN_ is special as there is no EV_BTN type */ 99 | if (startswith(name, len, "BTN_", 4)) 100 | return EV_KEY; 101 | /* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */ 102 | if (startswith(name, len, "FF_STATUS_", 10)) 103 | return EV_FF_STATUS; 104 | 105 | for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) { 106 | /* skip EV_ prefix so @e is suffix of [EV_]XYZ */ 107 | e = &ev_names[i].name[3]; 108 | l = strlen(e); 109 | 110 | /* compare prefix and test for trailing _ */ 111 | if (len > l && startswith(name, len, e, l) && name[l] == '_') 112 | return ev_names[i].value; 113 | } 114 | 115 | return -1; 116 | } 117 | 118 | LIBEVDEV_EXPORT int 119 | libevdev_event_code_from_name(unsigned int type, const char *name) 120 | { 121 | return libevdev_event_code_from_name_n(type, name, strlen(name)); 122 | } 123 | 124 | LIBEVDEV_EXPORT int 125 | libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len) 126 | { 127 | struct name_lookup lookup; 128 | const struct name_entry *entry; 129 | int real_type; 130 | 131 | /* verify that @name is really of type @type */ 132 | real_type = type_from_prefix(name, len); 133 | if (real_type < 0 || (unsigned int)real_type != type) 134 | return -1; 135 | 136 | /* now look up the name @name and return the constant */ 137 | lookup.name = name; 138 | lookup.len = len; 139 | 140 | entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup); 141 | 142 | return entry ? (int)entry->value : -1; 143 | } 144 | 145 | LIBEVDEV_EXPORT int 146 | libevdev_property_from_name(const char *name) 147 | { 148 | return libevdev_property_from_name_n(name, strlen(name)); 149 | } 150 | 151 | LIBEVDEV_EXPORT int 152 | libevdev_property_from_name_n(const char *name, size_t len) 153 | { 154 | struct name_lookup lookup; 155 | const struct name_entry *entry; 156 | 157 | lookup.name = name; 158 | lookup.len = len; 159 | 160 | entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup); 161 | 162 | return entry ? (int)entry->value : -1; 163 | } 164 | -------------------------------------------------------------------------------- /libevdev/libevdev-uinput-int.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | struct libevdev_uinput { 24 | int fd; /**< file descriptor to uinput */ 25 | int fd_is_managed; /**< do we need to close it? */ 26 | char *name; /**< device name */ 27 | char *syspath; /**< /sys path */ 28 | char *devnode; /**< device node */ 29 | time_t ctime[2]; /**< before/after UI_DEV_CREATE */ 30 | }; 31 | -------------------------------------------------------------------------------- /libevdev/libevdev-uinput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "libevdev.h" 36 | #include "libevdev-int.h" 37 | #include "libevdev-uinput.h" 38 | #include "libevdev-uinput-int.h" 39 | #include "libevdev-util.h" 40 | 41 | #define SYS_INPUT_DIR "/sys/devices/virtual/input/" 42 | 43 | #ifndef UINPUT_IOCTL_BASE 44 | #define UINPUT_IOCTL_BASE 'U' 45 | #endif 46 | 47 | #ifndef UI_SET_PROPBIT 48 | #define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int) 49 | #endif 50 | 51 | static struct libevdev_uinput * 52 | alloc_uinput_device(const char *name) 53 | { 54 | struct libevdev_uinput *uinput_dev; 55 | 56 | uinput_dev = calloc(1, sizeof(struct libevdev_uinput)); 57 | if (uinput_dev) { 58 | uinput_dev->name = strdup(name); 59 | uinput_dev->fd = -1; 60 | } 61 | 62 | return uinput_dev; 63 | } 64 | 65 | static inline int 66 | set_abs(const struct libevdev *dev, int fd, unsigned int code) 67 | { 68 | const struct input_absinfo *abs = libevdev_get_abs_info(dev, code); 69 | struct uinput_abs_setup abs_setup = {0}; 70 | int rc; 71 | 72 | abs_setup.code = code; 73 | abs_setup.absinfo = *abs; 74 | rc = ioctl(fd, UI_ABS_SETUP, &abs_setup); 75 | return rc; 76 | } 77 | 78 | static int 79 | set_evbits(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev) 80 | { 81 | int rc = 0; 82 | unsigned int type; 83 | 84 | for (type = 0; type < EV_CNT; type++) { 85 | unsigned int code; 86 | int max; 87 | int uinput_bit; 88 | const unsigned long *mask; 89 | 90 | if (!libevdev_has_event_type(dev, type)) 91 | continue; 92 | 93 | rc = ioctl(fd, UI_SET_EVBIT, type); 94 | if (rc == -1) 95 | break; 96 | 97 | /* uinput can't set EV_REP */ 98 | if (type == EV_REP) 99 | continue; 100 | 101 | max = type_to_mask_const(dev, type, &mask); 102 | if (max == -1) 103 | continue; 104 | 105 | switch(type) { 106 | case EV_KEY: uinput_bit = UI_SET_KEYBIT; break; 107 | case EV_REL: uinput_bit = UI_SET_RELBIT; break; 108 | case EV_ABS: uinput_bit = UI_SET_ABSBIT; break; 109 | case EV_MSC: uinput_bit = UI_SET_MSCBIT; break; 110 | case EV_LED: uinput_bit = UI_SET_LEDBIT; break; 111 | case EV_SND: uinput_bit = UI_SET_SNDBIT; break; 112 | case EV_FF: uinput_bit = UI_SET_FFBIT; break; 113 | case EV_SW: uinput_bit = UI_SET_SWBIT; break; 114 | default: 115 | rc = -1; 116 | errno = EINVAL; 117 | goto out; 118 | } 119 | 120 | for (code = 0; code <= (unsigned int)max; code++) { 121 | if (!libevdev_has_event_code(dev, type, code)) 122 | continue; 123 | 124 | rc = ioctl(fd, uinput_bit, code); 125 | if (rc == -1) 126 | goto out; 127 | 128 | if (type == EV_ABS) { 129 | if (uidev == NULL) { 130 | rc = set_abs(dev, fd, code); 131 | if (rc != 0) 132 | goto out; 133 | } else { 134 | const struct input_absinfo *abs = 135 | libevdev_get_abs_info(dev, code); 136 | 137 | uidev->absmin[code] = abs->minimum; 138 | uidev->absmax[code] = abs->maximum; 139 | uidev->absfuzz[code] = abs->fuzz; 140 | uidev->absflat[code] = abs->flat; 141 | /* uinput has no resolution in the 142 | * device struct */ 143 | } 144 | } 145 | } 146 | 147 | } 148 | 149 | out: 150 | return rc; 151 | } 152 | 153 | static int 154 | set_props(const struct libevdev *dev, int fd) 155 | { 156 | unsigned int prop; 157 | int rc = 0; 158 | 159 | for (prop = 0; prop <= INPUT_PROP_MAX; prop++) { 160 | if (!libevdev_has_property(dev, prop)) 161 | continue; 162 | 163 | rc = ioctl(fd, UI_SET_PROPBIT, prop); 164 | if (rc == -1) { 165 | /* If UI_SET_PROPBIT is not supported, treat -EINVAL 166 | * as success. The kernel only sends -EINVAL for an 167 | * invalid ioctl, invalid INPUT_PROP_MAX or if the 168 | * ioctl is called on an already created device. The 169 | * last two can't happen here. 170 | */ 171 | if (errno == EINVAL) 172 | rc = 0; 173 | break; 174 | } 175 | } 176 | return rc; 177 | } 178 | 179 | LIBEVDEV_EXPORT int 180 | libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev) 181 | { 182 | return uinput_dev->fd; 183 | } 184 | 185 | static int is_event_device(const struct dirent *dent) { 186 | return strncmp("event", dent->d_name, 5) == 0; 187 | } 188 | 189 | static char * 190 | fetch_device_node(const char *path) 191 | { 192 | char *devnode = NULL; 193 | struct dirent **namelist; 194 | int ndev, i; 195 | 196 | ndev = scandir(path, &namelist, is_event_device, alphasort); 197 | if (ndev <= 0) 198 | return NULL; 199 | 200 | /* ndev should only ever be 1 */ 201 | 202 | for (i = 0; i < ndev; i++) { 203 | if (!devnode && asprintf(&devnode, "/dev/input/%s", namelist[i]->d_name) == -1) 204 | devnode = NULL; 205 | free(namelist[i]); 206 | } 207 | 208 | free(namelist); 209 | 210 | return devnode; 211 | } 212 | 213 | static int is_input_device(const struct dirent *dent) { 214 | return strncmp("input", dent->d_name, 5) == 0; 215 | } 216 | 217 | static int 218 | fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev) 219 | { 220 | struct dirent **namelist; 221 | int ndev, i; 222 | int rc; 223 | char buf[sizeof(SYS_INPUT_DIR) + 64] = SYS_INPUT_DIR; 224 | 225 | rc = ioctl(uinput_dev->fd, 226 | UI_GET_SYSNAME(sizeof(buf) - strlen(SYS_INPUT_DIR)), 227 | &buf[strlen(SYS_INPUT_DIR)]); 228 | if (rc != -1) { 229 | uinput_dev->syspath = strdup(buf); 230 | uinput_dev->devnode = fetch_device_node(buf); 231 | return 0; 232 | } 233 | 234 | ndev = scandir(SYS_INPUT_DIR, &namelist, is_input_device, alphasort); 235 | if (ndev <= 0) 236 | return -1; 237 | 238 | for (i = 0; i < ndev; i++) { 239 | int fd, len; 240 | struct stat st; 241 | 242 | rc = snprintf(buf, sizeof(buf), "%s%s/name", 243 | SYS_INPUT_DIR, 244 | namelist[i]->d_name); 245 | if (rc < 0 || (size_t)rc >= sizeof(buf)) { 246 | continue; 247 | } 248 | 249 | /* created within time frame */ 250 | fd = open(buf, O_RDONLY); 251 | if (fd < 0) 252 | continue; 253 | 254 | /* created before UI_DEV_CREATE, or after it finished */ 255 | if (fstat(fd, &st) == -1 || 256 | st.st_ctime < uinput_dev->ctime[0] || 257 | st.st_ctime > uinput_dev->ctime[1]) { 258 | close(fd); 259 | continue; 260 | } 261 | 262 | len = read(fd, buf, sizeof(buf)); 263 | close(fd); 264 | if (len <= 0) 265 | continue; 266 | 267 | buf[len - 1] = '\0'; /* file contains \n */ 268 | if (strcmp(buf, uinput_dev->name) == 0) { 269 | if (uinput_dev->syspath) { 270 | /* FIXME: could descend into bit comparison here */ 271 | log_info(NULL, "multiple identical devices found. syspath is unreliable\n"); 272 | break; 273 | } else { 274 | rc = snprintf(buf, sizeof(buf), "%s%s", 275 | SYS_INPUT_DIR, 276 | namelist[i]->d_name); 277 | if (rc < 0 || (size_t)rc >= sizeof(buf)) { 278 | log_error(NULL, "Invalid syspath, syspath is unreliable\n"); 279 | break; 280 | } 281 | 282 | uinput_dev->syspath = strdup(buf); 283 | uinput_dev->devnode = fetch_device_node(buf); 284 | } 285 | } 286 | } 287 | 288 | for (i = 0; i < ndev; i++) 289 | free(namelist[i]); 290 | free(namelist); 291 | 292 | return uinput_dev->devnode ? 0 : -1; 293 | } 294 | 295 | static int 296 | uinput_create_write(const struct libevdev *dev, int fd, 297 | struct libevdev_uinput *new_device) 298 | { 299 | int rc; 300 | struct uinput_user_dev uidev; 301 | 302 | memset(&uidev, 0, sizeof(uidev)); 303 | 304 | strncpy(uidev.name, libevdev_get_name(dev), UINPUT_MAX_NAME_SIZE - 1); 305 | uidev.id.vendor = libevdev_get_id_vendor(dev); 306 | uidev.id.product = libevdev_get_id_product(dev); 307 | uidev.id.bustype = libevdev_get_id_bustype(dev); 308 | uidev.id.version = libevdev_get_id_version(dev); 309 | 310 | if (set_evbits(dev, fd, &uidev) != 0) 311 | goto error; 312 | if (set_props(dev, fd) != 0) 313 | goto error; 314 | 315 | rc = write(fd, &uidev, sizeof(uidev)); 316 | if (rc < 0) 317 | goto error; 318 | else if ((size_t)rc < sizeof(uidev)) { 319 | errno = EINVAL; 320 | goto error; 321 | } 322 | 323 | errno = 0; 324 | 325 | error: 326 | return -errno; 327 | } 328 | 329 | static int 330 | uinput_create_DEV_SETUP(const struct libevdev *dev, int fd, 331 | struct libevdev_uinput *new_device) 332 | { 333 | int rc; 334 | struct uinput_setup setup; 335 | 336 | if (set_evbits(dev, fd, NULL) != 0) 337 | goto error; 338 | if (set_props(dev, fd) != 0) 339 | goto error; 340 | 341 | memset(&setup, 0, sizeof(setup)); 342 | strncpy(setup.name, libevdev_get_name(dev), UINPUT_MAX_NAME_SIZE - 1); 343 | setup.id.vendor = libevdev_get_id_vendor(dev); 344 | setup.id.product = libevdev_get_id_product(dev); 345 | setup.id.bustype = libevdev_get_id_bustype(dev); 346 | setup.id.version = libevdev_get_id_version(dev); 347 | setup.ff_effects_max = libevdev_has_event_type(dev, EV_FF) ? 10 : 0; 348 | 349 | rc = ioctl(fd, UI_DEV_SETUP, &setup); 350 | if (rc == 0) 351 | errno = 0; 352 | error: 353 | return -errno; 354 | } 355 | 356 | LIBEVDEV_EXPORT int 357 | libevdev_uinput_create_from_device(const struct libevdev *dev, int fd, struct libevdev_uinput** uinput_dev) 358 | { 359 | int rc; 360 | struct libevdev_uinput *new_device; 361 | int close_fd_on_error = (fd == LIBEVDEV_UINPUT_OPEN_MANAGED); 362 | unsigned int uinput_version = 0; 363 | 364 | new_device = alloc_uinput_device(libevdev_get_name(dev)); 365 | if (!new_device) 366 | return -ENOMEM; 367 | 368 | if (fd == LIBEVDEV_UINPUT_OPEN_MANAGED) { 369 | fd = open("/dev/uinput", O_RDWR|O_CLOEXEC); 370 | if (fd < 0) 371 | goto error; 372 | 373 | new_device->fd_is_managed = 1; 374 | } else if (fd < 0) { 375 | log_bug(NULL, "Invalid fd %d\n", fd); 376 | errno = EBADF; 377 | goto error; 378 | } 379 | 380 | if (ioctl(fd, UI_GET_VERSION, &uinput_version) == 0 && 381 | uinput_version >= 5) 382 | rc = uinput_create_DEV_SETUP(dev, fd, new_device); 383 | else 384 | rc = uinput_create_write(dev, fd, new_device); 385 | 386 | if (rc != 0) 387 | goto error; 388 | 389 | /* ctime notes time before/after ioctl to help us filter out devices 390 | when traversing /sys/devices/virtual/input to find the device 391 | node. 392 | 393 | this is in seconds, so ctime[0]/[1] will almost always be 394 | identical but /sys doesn't give us sub-second ctime so... 395 | */ 396 | new_device->ctime[0] = time(NULL); 397 | 398 | rc = ioctl(fd, UI_DEV_CREATE, NULL); 399 | if (rc == -1) 400 | goto error; 401 | 402 | new_device->ctime[1] = time(NULL); 403 | new_device->fd = fd; 404 | 405 | if (fetch_syspath_and_devnode(new_device) == -1) { 406 | log_error(NULL, "unable to fetch syspath or device node.\n"); 407 | errno = ENODEV; 408 | goto error; 409 | } 410 | 411 | *uinput_dev = new_device; 412 | 413 | return 0; 414 | 415 | error: 416 | rc = -errno; 417 | libevdev_uinput_destroy(new_device); 418 | if (fd != -1 && close_fd_on_error) 419 | close(fd); 420 | return rc; 421 | } 422 | 423 | LIBEVDEV_EXPORT void 424 | libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev) 425 | { 426 | if (!uinput_dev) 427 | return; 428 | 429 | if (uinput_dev->fd >= 0) { 430 | (void)ioctl(uinput_dev->fd, UI_DEV_DESTROY, NULL); 431 | if (uinput_dev->fd_is_managed) 432 | close(uinput_dev->fd); 433 | } 434 | free(uinput_dev->syspath); 435 | free(uinput_dev->devnode); 436 | free(uinput_dev->name); 437 | free(uinput_dev); 438 | } 439 | 440 | LIBEVDEV_EXPORT const char* 441 | libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev) 442 | { 443 | return uinput_dev->syspath; 444 | } 445 | 446 | LIBEVDEV_EXPORT const char* 447 | libevdev_uinput_get_devnode(struct libevdev_uinput *uinput_dev) 448 | { 449 | return uinput_dev->devnode; 450 | } 451 | 452 | LIBEVDEV_EXPORT int 453 | libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev, 454 | unsigned int type, 455 | unsigned int code, 456 | int value) 457 | { 458 | struct input_event ev = { {0,0}, type, code, value }; 459 | int fd = libevdev_uinput_get_fd(uinput_dev); 460 | int rc, max; 461 | 462 | if (type > EV_MAX) 463 | return -EINVAL; 464 | 465 | max = libevdev_event_type_get_max(type); 466 | if (max == -1 || code > (unsigned int)max) 467 | return -EINVAL; 468 | 469 | rc = write(fd, &ev, sizeof(ev)); 470 | 471 | return rc < 0 ? -errno : 0; 472 | } 473 | -------------------------------------------------------------------------------- /libevdev/libevdev-uinput.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #ifndef LIBEVDEV_UINPUT_H 24 | #define LIBEVDEV_UINPUT_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | 32 | struct libevdev_uinput; 33 | 34 | /** 35 | * @defgroup uinput uinput device creation 36 | * 37 | * Creation of uinput devices based on existing libevdev devices. These functions 38 | * help to create uinput devices that emulate libevdev devices. In the simplest 39 | * form it serves to duplicate an existing device: 40 | * 41 | * @code 42 | * int err; 43 | * int fd, new_fd, uifd; 44 | * struct libevdev *dev; 45 | * struct libevdev_uinput *uidev; 46 | * struct input_event ev[2]; 47 | * 48 | * fd = open("/dev/input/event0", O_RDONLY); 49 | * if (fd < 0) 50 | * return err; 51 | * 52 | * err = libevdev_new_from_fd(fd, &dev); 53 | * if (err != 0) 54 | * return err; 55 | * 56 | * uifd = open("/dev/uinput", O_RDWR); 57 | * if (uifd < 0) 58 | * return -errno; 59 | * 60 | * err = libevdev_uinput_create_from_device(dev, uifd, &uidev); 61 | * if (err != 0) 62 | * return err; 63 | * 64 | * // post a REL_X event 65 | * err = libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1); 66 | * if (err != 0) 67 | * return err; 68 | * libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); 69 | * if (err != 0) 70 | * return err; 71 | * 72 | * libevdev_uinput_destroy(uidev); 73 | * libevdev_free(dev); 74 | * close(uifd); 75 | * close(fd); 76 | * 77 | * @endcode 78 | * 79 | * Alternatively, a device can be constructed from scratch: 80 | * 81 | * @code 82 | * int err; 83 | * struct libevdev *dev; 84 | * struct libevdev_uinput *uidev; 85 | * 86 | * dev = libevdev_new(); 87 | * libevdev_set_name(dev, "test device"); 88 | * libevdev_enable_event_type(dev, EV_REL); 89 | * libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 90 | * libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 91 | * libevdev_enable_event_type(dev, EV_KEY); 92 | * libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); 93 | * libevdev_enable_event_code(dev, EV_KEY, BTN_MIDDLE, NULL); 94 | * libevdev_enable_event_code(dev, EV_KEY, BTN_RIGHT, NULL); 95 | * 96 | * err = libevdev_uinput_create_from_device(dev, 97 | * LIBEVDEV_UINPUT_OPEN_MANAGED, 98 | * &uidev); 99 | * if (err != 0) 100 | * return err; 101 | * 102 | * // ... do something ... 103 | * 104 | * libevdev_uinput_destroy(uidev); 105 | * 106 | * @endcode 107 | */ 108 | 109 | enum libevdev_uinput_open_mode { 110 | /* intentionally -2 to avoid to avoid code like the below from accidentally working: 111 | fd = open("/dev/uinput", O_RDWR); // fails, fd is -1 112 | libevdev_uinput_create_from_device(dev, fd, &uidev); // may hide the error */ 113 | LIBEVDEV_UINPUT_OPEN_MANAGED = -2 /**< let libevdev open and close @c /dev/uinput */ 114 | }; 115 | 116 | /** 117 | * @ingroup uinput 118 | * 119 | * Create a uinput device based on the given libevdev device. The uinput device 120 | * will be an exact copy of the libevdev device, minus the bits that uinput doesn't 121 | * allow to be set. 122 | * 123 | * If uinput_fd is @ref LIBEVDEV_UINPUT_OPEN_MANAGED, libevdev_uinput_create_from_device() 124 | * will open @c /dev/uinput in read/write mode and manage the file descriptor. 125 | * Otherwise, uinput_fd must be opened by the caller and opened with the 126 | * appropriate permissions. 127 | * 128 | * The device's lifetime is tied to the uinput file descriptor, closing it will 129 | * destroy the uinput device. You should call libevdev_uinput_destroy() before 130 | * closing the file descriptor to free allocated resources. 131 | * A file descriptor can only create one uinput device at a time; the second device 132 | * will fail with -EINVAL. 133 | * 134 | * You don't need to keep the file descriptor variable around, 135 | * libevdev_uinput_get_fd() will return it when needed. 136 | * 137 | * @note Due to limitations in the uinput kernel module, REP_DELAY and 138 | * REP_PERIOD will default to the kernel defaults, not to the ones set in the 139 | * source device. 140 | * 141 | * @param dev The device to duplicate 142 | * @param uinput_fd @ref LIBEVDEV_UINPUT_OPEN_MANAGED or a file descriptor to @c /dev/uinput, 143 | * @param[out] uinput_dev The newly created libevdev device. 144 | * 145 | * @return 0 on success or a negative errno on failure. On failure, the value of 146 | * uinput_dev is unmodified. 147 | * 148 | * @see libevdev_uinput_destroy 149 | */ 150 | int libevdev_uinput_create_from_device(const struct libevdev *dev, 151 | int uinput_fd, 152 | struct libevdev_uinput **uinput_dev); 153 | 154 | /** 155 | * @ingroup uinput 156 | * 157 | * Destroy a previously created uinput device and free associated memory. 158 | * 159 | * If the device was opened with @ref LIBEVDEV_UINPUT_OPEN_MANAGED, 160 | * libevdev_uinput_destroy() also closes the file descriptor. Otherwise, the 161 | * fd is left as-is and must be closed by the caller. 162 | * 163 | * @param uinput_dev A previously created uinput device. 164 | */ 165 | void libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev); 166 | 167 | /** 168 | * @ingroup uinput 169 | * 170 | * Return the file descriptor used to create this uinput device. This is the 171 | * fd pointing to /dev/uinput. This file descriptor may be used to write 172 | * events that are emitted by the uinput device. 173 | * Closing this file descriptor will destroy the uinput device, you should 174 | * call libevdev_uinput_destroy() first to free allocated resources. 175 | * 176 | * @param uinput_dev A previously created uinput device. 177 | * 178 | * @return The file descriptor used to create this device 179 | */ 180 | int libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev); 181 | 182 | /** 183 | * @ingroup uinput 184 | * 185 | * Return the syspath representing this uinput device. If the UI_GET_SYSNAME 186 | * ioctl not available, libevdev makes an educated guess. 187 | * The UI_GET_SYSNAME ioctl is available since Linux 3.15. 188 | * 189 | * The syspath returned is the one of the input node itself 190 | * (e.g. /sys/devices/virtual/input/input123), not the syspath of the device 191 | * node returned with libevdev_uinput_get_devnode(). 192 | * 193 | * @note This function may return NULL if UI_GET_SYSNAME is not available. 194 | * In that case, libevdev uses ctime and the device name to guess devices. 195 | * To avoid false positives, wait at least wait at least 1.5s between 196 | * creating devices that have the same name. 197 | * 198 | * @param uinput_dev A previously created uinput device. 199 | * @return The syspath for this device, including the preceding /sys 200 | * 201 | * @see libevdev_uinput_get_devnode 202 | */ 203 | const char* libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev); 204 | 205 | /** 206 | * @ingroup uinput 207 | * 208 | * Return the device node representing this uinput device. 209 | * 210 | * This relies on libevdev_uinput_get_syspath() to provide a valid syspath. 211 | * See libevdev_uinput_get_syspath() for more details. 212 | * 213 | * @note This function may return NULL. libevdev may have to guess the 214 | * syspath and the device node. See libevdev_uinput_get_syspath() for details. 215 | * @param uinput_dev A previously created uinput device. 216 | * @return The device node for this device, in the form of /dev/input/eventN 217 | * 218 | * @see libevdev_uinput_get_syspath 219 | */ 220 | const char* libevdev_uinput_get_devnode(struct libevdev_uinput *uinput_dev); 221 | 222 | /** 223 | * @ingroup uinput 224 | * 225 | * Post an event through the uinput device. It is the caller's responsibility 226 | * that any event sequence is terminated with an EV_SYN/SYN_REPORT/0 event. 227 | * Otherwise, listeners on the device node will not see the events until the 228 | * next EV_SYN event is posted. 229 | * 230 | * @param uinput_dev A previously created uinput device. 231 | * @param type Event type (EV_ABS, EV_REL, etc.) 232 | * @param code Event code (ABS_X, REL_Y, etc.) 233 | * @param value The event value 234 | * @return 0 on success or a negative errno on error 235 | */ 236 | int libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev, 237 | unsigned int type, 238 | unsigned int code, 239 | int value); 240 | #ifdef __cplusplus 241 | } 242 | #endif 243 | 244 | #endif /* LIBEVDEV_UINPUT_H */ 245 | -------------------------------------------------------------------------------- /libevdev/libevdev-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #ifndef _UTIL_H_ 24 | #define _UTIL_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #define LONG_BITS (sizeof(long) * 8) 31 | #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) 32 | #define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0]))) 33 | #define unlikely(x) (__builtin_expect(!!(x),0)) 34 | 35 | #undef min 36 | #undef max 37 | #define min(a,b) \ 38 | ({ __typeof__ (a) _a = (a); \ 39 | __typeof__ (b) _b = (b); \ 40 | _a > _b ? _b : _a; \ 41 | }) 42 | #define max(a,b) \ 43 | ({ __typeof__ (a) _a = (a); \ 44 | __typeof__ (b) _b = (b); \ 45 | _a > _b ? _a : _b; \ 46 | }) 47 | 48 | static inline bool 49 | startswith(const char *str, size_t len, const char *prefix, size_t plen) 50 | { 51 | return len >= plen && !strncmp(str, prefix, plen); 52 | } 53 | 54 | static inline int 55 | bit_is_set(const unsigned long *array, int bit) 56 | { 57 | return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS))); 58 | } 59 | 60 | static inline void 61 | set_bit(unsigned long *array, int bit) 62 | { 63 | array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS)); 64 | } 65 | 66 | static inline void 67 | clear_bit(unsigned long *array, int bit) 68 | { 69 | array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS)); 70 | } 71 | 72 | static inline void 73 | set_bit_state(unsigned long *array, int bit, int state) 74 | { 75 | if (state) 76 | set_bit(array, bit); 77 | else 78 | clear_bit(array, bit); 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /libevdev/libevdev.sym: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 David Herrmann 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | LIBEVDEV_1 { 24 | global: 25 | libevdev_change_fd; 26 | libevdev_disable_event_code; 27 | libevdev_disable_event_type; 28 | libevdev_enable_event_code; 29 | libevdev_enable_event_type; 30 | libevdev_enable_property; 31 | libevdev_event_code_from_name; 32 | libevdev_event_code_from_name_n; 33 | libevdev_event_code_get_name; 34 | libevdev_event_is_code; 35 | libevdev_event_is_type; 36 | libevdev_event_type_from_name; 37 | libevdev_event_type_from_name_n; 38 | libevdev_event_type_get_max; 39 | libevdev_event_type_get_name; 40 | libevdev_fetch_event_value; 41 | libevdev_fetch_slot_value; 42 | libevdev_free; 43 | libevdev_get_abs_flat; 44 | libevdev_get_abs_fuzz; 45 | libevdev_get_abs_info; 46 | libevdev_get_abs_maximum; 47 | libevdev_get_abs_minimum; 48 | libevdev_get_abs_resolution; 49 | libevdev_get_current_slot; 50 | libevdev_get_driver_version; 51 | libevdev_get_event_value; 52 | libevdev_get_fd; 53 | libevdev_get_id_bustype; 54 | libevdev_get_id_product; 55 | libevdev_get_id_vendor; 56 | libevdev_get_id_version; 57 | libevdev_get_log_priority; 58 | libevdev_get_name; 59 | libevdev_get_num_slots; 60 | libevdev_get_phys; 61 | libevdev_get_repeat; 62 | libevdev_get_slot_value; 63 | libevdev_get_uniq; 64 | libevdev_grab; 65 | libevdev_has_event_code; 66 | libevdev_has_event_pending; 67 | libevdev_has_event_type; 68 | libevdev_has_property; 69 | libevdev_kernel_set_abs_info; 70 | libevdev_kernel_set_led_value; 71 | libevdev_kernel_set_led_values; 72 | libevdev_new; 73 | libevdev_new_from_fd; 74 | libevdev_next_event; 75 | libevdev_property_get_name; 76 | libevdev_set_abs_flat; 77 | libevdev_set_abs_fuzz; 78 | libevdev_set_abs_info; 79 | libevdev_set_abs_maximum; 80 | libevdev_set_abs_minimum; 81 | libevdev_set_abs_resolution; 82 | libevdev_set_clock_id; 83 | libevdev_set_event_value; 84 | libevdev_set_fd; 85 | libevdev_set_id_bustype; 86 | libevdev_set_id_product; 87 | libevdev_set_id_vendor; 88 | libevdev_set_id_version; 89 | libevdev_set_log_function; 90 | libevdev_set_log_priority; 91 | libevdev_set_name; 92 | libevdev_set_phys; 93 | libevdev_set_slot_value; 94 | libevdev_set_uniq; 95 | libevdev_uinput_create_from_device; 96 | libevdev_uinput_destroy; 97 | libevdev_uinput_get_devnode; 98 | libevdev_uinput_get_fd; 99 | libevdev_uinput_get_syspath; 100 | libevdev_uinput_write_event; 101 | 102 | local: 103 | *; 104 | }; 105 | 106 | LIBEVDEV_1_3 { 107 | global: 108 | libevdev_set_device_log_function; 109 | libevdev_property_from_name; 110 | libevdev_property_from_name_n; 111 | 112 | local: 113 | *; 114 | } LIBEVDEV_1; 115 | -------------------------------------------------------------------------------- /libevdev/make-event-names.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Parses linux/input.h scanning for #define KEY_FOO 134 3 | # Prints C header files or Python files that can be used as 4 | # mapping and lookup tables. 5 | # 6 | 7 | from __future__ import print_function 8 | import re 9 | import sys 10 | 11 | class Bits(object): 12 | pass 13 | 14 | prefixes = [ 15 | "EV_", 16 | "REL_", 17 | "ABS_", 18 | "KEY_", 19 | "BTN_", 20 | "LED_", 21 | "SND_", 22 | "MSC_", 23 | "SW_", 24 | "FF_", 25 | "SYN_", 26 | "REP_", 27 | "INPUT_PROP_", 28 | ] 29 | 30 | blacklist = [ 31 | "EV_VERSION", 32 | "BTN_MISC", 33 | "BTN_MOUSE", 34 | "BTN_JOYSTICK", 35 | "BTN_GAMEPAD", 36 | "BTN_DIGI", 37 | "BTN_WHEEL", 38 | "BTN_TRIGGER_HAPPY", 39 | "SW_MAX", 40 | "REP_MAX", 41 | ] 42 | 43 | btn_additional = [ 44 | [0, "BTN_A"], 45 | [0, "BTN_B"], 46 | [0, "BTN_X"], 47 | [0, "BTN_Y"], 48 | ] 49 | 50 | names = [ 51 | "REL_", 52 | "ABS_", 53 | "KEY_", 54 | "BTN_", 55 | "LED_", 56 | "SND_", 57 | "MSC_", 58 | "SW_", 59 | "FF_", 60 | "SYN_", 61 | "REP_", 62 | ] 63 | 64 | def print_bits(bits, prefix): 65 | if not hasattr(bits, prefix): 66 | return 67 | print("static const char * const %s_map[%s_MAX + 1] = {" % (prefix, prefix.upper())) 68 | for val, name in list(getattr(bits, prefix).items()): 69 | print(" [%s] = \"%s\"," % (name, name)) 70 | if prefix == "key": 71 | for val, name in list(getattr(bits, "btn").items()): 72 | print(" [%s] = \"%s\"," % (name, name)) 73 | print("};") 74 | print("") 75 | 76 | def print_map(bits): 77 | print("static const char * const * const event_type_map[EV_MAX + 1] = {") 78 | 79 | for prefix in prefixes: 80 | if prefix == "BTN_" or prefix == "EV_" or prefix == "INPUT_PROP_": 81 | continue 82 | print(" [EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower())) 83 | 84 | print("};") 85 | print("") 86 | 87 | print("#if __clang__") 88 | print("#pragma clang diagnostic push") 89 | print("#pragma clang diagnostic ignored \"-Winitializer-overrides\"") 90 | print("#else") 91 | print("#pragma GCC diagnostic push") 92 | print("#pragma GCC diagnostic ignored \"-Woverride-init\"") 93 | print("#endif") 94 | print("static const int ev_max[EV_MAX + 1] = {") 95 | print(" [0 ... EV_MAX] = -1,") 96 | for prefix in prefixes: 97 | if prefix == "BTN_" or prefix == "EV_" or prefix == "INPUT_PROP_": 98 | continue 99 | print(" [EV_%s] = %s_MAX," % (prefix[:-1], prefix[:-1])) 100 | print("};") 101 | print("#if __clang__") 102 | print("#pragma clang diagnostic pop /* \"-Winitializer-overrides\" */") 103 | print("#else") 104 | print("#pragma GCC diagnostic pop /* \"-Woverride-init\" */") 105 | print("#endif"); 106 | print("") 107 | 108 | def print_lookup(bits, prefix): 109 | if not hasattr(bits, prefix): 110 | return 111 | 112 | names = list(getattr(bits, prefix).items()) 113 | if prefix == "btn": 114 | names = names + btn_additional; 115 | 116 | for val, name in sorted(names, key=lambda e: e[1]): 117 | print(" { .name = \"%s\", .value = %s }," % (name, name)) 118 | 119 | def print_lookup_table(bits): 120 | print("struct name_entry {") 121 | print(" const char *name;") 122 | print(" unsigned int value;") 123 | print("};") 124 | print("") 125 | print("static const struct name_entry ev_names[] = {") 126 | print_lookup(bits, "ev") 127 | print("};") 128 | print("") 129 | 130 | print("static const struct name_entry code_names[] = {") 131 | for prefix in sorted(names, key=lambda e: e): 132 | print_lookup(bits, prefix[:-1].lower()) 133 | print("};") 134 | print("") 135 | print("static const struct name_entry prop_names[] = {") 136 | print_lookup(bits, "input_prop") 137 | print("};") 138 | print("") 139 | 140 | def print_mapping_table(bits): 141 | print("/* THIS FILE IS GENERATED, DO NOT EDIT */") 142 | print("") 143 | print("#ifndef EVENT_NAMES_H") 144 | print("#define EVENT_NAMES_H") 145 | print("") 146 | 147 | for prefix in prefixes: 148 | if prefix == "BTN_": 149 | continue 150 | print_bits(bits, prefix[:-1].lower()) 151 | 152 | print_map(bits) 153 | print_lookup_table(bits) 154 | 155 | print("#endif /* EVENT_NAMES_H */") 156 | 157 | def parse_define(bits, line): 158 | m = re.match(r"^#define\s+(\w+)\s+(\w+)", line) 159 | if m == None: 160 | return 161 | 162 | name = m.group(1) 163 | 164 | if name in blacklist: 165 | return 166 | 167 | try: 168 | value = int(m.group(2), 0) 169 | except ValueError: 170 | return 171 | 172 | for prefix in prefixes: 173 | if not name.startswith(prefix): 174 | continue 175 | 176 | attrname = prefix[:-1].lower() 177 | 178 | if not hasattr(bits, attrname): 179 | setattr(bits, attrname, {}) 180 | b = getattr(bits, attrname) 181 | b[value] = name 182 | 183 | def parse(fp): 184 | bits = Bits() 185 | 186 | lines = fp.readlines() 187 | for line in lines: 188 | if not line.startswith("#define"): 189 | continue 190 | parse_define(bits, line) 191 | 192 | return bits 193 | 194 | def usage(prog): 195 | print("Usage: cat | %s" % prog) 196 | 197 | if __name__ == "__main__": 198 | if len(sys.argv) != 1: 199 | usage(sys.argv[0]) 200 | sys.exit(2) 201 | 202 | bits = parse(sys.stdin) 203 | print_mapping_table(bits) 204 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | libtool.m4 2 | ltoptions.m4 3 | ltsugar.m4 4 | ltversion.m4 5 | lt~obsolete.m4 6 | -------------------------------------------------------------------------------- /m4/attributes.m4: -------------------------------------------------------------------------------- 1 | dnl Macros to check the presence of generic (non-typed) symbols. 2 | dnl Copyright (c) 2006-2008 Diego Pettenò 3 | dnl Copyright (c) 2006-2008 xine project 4 | dnl Copyright (c) 2012 Lucas De Marchi 5 | dnl 6 | dnl This program is free software; you can redistribute it and/or modify 7 | dnl it under the terms of the GNU General Public License as published by 8 | dnl the Free Software Foundation; either version 2, or (at your option) 9 | dnl any later version. 10 | dnl 11 | dnl This program is distributed in the hope that it will be useful, 12 | dnl but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | dnl GNU General Public License for more details. 15 | dnl 16 | dnl You should have received a copy of the GNU General Public License 17 | dnl along with this program; if not, write to the Free Software 18 | dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 | dnl 02110-1301, USA. 20 | dnl 21 | dnl As a special exception, the copyright owners of the 22 | dnl macro gives unlimited permission to copy, distribute and modify the 23 | dnl configure scripts that are the output of Autoconf when processing the 24 | dnl Macro. You need not follow the terms of the GNU General Public 25 | dnl License when using or distributing such scripts, even though portions 26 | dnl of the text of the Macro appear in them. The GNU General Public 27 | dnl License (GPL) does govern all other use of the material that 28 | dnl constitutes the Autoconf Macro. 29 | dnl 30 | dnl This special exception to the GPL applies to versions of the 31 | dnl Autoconf Macro released by this project. When you make and 32 | dnl distribute a modified version of the Autoconf Macro, you may extend 33 | dnl this special exception to the GPL to apply to your modified version as 34 | dnl well. 35 | 36 | dnl Check if FLAG in ENV-VAR is supported by compiler and append it 37 | dnl to WHERE-TO-APPEND variable 38 | dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG]) 39 | 40 | AC_DEFUN([CC_CHECK_FLAG_APPEND], [ 41 | AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], 42 | AS_TR_SH([cc_cv_$2_$3]), 43 | [eval "AS_TR_SH([cc_save_$2])='${$2}'" 44 | eval "AS_TR_SH([$2])='-Werror $3'" 45 | AC_LINK_IFELSE([AC_LANG_SOURCE([int a = 0; int main(void) { return a; } ])], 46 | [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], 47 | [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) 48 | eval "AS_TR_SH([$2])='$cc_save_$2'"]) 49 | 50 | AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], 51 | [eval "$1='${$1} $3'"]) 52 | ]) 53 | 54 | dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2]) 55 | AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ 56 | for flag in $3; do 57 | CC_CHECK_FLAG_APPEND($1, $2, $flag) 58 | done 59 | ]) 60 | 61 | dnl Check if the flag is supported by linker (cacheable) 62 | dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 63 | 64 | AC_DEFUN([CC_CHECK_LDFLAGS], [ 65 | AC_CACHE_CHECK([if $CC supports $1 flag], 66 | AS_TR_SH([cc_cv_ldflags_$1]), 67 | [ac_save_LDFLAGS="$LDFLAGS" 68 | LDFLAGS="$LDFLAGS $1" 69 | AC_LINK_IFELSE([int main() { return 1; }], 70 | [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], 71 | [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) 72 | LDFLAGS="$ac_save_LDFLAGS" 73 | ]) 74 | 75 | AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], 76 | [$2], [$3]) 77 | ]) 78 | 79 | dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for 80 | dnl the current linker to avoid undefined references in a shared object. 81 | AC_DEFUN([CC_NOUNDEFINED], [ 82 | dnl We check $host for which systems to enable this for. 83 | AC_REQUIRE([AC_CANONICAL_HOST]) 84 | 85 | case $host in 86 | dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads 87 | dnl are requested, as different implementations are present; to avoid problems 88 | dnl use -Wl,-z,defs only for those platform not behaving this way. 89 | *-freebsd* | *-openbsd*) ;; 90 | *) 91 | dnl First of all check for the --no-undefined variant of GNU ld. This allows 92 | dnl for a much more readable commandline, so that people can understand what 93 | dnl it does without going to look for what the heck -z defs does. 94 | for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do 95 | CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) 96 | break 97 | done 98 | ;; 99 | esac 100 | 101 | AC_SUBST([LDFLAGS_NOUNDEFINED]) 102 | ]) 103 | 104 | dnl Check for a -Werror flag or equivalent. -Werror is the GCC 105 | dnl and ICC flag that tells the compiler to treat all the warnings 106 | dnl as fatal. We usually need this option to make sure that some 107 | dnl constructs (like attributes) are not simply ignored. 108 | dnl 109 | dnl Other compilers don't support -Werror per se, but they support 110 | dnl an equivalent flag: 111 | dnl - Sun Studio compiler supports -errwarn=%all 112 | dnl we don't test for that, it gives us false positives when gcc doesn't 113 | dnl actually complain about it. If someone wants to compile this on sun, let 114 | dnl them fix it. 115 | AC_DEFUN([CC_CHECK_WERROR], [ 116 | AC_CACHE_CHECK( 117 | [for $CC way to treat warnings as errors], 118 | [cc_cv_werror], 119 | [CC_CHECK_FLAG_APPEND([cc_cv_werror], [CFLAGS], [-Werror])]) 120 | ]) 121 | 122 | AC_DEFUN([CC_CHECK_ATTRIBUTE], [ 123 | AC_REQUIRE([CC_CHECK_WERROR]) 124 | AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], 125 | AS_TR_SH([cc_cv_attribute_$1]), 126 | [ac_save_CFLAGS="$CFLAGS" 127 | CFLAGS="$CFLAGS $cc_cv_werror" 128 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], 129 | [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], 130 | [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) 131 | CFLAGS="$ac_save_CFLAGS" 132 | ]) 133 | 134 | AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], 135 | [AC_DEFINE( 136 | AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, 137 | [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] 138 | ) 139 | $4], 140 | [$5]) 141 | ]) 142 | 143 | AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ 144 | CC_CHECK_ATTRIBUTE( 145 | [constructor],, 146 | [void __attribute__((constructor)) ctor() { int a; }], 147 | [$1], [$2]) 148 | ]) 149 | 150 | AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ 151 | CC_CHECK_ATTRIBUTE( 152 | [format], [format(printf, n, n)], 153 | [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], 154 | [$1], [$2]) 155 | ]) 156 | 157 | AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ 158 | CC_CHECK_ATTRIBUTE( 159 | [format_arg], [format_arg(printf)], 160 | [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], 161 | [$1], [$2]) 162 | ]) 163 | 164 | AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ 165 | CC_CHECK_ATTRIBUTE( 166 | [visibility_$1], [visibility("$1")], 167 | [void __attribute__((visibility("$1"))) $1_function() { }], 168 | [$2], [$3]) 169 | ]) 170 | 171 | AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ 172 | CC_CHECK_ATTRIBUTE( 173 | [nonnull], [nonnull()], 174 | [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], 175 | [$1], [$2]) 176 | ]) 177 | 178 | AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ 179 | CC_CHECK_ATTRIBUTE( 180 | [unused], , 181 | [void some_function(void *foo, __attribute__((unused)) void *bar);], 182 | [$1], [$2]) 183 | ]) 184 | 185 | AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ 186 | CC_CHECK_ATTRIBUTE( 187 | [sentinel], , 188 | [void some_function(void *foo, ...) __attribute__((sentinel));], 189 | [$1], [$2]) 190 | ]) 191 | 192 | AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ 193 | CC_CHECK_ATTRIBUTE( 194 | [deprecated], , 195 | [void some_function(void *foo, ...) __attribute__((deprecated));], 196 | [$1], [$2]) 197 | ]) 198 | 199 | AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ 200 | CC_CHECK_ATTRIBUTE( 201 | [alias], [weak, alias], 202 | [void other_function(void *foo) { } 203 | void some_function(void *foo) __attribute__((weak, alias("other_function")));], 204 | [$1], [$2]) 205 | ]) 206 | 207 | AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ 208 | CC_CHECK_ATTRIBUTE( 209 | [malloc], , 210 | [void * __attribute__((malloc)) my_alloc(int n);], 211 | [$1], [$2]) 212 | ]) 213 | 214 | AC_DEFUN([CC_ATTRIBUTE_PACKED], [ 215 | CC_CHECK_ATTRIBUTE( 216 | [packed], , 217 | [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], 218 | [$1], [$2]) 219 | ]) 220 | 221 | AC_DEFUN([CC_ATTRIBUTE_CONST], [ 222 | CC_CHECK_ATTRIBUTE( 223 | [const], , 224 | [int __attribute__((const)) twopow(int n) { return 1 << n; } ], 225 | [$1], [$2]) 226 | ]) 227 | 228 | AC_DEFUN([CC_FLAG_VISIBILITY], [ 229 | AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], 230 | [cc_cv_flag_visibility], 231 | [CC_CHECK_FLAG_APPEND([cc_cv_flag_visibility], [CFLAGS], [-fvisibility=hidden])]) 232 | 233 | AS_IF([test "x$cc_cv_flag_visibility" != "x"], 234 | [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, 235 | [Define this if the compiler supports the -fvisibility flag]) 236 | $1], 237 | [$2]) 238 | ]) 239 | 240 | AC_DEFUN([CC_FUNC_EXPECT], [ 241 | AC_REQUIRE([CC_CHECK_WERROR]) 242 | AC_CACHE_CHECK([if compiler has __builtin_expect function], 243 | [cc_cv_func_expect], 244 | [ac_save_CFLAGS="$CFLAGS" 245 | CFLAGS="$CFLAGS $cc_cv_werror" 246 | AC_COMPILE_IFELSE([AC_LANG_SOURCE( 247 | [int some_function() { 248 | int a = 3; 249 | return (int)__builtin_expect(a, 3); 250 | }])], 251 | [cc_cv_func_expect=yes], 252 | [cc_cv_func_expect=no]) 253 | CFLAGS="$ac_save_CFLAGS" 254 | ]) 255 | 256 | AS_IF([test "x$cc_cv_func_expect" = "xyes"], 257 | [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, 258 | [Define this if the compiler supports __builtin_expect() function]) 259 | $1], 260 | [$2]) 261 | ]) 262 | 263 | AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ 264 | AC_REQUIRE([CC_CHECK_WERROR]) 265 | AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], 266 | [cc_cv_attribute_aligned], 267 | [ac_save_CFLAGS="$CFLAGS" 268 | CFLAGS="$CFLAGS $cc_cv_werror" 269 | for cc_attribute_align_try in 64 32 16 8 4 2; do 270 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([ 271 | int main() { 272 | static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; 273 | return c; 274 | }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) 275 | done 276 | CFLAGS="$ac_save_CFLAGS" 277 | ]) 278 | 279 | if test "x$cc_cv_attribute_aligned" != "x"; then 280 | AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], 281 | [Define the highest alignment supported]) 282 | fi 283 | ]) 284 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | gcov-report.txt 2 | test-libevdev 3 | test-link 4 | test-compile-pedantic 5 | test-kernel 6 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | build_tests = test-compile-pedantic test-link 2 | 3 | if ENABLE_STATIC_LINK_TEST 4 | build_tests += test-static-link 5 | endif 6 | 7 | noinst_PROGRAMS = $(build_tests) 8 | 9 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_builddir)/libevdev 10 | AM_LDFLAGS = 11 | 12 | test_compile_pedantic_SOURCES = test-compile-pedantic.c 13 | test_compile_pedantic_CFLAGS = $(AM_CPPFLAGS) -pedantic -Werror -std=c89 14 | 15 | test_link_SOURCES = test-link.c 16 | test_link_CFLAGS = -I$(top_srcdir) 17 | test_link_LDADD = $(top_builddir)/libevdev/libevdev.la 18 | 19 | test_static_link_SOURCES = test-link.c 20 | test_static_link_CFLAGS = -I$(top_srcdir) 21 | test_static_link_LDADD = $(top_builddir)/libevdev/libevdev.la 22 | test_static_link_LDFLAGS = $(AM_LDFLAGS) -static 23 | 24 | check_local_deps = 25 | 26 | if ENABLE_RUNTIME_TESTS 27 | run_tests = test-libevdev test-kernel 28 | 29 | .NOTPARALLEL: 30 | 31 | noinst_PROGRAMS += $(run_tests) 32 | 33 | if RUN_TESTS 34 | TESTS = $(run_tests) 35 | endif 36 | 37 | common_sources = \ 38 | test-common-uinput.c \ 39 | test-common-uinput.h \ 40 | test-common.c \ 41 | test-common.h 42 | 43 | # include builddir for event-names.h 44 | AM_CPPFLAGS += $(CHECK_CFLAGS) $(GCOV_CFLAGS) 45 | AM_LDFLAGS += $(GCOV_LDFLAGS) 46 | 47 | test_libevdev_SOURCES = \ 48 | test-main.c \ 49 | test-event-names.c \ 50 | test-event-codes.c \ 51 | test-libevdev-init.c \ 52 | test-libevdev-has-event.c \ 53 | test-int-queue.c \ 54 | test-libevdev-events.c \ 55 | test-uinput.c \ 56 | $(common_sources) 57 | 58 | test_libevdev_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la 59 | test_libevdev_LDFLAGS = -no-install 60 | 61 | test_kernel_SOURCES = \ 62 | test-kernel.c \ 63 | $(common_sources) 64 | test_kernel_CFLAGS = -I$(top_srcdir) 65 | test_kernel_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la 66 | 67 | if HAVE_VALGRIND 68 | VALGRIND_FLAGS=--leak-check=full \ 69 | --quiet \ 70 | --error-exitcode=3 \ 71 | --suppressions=$(srcdir)/valgrind.suppressions 72 | 73 | valgrind: 74 | $(MAKE) check-TESTS LOG_COMPILER="$(VALGRIND)" LOG_FLAGS="$(VALGRIND_FLAGS)" 75 | 76 | check_local_deps += valgrind 77 | 78 | endif 79 | 80 | EXTRA_DIST = valgrind.suppressions generate-gcov-report.sh 81 | 82 | if GCOV_ENABLED 83 | 84 | CLEANFILES = gcov-reports/*.gcov gcov-reports/summary.txt *.gcno *.gcda 85 | 86 | gcov-report: generate-gcov-report.sh check-TESTS 87 | $(AM_V_GEN)$(srcdir)/generate-gcov-report.sh gcov-reports $(top_builddir)/libevdev $(builddir) 88 | 89 | gcov: gcov-report 90 | @cat gcov-reports/summary.txt 91 | 92 | check_local_deps += gcov 93 | 94 | else 95 | 96 | gcov-report.txt: 97 | @true 98 | 99 | gcov: 100 | @true 101 | 102 | 103 | endif # GCOV_ENABLED 104 | 105 | .PHONY: gcov gcov-clean gcov-report 106 | 107 | endif # ENABLE_RUNTIME_TESTS 108 | 109 | if ENABLE_STATIC_SYMBOL_LEAKS_TEST 110 | # Hack to check for leaking symbols in the static library. 111 | # See https://bugs.freedesktop.org/show_bug.cgi?id=82785 112 | # Note the spaces in the expressions! After the first grep, each line 113 | # is " T symbol_name" 114 | static-symbol-leaks: test-static-link 115 | $(AM_V_GEN)(\ 116 | $(NM) --extern-only $(builddir)/test-static-link | \ 117 | grep -o -e " T .*" | \ 118 | grep -v -e " main$$" \ 119 | -e " atexit" \ 120 | -e " *gcov.*" \ 121 | -e " _.*" \ 122 | -e " libevdev_*" && \ 123 | echo "Leaking symbols found" && \ 124 | exit 1 || exit 0 \ 125 | ) 126 | 127 | check_local_deps += static-symbol-leaks 128 | endif # HAVE_NM 129 | 130 | check-local: $(check_local_deps) 131 | 132 | -------------------------------------------------------------------------------- /test/generate-gcov-report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ $# -lt 2 ]]; then 4 | echo "Usage: ./generate-gcov-report.sh [ ... ]" 5 | exit 1 6 | fi 7 | 8 | target_dir=$1 9 | shift 10 | source_dirs=$* 11 | 12 | if [[ "${target_dir:0:1}" != '/' ]]; then 13 | target_dir="$PWD/$target_dir" 14 | fi 15 | summary_file="$target_dir/summary.txt" 16 | 17 | mkdir -p "$target_dir" 18 | rm -f "$target_dir"/*.gcov 19 | 20 | for dir in $source_dirs; do 21 | pushd "$dir" > /dev/null 22 | for file in *.c; do 23 | find ./ -name "*${file/\.c/.gcda}" -exec gcov {} \; > /dev/null 24 | done 25 | find ./ -name "*.gcov" \! -path "*/`basename "$target_dir"`/*" -exec mv {} "$target_dir" \; 26 | popd > /dev/null 27 | done 28 | 29 | echo "========== coverage report ========" > "$summary_file" 30 | for file in "$target_dir"/*.gcov; do 31 | total=`grep -v " -:" "$file" | wc -l` 32 | missing=`grep "#####" "$file" | wc -l` 33 | hit=$((total - missing)); 34 | percent=$((($hit * 100)/$total)) 35 | fname=`basename "$file"` 36 | printf "%-32s total lines: %4s not tested: %4s (%3s%%)\n" "$fname" "$total" "$missing" "$percent">> "$summary_file" 37 | done 38 | echo "========== =============== ========" >> "$summary_file" 39 | -------------------------------------------------------------------------------- /test/test-common-uinput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "test-common-uinput.h" 39 | 40 | #define SYS_INPUT_DIR "/sys/class/input" 41 | #define DEV_INPUT_DIR "/dev/input/" 42 | 43 | struct uinput_device 44 | { 45 | struct libevdev *d; /* lazy, it has all the accessors */ 46 | struct libevdev_uinput *uidev; 47 | int dev_fd; /* open fd to the devnode */ 48 | int uinput_fd; 49 | }; 50 | 51 | struct uinput_device* 52 | uinput_device_new(const char *name) 53 | { 54 | struct uinput_device *dev; 55 | 56 | dev = calloc(1, sizeof(*dev)); 57 | if (!dev) 58 | return NULL; 59 | 60 | dev->d = libevdev_new(); 61 | dev->dev_fd = -1; 62 | dev->uinput_fd = -1; 63 | 64 | if (name) 65 | libevdev_set_name(dev->d, name); 66 | 67 | return dev; 68 | } 69 | 70 | int 71 | uinput_device_new_with_events_v(struct uinput_device **d, const char *name, const struct input_id *id, va_list args) 72 | { 73 | int rc; 74 | struct uinput_device *dev; 75 | 76 | dev = uinput_device_new(name); 77 | if (!dev) 78 | return -ENOMEM; 79 | if (id != DEFAULT_IDS) 80 | uinput_device_set_ids(dev, id); 81 | 82 | rc = uinput_device_set_event_bits_v(dev, args); 83 | 84 | if (rc == 0) 85 | rc = uinput_device_create(dev); 86 | 87 | if (rc != 0) { 88 | uinput_device_free(dev); 89 | dev = NULL; 90 | } else 91 | *d = dev; 92 | 93 | return rc; 94 | } 95 | 96 | int 97 | uinput_device_new_with_events(struct uinput_device **d, const char *name, const struct input_id *id, ...) 98 | { 99 | int rc; 100 | va_list args; 101 | 102 | va_start(args, id); 103 | rc = uinput_device_new_with_events_v(d, name, id, args); 104 | va_end(args); 105 | 106 | return rc; 107 | } 108 | 109 | void 110 | uinput_device_free(struct uinput_device *dev) 111 | { 112 | if (!dev) 113 | return; 114 | 115 | if (dev->uinput_fd != -1) { 116 | (void)ioctl(dev->uinput_fd, UI_DEV_DESTROY, NULL); 117 | close(dev->uinput_fd); 118 | } 119 | if (dev->dev_fd != -1) 120 | close(dev->dev_fd); 121 | libevdev_free(dev->d); 122 | libevdev_uinput_destroy(dev->uidev); 123 | free(dev); 124 | } 125 | 126 | int 127 | uinput_device_get_fd(const struct uinput_device *dev) 128 | { 129 | return dev->dev_fd; 130 | } 131 | 132 | const char* 133 | uinput_device_get_devnode(const struct uinput_device *dev) 134 | { 135 | return libevdev_uinput_get_devnode(dev->uidev); 136 | } 137 | 138 | int 139 | uinput_device_create(struct uinput_device* d) 140 | { 141 | int rc; 142 | int fd; 143 | const char *devnode; 144 | 145 | fd = open("/dev/uinput", O_RDWR); 146 | if (fd < 0) 147 | goto error; 148 | 149 | d->uinput_fd = fd; 150 | 151 | rc = libevdev_uinput_create_from_device(d->d, fd, &d->uidev); 152 | if (rc != 0) 153 | goto error; 154 | 155 | devnode = libevdev_uinput_get_devnode(d->uidev); 156 | if (devnode == NULL) 157 | goto error; 158 | 159 | d->dev_fd = open(devnode, O_RDWR); 160 | if (d->dev_fd == -1) 161 | goto error; 162 | 163 | /* write abs resolution now */ 164 | if (libevdev_has_event_type(d->d, EV_ABS)) { 165 | int code; 166 | for (code = 0; code < ABS_CNT; code++) { 167 | const struct input_absinfo *abs; 168 | 169 | /* can't change slots */ 170 | if (code == ABS_MT_SLOT) 171 | continue; 172 | 173 | abs = libevdev_get_abs_info(d->d, code); 174 | if (!abs) 175 | continue; 176 | 177 | rc = ioctl(d->dev_fd, EVIOCSABS(code), abs); 178 | if (rc < 0) { 179 | printf("error %s for code %d\n", strerror(-rc), code); 180 | goto error; 181 | } 182 | } 183 | } 184 | 185 | return 0; 186 | 187 | error: 188 | if (d->dev_fd != -1) 189 | close(d->dev_fd); 190 | if (d->uinput_fd != -1) 191 | close(d->uinput_fd); 192 | return -errno; 193 | 194 | } 195 | 196 | int uinput_device_set_name(struct uinput_device *dev, const char *name) 197 | { 198 | libevdev_set_name(dev->d, name); 199 | return 0; 200 | } 201 | 202 | int uinput_device_set_ids(struct uinput_device *dev, const struct input_id *ids) 203 | { 204 | libevdev_set_id_product(dev->d, ids->product); 205 | libevdev_set_id_vendor(dev->d, ids->vendor); 206 | libevdev_set_id_bustype(dev->d, ids->bustype); 207 | libevdev_set_id_version(dev->d, ids->version); 208 | return 0; 209 | } 210 | 211 | int 212 | uinput_device_set_bit(struct uinput_device* dev, unsigned int bit) 213 | { 214 | return libevdev_enable_event_type(dev->d, bit); 215 | } 216 | 217 | int 218 | uinput_device_set_prop(struct uinput_device *dev, unsigned int prop) 219 | { 220 | return libevdev_enable_property(dev->d, prop); 221 | } 222 | 223 | int 224 | uinput_device_set_event_bit(struct uinput_device* dev, unsigned int type, unsigned int code) 225 | { 226 | return libevdev_enable_event_code(dev->d, type, code, NULL); 227 | } 228 | 229 | int 230 | uinput_device_set_event_bits_v(struct uinput_device *dev, va_list args) 231 | { 232 | int type, code; 233 | int rc = 0; 234 | 235 | do { 236 | type = va_arg(args, int); 237 | if (type == -1) 238 | break; 239 | code = va_arg(args, int); 240 | if (code == -1) 241 | break; 242 | rc = libevdev_enable_event_code(dev->d, type, code, NULL); 243 | } while (rc == 0); 244 | 245 | return rc; 246 | } 247 | 248 | int 249 | uinput_device_set_event_bits(struct uinput_device *dev, ...) 250 | { 251 | int rc; 252 | va_list args; 253 | va_start(args, dev); 254 | rc = uinput_device_set_event_bits_v(dev, args); 255 | va_end(args); 256 | 257 | return rc; 258 | } 259 | 260 | int 261 | uinput_device_set_abs_bit(struct uinput_device* dev, unsigned int code, const struct input_absinfo *absinfo) 262 | { 263 | return libevdev_enable_event_code(dev->d, EV_ABS, code, absinfo); 264 | } 265 | 266 | int 267 | uinput_device_event(const struct uinput_device *dev, unsigned int type, unsigned int code, int value) 268 | { 269 | return libevdev_uinput_write_event(dev->uidev, type, code, value); 270 | } 271 | 272 | int uinput_device_event_multiple_v(const struct uinput_device* dev, va_list args) 273 | { 274 | int type, code, value; 275 | int rc = 0; 276 | 277 | do { 278 | type = va_arg(args, int); 279 | if (type == -1) 280 | break; 281 | code = va_arg(args, int); 282 | if (code == -1) 283 | break; 284 | value = va_arg(args, int); 285 | rc = uinput_device_event(dev, type, code, value); 286 | } while (rc == 0); 287 | 288 | return rc; 289 | } 290 | 291 | int uinput_device_event_multiple(const struct uinput_device* dev, ...) 292 | { 293 | int rc; 294 | va_list args; 295 | va_start(args, dev); 296 | rc = uinput_device_event_multiple_v(dev, args); 297 | va_end(args); 298 | return rc; 299 | } 300 | -------------------------------------------------------------------------------- /test/test-common-uinput.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #define DEFAULT_IDS NULL 27 | 28 | struct uinput_device* uinput_device_new(const char *name); 29 | int uinput_device_new_with_events(struct uinput_device **dev, const char *name, const struct input_id *ids, ...); 30 | int uinput_device_new_with_events_v(struct uinput_device **dev, const char *name, const struct input_id *ids, va_list args); 31 | void uinput_device_free(struct uinput_device *dev); 32 | 33 | int uinput_device_create(struct uinput_device* dev); 34 | int uinput_device_set_name(struct uinput_device* dev, const char *name); 35 | int uinput_device_set_ids(struct uinput_device* dev, const struct input_id *ids); 36 | int uinput_device_set_bit(struct uinput_device* dev, unsigned int bit); 37 | int uinput_device_set_prop(struct uinput_device *dev, unsigned int prop); 38 | int uinput_device_set_event_bit(struct uinput_device* dev, unsigned int type, unsigned int code); 39 | int uinput_device_set_event_bits(struct uinput_device* dev, ...); 40 | int uinput_device_set_event_bits_v(struct uinput_device* dev, va_list args); 41 | int uinput_device_set_abs_bit(struct uinput_device* dev, unsigned int code, const struct input_absinfo *absinfo); 42 | int uinput_device_event(const struct uinput_device* dev, unsigned int type, unsigned int code, int value); 43 | int uinput_device_event_multiple(const struct uinput_device* dev, ...); 44 | int uinput_device_event_multiple_v(const struct uinput_device* dev, va_list args); 45 | int uinput_device_get_fd(const struct uinput_device *dev); 46 | const char* uinput_device_get_devnode(const struct uinput_device *dev); 47 | 48 | char *uinput_devnode_from_syspath(const char *syspath); 49 | -------------------------------------------------------------------------------- /test/test-common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "test-common.h" 30 | 31 | void test_logfunc_abort_on_error(enum libevdev_log_priority priority, 32 | void *data, 33 | const char *file, int line, 34 | const char *func, 35 | const char *format, va_list args) 36 | { 37 | vprintf(format, args); 38 | ck_abort(); 39 | } 40 | 41 | void test_logfunc_ignore_error(enum libevdev_log_priority priority, 42 | void *data, 43 | const char *file, int line, 44 | const char *func, 45 | const char *format, va_list args) 46 | { 47 | } 48 | 49 | void test_create_device(struct uinput_device **uidev_return, 50 | struct libevdev **dev_return, 51 | ...) 52 | { 53 | int rc, fd; 54 | struct uinput_device *uidev; 55 | struct libevdev *dev; 56 | va_list args; 57 | 58 | va_start(args, dev_return); 59 | 60 | rc = uinput_device_new_with_events_v(&uidev, TEST_DEVICE_NAME, DEFAULT_IDS, args); 61 | va_end(args); 62 | 63 | ck_assert_msg(rc == 0, "Failed to create uinput device: %s", strerror(-rc)); 64 | 65 | fd = uinput_device_get_fd(uidev); 66 | 67 | rc = libevdev_new_from_fd(fd, &dev); 68 | ck_assert_msg(rc == 0, "Failed to init device device: %s", strerror(-rc)); 69 | rc = fcntl(fd, F_SETFL, O_NONBLOCK); 70 | ck_assert_msg(rc == 0, "fcntl failed: %s", strerror(errno)); 71 | 72 | *uidev_return = uidev; 73 | *dev_return = dev; 74 | } 75 | 76 | void test_create_abs_device(struct uinput_device **uidev_return, 77 | struct libevdev **dev_return, 78 | int nabs, 79 | const struct input_absinfo *abs, 80 | ...) 81 | { 82 | int rc, fd; 83 | struct uinput_device *uidev; 84 | struct libevdev *dev; 85 | va_list args; 86 | 87 | uidev = uinput_device_new(TEST_DEVICE_NAME); 88 | ck_assert(uidev != NULL); 89 | 90 | va_start(args, abs); 91 | rc = uinput_device_set_event_bits_v(uidev, args); 92 | va_end(args); 93 | 94 | while (--nabs >= 0) { 95 | int code; 96 | struct input_absinfo a; 97 | 98 | code = abs[nabs].value; 99 | a = abs[nabs]; 100 | a.value = 0; 101 | 102 | rc = uinput_device_set_abs_bit(uidev, code, &a); 103 | ck_assert_msg(rc == 0, "for abs field %d\n", nabs); 104 | } 105 | 106 | rc = uinput_device_create(uidev); 107 | ck_assert_msg(rc == 0, "Failed to create uinput device: %s", strerror(-rc)); 108 | 109 | fd = uinput_device_get_fd(uidev); 110 | 111 | rc = libevdev_new_from_fd(fd, &dev); 112 | ck_assert_msg(rc == 0, "Failed to init device device: %s", strerror(-rc)); 113 | rc = fcntl(fd, F_SETFL, O_NONBLOCK); 114 | ck_assert_msg(rc == 0, "fcntl failed: %s", strerror(errno)); 115 | 116 | *uidev_return = uidev; 117 | *dev_return = dev; 118 | } 119 | -------------------------------------------------------------------------------- /test/test-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #ifndef _TEST_COMMON_H_ 29 | #define _TEST_COMMON_H_ 30 | 31 | #define TEST_DEVICE_NAME "libevdev test device" 32 | 33 | #include "test-common-uinput.h" 34 | 35 | void test_create_device(struct uinput_device **uidev, 36 | struct libevdev **dev, 37 | ...); 38 | void test_create_abs_device(struct uinput_device **uidev, 39 | struct libevdev **dev, 40 | int nabs, 41 | const struct input_absinfo *abs, 42 | ...); 43 | 44 | void test_logfunc_abort_on_error(enum libevdev_log_priority priority, 45 | void *data, 46 | const char *file, int line, 47 | const char *func, 48 | const char *format, va_list args); 49 | void test_logfunc_ignore_error(enum libevdev_log_priority priority, 50 | void *data, 51 | const char *file, int line, 52 | const char *func, 53 | const char *format, va_list args); 54 | #endif /* _TEST_COMMON_H_ */ 55 | -------------------------------------------------------------------------------- /test/test-compile-pedantic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /test/test-event-codes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 David Herrmann 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "test-common.h" 25 | 26 | START_TEST(test_type_codes) 27 | { 28 | ck_assert_int_eq(libevdev_event_type_from_name("EV_SYN"), EV_SYN); 29 | ck_assert_int_eq(libevdev_event_type_from_name("EV_KEY"), EV_KEY); 30 | ck_assert_int_eq(libevdev_event_type_from_name("EV_REL"), EV_REL); 31 | ck_assert_int_eq(libevdev_event_type_from_name("EV_ABS"), EV_ABS); 32 | ck_assert_int_eq(libevdev_event_type_from_name("EV_MSC"), EV_MSC); 33 | ck_assert_int_eq(libevdev_event_type_from_name("EV_SND"), EV_SND); 34 | ck_assert_int_eq(libevdev_event_type_from_name("EV_SW"), EV_SW); 35 | ck_assert_int_eq(libevdev_event_type_from_name("EV_LED"), EV_LED); 36 | ck_assert_int_eq(libevdev_event_type_from_name("EV_REP"), EV_REP); 37 | ck_assert_int_eq(libevdev_event_type_from_name("EV_FF"), EV_FF); 38 | ck_assert_int_eq(libevdev_event_type_from_name("EV_FF_STATUS"), EV_FF_STATUS); 39 | ck_assert_int_eq(libevdev_event_type_from_name("EV_MAX"), EV_MAX); 40 | 41 | ck_assert_int_eq(libevdev_event_type_from_name_n("EV_SYNTAX", 6), EV_SYN); 42 | ck_assert_int_eq(libevdev_event_type_from_name_n("EV_REPTILE", 6), EV_REP); 43 | } 44 | END_TEST 45 | 46 | START_TEST(test_type_invalid) 47 | { 48 | ck_assert_int_eq(libevdev_event_type_from_name("EV_Syn"), -1); 49 | ck_assert_int_eq(libevdev_event_type_from_name("ev_SYN"), -1); 50 | ck_assert_int_eq(libevdev_event_type_from_name("SYN"), -1); 51 | ck_assert_int_eq(libevdev_event_type_from_name("EV_SYNTAX"), -1); 52 | 53 | ck_assert_int_eq(libevdev_event_type_from_name_n("EV_SYN", 5), -1); 54 | ck_assert_int_eq(libevdev_event_type_from_name_n("EV_REPTILE", 7), -1); 55 | } 56 | END_TEST 57 | 58 | START_TEST(test_key_codes) 59 | { 60 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SYN, "SYN_REPORT"), SYN_REPORT); 61 | ck_assert_int_eq(libevdev_event_code_from_name(EV_ABS, "ABS_X"), ABS_X); 62 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "BTN_A"), BTN_A); 63 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "KEY_A"), KEY_A); 64 | ck_assert_int_eq(libevdev_event_code_from_name(EV_REL, "REL_X"), REL_X); 65 | ck_assert_int_eq(libevdev_event_code_from_name(EV_MSC, "MSC_RAW"), MSC_RAW); 66 | ck_assert_int_eq(libevdev_event_code_from_name(EV_LED, "LED_KANA"), LED_KANA); 67 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SND, "SND_BELL"), SND_BELL); 68 | ck_assert_int_eq(libevdev_event_code_from_name(EV_REP, "REP_DELAY"), REP_DELAY); 69 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SYN, "SYN_DROPPED"), SYN_DROPPED); 70 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "KEY_RESERVED"), KEY_RESERVED); 71 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "BTN_0"), BTN_0); 72 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "KEY_0"), KEY_0); 73 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF, "FF_GAIN"), FF_GAIN); 74 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF_STATUS, "FF_STATUS_MAX"), FF_STATUS_MAX); 75 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SW, "SW_PEN_INSERTED"), SW_PEN_INSERTED); 76 | 77 | ck_assert_int_eq(libevdev_event_code_from_name_n(EV_ABS, "ABS_YXZ", 5), ABS_Y); 78 | } 79 | END_TEST 80 | 81 | START_TEST(test_key_invalid) 82 | { 83 | ck_assert_int_eq(libevdev_event_code_from_name(EV_MAX, "MAX_FAKE"), -1); 84 | ck_assert_int_eq(libevdev_event_code_from_name(EV_CNT, "CNT_FAKE"), -1); 85 | ck_assert_int_eq(libevdev_event_code_from_name(EV_PWR, "PWR_SOMETHING"), -1); 86 | ck_assert_int_eq(libevdev_event_code_from_name(EV_ABS, "EV_ABS"), -1); 87 | ck_assert_int_eq(libevdev_event_code_from_name(EV_ABS, "ABS_XY"), -1); 88 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "BTN_GAMEPAD"), -1); 89 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "BUS_PCI"), -1); 90 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF_STATUS, "FF_STATUS"), -1); 91 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF_STATUS, "FF_STATUS_"), -1); 92 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF, "FF_STATUS"), -1); 93 | ck_assert_int_eq(libevdev_event_code_from_name(EV_FF, "FF_STATUS_"), -1); 94 | ck_assert_int_eq(libevdev_event_code_from_name(EV_KEY, "ID_BUS"), -1); 95 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SND, "SND_CNT"), -1); 96 | ck_assert_int_eq(libevdev_event_code_from_name(EV_SW, "SW_CNT"), -1); 97 | 98 | ck_assert_int_eq(libevdev_event_code_from_name_n(EV_ABS, "ABS_X", 4), -1); 99 | } 100 | END_TEST 101 | 102 | START_TEST(test_properties) 103 | { 104 | struct prop { 105 | int val; 106 | const char *name; 107 | } lut[] = { 108 | { INPUT_PROP_DIRECT, "INPUT_PROP_DIRECT" }, 109 | { INPUT_PROP_POINTER, "INPUT_PROP_POINTER" }, 110 | { INPUT_PROP_MAX, "INPUT_PROP_MAX" }, 111 | { -1, NULL} 112 | }; 113 | struct prop *p = lut; 114 | while (p->val != -1) { 115 | ck_assert_int_eq(libevdev_property_from_name(p->name), p->val); 116 | p++; 117 | } 118 | } 119 | END_TEST 120 | 121 | START_TEST(test_properties_invalid) 122 | { 123 | ck_assert_int_eq(libevdev_property_from_name("EV_ABS"), -1); 124 | ck_assert_int_eq(libevdev_property_from_name("INPUT_PROP"), -1); 125 | ck_assert_int_eq(libevdev_property_from_name("INPUT_PROP_"), -1); 126 | ck_assert_int_eq(libevdev_property_from_name("INPUT_PROP_FOO"), -1); 127 | 128 | ck_assert_int_eq(libevdev_property_from_name_n("INPUT_PROP_POINTER", 11), -1); 129 | ck_assert_int_eq(libevdev_property_from_name_n("INPUT_PROP_POINTER", 130 | strlen("INPUT_PROP_POINTER") - 1), -1); 131 | } 132 | END_TEST 133 | 134 | Suite * 135 | event_code_suite(void) 136 | { 137 | Suite *s = suite_create("Event codes"); 138 | 139 | TCase *tc = tcase_create("type tests"); 140 | tcase_add_test(tc, test_type_codes); 141 | tcase_add_test(tc, test_type_invalid); 142 | suite_add_tcase(s, tc); 143 | 144 | tc = tcase_create("key tests"); 145 | tcase_add_test(tc, test_key_codes); 146 | tcase_add_test(tc, test_key_invalid); 147 | suite_add_tcase(s, tc); 148 | 149 | tc = tcase_create("property tests"); 150 | tcase_add_test(tc, test_properties); 151 | tcase_add_test(tc, test_properties_invalid); 152 | suite_add_tcase(s, tc); 153 | 154 | return s; 155 | } 156 | -------------------------------------------------------------------------------- /test/test-event-names.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "test-common.h" 25 | 26 | START_TEST(test_limits) 27 | { 28 | ck_assert(libevdev_event_type_get_name(EV_MAX + 1) == NULL); 29 | ck_assert(libevdev_event_code_get_name(EV_ABS, ABS_MAX + 1) == NULL); 30 | ck_assert(libevdev_event_code_get_name(EV_REL, REL_MAX + 1) == NULL); 31 | ck_assert(libevdev_event_code_get_name(EV_KEY, KEY_MAX + 1) == NULL); 32 | ck_assert(libevdev_event_code_get_name(EV_LED, LED_MAX + 1) == NULL); 33 | ck_assert(libevdev_event_code_get_name(EV_SW, SW_MAX + 1) == NULL); 34 | ck_assert(libevdev_event_code_get_name(EV_MSC, MSC_MAX + 1) == NULL); 35 | ck_assert(libevdev_event_code_get_name(EV_SND, SND_MAX + 1) == NULL); 36 | ck_assert(libevdev_event_code_get_name(EV_REP, REP_MAX + 1) == NULL); 37 | ck_assert(libevdev_event_code_get_name(EV_FF, FF_MAX + 1) == NULL); 38 | ck_assert(libevdev_event_code_get_name(EV_MAX + 1, 0) == NULL); 39 | } 40 | END_TEST 41 | 42 | START_TEST(test_type_name) 43 | { 44 | ck_assert_str_eq(libevdev_event_type_get_name(EV_SYN), "EV_SYN"); 45 | ck_assert_str_eq(libevdev_event_type_get_name(EV_REL), "EV_REL"); 46 | ck_assert_str_eq(libevdev_event_type_get_name(EV_ABS), "EV_ABS"); 47 | ck_assert_str_eq(libevdev_event_type_get_name(EV_MSC), "EV_MSC"); 48 | ck_assert_str_eq(libevdev_event_type_get_name(EV_SW), "EV_SW"); 49 | ck_assert_str_eq(libevdev_event_type_get_name(EV_LED), "EV_LED"); 50 | ck_assert_str_eq(libevdev_event_type_get_name(EV_SND), "EV_SND"); 51 | ck_assert_str_eq(libevdev_event_type_get_name(EV_REP), "EV_REP"); 52 | ck_assert_str_eq(libevdev_event_type_get_name(EV_FF), "EV_FF"); 53 | ck_assert_str_eq(libevdev_event_type_get_name(EV_PWR), "EV_PWR"); 54 | ck_assert_str_eq(libevdev_event_type_get_name(EV_FF_STATUS), "EV_FF_STATUS"); 55 | ck_assert_str_eq(libevdev_event_type_get_name(EV_MAX), "EV_MAX"); 56 | } 57 | END_TEST 58 | 59 | START_TEST(test_code_abs_name) 60 | { 61 | /* pick out a few only */ 62 | ck_assert_str_eq(libevdev_event_code_get_name(EV_ABS, ABS_X), "ABS_X"); 63 | ck_assert_str_eq(libevdev_event_code_get_name(EV_ABS, ABS_Y), "ABS_Y"); 64 | 65 | ck_assert_str_eq(libevdev_event_code_get_name(EV_ABS, ABS_MT_SLOT), "ABS_MT_SLOT"); 66 | ck_assert_str_eq(libevdev_event_code_get_name(EV_ABS, ABS_MISC), "ABS_MISC"); 67 | ck_assert_str_eq(libevdev_event_code_get_name(EV_ABS, ABS_MAX), "ABS_MAX"); 68 | 69 | ck_assert(libevdev_event_code_get_name(EV_ABS, ABS_MAX - 1) == NULL); 70 | 71 | } 72 | END_TEST 73 | 74 | START_TEST(test_code_rel_name) 75 | { 76 | /* pick out a few only */ 77 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REL, REL_X), "REL_X"); 78 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REL, REL_Y), "REL_Y"); 79 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REL, REL_MISC), "REL_MISC"); 80 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REL, REL_MAX), "REL_MAX"); 81 | 82 | ck_assert(libevdev_event_code_get_name(EV_REL, REL_MAX - 1) == NULL); 83 | 84 | } 85 | END_TEST 86 | 87 | START_TEST(test_code_key_name) 88 | { 89 | /* pick out a few only */ 90 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_RESERVED), "KEY_RESERVED"); 91 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_ESC), "KEY_ESC"); 92 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_1), "KEY_1"); 93 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_2), "KEY_2"); 94 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_UNKNOWN), "KEY_UNKNOWN"); 95 | 96 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_0), "BTN_0"); 97 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_LEFT), "BTN_LEFT"); 98 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_TRIGGER), "BTN_TRIGGER"); 99 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_A), "BTN_SOUTH"); 100 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_TOOL_PEN), "BTN_TOOL_PEN"); 101 | 102 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_TOUCHPAD_TOGGLE), "KEY_TOUCHPAD_TOGGLE"); 103 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_TRIGGER_HAPPY), "BTN_TRIGGER_HAPPY1"); 104 | 105 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_MAX), "KEY_MAX"); 106 | ck_assert(libevdev_event_code_get_name(EV_KEY, KEY_MAX - 1) == NULL); 107 | 108 | /* special cases that resolve to something else */ 109 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_HANGUEL), "KEY_HANGEUL"); 110 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, KEY_SCREENLOCK), "KEY_COFFEE"); 111 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_MISC), "BTN_0"); 112 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_MOUSE), "BTN_LEFT"); 113 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_JOYSTICK), "BTN_TRIGGER"); 114 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_GAMEPAD), "BTN_SOUTH"); 115 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_DIGI), "BTN_TOOL_PEN"); 116 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_WHEEL), "BTN_GEAR_DOWN"); 117 | ck_assert_str_eq(libevdev_event_code_get_name(EV_KEY, BTN_TRIGGER_HAPPY), "BTN_TRIGGER_HAPPY1"); 118 | 119 | } 120 | END_TEST 121 | 122 | START_TEST(test_code_led_name) 123 | { 124 | /* pick out a few only */ 125 | ck_assert_str_eq(libevdev_event_code_get_name(EV_LED, LED_NUML), "LED_NUML"); 126 | ck_assert_str_eq(libevdev_event_code_get_name(EV_LED, LED_KANA), "LED_KANA"); 127 | ck_assert_str_eq(libevdev_event_code_get_name(EV_LED, LED_MAX), "LED_MAX"); 128 | 129 | ck_assert(libevdev_event_code_get_name(EV_LED, LED_MAX - 1) == NULL); 130 | 131 | } 132 | END_TEST 133 | 134 | START_TEST(test_code_snd_name) 135 | { 136 | /* pick out a few only */ 137 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SND, SND_CLICK), "SND_CLICK"); 138 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SND, SND_TONE), "SND_TONE"); 139 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SND, SND_MAX), "SND_MAX"); 140 | 141 | ck_assert(libevdev_event_code_get_name(EV_SND, SND_MAX - 1) == NULL); 142 | 143 | } 144 | END_TEST 145 | 146 | START_TEST(test_code_rep_name) 147 | { 148 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_DELAY), "REP_DELAY"); 149 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_PERIOD), "REP_PERIOD"); 150 | ck_assert_str_eq(libevdev_event_code_get_name(EV_REP, REP_MAX), "REP_PERIOD"); 151 | 152 | } 153 | END_TEST 154 | 155 | START_TEST(test_code_msc_name) 156 | { 157 | /* pick out a few only */ 158 | ck_assert_str_eq(libevdev_event_code_get_name(EV_MSC, MSC_SERIAL), "MSC_SERIAL"); 159 | ck_assert_str_eq(libevdev_event_code_get_name(EV_MSC, MSC_RAW), "MSC_RAW"); 160 | #ifdef MSC_TIMESTAMP 161 | ck_assert_str_eq(libevdev_event_code_get_name(EV_MSC, MSC_TIMESTAMP), "MSC_TIMESTAMP"); 162 | #endif 163 | ck_assert_str_eq(libevdev_event_code_get_name(EV_MSC, MSC_MAX), "MSC_MAX"); 164 | 165 | ck_assert(libevdev_event_code_get_name(EV_MSC, MSC_MAX - 1) == NULL); 166 | 167 | } 168 | END_TEST 169 | 170 | START_TEST(test_code_sw_name) 171 | { 172 | /* pick out a few only */ 173 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_LID), "SW_LID"); 174 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_RFKILL_ALL), "SW_RFKILL_ALL"); 175 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_LINEIN_INSERT), "SW_LINEIN_INSERT"); 176 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_PEN_INSERTED), "SW_PEN_INSERTED"); 177 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SW, SW_MAX), "SW_PEN_INSERTED"); 178 | } 179 | END_TEST 180 | 181 | START_TEST(test_code_ff_name) 182 | { 183 | /* pick out a few only */ 184 | ck_assert_str_eq(libevdev_event_code_get_name(EV_FF, FF_STATUS_STOPPED), "FF_STATUS_STOPPED"); 185 | ck_assert_str_eq(libevdev_event_code_get_name(EV_FF, FF_FRICTION), "FF_FRICTION"); 186 | ck_assert_str_eq(libevdev_event_code_get_name(EV_FF, FF_CUSTOM), "FF_CUSTOM"); 187 | ck_assert_str_eq(libevdev_event_code_get_name(EV_FF, FF_MAX), "FF_MAX"); 188 | 189 | ck_assert(libevdev_event_code_get_name(EV_FF, FF_MAX - 1) == NULL); 190 | 191 | } 192 | END_TEST 193 | 194 | START_TEST(test_code_syn_name) 195 | { 196 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SYN, SYN_REPORT), "SYN_REPORT"); 197 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SYN, SYN_CONFIG), "SYN_CONFIG"); 198 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SYN, SYN_MT_REPORT), "SYN_MT_REPORT"); 199 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SYN, SYN_DROPPED), "SYN_DROPPED"); 200 | ck_assert_str_eq(libevdev_event_code_get_name(EV_SYN, SYN_MAX), "SYN_MAX"); 201 | } 202 | END_TEST 203 | 204 | START_TEST(test_prop_name) 205 | { 206 | ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_POINTER), "INPUT_PROP_POINTER"); 207 | ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_DIRECT), "INPUT_PROP_DIRECT"); 208 | ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_BUTTONPAD), "INPUT_PROP_BUTTONPAD"); 209 | ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_SEMI_MT), "INPUT_PROP_SEMI_MT"); 210 | ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_MAX), "INPUT_PROP_MAX"); 211 | 212 | ck_assert(libevdev_property_get_name(INPUT_PROP_MAX - 1) == NULL); 213 | ck_assert(libevdev_property_get_name(INPUT_PROP_MAX + 1) == NULL); 214 | } 215 | END_TEST 216 | 217 | START_TEST(test_event_type_max) 218 | { 219 | ck_assert_int_eq(libevdev_event_type_get_max(EV_ABS), ABS_MAX); 220 | ck_assert_int_eq(libevdev_event_type_get_max(EV_REL), REL_MAX); 221 | ck_assert_int_eq(libevdev_event_type_get_max(EV_KEY), KEY_MAX); 222 | 223 | ck_assert_int_eq(libevdev_event_type_get_max(EV_MAX - 1), -1); 224 | ck_assert_int_eq(libevdev_event_type_get_max(EV_MAX + 1), -1); 225 | 226 | } 227 | END_TEST 228 | 229 | START_TEST(test_event_type) 230 | { 231 | struct input_event ev; 232 | int i = 0; 233 | 234 | ev.type = EV_REL; 235 | 236 | ck_assert_int_eq(libevdev_event_is_type(&ev, EV_REL), 1); 237 | for (i = 0; i < EV_CNT; i++) { 238 | if (i == ev.type) 239 | continue; 240 | ck_assert_int_eq(libevdev_event_is_type(&ev, i), 0); 241 | } 242 | ck_assert_int_eq(libevdev_event_is_type(&ev, EV_MAX + 1), 0); 243 | } 244 | END_TEST 245 | 246 | START_TEST(test_event_code) 247 | { 248 | struct input_event ev; 249 | int i = 0; 250 | 251 | ev.type = EV_REL; 252 | ev.code = REL_Y; 253 | 254 | ck_assert_int_eq(libevdev_event_is_code(&ev, EV_REL, REL_Y), 1); 255 | for (i = 0; i < EV_CNT; i++) { 256 | int j; 257 | if (i == ev.type || i == EV_SYN) 258 | continue; 259 | 260 | for (j = 0; j < libevdev_event_type_get_max(i); i++) { 261 | ck_assert_int_eq(libevdev_event_is_code(&ev, i, j), 0); 262 | } 263 | } 264 | ck_assert_int_eq(libevdev_event_is_code(&ev, EV_MAX + 1, ev.code), 0); 265 | ck_assert_int_eq(libevdev_event_is_code(&ev, EV_REL, REL_MAX + 1), 0); 266 | 267 | ev.type = EV_SYN; 268 | ev.code = SYN_REPORT; 269 | ck_assert_int_eq(libevdev_event_is_code(&ev, EV_SYN, SYN_REPORT), 1); 270 | ck_assert_int_eq(libevdev_event_is_code(&ev, EV_SYN, SYN_DROPPED), 0); 271 | } 272 | END_TEST 273 | 274 | Suite * 275 | event_name_suite(void) 276 | { 277 | Suite *s = suite_create("Event names"); 278 | 279 | TCase *tc = tcase_create("type limits"); 280 | tcase_add_test(tc, test_limits); 281 | tcase_add_test(tc, test_event_type_max); 282 | suite_add_tcase(s, tc); 283 | 284 | tc = tcase_create("type names"); 285 | tcase_add_test(tc, test_type_name); 286 | suite_add_tcase(s, tc); 287 | 288 | tc = tcase_create("code names"); 289 | tcase_add_test(tc, test_code_abs_name); 290 | tcase_add_test(tc, test_code_rel_name); 291 | tcase_add_test(tc, test_code_key_name); 292 | tcase_add_test(tc, test_code_led_name); 293 | tcase_add_test(tc, test_code_snd_name); 294 | tcase_add_test(tc, test_code_rep_name); 295 | tcase_add_test(tc, test_code_msc_name); 296 | tcase_add_test(tc, test_code_sw_name); 297 | tcase_add_test(tc, test_code_ff_name); 298 | tcase_add_test(tc, test_code_syn_name); 299 | suite_add_tcase(s, tc); 300 | 301 | tc = tcase_create("prop names"); 302 | tcase_add_test(tc, test_prop_name); 303 | suite_add_tcase(s, tc); 304 | 305 | tc = tcase_create("event values"); 306 | tcase_add_test(tc, test_event_type); 307 | tcase_add_test(tc, test_event_code); 308 | suite_add_tcase(s, tc); 309 | 310 | return s; 311 | } 312 | -------------------------------------------------------------------------------- /test/test-int-queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "test-common.h" 27 | 28 | START_TEST(test_queue_alloc) 29 | { 30 | struct libevdev dev; 31 | int rc; 32 | 33 | rc = queue_alloc(&dev, 0); 34 | ck_assert_int_eq(rc, -ENOMEM); 35 | 36 | rc = queue_alloc(&dev, 100); 37 | ck_assert_int_eq(rc, 0); 38 | 39 | ck_assert_int_eq(dev.queue_size, 100); 40 | ck_assert_int_eq(dev.queue_next, 0); 41 | 42 | queue_free(&dev); 43 | ck_assert_int_eq(dev.queue_size, 0); 44 | ck_assert_int_eq(dev.queue_next, 0); 45 | 46 | } 47 | END_TEST 48 | 49 | START_TEST(test_queue_sizes) 50 | { 51 | struct libevdev dev = {0}; 52 | 53 | queue_alloc(&dev, 0); 54 | ck_assert_int_eq(queue_num_elements(&dev), 0); 55 | ck_assert_int_eq(queue_num_free_elements(&dev), 0); 56 | ck_assert_int_eq(queue_size(&dev), 0); 57 | 58 | queue_alloc(&dev, 100); 59 | ck_assert_int_eq(queue_num_elements(&dev), 0); 60 | ck_assert_int_eq(queue_num_free_elements(&dev), 100); 61 | ck_assert_int_eq(queue_size(&dev), 100); 62 | 63 | queue_free(&dev); 64 | 65 | ck_assert_int_eq(queue_num_elements(&dev), 0); 66 | ck_assert_int_eq(queue_num_free_elements(&dev), 0); 67 | ck_assert_int_eq(queue_size(&dev), 0); 68 | } 69 | END_TEST 70 | 71 | START_TEST(test_queue_push) 72 | { 73 | struct libevdev dev = {0}; 74 | struct input_event *ev; 75 | 76 | queue_alloc(&dev, 0); 77 | ev = queue_push(&dev); 78 | ck_assert(ev == NULL); 79 | 80 | queue_alloc(&dev, 2); 81 | ev = queue_push(&dev); 82 | ck_assert(ev == dev.queue); 83 | ck_assert_int_eq(queue_num_elements(&dev), 1); 84 | ck_assert_int_eq(queue_num_free_elements(&dev), 1); 85 | 86 | ev = queue_push(&dev); 87 | ck_assert(ev == dev.queue + 1); 88 | 89 | ev = queue_push(&dev); 90 | ck_assert(ev == NULL); 91 | 92 | queue_free(&dev); 93 | ev = queue_push(&dev); 94 | ck_assert(ev == NULL); 95 | 96 | } 97 | END_TEST 98 | 99 | START_TEST(test_queue_pop) 100 | { 101 | struct libevdev dev = {0}; 102 | struct input_event ev, *e, tmp; 103 | int rc; 104 | 105 | queue_alloc(&dev, 0); 106 | rc = queue_pop(&dev, &ev); 107 | ck_assert_int_eq(rc, 1); 108 | 109 | queue_alloc(&dev, 2); 110 | e = queue_push(&dev); 111 | memset(e, 0xab, sizeof(*e)); 112 | ck_assert_int_eq(queue_num_elements(&dev), 1); 113 | ck_assert_int_eq(queue_num_free_elements(&dev), 1); 114 | 115 | rc = queue_pop(&dev, &ev); 116 | ck_assert_int_eq(rc, 0); 117 | memset(&tmp, 0xab, sizeof(tmp)); 118 | rc = memcmp(&tmp, &ev, sizeof(tmp)); 119 | ck_assert_int_eq(rc, 0); 120 | 121 | ck_assert_int_eq(queue_num_elements(&dev), 0); 122 | ck_assert_int_eq(queue_num_free_elements(&dev), 2); 123 | 124 | rc = queue_pop(&dev, &ev); 125 | ck_assert_int_eq(rc, 1); 126 | 127 | queue_free(&dev); 128 | } 129 | END_TEST 130 | 131 | START_TEST(test_queue_peek) 132 | { 133 | struct libevdev dev = {0}; 134 | struct input_event ev, *e, tmp; 135 | int rc; 136 | 137 | queue_alloc(&dev, 0); 138 | rc = queue_peek(&dev, 0, &ev); 139 | ck_assert_int_eq(rc, 1); 140 | 141 | queue_alloc(&dev, 2); 142 | e = queue_push(&dev); 143 | memset(e, 0xab, sizeof(*e)); 144 | 145 | rc = queue_peek(&dev, 0, &ev); 146 | ck_assert_int_eq(rc, 0); 147 | memset(&tmp, 0xab, sizeof(tmp)); 148 | rc = memcmp(&tmp, &ev, sizeof(tmp)); 149 | ck_assert_int_eq(rc, 0); 150 | 151 | ck_assert_int_eq(queue_num_elements(&dev), 1); 152 | e = queue_push(&dev); 153 | memset(e, 0xbc, sizeof(*e)); 154 | 155 | rc = queue_peek(&dev, 1, &ev); 156 | ck_assert_int_eq(rc, 0); 157 | memset(&tmp, 0xbc, sizeof(tmp)); 158 | rc = memcmp(&tmp, &ev, sizeof(tmp)); 159 | ck_assert_int_eq(rc, 0); 160 | 161 | rc = queue_peek(&dev, 0, &ev); 162 | ck_assert_int_eq(rc, 0); 163 | memset(&tmp, 0xab, sizeof(tmp)); 164 | rc = memcmp(&tmp, &ev, sizeof(tmp)); 165 | ck_assert_int_eq(rc, 0); 166 | 167 | ck_assert_int_eq(queue_num_elements(&dev), 2); 168 | 169 | queue_free(&dev); 170 | } 171 | END_TEST 172 | 173 | START_TEST(test_queue_shift) 174 | { 175 | struct libevdev dev = {0}; 176 | struct input_event ev, *first, *second, e1, e2; 177 | int rc; 178 | 179 | ck_assert_int_eq(queue_shift(&dev, &ev), 1); 180 | 181 | queue_alloc(&dev, 10); 182 | ck_assert_int_eq(queue_shift(&dev, &ev), 1); 183 | 184 | first = queue_push(&dev); 185 | ck_assert(first != NULL); 186 | memset(first, 0xab, sizeof(*first)); 187 | 188 | e1 = *first; 189 | 190 | second = queue_push(&dev); 191 | ck_assert(second != NULL); 192 | memset(second, 0x12, sizeof(*second)); 193 | 194 | e2 = *second; 195 | 196 | rc = queue_shift(&dev, &ev); 197 | ck_assert_int_eq(rc, 0); 198 | rc = memcmp(&ev, &e1, sizeof(ev)); 199 | ck_assert_int_eq(rc, 0); 200 | 201 | rc = queue_shift(&dev, &ev); 202 | ck_assert_int_eq(rc, 0); 203 | rc = memcmp(&ev, &e2, sizeof(ev)); 204 | ck_assert_int_eq(rc, 0); 205 | 206 | ck_assert_int_eq(queue_shift(&dev, &ev), 1); 207 | 208 | queue_free(&dev); 209 | } 210 | END_TEST 211 | 212 | START_TEST(test_queue_shift_multiple) 213 | { 214 | struct libevdev dev = {0}; 215 | struct input_event ev, *first, *second, e1, e2; 216 | struct input_event events[5]; 217 | int rc; 218 | 219 | ck_assert_int_eq(queue_shift_multiple(&dev, 1, &ev), 0); 220 | ck_assert_int_eq(queue_shift_multiple(&dev, 0, &ev), 0); 221 | 222 | queue_alloc(&dev, 10); 223 | ck_assert_int_eq(queue_shift_multiple(&dev, 1, &ev), 0); 224 | ck_assert_int_eq(queue_shift_multiple(&dev, 0, &ev), 0); 225 | 226 | first = queue_push(&dev); 227 | ck_assert(first != NULL); 228 | memset(first, 0xab, sizeof(*first)); 229 | e1 = *first; 230 | 231 | second = queue_push(&dev); 232 | ck_assert(second != NULL); 233 | memset(second, 0x12, sizeof(*second)); 234 | e2 = *second; 235 | 236 | rc = queue_shift_multiple(&dev, 5, events); 237 | ck_assert_int_eq(rc, 2); 238 | rc = memcmp(&events[0], &e1, sizeof(ev)); 239 | ck_assert_int_eq(rc, 0); 240 | rc = memcmp(&events[1], &e2, sizeof(ev)); 241 | ck_assert_int_eq(rc, 0); 242 | 243 | first = queue_push(&dev); 244 | ck_assert(first != NULL); 245 | memset(first, 0xab, sizeof(*first)); 246 | e1 = *first; 247 | 248 | second = queue_push(&dev); 249 | ck_assert(second != NULL); 250 | memset(second, 0x12, sizeof(*second)); 251 | e2 = *second; 252 | 253 | rc = queue_shift_multiple(&dev, 1, events); 254 | ck_assert_int_eq(rc, 1); 255 | rc = memcmp(&events[0], &e1, sizeof(ev)); 256 | ck_assert_int_eq(rc, 0); 257 | 258 | rc = queue_shift_multiple(&dev, 1, events); 259 | ck_assert_int_eq(rc, 1); 260 | rc = memcmp(&events[0], &e2, sizeof(ev)); 261 | ck_assert_int_eq(rc, 0); 262 | 263 | ck_assert_int_eq(queue_shift_multiple(&dev, 1, events), 0); 264 | 265 | queue_free(&dev); 266 | } 267 | END_TEST 268 | 269 | START_TEST(test_queue_next_element) 270 | { 271 | struct libevdev dev = {0}; 272 | struct input_event ev, *first, *second; 273 | int rc; 274 | 275 | queue_alloc(&dev, 0); 276 | first = queue_next_element(&dev); 277 | ck_assert(first == NULL); 278 | 279 | queue_alloc(&dev, 2); 280 | first = queue_next_element(&dev); 281 | ck_assert(first != NULL); 282 | memset(first, 0xab, sizeof(*first)); 283 | 284 | second = queue_next_element(&dev); 285 | ck_assert(second != NULL); 286 | memset(second, 0xbc, sizeof(*second)); 287 | 288 | /* queue_next_element does not advance, so we overwrite */ 289 | memset(&ev, 0xbc, sizeof(ev)); 290 | rc = memcmp(&ev, first, sizeof(ev)); 291 | ck_assert_int_eq(rc, 0); 292 | 293 | ck_assert_int_eq(queue_num_elements(&dev), 0); 294 | 295 | first = queue_next_element(&dev); 296 | ck_assert(first != NULL); 297 | memset(first, 0xab, sizeof(*first)); 298 | 299 | queue_set_num_elements(&dev, 1); 300 | ck_assert_int_eq(queue_num_elements(&dev), 1); 301 | 302 | second = queue_next_element(&dev); 303 | ck_assert(second != NULL); 304 | memset(second, 0xbc, sizeof(*second)); 305 | 306 | memset(&ev, 0xab, sizeof(ev)); 307 | rc = memcmp(&ev, first, sizeof(ev)); 308 | ck_assert_int_eq(rc, 0); 309 | 310 | queue_free(&dev); 311 | } 312 | END_TEST 313 | 314 | START_TEST(test_queue_set_num_elements) 315 | { 316 | struct libevdev dev = {0}; 317 | 318 | queue_alloc(&dev, 0); 319 | ck_assert_int_eq(queue_set_num_elements(&dev, 1), 1); 320 | 321 | queue_alloc(&dev, 2); 322 | ck_assert_int_eq(queue_set_num_elements(&dev, 3), 1); 323 | ck_assert_int_eq(queue_set_num_elements(&dev, 2), 0); 324 | 325 | queue_free(&dev); 326 | } 327 | END_TEST 328 | 329 | Suite * 330 | queue_suite(void) 331 | { 332 | Suite *s = suite_create("Event queue"); 333 | 334 | TCase *tc = tcase_create("Queue allocation"); 335 | tcase_add_test(tc, test_queue_alloc); 336 | tcase_add_test(tc, test_queue_sizes); 337 | suite_add_tcase(s, tc); 338 | 339 | tc = tcase_create("Queue push/pop/peek"); 340 | tcase_add_test(tc, test_queue_push); 341 | tcase_add_test(tc, test_queue_pop); 342 | tcase_add_test(tc, test_queue_peek); 343 | suite_add_tcase(s, tc); 344 | 345 | tc = tcase_create("Queue shift"); 346 | tcase_add_test(tc, test_queue_shift); 347 | tcase_add_test(tc, test_queue_shift_multiple); 348 | suite_add_tcase(s, tc); 349 | 350 | tc = tcase_create("Queue next elem"); 351 | tcase_add_test(tc, test_queue_next_element); 352 | tcase_add_test(tc, test_queue_set_num_elements); 353 | suite_add_tcase(s, tc); 354 | 355 | return s; 356 | } 357 | -------------------------------------------------------------------------------- /test/test-kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2014 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include "test-common.h" 37 | 38 | START_TEST(test_revoke) 39 | { 40 | struct uinput_device* uidev; 41 | struct libevdev *dev, *dev2; 42 | int rc, fd; 43 | struct input_event ev1, ev2; 44 | int dev_fd; 45 | 46 | test_create_device(&uidev, &dev, 47 | EV_SYN, SYN_REPORT, 48 | EV_REL, REL_X, 49 | EV_REL, REL_Y, 50 | EV_REL, REL_WHEEL, 51 | EV_KEY, BTN_LEFT, 52 | EV_KEY, BTN_MIDDLE, 53 | EV_KEY, BTN_RIGHT, 54 | -1); 55 | 56 | fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK); 57 | ck_assert_int_gt(fd, -1); 58 | rc = libevdev_new_from_fd(fd, &dev2); 59 | ck_assert_msg(rc == 0, "Failed to create second device: %s", strerror(-rc)); 60 | 61 | uinput_device_event(uidev, EV_REL, REL_X, 1); 62 | uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0); 63 | 64 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1); 65 | ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); 66 | 67 | rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2); 68 | ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); 69 | 70 | ck_assert_int_eq(ev1.type, ev2.type); 71 | ck_assert_int_eq(ev1.code, ev2.code); 72 | ck_assert_int_eq(ev1.value, ev2.value); 73 | 74 | /* revoke first device, expect it closed, second device still open */ 75 | dev_fd = libevdev_get_fd(dev); 76 | ck_assert_int_ge(dev_fd, 0); 77 | rc = ioctl(dev_fd, EVIOCREVOKE, NULL); 78 | if (rc == -1 && errno == EINVAL) { 79 | fprintf(stderr, "WARNING: skipping EVIOCREVOKE test, not suported by current kernel\n"); 80 | goto out; 81 | } 82 | ck_assert_msg(rc == 0, "Failed to revoke device: %s", strerror(errno)); 83 | 84 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1); 85 | ck_assert_int_eq(rc, -ENODEV); 86 | 87 | rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2); 88 | ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); 89 | 90 | out: 91 | uinput_device_free(uidev); 92 | libevdev_free(dev); 93 | libevdev_free(dev2); 94 | close(fd); 95 | } 96 | END_TEST 97 | 98 | START_TEST(test_revoke_invalid) 99 | { 100 | struct uinput_device* uidev; 101 | struct libevdev *dev; 102 | int rc; 103 | int dev_fd; 104 | 105 | test_create_device(&uidev, &dev, 106 | EV_SYN, SYN_REPORT, 107 | EV_REL, REL_X, 108 | EV_REL, REL_Y, 109 | EV_REL, REL_WHEEL, 110 | EV_KEY, BTN_LEFT, 111 | EV_KEY, BTN_MIDDLE, 112 | EV_KEY, BTN_RIGHT, 113 | -1); 114 | 115 | dev_fd = libevdev_get_fd(dev); 116 | ck_assert_int_ge(dev_fd, 0); 117 | /* ioctl requires 0 as value */ 118 | rc = ioctl(dev_fd, EVIOCREVOKE, 1); 119 | ck_assert_int_eq(rc, -1); 120 | ck_assert_int_eq(errno, EINVAL); 121 | 122 | uinput_device_free(uidev); 123 | libevdev_free(dev); 124 | } 125 | END_TEST 126 | 127 | START_TEST(test_revoke_fail_after) 128 | { 129 | struct uinput_device* uidev; 130 | struct libevdev *dev, *dev2 = NULL; 131 | int rc, fd; 132 | 133 | test_create_device(&uidev, &dev, 134 | EV_SYN, SYN_REPORT, 135 | EV_REL, REL_X, 136 | EV_REL, REL_Y, 137 | EV_REL, REL_WHEEL, 138 | EV_KEY, BTN_LEFT, 139 | EV_KEY, BTN_MIDDLE, 140 | EV_KEY, BTN_RIGHT, 141 | -1); 142 | 143 | fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK); 144 | ck_assert_int_gt(fd, -1); 145 | 146 | rc = ioctl(fd, EVIOCREVOKE, NULL); 147 | if (rc == -1 && errno == EINVAL) { 148 | fprintf(stderr, "WARNING: skipping EVIOCREVOKE test, not suported by current kernel\n"); 149 | goto out; 150 | } 151 | ck_assert_msg(rc == 0, "Failed to revoke device: %s", strerror(errno)); 152 | 153 | rc = libevdev_new_from_fd(fd, &dev2); 154 | ck_assert_int_eq(rc, -ENODEV); 155 | 156 | out: 157 | uinput_device_free(uidev); 158 | libevdev_free(dev); 159 | close(fd); 160 | } 161 | END_TEST 162 | 163 | int main(int argc, char **argv) 164 | { 165 | SRunner *sr; 166 | Suite *s; 167 | TCase *tc; 168 | int failed; 169 | 170 | if (getuid() != 0) { 171 | fprintf(stderr, "This test needs to run as root\n"); 172 | return 77; 173 | } 174 | 175 | s = suite_create("kernel tests"); 176 | 177 | tc = tcase_create("EVIOCREVOKE"); 178 | tcase_add_test(tc, test_revoke); 179 | tcase_add_test(tc, test_revoke_invalid); 180 | tcase_add_test(tc, test_revoke_fail_after); 181 | suite_add_tcase(s, tc); 182 | 183 | sr = srunner_create(s); 184 | srunner_run_all(sr, CK_NORMAL); 185 | 186 | failed = srunner_ntests_failed(sr); 187 | srunner_free(sr); 188 | 189 | return failed; 190 | } 191 | -------------------------------------------------------------------------------- /test/test-link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | return libevdev_new_from_fd(0, NULL); 6 | } 7 | -------------------------------------------------------------------------------- /test/test-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "test-common.h" 34 | 35 | extern Suite *event_name_suite(void); 36 | extern Suite *event_code_suite(void); 37 | extern Suite *libevdev_init_test(void); 38 | extern Suite *queue_suite(void); 39 | extern Suite *libevdev_has_event_test(void); 40 | extern Suite *libevdev_events(void); 41 | extern Suite *uinput_suite(void); 42 | 43 | static int 44 | is_debugger_attached(void) 45 | { 46 | int status; 47 | int rc; 48 | int pid = fork(); 49 | 50 | if (pid == -1) 51 | return 0; 52 | 53 | if (pid == 0) { 54 | int ppid = getppid(); 55 | if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0) { 56 | waitpid(ppid, NULL, 0); 57 | ptrace(PTRACE_CONT, NULL, NULL); 58 | ptrace(PTRACE_DETACH, ppid, NULL, NULL); 59 | rc = 0; 60 | } else 61 | rc = 1; 62 | _exit(rc); 63 | } else { 64 | waitpid(pid, &status, 0); 65 | rc = WEXITSTATUS(status); 66 | } 67 | 68 | return rc; 69 | } 70 | 71 | int main(void) 72 | { 73 | const struct rlimit corelimit = {0, 0}; 74 | int failed; 75 | 76 | if (getuid() != 0) { 77 | fprintf(stderr, "This test needs to run as root\n"); 78 | return 77; 79 | } 80 | 81 | if (is_debugger_attached()) 82 | setenv("CK_FORK", "no", 0); 83 | 84 | if (setrlimit(RLIMIT_CORE, &corelimit) != 0) 85 | perror("WARNING: Core dumps not disabled. Reason"); 86 | 87 | libevdev_set_log_function(test_logfunc_abort_on_error, NULL); 88 | 89 | Suite *s = libevdev_has_event_test(); 90 | SRunner *sr = srunner_create(s); 91 | srunner_add_suite(sr, libevdev_events()); 92 | srunner_add_suite(sr, libevdev_init_test()); 93 | srunner_add_suite(sr, queue_suite()); 94 | srunner_add_suite(sr, event_name_suite()); 95 | srunner_add_suite(sr, event_code_suite()); 96 | srunner_add_suite(sr, uinput_suite()); 97 | srunner_run_all(sr, CK_NORMAL); 98 | 99 | failed = srunner_ntests_failed(sr); 100 | srunner_free(sr); 101 | 102 | return failed; 103 | } 104 | -------------------------------------------------------------------------------- /test/test-uinput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "test-common.h" 32 | #define UINPUT_NODE "/dev/uinput" 33 | 34 | START_TEST(test_uinput_create_device) 35 | { 36 | struct libevdev *dev, *dev2; 37 | struct libevdev_uinput *uidev; 38 | int fd, uinput_fd; 39 | unsigned int type, code; 40 | int rc; 41 | const char *devnode; 42 | 43 | dev = libevdev_new(); 44 | ck_assert(dev != NULL); 45 | libevdev_set_name(dev, TEST_DEVICE_NAME); 46 | libevdev_enable_event_type(dev, EV_SYN); 47 | libevdev_enable_event_type(dev, EV_REL); 48 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 49 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 50 | libevdev_enable_event_code(dev, EV_REL, REL_MAX, NULL); 51 | 52 | rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev); 53 | ck_assert_int_eq(rc, 0); 54 | ck_assert(uidev != NULL); 55 | 56 | uinput_fd = libevdev_uinput_get_fd(uidev); 57 | ck_assert_int_gt(uinput_fd, -1); 58 | 59 | devnode = libevdev_uinput_get_devnode(uidev); 60 | ck_assert(devnode != NULL); 61 | 62 | fd = open(devnode, O_RDONLY); 63 | ck_assert_int_gt(fd, -1); 64 | rc = libevdev_new_from_fd(fd, &dev2); 65 | ck_assert_int_eq(rc, 0); 66 | 67 | for (type = 0; type < EV_CNT; type++) { 68 | int max = libevdev_event_type_get_max(type); 69 | if (max == -1) 70 | continue; 71 | 72 | for (code = 0; code < max; code++) { 73 | ck_assert_int_eq(libevdev_has_event_code(dev, type, code), 74 | libevdev_has_event_code(dev2, type, code)); 75 | } 76 | } 77 | 78 | libevdev_free(dev); 79 | libevdev_free(dev2); 80 | libevdev_uinput_destroy(uidev); 81 | close(fd); 82 | 83 | /* uinput fd is managed, so make sure it did get closed */ 84 | ck_assert_int_eq(close(uinput_fd), -1); 85 | ck_assert_int_eq(errno, EBADF); 86 | 87 | } 88 | END_TEST 89 | 90 | START_TEST(test_uinput_create_device_invalid) 91 | { 92 | struct libevdev *dev; 93 | struct libevdev_uinput *uidev = NULL; 94 | int rc; 95 | 96 | dev = libevdev_new(); 97 | ck_assert(dev != NULL); 98 | libevdev_set_name(dev, TEST_DEVICE_NAME); 99 | libevdev_enable_event_type(dev, EV_SYN); 100 | libevdev_enable_event_type(dev, EV_REL); 101 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 102 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 103 | 104 | libevdev_set_log_function(test_logfunc_ignore_error, NULL); 105 | rc = libevdev_uinput_create_from_device(dev, -1, &uidev); 106 | ck_assert_int_eq(rc, -EBADF); 107 | ck_assert(uidev == NULL); 108 | libevdev_set_log_function(test_logfunc_abort_on_error, NULL); 109 | 110 | libevdev_free(dev); 111 | } 112 | END_TEST 113 | 114 | START_TEST(test_uinput_create_device_from_fd) 115 | { 116 | struct libevdev *dev, *dev2; 117 | struct libevdev_uinput *uidev; 118 | int fd, fd2; 119 | unsigned int type, code; 120 | int rc; 121 | const char *devnode; 122 | 123 | dev = libevdev_new(); 124 | ck_assert(dev != NULL); 125 | libevdev_set_name(dev, TEST_DEVICE_NAME); 126 | libevdev_enable_event_type(dev, EV_SYN); 127 | libevdev_enable_event_type(dev, EV_REL); 128 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 129 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 130 | 131 | fd = open(UINPUT_NODE, O_RDWR); 132 | ck_assert_int_gt(fd, -1); 133 | 134 | rc = libevdev_uinput_create_from_device(dev, fd, &uidev); 135 | ck_assert_int_eq(rc, 0); 136 | ck_assert(uidev != NULL); 137 | 138 | ck_assert_int_eq(libevdev_uinput_get_fd(uidev), fd); 139 | 140 | devnode = libevdev_uinput_get_devnode(uidev); 141 | ck_assert(devnode != NULL); 142 | 143 | fd2 = open(devnode, O_RDONLY); 144 | ck_assert_int_gt(fd2, -1); 145 | rc = libevdev_new_from_fd(fd2, &dev2); 146 | ck_assert_int_eq(rc, 0); 147 | 148 | for (type = 0; type < EV_CNT; type++) { 149 | int max = libevdev_event_type_get_max(type); 150 | if (max == -1) 151 | continue; 152 | 153 | for (code = 0; code < max; code++) { 154 | ck_assert_int_eq(libevdev_has_event_code(dev, type, code), 155 | libevdev_has_event_code(dev2, type, code)); 156 | } 157 | } 158 | 159 | libevdev_free(dev); 160 | libevdev_free(dev2); 161 | libevdev_uinput_destroy(uidev); 162 | close(fd); 163 | close(fd2); 164 | } 165 | END_TEST 166 | 167 | START_TEST(test_uinput_check_syspath_time) 168 | { 169 | struct libevdev *dev; 170 | struct libevdev_uinput *uidev, *uidev2; 171 | const char *syspath, *syspath2; 172 | int fd, fd2; 173 | int rc; 174 | 175 | dev = libevdev_new(); 176 | ck_assert(dev != NULL); 177 | libevdev_set_name(dev, TEST_DEVICE_NAME); 178 | libevdev_enable_event_type(dev, EV_SYN); 179 | libevdev_enable_event_type(dev, EV_REL); 180 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 181 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 182 | 183 | fd = open(UINPUT_NODE, O_RDWR); 184 | ck_assert_int_gt(fd, -1); 185 | fd2 = open(UINPUT_NODE, O_RDWR); 186 | ck_assert_int_gt(fd2, -1); 187 | 188 | rc = libevdev_uinput_create_from_device(dev, fd, &uidev); 189 | ck_assert_int_eq(rc, 0); 190 | 191 | /* sleep for 1.5 seconds. sysfs resolution is 1 second, so 192 | creating both devices without delay means 193 | libevdev_uinput_get_syspath can't actually differ between 194 | them. By waiting, we get different ctime for uidev and uidev2, 195 | and exercise that part of the code. 196 | */ 197 | usleep(1500000); 198 | 199 | /* create a second one to test the syspath time filtering code */ 200 | rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2); 201 | ck_assert_int_eq(rc, 0); 202 | 203 | syspath = libevdev_uinput_get_syspath(uidev); 204 | ck_assert(syspath != NULL); 205 | 206 | /* get syspath twice returns same pointer */ 207 | syspath2 = libevdev_uinput_get_syspath(uidev); 208 | ck_assert(syspath == syspath2); 209 | 210 | /* second dev has different syspath */ 211 | syspath2 = libevdev_uinput_get_syspath(uidev2); 212 | ck_assert(strcmp(syspath, syspath2) != 0); 213 | 214 | libevdev_free(dev); 215 | libevdev_uinput_destroy(uidev); 216 | libevdev_uinput_destroy(uidev2); 217 | 218 | close(fd); 219 | close(fd2); 220 | } 221 | END_TEST 222 | 223 | START_TEST(test_uinput_check_syspath_name) 224 | { 225 | struct libevdev *dev; 226 | struct libevdev_uinput *uidev, *uidev2; 227 | const char *syspath, *syspath2; 228 | int fd, fd2; 229 | int rc; 230 | 231 | dev = libevdev_new(); 232 | ck_assert(dev != NULL); 233 | libevdev_set_name(dev, TEST_DEVICE_NAME); 234 | libevdev_enable_event_type(dev, EV_SYN); 235 | libevdev_enable_event_type(dev, EV_REL); 236 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 237 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 238 | 239 | fd = open(UINPUT_NODE, O_RDWR); 240 | ck_assert_int_gt(fd, -1); 241 | fd2 = open(UINPUT_NODE, O_RDWR); 242 | ck_assert_int_gt(fd2, -1); 243 | 244 | rc = libevdev_uinput_create_from_device(dev, fd, &uidev); 245 | ck_assert_int_eq(rc, 0); 246 | 247 | /* create a second one to stress the syspath filtering code */ 248 | libevdev_set_name(dev, TEST_DEVICE_NAME " 2"); 249 | rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2); 250 | ck_assert_int_eq(rc, 0); 251 | 252 | syspath = libevdev_uinput_get_syspath(uidev); 253 | ck_assert(syspath != NULL); 254 | 255 | /* get syspath twice returns same pointer */ 256 | syspath2 = libevdev_uinput_get_syspath(uidev); 257 | ck_assert(syspath == syspath2); 258 | 259 | /* second dev has different syspath */ 260 | syspath2 = libevdev_uinput_get_syspath(uidev2); 261 | ck_assert(strcmp(syspath, syspath2) != 0); 262 | 263 | libevdev_free(dev); 264 | libevdev_uinput_destroy(uidev); 265 | libevdev_uinput_destroy(uidev2); 266 | 267 | close(fd); 268 | close(fd2); 269 | } 270 | END_TEST 271 | 272 | START_TEST(test_uinput_events) 273 | { 274 | struct libevdev *dev; 275 | struct libevdev_uinput *uidev; 276 | int fd, fd2; 277 | int rc; 278 | const char *devnode; 279 | int i; 280 | const int nevents = 5; 281 | struct input_event events[] = { {{0, 0}, EV_REL, REL_X, 1}, 282 | {{0, 0}, EV_REL, REL_Y, -1}, 283 | {{0, 0}, EV_SYN, SYN_REPORT, 0}, 284 | {{0, 0}, EV_KEY, BTN_LEFT, 1}, 285 | {{0, 0}, EV_SYN, SYN_REPORT, 0}}; 286 | struct input_event events_read[nevents]; 287 | 288 | dev = libevdev_new(); 289 | ck_assert(dev != NULL); 290 | libevdev_set_name(dev, TEST_DEVICE_NAME); 291 | libevdev_enable_event_type(dev, EV_SYN); 292 | libevdev_enable_event_type(dev, EV_REL); 293 | libevdev_enable_event_type(dev, EV_KEY); 294 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 295 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 296 | libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); 297 | 298 | fd = open(UINPUT_NODE, O_RDWR); 299 | ck_assert_int_gt(fd, -1); 300 | 301 | rc = libevdev_uinput_create_from_device(dev, fd, &uidev); 302 | ck_assert_int_eq(rc, 0); 303 | ck_assert(uidev != NULL); 304 | 305 | devnode = libevdev_uinput_get_devnode(uidev); 306 | ck_assert(devnode != NULL); 307 | 308 | fd2 = open(devnode, O_RDONLY); 309 | 310 | for (i = 0; i < nevents; i++) 311 | libevdev_uinput_write_event(uidev, events[i].type, events[i].code, events[i].value); 312 | 313 | rc = read(fd2, events_read, sizeof(events_read)); 314 | ck_assert_int_eq(rc, sizeof(events_read)); 315 | 316 | for (i = 0; i < nevents; i++) { 317 | ck_assert_int_eq(events[i].type, events_read[i].type); 318 | ck_assert_int_eq(events[i].code, events_read[i].code); 319 | ck_assert_int_eq(events[i].value, events_read[i].value); 320 | } 321 | 322 | libevdev_free(dev); 323 | libevdev_uinput_destroy(uidev); 324 | close(fd); 325 | close(fd2); 326 | } 327 | END_TEST 328 | 329 | START_TEST(test_uinput_properties) 330 | { 331 | struct libevdev *dev, *dev2; 332 | struct libevdev_uinput *uidev; 333 | int fd; 334 | int rc; 335 | const char *devnode; 336 | 337 | dev = libevdev_new(); 338 | ck_assert(dev != NULL); 339 | libevdev_set_name(dev, TEST_DEVICE_NAME); 340 | libevdev_enable_event_type(dev, EV_SYN); 341 | libevdev_enable_event_type(dev, EV_REL); 342 | libevdev_enable_event_type(dev, EV_KEY); 343 | libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); 344 | libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); 345 | libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); 346 | libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD); 347 | libevdev_enable_property(dev, INPUT_PROP_MAX); 348 | 349 | rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev); 350 | ck_assert_int_eq(rc, 0); 351 | ck_assert(uidev != NULL); 352 | 353 | devnode = libevdev_uinput_get_devnode(uidev); 354 | ck_assert(devnode != NULL); 355 | 356 | fd = open(devnode, O_RDONLY); 357 | ck_assert_int_gt(fd, -1); 358 | rc = libevdev_new_from_fd(fd, &dev2); 359 | ck_assert_int_eq(rc, 0); 360 | 361 | ck_assert(libevdev_has_property(dev2, INPUT_PROP_BUTTONPAD)); 362 | ck_assert(libevdev_has_property(dev2, INPUT_PROP_MAX)); 363 | 364 | libevdev_free(dev); 365 | libevdev_free(dev2); 366 | libevdev_uinput_destroy(uidev); 367 | close(fd); 368 | } 369 | END_TEST 370 | 371 | Suite * 372 | uinput_suite(void) 373 | { 374 | Suite *s = suite_create("libevdev uinput device tests"); 375 | 376 | TCase *tc = tcase_create("device creation"); 377 | tcase_add_test(tc, test_uinput_create_device); 378 | tcase_add_test(tc, test_uinput_create_device_invalid); 379 | tcase_add_test(tc, test_uinput_create_device_from_fd); 380 | tcase_add_test(tc, test_uinput_check_syspath_time); 381 | tcase_add_test(tc, test_uinput_check_syspath_name); 382 | suite_add_tcase(s, tc); 383 | 384 | tc = tcase_create("device events"); 385 | tcase_add_test(tc, test_uinput_events); 386 | suite_add_tcase(s, tc); 387 | 388 | tc = tcase_create("device properties"); 389 | tcase_add_test(tc, test_uinput_properties); 390 | suite_add_tcase(s, tc); 391 | 392 | return s; 393 | } 394 | -------------------------------------------------------------------------------- /test/valgrind.suppressions: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | timer_create(evp) 5 | fun:timer_create@@GLIBC_2.3.3 6 | } 7 | { 8 | 9 | Memcheck:Param 10 | ioctl(generic) 11 | fun:ioctl 12 | fun:libevdev_grab 13 | } 14 | { 15 | 16 | Memcheck:Param 17 | ioctl(generic) 18 | fun:ioctl 19 | fun:test_revoke* 20 | } 21 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | libevdev-events 2 | touchpad-edge-detector 3 | mouse-dpi-tool 4 | libevdev-tweak-device 5 | -------------------------------------------------------------------------------- /tools/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = libevdev-events 2 | bin_PROGRAMS = \ 3 | touchpad-edge-detector \ 4 | mouse-dpi-tool \ 5 | libevdev-tweak-device 6 | 7 | AM_CPPFLAGS = $(GCC_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/libevdev 8 | libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la 9 | 10 | libevdev_events_SOURCES = libevdev-events.c 11 | libevdev_events_LDADD = $(libevdev_ldadd) 12 | 13 | touchpad_edge_detector_SOURCES = touchpad-edge-detector.c 14 | touchpad_edge_detector_LDADD = $(libevdev_ldadd) 15 | 16 | mouse_dpi_tool_SOURCES = mouse-dpi-tool.c 17 | mouse_dpi_tool_LDADD = $(libevdev_ldadd) 18 | 19 | libevdev_tweak_device_SOURCES = libevdev-tweak-device.c 20 | libevdev_tweak_device_LDADD = $(libevdev_ldadd) 21 | libevdev_tweak_device_MANS = libevdev-tweak-device.1 22 | -------------------------------------------------------------------------------- /tools/libevdev-events.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "libevdev.h" 35 | 36 | static void 37 | print_abs_bits(struct libevdev *dev, int axis) 38 | { 39 | const struct input_absinfo *abs; 40 | 41 | if (!libevdev_has_event_code(dev, EV_ABS, axis)) 42 | return; 43 | 44 | abs = libevdev_get_abs_info(dev, axis); 45 | 46 | printf(" Value %6d\n", abs->value); 47 | printf(" Min %6d\n", abs->minimum); 48 | printf(" Max %6d\n", abs->maximum); 49 | if (abs->fuzz) 50 | printf(" Fuzz %6d\n", abs->fuzz); 51 | if (abs->flat) 52 | printf(" Flat %6d\n", abs->flat); 53 | if (abs->resolution) 54 | printf(" Resolution %6d\n", abs->resolution); 55 | } 56 | 57 | static void 58 | print_code_bits(struct libevdev *dev, unsigned int type, unsigned int max) 59 | { 60 | unsigned int i; 61 | for (i = 0; i <= max; i++) { 62 | if (!libevdev_has_event_code(dev, type, i)) 63 | continue; 64 | 65 | printf(" Event code %i (%s)\n", i, libevdev_event_code_get_name(type, i)); 66 | if (type == EV_ABS) 67 | print_abs_bits(dev, i); 68 | } 69 | } 70 | 71 | static void 72 | print_bits(struct libevdev *dev) 73 | { 74 | unsigned int i; 75 | printf("Supported events:\n"); 76 | 77 | for (i = 0; i <= EV_MAX; i++) { 78 | if (libevdev_has_event_type(dev, i)) 79 | printf(" Event type %d (%s)\n", i, libevdev_event_type_get_name(i)); 80 | switch(i) { 81 | case EV_KEY: 82 | print_code_bits(dev, EV_KEY, KEY_MAX); 83 | break; 84 | case EV_REL: 85 | print_code_bits(dev, EV_REL, REL_MAX); 86 | break; 87 | case EV_ABS: 88 | print_code_bits(dev, EV_ABS, ABS_MAX); 89 | break; 90 | case EV_LED: 91 | print_code_bits(dev, EV_LED, LED_MAX); 92 | break; 93 | } 94 | } 95 | } 96 | 97 | static void 98 | print_props(struct libevdev *dev) 99 | { 100 | unsigned int i; 101 | printf("Properties:\n"); 102 | 103 | for (i = 0; i <= INPUT_PROP_MAX; i++) { 104 | if (libevdev_has_property(dev, i)) 105 | printf(" Property type %d (%s)\n", i, 106 | libevdev_property_get_name(i)); 107 | } 108 | } 109 | 110 | static int 111 | print_event(struct input_event *ev) 112 | { 113 | if (ev->type == EV_SYN) 114 | printf("Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n", 115 | ev->input_event_sec, 116 | ev->input_event_usec, 117 | libevdev_event_type_get_name(ev->type)); 118 | else 119 | printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n", 120 | ev->input_event_sec, 121 | ev->input_event_usec, 122 | ev->type, 123 | libevdev_event_type_get_name(ev->type), 124 | ev->code, 125 | libevdev_event_code_get_name(ev->type, ev->code), 126 | ev->value); 127 | return 0; 128 | } 129 | 130 | static int 131 | print_sync_event(struct input_event *ev) 132 | { 133 | printf("SYNC: "); 134 | print_event(ev); 135 | return 0; 136 | } 137 | 138 | int 139 | main(int argc, char **argv) 140 | { 141 | struct libevdev *dev = NULL; 142 | const char *file; 143 | int fd; 144 | int rc = 1; 145 | 146 | if (argc < 2) 147 | goto out; 148 | 149 | file = argv[1]; 150 | fd = open(file, O_RDONLY); 151 | if (fd < 0) { 152 | perror("Failed to open device"); 153 | goto out; 154 | } 155 | 156 | rc = libevdev_new_from_fd(fd, &dev); 157 | if (rc < 0) { 158 | fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc)); 159 | goto out; 160 | } 161 | 162 | printf("Input device ID: bus %#x vendor %#x product %#x\n", 163 | libevdev_get_id_bustype(dev), 164 | libevdev_get_id_vendor(dev), 165 | libevdev_get_id_product(dev)); 166 | printf("Evdev version: %x\n", libevdev_get_driver_version(dev)); 167 | printf("Input device name: \"%s\"\n", libevdev_get_name(dev)); 168 | printf("Phys location: %s\n", libevdev_get_phys(dev)); 169 | printf("Uniq identifier: %s\n", libevdev_get_uniq(dev)); 170 | print_bits(dev); 171 | print_props(dev); 172 | 173 | do { 174 | struct input_event ev; 175 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL|LIBEVDEV_READ_FLAG_BLOCKING, &ev); 176 | if (rc == LIBEVDEV_READ_STATUS_SYNC) { 177 | printf("::::::::::::::::::::: dropped ::::::::::::::::::::::\n"); 178 | while (rc == LIBEVDEV_READ_STATUS_SYNC) { 179 | print_sync_event(&ev); 180 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev); 181 | } 182 | printf("::::::::::::::::::::: re-synced ::::::::::::::::::::::\n"); 183 | } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) 184 | print_event(&ev); 185 | } while (rc == LIBEVDEV_READ_STATUS_SYNC || rc == LIBEVDEV_READ_STATUS_SUCCESS || rc == -EAGAIN); 186 | 187 | if (rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN) 188 | fprintf(stderr, "Failed to handle events: %s\n", strerror(-rc)); 189 | 190 | rc = 0; 191 | out: 192 | libevdev_free(dev); 193 | 194 | return rc; 195 | } 196 | -------------------------------------------------------------------------------- /tools/libevdev-tweak-device.1: -------------------------------------------------------------------------------- 1 | .TH LIBEVDEV-TWEAK-DEVICE "1" 2 | .SH NAME 3 | libevdev-tweak-device \- modify an evdev kernel device 4 | .SH SYNOPSIS 5 | .B libevdev-tweak-device 6 | --abs ABS_X [--min a] [--max b] [--res c] [--fuzz d] [--flat e] 7 | /dev/input/eventX 8 | .B libevdev-tweak-device 9 | --resolution res[,yres] /dev/input/eventX 10 | .PP 11 | .B libevdev-tweak-device 12 | --led LED_NUML --on|--off /dev/input/eventX 13 | .SH DESCRIPTION 14 | .PP 15 | The 16 | .I libevdev-tweak-device 17 | tool changes the properties of the evdev kernel device at 18 | .I /dev/input/eventX. 19 | Currently this may be used to force an LED on or off, or to change the 20 | properties of an absolute axis (e.g. its minimum/maximum range or 21 | resolution). Changes are permanent until the device is removed. 22 | .SH OPTIONS 23 | .SS Changing absolute axes 24 | .TP 8 25 | .B --abs axis 26 | Change the given named ABS_ kernel axis, e.g. ABS_X. For a full list, see linux/input.h. 27 | Each of the options 28 | .B min, max, res, fuzz, flat 29 | may be given. 30 | .TP 8 31 | .B --min v 32 | Set the absinfo minimum to the value v 33 | .TP 8 34 | .B --max v 35 | Set the absinfo maximum to the value v 36 | .TP 8 37 | .B --res v 38 | Set the absinfo resolution to the value v 39 | .TP 8 40 | .B --fuzz v 41 | Set the absinfo fuzz to the value v 42 | .TP 8 43 | .B --flat v 44 | Set the absinfo flat to the value v 45 | .PP 46 | .SS Changing the x/y resolution 47 | .TP 8 48 | .B --resolution res[,yres] 49 | Changes the resolution of the ABS_X, ABS_MT_POSITION_X, ABS_Y, and 50 | ABS_MT_POSITION_Y axis to the given resolution. If only one resolution value 51 | is provided, both x and y axis are set to the same resolution, otherwise the 52 | first resolution value is applied to the x axes and the second value to the 53 | y axes. 54 | .SS Toggling LEDs 55 | .TP 8 56 | .B --led led 57 | Change the given LED, e.g. LED_NUML. For a full list, see linux/input.h. 58 | .TP 8 59 | .B --on 60 | Change the LED state to on 61 | .TP 8 62 | .B --off 63 | Change the LED state to off 64 | .SH NOTES 65 | .PP 66 | The kernel does not notify processes about absinfo property changes. Any 67 | process that has previously obtained the absinfo from the device will remain 68 | on the old information. This makes using this tool potentially racy, use 69 | with caution. 70 | -------------------------------------------------------------------------------- /tools/libevdev-tweak-device.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2014 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "libevdev.h" 41 | 42 | static void 43 | usage(void) 44 | { 45 | printf("%s --abs [--min min] [--max max] [--res res] [--fuzz fuzz] [--flat flat] /dev/input/eventXYZ\n" 46 | "\tChange the absinfo struct for the named axis\n" 47 | "%s --resolution res[,yres] /dev/input/eventXYZ\n" 48 | "\tChange the x/y resolution on the given device\n" 49 | "%s --led --on|--off /dev/input/eventXYZ\n" 50 | "\tEnable or disable the named LED\n", 51 | program_invocation_short_name, 52 | program_invocation_short_name, 53 | program_invocation_short_name); 54 | } 55 | 56 | enum mode { 57 | MODE_NONE = 0, 58 | MODE_ABS, 59 | MODE_LED, 60 | MODE_RESOLUTION, 61 | MODE_HELP, 62 | }; 63 | 64 | enum opts { 65 | OPT_ABS = 1 << 0, 66 | OPT_MIN = 1 << 1, 67 | OPT_MAX = 1 << 2, 68 | OPT_FUZZ = 1 << 3, 69 | OPT_FLAT = 1 << 4, 70 | OPT_RES = 1 << 5, 71 | OPT_LED = 1 << 6, 72 | OPT_ON = 1 << 7, 73 | OPT_OFF = 1 << 8, 74 | OPT_RESOLUTION = 1 << 9, 75 | OPT_HELP = 1 << 10, 76 | }; 77 | 78 | static bool 79 | parse_resolution_argument(const char *arg, int *xres, int *yres) 80 | { 81 | int matched; 82 | 83 | matched = sscanf(arg, "%d,%d", xres, yres); 84 | 85 | switch(matched) { 86 | case 2: 87 | break; 88 | case 1: 89 | *yres = *xres; 90 | break; 91 | default: 92 | return false; 93 | } 94 | 95 | return true; 96 | } 97 | 98 | static inline bool 99 | safe_atoi(const char *str, int *val) 100 | { 101 | char *endptr; 102 | long v; 103 | 104 | v = strtol(str, &endptr, 10); 105 | if (str == endptr) 106 | return false; 107 | if (*str != '\0' && *endptr != '\0') 108 | return false; 109 | 110 | if (v > INT_MAX || v < INT_MIN) 111 | return false; 112 | 113 | *val = v; 114 | return true; 115 | } 116 | 117 | static int 118 | parse_event_code(int type, const char *str) 119 | { 120 | int code; 121 | 122 | code = libevdev_event_code_from_name(type, str); 123 | if (code != -1) 124 | return code; 125 | 126 | if (safe_atoi(str, &code)) 127 | return code; 128 | 129 | return -1; 130 | } 131 | 132 | static int 133 | parse_options_abs(int argc, char **argv, unsigned int *changes, 134 | int *axis, struct input_absinfo *absinfo) 135 | { 136 | int rc = 1; 137 | int c; 138 | int option_index = 0; 139 | static struct option opts[] = { 140 | { "abs", 1, 0, OPT_ABS }, 141 | { "min", 1, 0, OPT_MIN }, 142 | { "max", 1, 0, OPT_MAX }, 143 | { "fuzz", 1, 0, OPT_FUZZ }, 144 | { "flat", 1, 0, OPT_FLAT }, 145 | { "res", 1, 0, OPT_RES }, 146 | { NULL, 0, 0, 0 }, 147 | }; 148 | 149 | if (argc < 2) 150 | goto error; 151 | 152 | optind = 1; 153 | while (1) { 154 | c = getopt_long(argc, argv, "h", opts, &option_index); 155 | if (c == -1) 156 | break; 157 | 158 | switch (c) { 159 | case OPT_ABS: 160 | *axis = parse_event_code(EV_ABS, optarg); 161 | if (*axis == -1) 162 | goto error; 163 | break; 164 | case OPT_MIN: 165 | absinfo->minimum = atoi(optarg); 166 | break; 167 | case OPT_MAX: 168 | absinfo->maximum = atoi(optarg); 169 | break; 170 | case OPT_FUZZ: 171 | absinfo->fuzz = atoi(optarg); 172 | break; 173 | case OPT_FLAT: 174 | absinfo->flat = atoi(optarg); 175 | break; 176 | case OPT_RES: 177 | absinfo->resolution = atoi(optarg); 178 | break; 179 | default: 180 | goto error; 181 | } 182 | *changes |= c; 183 | } 184 | rc = 0; 185 | error: 186 | return rc; 187 | } 188 | 189 | static int 190 | parse_options_led(int argc, char **argv, int *led, int *led_state) 191 | { 192 | int rc = 1; 193 | int c; 194 | int option_index = 0; 195 | static struct option opts[] = { 196 | { "led", 1, 0, OPT_LED }, 197 | { "on", 0, 0, OPT_ON }, 198 | { "off", 0, 0, OPT_OFF }, 199 | { NULL, 0, 0, 0 }, 200 | }; 201 | 202 | if (argc < 2) 203 | goto error; 204 | 205 | optind = 1; 206 | while (1) { 207 | c = getopt_long(argc, argv, "h", opts, &option_index); 208 | if (c == -1) 209 | break; 210 | 211 | switch (c) { 212 | case OPT_LED: 213 | *led = parse_event_code(EV_LED, optarg); 214 | if (*led == -1) 215 | goto error; 216 | break; 217 | case OPT_ON: 218 | if (*led_state != -1) 219 | goto error; 220 | *led_state = 1; 221 | break; 222 | case OPT_OFF: 223 | if (*led_state != -1) 224 | goto error; 225 | *led_state = 0; 226 | break; 227 | default: 228 | goto error; 229 | } 230 | } 231 | 232 | rc = 0; 233 | error: 234 | return rc; 235 | } 236 | 237 | static int 238 | parse_options_resolution(int argc, char **argv, int *xres, int *yres) 239 | { 240 | int rc = 1; 241 | int c; 242 | int option_index = 0; 243 | static struct option opts[] = { 244 | { "resolution", 1, 0, OPT_RESOLUTION }, 245 | { NULL, 0, 0, 0 }, 246 | }; 247 | 248 | if (argc < 2) 249 | goto error; 250 | 251 | optind = 1; 252 | while (1) { 253 | c = getopt_long(argc, argv, "h", opts, &option_index); 254 | if (c == -1) 255 | break; 256 | 257 | switch (c) { 258 | case OPT_RESOLUTION: 259 | if (!parse_resolution_argument(optarg, 260 | xres, yres)) 261 | goto error; 262 | break; 263 | default: 264 | goto error; 265 | } 266 | } 267 | 268 | rc = 0; 269 | error: 270 | return rc; 271 | } 272 | 273 | static enum mode 274 | parse_options_mode(int argc, char **argv) 275 | { 276 | int c; 277 | int option_index = 0; 278 | static const struct option opts[] = { 279 | { "abs", 1, 0, OPT_ABS }, 280 | { "led", 1, 0, OPT_LED }, 281 | { "resolution", 1, 0, OPT_RESOLUTION }, 282 | { "help", 0, 0, OPT_HELP }, 283 | { NULL, 0, 0, 0 }, 284 | }; 285 | enum mode mode = MODE_NONE; 286 | 287 | if (argc < 2) 288 | return mode; 289 | 290 | while (mode == MODE_NONE) { 291 | c = getopt_long(argc, argv, "h", opts, &option_index); 292 | if (c == -1) 293 | break; 294 | 295 | switch (c) { 296 | case 'h': 297 | case OPT_HELP: 298 | mode = MODE_HELP; 299 | break; 300 | case OPT_ABS: 301 | mode = MODE_ABS; 302 | break; 303 | case OPT_LED: 304 | mode = MODE_LED; 305 | break; 306 | case OPT_RESOLUTION: 307 | mode = MODE_RESOLUTION; 308 | break; 309 | default: 310 | break; 311 | } 312 | } 313 | 314 | if (optind >= argc && mode != MODE_HELP) 315 | return MODE_NONE; 316 | 317 | return mode; 318 | } 319 | 320 | static void 321 | set_abs(struct libevdev *dev, unsigned int changes, 322 | unsigned int axis, struct input_absinfo *absinfo) 323 | { 324 | int rc; 325 | struct input_absinfo abs; 326 | const struct input_absinfo *a; 327 | 328 | if ((a = libevdev_get_abs_info(dev, axis)) == NULL) { 329 | fprintf(stderr, 330 | "Device '%s' doesn't have axis %s\n", 331 | libevdev_get_name(dev), 332 | libevdev_event_code_get_name(EV_ABS, axis)); 333 | return; 334 | } 335 | 336 | abs = *a; 337 | if (changes & OPT_MIN) 338 | abs.minimum = absinfo->minimum; 339 | if (changes & OPT_MAX) 340 | abs.maximum = absinfo->maximum; 341 | if (changes & OPT_FUZZ) 342 | abs.fuzz = absinfo->fuzz; 343 | if (changes & OPT_FLAT) 344 | abs.flat = absinfo->flat; 345 | if (changes & OPT_RES) 346 | abs.resolution = absinfo->resolution; 347 | 348 | rc = libevdev_kernel_set_abs_info(dev, axis, &abs); 349 | if (rc != 0) 350 | fprintf(stderr, 351 | "Failed to set absinfo %s: %s", 352 | libevdev_event_code_get_name(EV_ABS, axis), 353 | strerror(-rc)); 354 | } 355 | 356 | static void 357 | set_led(struct libevdev *dev, unsigned int led, int led_state) 358 | { 359 | int rc; 360 | enum libevdev_led_value state = 361 | led_state ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF; 362 | 363 | if (!libevdev_has_event_code(dev, EV_LED, led)) { 364 | fprintf(stderr, 365 | "Device '%s' doesn't have %s\n", 366 | libevdev_get_name(dev), 367 | libevdev_event_code_get_name(EV_LED, led)); 368 | return; 369 | } 370 | 371 | rc = libevdev_kernel_set_led_value(dev, led, state); 372 | if (rc != 0) 373 | fprintf(stderr, 374 | "Failed to set LED %s: %s", 375 | libevdev_event_code_get_name(EV_LED, led), 376 | strerror(-rc)); 377 | } 378 | 379 | static void 380 | set_resolution(struct libevdev *dev, int xres, int yres) 381 | { 382 | struct input_absinfo abs; 383 | 384 | abs.resolution = xres; 385 | if (libevdev_has_event_code(dev, EV_ABS, ABS_X)) 386 | set_abs(dev, OPT_RES, ABS_X, &abs); 387 | if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_X)) 388 | set_abs(dev, OPT_RES, ABS_MT_POSITION_X, &abs); 389 | 390 | abs.resolution = yres; 391 | if (libevdev_has_event_code(dev, EV_ABS, ABS_Y)) 392 | set_abs(dev, OPT_RES, ABS_Y, &abs); 393 | if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_Y)) 394 | set_abs(dev, OPT_RES, ABS_MT_POSITION_Y, &abs); 395 | } 396 | 397 | int 398 | main(int argc, char **argv) 399 | { 400 | struct libevdev *dev = NULL; 401 | int fd = -1; 402 | int rc = EXIT_FAILURE; 403 | enum mode mode; 404 | const char *path; 405 | struct input_absinfo absinfo; 406 | int axis = -1; 407 | int led = -1; 408 | int led_state = -1; 409 | unsigned int changes = 0; /* bitmask of changes */ 410 | int xres = 0, 411 | yres = 0; 412 | 413 | mode = parse_options_mode(argc, argv); 414 | switch (mode) { 415 | case MODE_HELP: 416 | rc = EXIT_SUCCESS; 417 | /* fallthrough */ 418 | case MODE_NONE: 419 | usage(); 420 | goto out; 421 | case MODE_ABS: 422 | rc = parse_options_abs(argc, argv, &changes, &axis, 423 | &absinfo); 424 | break; 425 | case MODE_LED: 426 | rc = parse_options_led(argc, argv, &led, &led_state); 427 | break; 428 | case MODE_RESOLUTION: 429 | rc = parse_options_resolution(argc, argv, &xres, 430 | &yres); 431 | break; 432 | default: 433 | fprintf(stderr, 434 | "++?????++ Out of Cheese Error. Redo From Start.\n"); 435 | goto out; 436 | } 437 | 438 | if (rc != EXIT_SUCCESS) 439 | goto out; 440 | 441 | if (optind >= argc) { 442 | rc = EXIT_FAILURE; 443 | usage(); 444 | goto out; 445 | } 446 | 447 | path = argv[optind]; 448 | 449 | fd = open(path, O_RDWR); 450 | if (fd < 0) { 451 | rc = EXIT_FAILURE; 452 | perror("Failed to open device"); 453 | goto out; 454 | } 455 | 456 | rc = libevdev_new_from_fd(fd, &dev); 457 | if (rc < 0) { 458 | fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc)); 459 | goto out; 460 | } 461 | 462 | switch (mode) { 463 | case MODE_ABS: 464 | set_abs(dev, changes, axis, &absinfo); 465 | break; 466 | case MODE_LED: 467 | set_led(dev, led, led_state); 468 | break; 469 | case MODE_RESOLUTION: 470 | set_resolution(dev, xres, yres); 471 | break; 472 | default: 473 | break; 474 | } 475 | 476 | out: 477 | libevdev_free(dev); 478 | if (fd != -1) 479 | close(fd); 480 | 481 | return rc; 482 | } 483 | -------------------------------------------------------------------------------- /tools/mouse-dpi-tool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2014 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software 5 | * and its documentation for any purpose is hereby granted without 6 | * fee, provided that the above copyright notice appear in all copies 7 | * and that both that copyright notice and this permission notice 8 | * appear in supporting documentation, and that the name of Red Hat 9 | * not be used in advertising or publicity pertaining to distribution 10 | * of the software without specific, written prior permission. Red 11 | * Hat makes no representations about the suitability of this software 12 | * for any purpose. It is provided "as is" without express or implied 13 | * warranty. 14 | * 15 | * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 17 | * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 | */ 23 | 24 | #ifdef HAVE_CONFIG_H 25 | #include "config.h" 26 | #endif 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 42 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 43 | 44 | struct measurements { 45 | int distance; 46 | double max_frequency; 47 | double *frequencies; 48 | size_t frequencies_sz; 49 | size_t nfrequencies; 50 | uint64_t us; 51 | }; 52 | 53 | static int 54 | usage(void) { 55 | printf("Usage: %s /dev/input/event0\n", program_invocation_short_name); 56 | printf("\n"); 57 | printf("This tool reads relative events from the kernel and calculates\n" 58 | "the distance covered and maximum frequency of the incoming events.\n" 59 | "Some mouse devices provide dynamic frequencies, it is\n" 60 | "recommended to measure multiple times to obtain the highest value.\n"); 61 | return 1; 62 | } 63 | 64 | static inline double 65 | get_frequency(uint64_t last, uint64_t current) 66 | { 67 | return 1000000.0/(current - last); 68 | } 69 | 70 | static inline void 71 | push_frequency(struct measurements *m, double freq) 72 | { 73 | if (m->nfrequencies == m->frequencies_sz) { 74 | m->frequencies_sz += 100; 75 | m->frequencies = realloc(m->frequencies, 76 | m->frequencies_sz * sizeof *m->frequencies); 77 | if (!m->frequencies) 78 | abort(); 79 | } 80 | 81 | m->frequencies[m->nfrequencies] = freq; 82 | m->nfrequencies++; 83 | } 84 | 85 | static int 86 | print_current_values(const struct measurements *m) 87 | { 88 | static int progress = 0; 89 | char status = 0; 90 | 91 | switch (progress) { 92 | case 0: status = '|'; break; 93 | case 1: status = '/'; break; 94 | case 2: status = '-'; break; 95 | case 3: status = '\\'; break; 96 | default: 97 | status = '?'; 98 | break; 99 | } 100 | 101 | progress = (progress + 1) % 4; 102 | 103 | printf("\rCovered distance in device units: %8d at frequency %3.1fHz %c", 104 | abs(m->distance), m->max_frequency, status); 105 | 106 | return 0; 107 | } 108 | 109 | static int 110 | handle_event(struct measurements *m, const struct input_event *ev) 111 | { 112 | if (ev->type == EV_SYN) { 113 | const int idle_reset = 3000000; /* us */ 114 | uint64_t last_us = m->us; 115 | 116 | m->us = ev->input_event_sec * 1000000 + ev->input_event_usec; 117 | 118 | /* reset after pause */ 119 | if (last_us + idle_reset < m->us) { 120 | m->max_frequency = 0.0; 121 | m->distance = 0; 122 | } else { 123 | double freq = get_frequency(last_us, m->us); 124 | push_frequency(m, freq); 125 | m->max_frequency = max(freq, m->max_frequency); 126 | return print_current_values(m); 127 | } 128 | 129 | return 0; 130 | } else if (ev->type != EV_REL) 131 | return 0; 132 | 133 | switch(ev->code) { 134 | case REL_X: 135 | m->distance += ev->value; 136 | break; 137 | } 138 | 139 | return 0; 140 | } 141 | 142 | static int 143 | mainloop(struct libevdev *dev, struct measurements *m) { 144 | struct pollfd fds[2]; 145 | sigset_t mask; 146 | 147 | fds[0].fd = libevdev_get_fd(dev); 148 | fds[0].events = POLLIN; 149 | 150 | sigemptyset(&mask); 151 | sigaddset(&mask, SIGINT); 152 | fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK); 153 | fds[1].events = POLLIN; 154 | 155 | sigprocmask(SIG_BLOCK, &mask, NULL); 156 | 157 | while (poll(fds, 2, -1)) { 158 | struct input_event ev; 159 | int rc; 160 | 161 | if (fds[1].revents) 162 | break; 163 | 164 | do { 165 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); 166 | if (rc == LIBEVDEV_READ_STATUS_SYNC) { 167 | fprintf(stderr, "Error: cannot keep up\n"); 168 | return 1; 169 | } else if (rc != -EAGAIN && rc < 0) { 170 | fprintf(stderr, "Error: %s\n", strerror(-rc)); 171 | return 1; 172 | } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { 173 | handle_event(m, &ev); 174 | } 175 | } while (rc != -EAGAIN); 176 | } 177 | 178 | return 0; 179 | } 180 | 181 | static inline double 182 | mean_frequency(struct measurements *m) 183 | { 184 | int idx; 185 | 186 | idx = m->nfrequencies/2; 187 | return m->frequencies[idx]; 188 | } 189 | 190 | static inline const char* 191 | bustype(int bustype) 192 | { 193 | const char *bus; 194 | 195 | switch(bustype) { 196 | case BUS_PCI: bus = "pci"; break; 197 | case BUS_ISAPNP: bus = "isapnp"; break; 198 | case BUS_USB: bus = "usb"; break; 199 | case BUS_HIL: bus = "hil"; break; 200 | case BUS_BLUETOOTH: bus = "bluetooth"; break; 201 | case BUS_VIRTUAL: bus = "virtual"; break; 202 | default: bus = "unknown bus type"; break; 203 | } 204 | 205 | return bus; 206 | } 207 | 208 | static void 209 | print_summary(struct libevdev *dev, struct measurements *m) 210 | { 211 | int res; 212 | int max_freq, mean_freq; 213 | 214 | if (m->nfrequencies == 0) { 215 | fprintf(stderr, "Error: no matching events received.\n"); 216 | return; 217 | } 218 | 219 | max_freq = (int)m->max_frequency; 220 | mean_freq = (int)mean_frequency(m); 221 | 222 | printf("Estimated sampling frequency: %dHz (mean %dHz)\n", 223 | max_freq, mean_freq); 224 | 225 | if (max_freq > mean_freq * 1.3) 226 | printf("WARNING: Max frequency is more than 30%% higher " 227 | "than mean frequency. Manual verification required!\n"); 228 | 229 | printf("To calculate resolution, measure physical distance covered\n" 230 | "and look up the matching resolution in the table below\n"); 231 | 232 | m->distance = abs(m->distance); 233 | 234 | /* If the mouse has more than 2500dpi, the manufacturer usually 235 | shows off on their website anyway */ 236 | for (res = 400; res <= 2500; res += 200) { 237 | double inch = m->distance/(double)res; 238 | printf("%8dmm %8.2fin %8ddpi\n", 239 | (int)(inch * 25.4), inch, res); 240 | } 241 | printf("If your resolution is not in the list, calculate it with:\n" 242 | "\tresolution=%d/inches, or\n" 243 | "\tresolution=%d * 25.4/mm\n", m->distance, m->distance); 244 | 245 | printf("\n"); 246 | printf("Entry for hwdb match (replace XXX with the resolution in DPI):\n" 247 | "mouse:%s:v%04xp%04x:name:%s:\n" 248 | " MOUSE_DPI=XXX@%d\n", 249 | bustype(libevdev_get_id_bustype(dev)), 250 | libevdev_get_id_vendor(dev), 251 | libevdev_get_id_product(dev), 252 | libevdev_get_name(dev), 253 | (int)m->max_frequency); 254 | } 255 | 256 | int 257 | main (int argc, char **argv) { 258 | int rc; 259 | int fd; 260 | const char *path; 261 | struct libevdev *dev; 262 | struct measurements measurements = {0}; 263 | 264 | if (argc < 2) 265 | return usage(); 266 | 267 | path = argv[1]; 268 | if (path[0] == '-') 269 | return usage(); 270 | 271 | fd = open(path, O_RDONLY|O_NONBLOCK); 272 | if (fd < 0) { 273 | fprintf(stderr, "Error opening the device: %s\n", strerror(errno)); 274 | return 1; 275 | } 276 | 277 | rc = libevdev_new_from_fd(fd, &dev); 278 | if (rc != 0) { 279 | fprintf(stderr, "Error fetching the device info: %s\n", strerror(-rc)); 280 | return 1; 281 | } 282 | 283 | if (libevdev_grab(dev, LIBEVDEV_GRAB) != 0) { 284 | fprintf(stderr, "Error: cannot grab the device, something else is grabbing it.\n"); 285 | fprintf(stderr, "Use 'fuser -v %s' to find processes with an open fd\n", path); 286 | return 1; 287 | } 288 | libevdev_grab(dev, LIBEVDEV_UNGRAB); 289 | 290 | printf("Mouse %s on %s\n", libevdev_get_name(dev), path); 291 | printf("Move the device 250mm/10in or more along the x-axis.\n"); 292 | printf("Pause 3 seconds before movement to reset, Ctrl+C to exit.\n"); 293 | setbuf(stdout, NULL); 294 | 295 | rc = mainloop(dev, &measurements); 296 | 297 | printf("\n"); 298 | 299 | print_summary(dev, &measurements); 300 | 301 | libevdev_free(dev); 302 | close(fd); 303 | 304 | return rc; 305 | } 306 | -------------------------------------------------------------------------------- /tools/publish-doc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | make 6 | rsync --delete -avz doc/html/ freedesktop.org:/srv/www.freedesktop.org/www/software/libevdev/doc/latest 7 | 8 | -------------------------------------------------------------------------------- /tools/sync-with-kernel-headers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Syncs the repository with the input.h and input-event-codes.h headers from 4 | # a checked out source directory. 5 | # 6 | # Usage: 7 | # sync-with-kernel-headers.sh path/to/kernel v4.12 8 | 9 | KERNEL_TREE="$1" 10 | GIT_DIR="$KERNEL_TREE/.git" 11 | TAG="$2" 12 | 13 | export GIT_DIR 14 | 15 | if [ -z "$TAG" ] || ! [ -d "$GIT_DIR" ]; then 16 | echo "Usage: `basename $0` path/to/kernel tag" 17 | exit 1 18 | fi 19 | if ! [ -d .git ]; then 20 | echo "Run me from the top-level git tree" 21 | exit 1 22 | fi 23 | 24 | files="linux/input.h linux/input-event-codes.h" 25 | 26 | 27 | for file in $files; do 28 | git cat-file -p "$TAG:include/uapi/$file" > "include/$file" 29 | done 30 | 31 | -------------------------------------------------------------------------------- /tools/touchpad-edge-detector.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2014 Red Hat, Inc. 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software 5 | * and its documentation for any purpose is hereby granted without 6 | * fee, provided that the above copyright notice appear in all copies 7 | * and that both that copyright notice and this permission notice 8 | * appear in supporting documentation, and that the name of Red Hat 9 | * not be used in advertising or publicity pertaining to distribution 10 | * of the software without specific, written prior permission. Red 11 | * Hat makes no representations about the suitability of this software 12 | * for any purpose. It is provided "as is" without express or implied 13 | * warranty. 14 | * 15 | * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 17 | * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 | */ 23 | 24 | #ifdef HAVE_CONFIG_H 25 | #include "config.h" 26 | #endif 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 43 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 44 | 45 | static int 46 | usage(void) { 47 | printf("Usage: %s 12x34 /dev/input/event0\n", program_invocation_short_name); 48 | printf("\n"); 49 | printf("This tool reads the touchpad events from the kernel and calculates\n " 50 | "the minimum and maximum for the x and y coordinates, respectively.\n" 51 | "The first argument is the physical size of the touchpad in mm.\n"); 52 | return 1; 53 | } 54 | 55 | struct dimensions { 56 | int top, bottom, left, right; 57 | }; 58 | 59 | struct size { 60 | int w, h; 61 | }; 62 | 63 | static int 64 | print_current_values(const struct dimensions *d) 65 | { 66 | static int progress; 67 | char status = 0; 68 | 69 | switch (progress) { 70 | case 0: status = '|'; break; 71 | case 1: status = '/'; break; 72 | case 2: status = '-'; break; 73 | case 3: status = '\\'; break; 74 | } 75 | 76 | progress = (progress + 1) % 4; 77 | 78 | printf("\rTouchpad sends: x [%d..%d], y [%d..%d] %c", 79 | d->left, d->right, d->top, d->bottom, status); 80 | return 0; 81 | } 82 | 83 | static int 84 | handle_event(struct dimensions *d, const struct input_event *ev) { 85 | if (ev->type == EV_SYN) { 86 | return print_current_values(d); 87 | } else if (ev->type != EV_ABS) 88 | return 0; 89 | 90 | switch(ev->code) { 91 | case ABS_X: 92 | case ABS_MT_POSITION_X: 93 | d->left = min(d->left, ev->value); 94 | d->right = max(d->right, ev->value); 95 | break; 96 | case ABS_Y: 97 | case ABS_MT_POSITION_Y: 98 | d->top = min(d->top, ev->value); 99 | d->bottom = max(d->bottom, ev->value); 100 | break; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | static int 107 | mainloop(struct libevdev *dev, struct dimensions *dim) { 108 | struct pollfd fds[2]; 109 | sigset_t mask; 110 | 111 | fds[0].fd = libevdev_get_fd(dev); 112 | fds[0].events = POLLIN; 113 | 114 | sigemptyset(&mask); 115 | sigaddset(&mask, SIGINT); 116 | fds[1].fd = signalfd(-1, &mask, SFD_NONBLOCK); 117 | fds[1].events = POLLIN; 118 | 119 | sigprocmask(SIG_BLOCK, &mask, NULL); 120 | 121 | while (poll(fds, 2, -1)) { 122 | struct input_event ev; 123 | int rc; 124 | 125 | if (fds[1].revents) 126 | break; 127 | 128 | do { 129 | rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); 130 | if (rc == LIBEVDEV_READ_STATUS_SYNC) { 131 | fprintf(stderr, "Error: cannot keep up\n"); 132 | return 1; 133 | } else if (rc != -EAGAIN && rc < 0) { 134 | fprintf(stderr, "Error: %s\n", strerror(-rc)); 135 | return 1; 136 | } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { 137 | handle_event(dim, &ev); 138 | } 139 | } while (rc != -EAGAIN); 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | static inline void 146 | pid_vid_matchstr(struct libevdev *dev, char *match, size_t sz) 147 | { 148 | snprintf(match, sz, "input:b%04Xv%04Xp%04X", 149 | libevdev_get_id_bustype(dev), 150 | libevdev_get_id_vendor(dev), 151 | libevdev_get_id_product(dev)); 152 | } 153 | 154 | static inline void 155 | dmi_matchstr(struct libevdev *dev, char *match, size_t sz) 156 | { 157 | char modalias[PATH_MAX]; 158 | FILE *fp; 159 | 160 | fp = fopen("/sys/class/dmi/id/modalias", "r"); 161 | if (!fp || fgets(modalias, sizeof(modalias), fp) == NULL) { 162 | sprintf(match, "ERROR READING DMI MODALIAS"); 163 | if (fp) 164 | fclose(fp); 165 | return; 166 | } 167 | 168 | fclose(fp); 169 | 170 | modalias[strlen(modalias) - 1] = '\0'; /* drop \n */ 171 | snprintf(match, sz, "name:%s:%s", libevdev_get_name(dev), modalias); 172 | 173 | return; 174 | } 175 | 176 | static void 177 | print_udev_override_rule(struct libevdev *dev, 178 | const struct dimensions *dim, 179 | const struct size *size) { 180 | const struct input_absinfo *x, *y; 181 | char match[PATH_MAX]; 182 | int w, h; 183 | int xres, yres; 184 | 185 | x = libevdev_get_abs_info(dev, ABS_X); 186 | y = libevdev_get_abs_info(dev, ABS_Y); 187 | w = dim->right - dim->left; 188 | h = dim->bottom - dim->top; 189 | xres = round((double)w/size->w); 190 | yres = round((double)h/size->h); 191 | 192 | if (x->resolution && y->resolution) { 193 | int width = x->maximum - x->minimum, 194 | height = y->maximum - y->minimum; 195 | printf("Touchpad size as listed by the kernel: %dx%dmm\n", 196 | width/x->resolution, height/y->resolution); 197 | } else { 198 | printf("Touchpad has no resolution, size unknown\n"); 199 | } 200 | 201 | printf("User-specified touchpad size: %dx%dmm\n", size->w, size->h); 202 | printf("Calculated ranges: %d/%d\n", w, h); 203 | printf("\n"); 204 | printf("Suggested udev rule:\n"); 205 | 206 | switch(libevdev_get_id_bustype(dev)) { 207 | case BUS_USB: 208 | case BUS_BLUETOOTH: 209 | pid_vid_matchstr(dev, match, sizeof(match)); 210 | break; 211 | default: 212 | dmi_matchstr(dev, match, sizeof(match)); 213 | break; 214 | } 215 | 216 | printf("# \n" 217 | "evdev:%s*\n" 218 | " EVDEV_ABS_00=%d:%d:%d\n" 219 | " EVDEV_ABS_01=%d:%d:%d\n", 220 | match, 221 | dim->left, dim->right, xres, 222 | dim->top, dim->bottom, yres); 223 | if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_X)) 224 | printf(" EVDEV_ABS_35=%d:%d:%d\n" 225 | " EVDEV_ABS_36=%d:%d:%d\n", 226 | dim->left, dim->right, xres, 227 | dim->top, dim->bottom, yres); 228 | } 229 | 230 | int main (int argc, char **argv) { 231 | int rc; 232 | int fd; 233 | const char *path; 234 | struct libevdev *dev; 235 | struct dimensions dim; 236 | struct size size; 237 | 238 | if (argc < 3) 239 | return usage(); 240 | 241 | if (sscanf(argv[1], "%dx%d", &size.w, &size.h) != 2 || 242 | size.w <= 0 || size.h <= 0) 243 | return usage(); 244 | 245 | if (size.w < 30 || size.h < 30) { 246 | fprintf(stderr, 247 | "%dx%dmm is too small for a touchpad.\n" 248 | "Please specify the touchpad size in mm.\n", 249 | size.w, size.h); 250 | return 1; 251 | } 252 | 253 | path = argv[2]; 254 | if (path[0] == '-') 255 | return usage(); 256 | 257 | fd = open(path, O_RDONLY|O_NONBLOCK); 258 | if (fd < 0) { 259 | fprintf(stderr, "Error opening the device: %s\n", strerror(errno)); 260 | return 1; 261 | } 262 | 263 | rc = libevdev_new_from_fd(fd, &dev); 264 | if (rc != 0) { 265 | fprintf(stderr, "Error fetching the device info: %s\n", strerror(-rc)); 266 | return 1; 267 | } 268 | 269 | if (libevdev_grab(dev, LIBEVDEV_GRAB) != 0) { 270 | fprintf(stderr, "Error: cannot grab the device, something else is grabbing it.\n"); 271 | fprintf(stderr, "Use 'fuser -v %s' to find processes with an open fd\n", path); 272 | return 1; 273 | } 274 | libevdev_grab(dev, LIBEVDEV_UNGRAB); 275 | 276 | if (!libevdev_has_event_code(dev, EV_ABS, ABS_X) || 277 | !libevdev_has_event_code(dev, EV_ABS, ABS_Y)) { 278 | fprintf(stderr, "Error: this device does not have abs axes\n"); 279 | rc = EXIT_FAILURE; 280 | goto out; 281 | } 282 | 283 | dim.left = INT_MAX; 284 | dim.right = INT_MIN; 285 | dim.top = INT_MAX; 286 | dim.bottom = INT_MIN; 287 | 288 | printf("Touchpad %s on %s\n", libevdev_get_name(dev), path); 289 | printf("Move one finger around the touchpad to detect the actual edges\n"); 290 | printf("Kernel says: x [%d..%d], y [%d..%d]\n", 291 | libevdev_get_abs_minimum(dev, ABS_X), 292 | libevdev_get_abs_maximum(dev, ABS_X), 293 | libevdev_get_abs_minimum(dev, ABS_Y), 294 | libevdev_get_abs_maximum(dev, ABS_Y)); 295 | 296 | setbuf(stdout, NULL); 297 | 298 | rc = mainloop(dev, &dim); 299 | printf("\n\n"); 300 | 301 | print_udev_override_rule(dev, &dim, &size); 302 | 303 | out: 304 | libevdev_free(dev); 305 | close(fd); 306 | 307 | return rc; 308 | } 309 | --------------------------------------------------------------------------------