From dfb70bc088491187ec53d456fe5093093a2e411c Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Mon, 19 Oct 2026 03:03:16 +0200 Subject: [PATCH] fix(gamepad): build libevdev from a vendored copy The Linux gamepad backend included from /usr/include/libevdev-1.0 and linked the system libevdev, but the Flatpak SDK crafter-build runs in (org.freedesktop.Sdk 26.08) ships no libevdev headers, so Crafter.Graphics stopped building there. lib/libevdev now carries libevdev 1.14.0 (MIT), built once as its own static library that Crafter.Graphics depends on. As part of cfg it would be compiled again in every test configuration, since they copy cfg.cFiles. libevdev's generated event-names.h names every input code by its macro, so the library compiles against the kernel input headers that table was generated from (lib/libevdev/kernel-headers), not the target's. That directory is deliberately not called include: Crafter.Build puts every include directory of a dependency on its consumers' include path, where those headers would shadow each consumer's own . The paths are absolute because Crafter.Build only resolves the returned configuration's paths against the project root. Co-Authored-By: Claude Opus 5.5 --- README.md | 3 +- lib/libevdev/COPYING | 32 + lib/libevdev/README.md | 30 + .../kernel-headers/linux/input-event-codes.h | 1016 +++++++ lib/libevdev/kernel-headers/linux/input.h | 539 ++++ lib/libevdev/libevdev/config.h | 3 + lib/libevdev/libevdev/event-names.h | 1692 ++++++++++++ lib/libevdev/libevdev/libevdev-int.h | 333 +++ lib/libevdev/libevdev/libevdev-names.c | 213 ++ lib/libevdev/libevdev/libevdev-util.h | 69 + lib/libevdev/libevdev/libevdev.c | 1912 +++++++++++++ lib/libevdev/libevdev/libevdev.h | 2404 +++++++++++++++++ lib/libevdev/libevdev/make-event-names.py | 235 ++ project.cpp | 39 +- 14 files changed, 8515 insertions(+), 5 deletions(-) create mode 100644 lib/libevdev/COPYING create mode 100644 lib/libevdev/README.md create mode 100644 lib/libevdev/kernel-headers/linux/input-event-codes.h create mode 100644 lib/libevdev/kernel-headers/linux/input.h create mode 100644 lib/libevdev/libevdev/config.h create mode 100644 lib/libevdev/libevdev/event-names.h create mode 100644 lib/libevdev/libevdev/libevdev-int.h create mode 100644 lib/libevdev/libevdev/libevdev-names.c create mode 100644 lib/libevdev/libevdev/libevdev-util.h create mode 100644 lib/libevdev/libevdev/libevdev.c create mode 100644 lib/libevdev/libevdev/libevdev.h create mode 100755 lib/libevdev/libevdev/make-event-names.py diff --git a/README.md b/README.md index be5aeb8..8c2d371 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,8 @@ shaded through an intersection shader with an any-hit cut-out. per-vertex attribs) into global mesh heaps and builds the TLAS in a library compute pass. - **Clipboard / Input / Gamepad / Router / Dom** — input plumbing. - Gamepad uses libudev+libevdev on Linux and WGI on Windows; the DOM + Gamepad uses libudev+libevdev on Linux (libevdev is vendored in + `lib/libevdev`) and WGI on Windows; the DOM backend exposes the host page DOM (`Dom::HtmlElement`) and a router for hash-routed wasm apps. diff --git a/lib/libevdev/COPYING b/lib/libevdev/COPYING new file mode 100644 index 0000000..1974905 --- /dev/null +++ b/lib/libevdev/COPYING @@ -0,0 +1,32 @@ +SPDX-License-Identifier: MIT + +Copyright © 2013 Red Hat, Inc. +Copyright © 2013 David Herrmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +The following license is from a Linux kernel header file and there is no GPL +code this package links to. + +Copyright (c) 1999-2002 Vojtech Pavlik + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as published by +the Free Software Foundation. diff --git a/lib/libevdev/README.md b/lib/libevdev/README.md new file mode 100644 index 0000000..2876434 --- /dev/null +++ b/lib/libevdev/README.md @@ -0,0 +1,30 @@ +# libevdev (vendored) + +The Linux gamepad backend (`implementations/Crafter.Graphics-Gamepad.cpp`) parses evdev events with +[libevdev](https://gitlab.freedesktop.org/libevdev/libevdev). It is compiled into Crafter.Graphics from +this directory instead of being linked from the system. The Flatpak SDK that crafter-build runs in has no +libevdev headers, and a vendored copy builds the same way for every target, including cross sysroots. + +- Upstream: `https://gitlab.freedesktop.org/libevdev/libevdev.git`, tag `libevdev-1.14.0` + (commit `d9af2e4580297e9c14715fef06621dd39d9d8a3a`). MIT, see `COPYING`. +- `libevdev/`: the core library sources, unchanged. The uinput half isn't used and isn't included. +- `libevdev/event-names.h`: generated, the way libevdev's meson build does it, from the kernel headers + below. +- `libevdev/config.h`: what libevdev's meson build writes on Linux (`_GNU_SOURCE`). +- `kernel-headers/linux/`: the kernel uapi `input.h` and `input-event-codes.h` that ship with that + libevdev release. libevdev compiles against its own copy (its meson build puts them first on the path), + because `event-names.h` names every code by its macro and has to see the same set of codes. Only the + libevdev library sees them, and the directory isn't called `include`, because Crafter.Build puts every + `include` directory of a dependency on its consumers' include path. + +`project.cpp` builds these sources once, as their own static library, which Crafter.Graphics depends on. + +## Updating + +Copy `COPYING`, the files under `libevdev/` and upstream's `include/linux/linux/{input.h,input-event-codes.h}` +(into `kernel-headers/linux/`) from the new release, keep `config.h`, then regenerate the name table: + +```sh +python3 libevdev/make-event-names.py kernel-headers/linux/input.h kernel-headers/linux/input-event-codes.h \ + > libevdev/event-names.h +``` diff --git a/lib/libevdev/kernel-headers/linux/input-event-codes.h b/lib/libevdev/kernel-headers/linux/input-event-codes.h new file mode 100644 index 0000000..3528168 --- /dev/null +++ b/lib/libevdev/kernel-headers/linux/input-event-codes.h @@ -0,0 +1,1016 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Input event codes + * + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 2015 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef _UAPI_INPUT_EVENT_CODES_H +#define _UAPI_INPUT_EVENT_CODES_H + +/* + * Device properties and quirks + */ + +#define INPUT_PROP_POINTER 0x00 /* needs a pointer */ +#define INPUT_PROP_DIRECT 0x01 /* direct input devices */ +#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ +#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ +#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ +#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ +#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ +#define INPUT_PROP_PRESSUREPAD 0x07 /* pressure triggers clicks */ + +#define INPUT_PROP_MAX 0x1f +#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) + +/* + * Event types + */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX+1) + +/* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 +#define SYN_MAX 0xf +#define SYN_CNT (SYN_MAX+1) + +/* + * Keys and buttons + * + * Most of the keys/buttons are modeled after USB HUT 1.12 + * (see http://www.usb.org/developers/hidpage). + * Abbreviations in the comments: + * AC - Application Control + * AL - Application Launch Button + * SC - System Control + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 /* SC System Power Down */ +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ + +#define KEY_KPCOMMA 121 +#define KEY_HANGEUL 122 +#define KEY_HANGUEL KEY_HANGEUL +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 /* AC Stop */ +#define KEY_AGAIN 129 +#define KEY_PROPS 130 /* AC Properties */ +#define KEY_UNDO 131 /* AC Undo */ +#define KEY_FRONT 132 +#define KEY_COPY 133 /* AC Copy */ +#define KEY_OPEN 134 /* AC Open */ +#define KEY_PASTE 135 /* AC Paste */ +#define KEY_FIND 136 /* AC Search */ +#define KEY_CUT 137 /* AC Cut */ +#define KEY_HELP 138 /* AL Integrated Help Center */ +#define KEY_MENU 139 /* Menu (show menu) */ +#define KEY_CALC 140 /* AL Calculator */ +#define KEY_SETUP 141 +#define KEY_SLEEP 142 /* SC System Sleep */ +#define KEY_WAKEUP 143 /* System Wake Up */ +#define KEY_FILE 144 /* AL Local Machine Browser */ +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 /* AL Internet Browser */ +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ +#define KEY_SCREENLOCK KEY_COFFEE +#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ +#define KEY_DIRECTION KEY_ROTATE_DISPLAY +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 /* AC Bookmarks */ +#define KEY_COMPUTER 157 +#define KEY_BACK 158 /* AC Back */ +#define KEY_FORWARD 159 /* AC Forward */ +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 /* Media Select Telephone */ +#define KEY_ISO 170 +#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ +#define KEY_HOMEPAGE 172 /* AC Home */ +#define KEY_REFRESH 173 /* AC Refresh */ +#define KEY_EXIT 174 /* AC Exit */ +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 /* AC New */ +#define KEY_REDO 182 /* AC Redo/Repeat */ + +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */ +#define KEY_DASHBOARD KEY_ALL_APPLICATIONS +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 /* AC Close */ +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 /* AC Print */ +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 /* AL Checkbook/Finance */ +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 /* AC Cancel */ +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video + outputs (Monitor/LCD/TV-out/etc) */ +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 + +#define KEY_SEND 231 /* AC Send */ +#define KEY_REPLY 232 /* AC Reply */ +#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ +#define KEY_SAVE 234 /* AC Save */ +#define KEY_DOCUMENTS 235 + +#define KEY_BATTERY 236 + +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 + +#define KEY_UNKNOWN 240 + +#define KEY_VIDEO_NEXT 241 /* drive next video source */ +#define KEY_VIDEO_PREV 242 /* drive previous video source */ +#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO +#define KEY_DISPLAY_OFF 245 /* display device to off state */ + +#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ +#define KEY_WIMAX KEY_WWAN +#define KEY_RFKILL 247 /* Key that controls all radios */ + +#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ + +/* Code 255 is reserved for special needs of AT keyboard driver */ + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_SOUTH 0x130 +#define BTN_A BTN_SOUTH +#define BTN_EAST 0x131 +#define BTN_B BTN_EAST +#define BTN_C 0x132 +#define BTN_NORTH 0x133 +#define BTN_X BTN_NORTH +#define BTN_WEST 0x134 +#define BTN_Y BTN_WEST +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ +#define BTN_STYLUS3 0x149 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e +#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e /* Media Select Home */ +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */ +#define KEY_ZOOM KEY_FULL_SCREEN +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */ +#define KEY_SCREEN KEY_ASPECT_RATIO +#define KEY_PC 0x178 /* Media Select Computer */ +#define KEY_TV 0x179 /* Media Select TV */ +#define KEY_TV2 0x17a /* Media Select Cable */ +#define KEY_VCR 0x17b /* Media Select VCR */ +#define KEY_VCR2 0x17c /* VCR Plus */ +#define KEY_SAT 0x17d /* Media Select Satellite */ +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f /* Media Select CD */ +#define KEY_TAPE 0x180 /* Media Select Tape */ +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 /* Media Select Tuner */ +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 /* Media Select DVD */ +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 /* AL Audio Browser */ +#define KEY_VIDEO 0x189 /* AL Movie Browser */ +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c /* Media Select Messages */ +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 /* Channel Increment */ +#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 /* Recall Last */ +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f +#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ +#define KEY_GAMES 0x1a1 /* Media Select Games */ +#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ +#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ +#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ +#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ +#define KEY_EDITOR 0x1a6 /* AL Text Editor */ +#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ +#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ +#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ +#define KEY_DATABASE 0x1aa /* AL Database App */ +#define KEY_NEWS 0x1ab /* AL Newsreader */ +#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ +#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ +#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ +#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE +#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ +#define KEY_LOGOFF 0x1b1 /* AL Logoff */ + +#define KEY_DOLLAR 0x1b2 +#define KEY_EURO 0x1b3 + +#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ +#define KEY_FRAMEFORWARD 0x1b5 +#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ +#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ +#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ +#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ +#define KEY_IMAGES 0x1ba /* AL Image Browser */ +#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */ +#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */ +#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */ +#define KEY_LINK_PHONE 0x1bf /* AL Phone Syncing */ + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_FN 0x1d0 +#define KEY_FN_ESC 0x1d1 +#define KEY_FN_F1 0x1d2 +#define KEY_FN_F2 0x1d3 +#define KEY_FN_F3 0x1d4 +#define KEY_FN_F4 0x1d5 +#define KEY_FN_F5 0x1d6 +#define KEY_FN_F6 0x1d7 +#define KEY_FN_F7 0x1d8 +#define KEY_FN_F8 0x1d9 +#define KEY_FN_F9 0x1da +#define KEY_FN_F10 0x1db +#define KEY_FN_F11 0x1dc +#define KEY_FN_F12 0x1dd +#define KEY_FN_1 0x1de +#define KEY_FN_2 0x1df +#define KEY_FN_D 0x1e0 +#define KEY_FN_E 0x1e1 +#define KEY_FN_F 0x1e2 +#define KEY_FN_S 0x1e3 +#define KEY_FN_B 0x1e4 +#define KEY_FN_RIGHT_SHIFT 0x1e5 + +#define KEY_BRL_DOT1 0x1f1 +#define KEY_BRL_DOT2 0x1f2 +#define KEY_BRL_DOT3 0x1f3 +#define KEY_BRL_DOT4 0x1f4 +#define KEY_BRL_DOT5 0x1f5 +#define KEY_BRL_DOT6 0x1f6 +#define KEY_BRL_DOT7 0x1f7 +#define KEY_BRL_DOT8 0x1f8 +#define KEY_BRL_DOT9 0x1f9 +#define KEY_BRL_DOT10 0x1fa + +#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ +#define KEY_NUMERIC_1 0x201 /* and other keypads */ +#define KEY_NUMERIC_2 0x202 +#define KEY_NUMERIC_3 0x203 +#define KEY_NUMERIC_4 0x204 +#define KEY_NUMERIC_5 0x205 +#define KEY_NUMERIC_6 0x206 +#define KEY_NUMERIC_7 0x207 +#define KEY_NUMERIC_8 0x208 +#define KEY_NUMERIC_9 0x209 +#define KEY_NUMERIC_STAR 0x20a +#define KEY_NUMERIC_POUND 0x20b +#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ +#define KEY_NUMERIC_B 0x20d +#define KEY_NUMERIC_C 0x20e +#define KEY_NUMERIC_D 0x20f + +#define KEY_CAMERA_FOCUS 0x210 +#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ + +#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ +#define KEY_TOUCHPAD_ON 0x213 +#define KEY_TOUCHPAD_OFF 0x214 + +#define KEY_CAMERA_ZOOMIN 0x215 +#define KEY_CAMERA_ZOOMOUT 0x216 +#define KEY_CAMERA_UP 0x217 +#define KEY_CAMERA_DOWN 0x218 +#define KEY_CAMERA_LEFT 0x219 +#define KEY_CAMERA_RIGHT 0x21a + +#define KEY_ATTENDANT_ON 0x21b +#define KEY_ATTENDANT_OFF 0x21c +#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ +#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ + +#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_DOWN 0x221 +#define BTN_DPAD_LEFT 0x222 +#define BTN_DPAD_RIGHT 0x223 + +#define BTN_GRIPL 0x224 +#define BTN_GRIPR 0x225 +#define BTN_GRIPL2 0x226 +#define BTN_GRIPR2 0x227 + +#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ +#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ +#define KEY_REFRESH_RATE_TOGGLE 0x232 /* Display refresh rate toggle */ + +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ +#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ +#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ +#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ +#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ +#define KEY_CAMERA_ACCESS_ENABLE 0x24b /* Enables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_DISABLE 0x24c /* Disables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_TOGGLE 0x24d /* Toggles the current state of the camera access control. (HUTRR72) */ +#define KEY_ACCESSIBILITY 0x24e /* Toggles the system bound accessibility UI/command (HUTRR116) */ +#define KEY_DO_NOT_DISTURB 0x24f /* Toggles the system-wide "Do Not Disturb" control (HUTRR94)*/ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + +/* + * Keycodes for hotkeys toggling the electronic privacy screen found on some + * laptops on/off. Note when the embedded-controller turns on/off the eprivacy + * screen itself then the state should be reported through drm connecter props: + * https://www.kernel.org/doc/html/latest/gpu/drm-kms.html#standard-connector-properties + * Except when implementing the drm connecter properties API is not possible + * because e.g. the firmware does not allow querying the presence and/or status + * of the eprivacy screen at boot. + */ +#define KEY_EPRIVACY_SCREEN_ON 0x252 +#define KEY_EPRIVACY_SCREEN_OFF 0x253 + +#define KEY_ACTION_ON_SELECTION 0x254 /* AL Action on Selection (HUTRR119) */ +#define KEY_CONTEXTUAL_INSERT 0x255 /* AL Contextual Insertion (HUTRR119) */ +#define KEY_CONTEXTUAL_QUERY 0x256 /* AL Contextual Query (HUTRR119) */ + +#define KEY_KBDINPUTASSIST_PREV 0x260 +#define KEY_KBDINPUTASSIST_NEXT 0x261 +#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 +#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 +#define KEY_KBDINPUTASSIST_ACCEPT 0x264 +#define KEY_KBDINPUTASSIST_CANCEL 0x265 + +/* Diagonal movement keys */ +#define KEY_RIGHT_UP 0x266 +#define KEY_RIGHT_DOWN 0x267 +#define KEY_LEFT_UP 0x268 +#define KEY_LEFT_DOWN 0x269 + +#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */ +/* Show Top Menu of the Media (e.g. DVD) */ +#define KEY_MEDIA_TOP_MENU 0x26b +#define KEY_NUMERIC_11 0x26c +#define KEY_NUMERIC_12 0x26d +/* + * Toggle Audio Description: refers to an audio service that helps blind and + * visually impaired consumers understand the action in a program. Note: in + * some countries this is referred to as "Video Description". + */ +#define KEY_AUDIO_DESC 0x26e +#define KEY_3D_MODE 0x26f +#define KEY_NEXT_FAVORITE 0x270 +#define KEY_STOP_RECORD 0x271 +#define KEY_PAUSE_RECORD 0x272 +#define KEY_VOD 0x273 /* Video on Demand */ +#define KEY_UNMUTE 0x274 +#define KEY_FASTREVERSE 0x275 +#define KEY_SLOWREVERSE 0x276 +/* + * Control a data application associated with the currently viewed channel, + * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) + */ +#define KEY_DATA 0x277 +#define KEY_ONSCREEN_KEYBOARD 0x278 +/* Electronic privacy screen control */ +#define KEY_PRIVACY_SCREEN_TOGGLE 0x279 + +/* Select an area of screen to be copied */ +#define KEY_SELECTIVE_SCREENSHOT 0x27a + +/* Move the focus to the next or previous user controllable element within a UI container */ +#define KEY_NEXT_ELEMENT 0x27b +#define KEY_PREVIOUS_ELEMENT 0x27c + +/* Toggle Autopilot engagement */ +#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d + +/* Shortcut Keys */ +#define KEY_MARK_WAYPOINT 0x27e +#define KEY_SOS 0x27f +#define KEY_NAV_CHART 0x280 +#define KEY_FISHING_CHART 0x281 +#define KEY_SINGLE_RANGE_RADAR 0x282 +#define KEY_DUAL_RANGE_RADAR 0x283 +#define KEY_RADAR_OVERLAY 0x284 +#define KEY_TRADITIONAL_SONAR 0x285 +#define KEY_CLEARVU_SONAR 0x286 +#define KEY_SIDEVU_SONAR 0x287 +#define KEY_NAV_INFO 0x288 +#define KEY_BRIGHTNESS_MENU 0x289 + +/* + * Some keyboards have keys which do not have a defined meaning, these keys + * are intended to be programmed / bound to macros by the user. For most + * keyboards with these macro-keys the key-sequence to inject, or action to + * take, is all handled by software on the host side. So from the kernel's + * point of view these are just normal keys. + * + * The KEY_MACRO# codes below are intended for such keys, which may be labeled + * e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys + * where the marking on the key does indicate a defined meaning / purpose. + * + * The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing + * KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO + * define MUST be added. + */ +#define KEY_MACRO1 0x290 +#define KEY_MACRO2 0x291 +#define KEY_MACRO3 0x292 +#define KEY_MACRO4 0x293 +#define KEY_MACRO5 0x294 +#define KEY_MACRO6 0x295 +#define KEY_MACRO7 0x296 +#define KEY_MACRO8 0x297 +#define KEY_MACRO9 0x298 +#define KEY_MACRO10 0x299 +#define KEY_MACRO11 0x29a +#define KEY_MACRO12 0x29b +#define KEY_MACRO13 0x29c +#define KEY_MACRO14 0x29d +#define KEY_MACRO15 0x29e +#define KEY_MACRO16 0x29f +#define KEY_MACRO17 0x2a0 +#define KEY_MACRO18 0x2a1 +#define KEY_MACRO19 0x2a2 +#define KEY_MACRO20 0x2a3 +#define KEY_MACRO21 0x2a4 +#define KEY_MACRO22 0x2a5 +#define KEY_MACRO23 0x2a6 +#define KEY_MACRO24 0x2a7 +#define KEY_MACRO25 0x2a8 +#define KEY_MACRO26 0x2a9 +#define KEY_MACRO27 0x2aa +#define KEY_MACRO28 0x2ab +#define KEY_MACRO29 0x2ac +#define KEY_MACRO30 0x2ad + +/* + * Some keyboards with the macro-keys described above have some extra keys + * for controlling the host-side software responsible for the macro handling: + * -A macro recording start/stop key. Note that not all keyboards which emit + * KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if + * KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START + * should be interpreted as a recording start/stop toggle; + * -Keys for switching between different macro (pre)sets, either a key for + * cycling through the configured presets or keys to directly select a preset. + */ +#define KEY_MACRO_RECORD_START 0x2b0 +#define KEY_MACRO_RECORD_STOP 0x2b1 +#define KEY_MACRO_PRESET_CYCLE 0x2b2 +#define KEY_MACRO_PRESET1 0x2b3 +#define KEY_MACRO_PRESET2 0x2b4 +#define KEY_MACRO_PRESET3 0x2b5 + +/* + * Some keyboards have a buildin LCD panel where the contents are controlled + * by the host. Often these have a number of keys directly below the LCD + * intended for controlling a menu shown on the LCD. These keys often don't + * have any labeling so we just name them KEY_KBD_LCD_MENU# + */ +#define KEY_KBD_LCD_MENU1 0x2b8 +#define KEY_KBD_LCD_MENU2 0x2b9 +#define KEY_KBD_LCD_MENU3 0x2ba +#define KEY_KBD_LCD_MENU4 0x2bb +#define KEY_KBD_LCD_MENU5 0x2bc + +/* Performance Boost key (Alienware)/G-Mode key (Dell) */ +#define KEY_PERFORMANCE 0x2bd + +#define BTN_TRIGGER_HAPPY 0x2c0 +#define BTN_TRIGGER_HAPPY1 0x2c0 +#define BTN_TRIGGER_HAPPY2 0x2c1 +#define BTN_TRIGGER_HAPPY3 0x2c2 +#define BTN_TRIGGER_HAPPY4 0x2c3 +#define BTN_TRIGGER_HAPPY5 0x2c4 +#define BTN_TRIGGER_HAPPY6 0x2c5 +#define BTN_TRIGGER_HAPPY7 0x2c6 +#define BTN_TRIGGER_HAPPY8 0x2c7 +#define BTN_TRIGGER_HAPPY9 0x2c8 +#define BTN_TRIGGER_HAPPY10 0x2c9 +#define BTN_TRIGGER_HAPPY11 0x2ca +#define BTN_TRIGGER_HAPPY12 0x2cb +#define BTN_TRIGGER_HAPPY13 0x2cc +#define BTN_TRIGGER_HAPPY14 0x2cd +#define BTN_TRIGGER_HAPPY15 0x2ce +#define BTN_TRIGGER_HAPPY16 0x2cf +#define BTN_TRIGGER_HAPPY17 0x2d0 +#define BTN_TRIGGER_HAPPY18 0x2d1 +#define BTN_TRIGGER_HAPPY19 0x2d2 +#define BTN_TRIGGER_HAPPY20 0x2d3 +#define BTN_TRIGGER_HAPPY21 0x2d4 +#define BTN_TRIGGER_HAPPY22 0x2d5 +#define BTN_TRIGGER_HAPPY23 0x2d6 +#define BTN_TRIGGER_HAPPY24 0x2d7 +#define BTN_TRIGGER_HAPPY25 0x2d8 +#define BTN_TRIGGER_HAPPY26 0x2d9 +#define BTN_TRIGGER_HAPPY27 0x2da +#define BTN_TRIGGER_HAPPY28 0x2db +#define BTN_TRIGGER_HAPPY29 0x2dc +#define BTN_TRIGGER_HAPPY30 0x2dd +#define BTN_TRIGGER_HAPPY31 0x2de +#define BTN_TRIGGER_HAPPY32 0x2df +#define BTN_TRIGGER_HAPPY33 0x2e0 +#define BTN_TRIGGER_HAPPY34 0x2e1 +#define BTN_TRIGGER_HAPPY35 0x2e2 +#define BTN_TRIGGER_HAPPY36 0x2e3 +#define BTN_TRIGGER_HAPPY37 0x2e4 +#define BTN_TRIGGER_HAPPY38 0x2e5 +#define BTN_TRIGGER_HAPPY39 0x2e6 +#define BTN_TRIGGER_HAPPY40 0x2e7 + +/* We avoid low common keys in module aliases so they don't get huge. */ +#define KEY_MIN_INTERESTING KEY_MUTE +#define KEY_MAX 0x2ff +#define KEY_CNT (KEY_MAX+1) + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +/* + * 0x0a is reserved and should not be used in input drivers. + * It was used by HID as REL_MISC+1 and userspace needs to detect if + * the next REL_* event is correct or is just REL_MISC + n. + * We define here REL_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define REL_RESERVED 0x0a +#define REL_WHEEL_HI_RES 0x0b +#define REL_HWHEEL_HI_RES 0x0c +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX+1) + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c + +#define ABS_VOLUME 0x20 +#define ABS_PROFILE 0x21 +#define ABS_SND_PROFILE 0x22 + +#define ABS_MISC 0x28 + +/* + * 0x2e is reserved and should not be used in input drivers. + * It was used by HID as ABS_MISC+6 and userspace needs to detect if + * the next ABS_* event is correct or is just ABS_MISC + n. + * We define here ABS_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define ABS_RESERVED 0x2e + +#define ABS_MT_SLOT 0x2f /* MT slot being modified */ +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ +#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ +#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ +#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ +#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ +#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ +#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ +#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ +#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ +#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ +#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ + + +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX+1) + +/* + * Switch events + */ + +#define SW_LID 0x00 /* set = lid shut */ +#define SW_TABLET_MODE 0x01 /* set = tablet mode */ +#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ +#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" + set = radio enabled */ +#define SW_RADIO SW_RFKILL_ALL /* deprecated */ +#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ +#define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ +#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ +#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ +#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ +#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ +#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ +#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ +#define SW_LINEIN_INSERT 0x0d /* set = inserted */ +#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ +#define SW_PEN_INSERTED 0x0f /* set = pen inserted */ +#define SW_MACHINE_COVER 0x10 /* set = cover closed */ +#define SW_USB_INSERT 0x11 /* set = USB audio device connected */ +#define SW_MAX 0x11 +#define SW_CNT (SW_MAX+1) + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_TIMESTAMP 0x05 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX+1) + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAIL 0x09 +#define LED_CHARGING 0x0a +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX+1) + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX+1) + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 +#define SND_CNT (SND_MAX+1) + +/* + * ABS_SND_PROFILE values + */ + +#define SND_PROFILE_SILENT 0x00 +#define SND_PROFILE_VIBRATE 0x01 +#define SND_PROFILE_RING 0x02 + +#endif diff --git a/lib/libevdev/kernel-headers/linux/input.h b/lib/libevdev/kernel-headers/linux/input.h new file mode 100644 index 0000000..5285f88 --- /dev/null +++ b/lib/libevdev/kernel-headers/linux/input.h @@ -0,0 +1,539 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 1999-2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef _UAPI_INPUT_H +#define _UAPI_INPUT_H + + +#ifndef __KERNEL__ +#include +#include +#include +#include +#endif + +#include "input-event-codes.h" + +/* + * The event structure itself + * Note that __USE_TIME_BITS64 is defined by libc based on + * application's request to use 64 bit time_t. + */ + +struct input_event { +#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__) + struct timeval time; +#define input_event_sec time.tv_sec +#define input_event_usec time.tv_usec +#else + __kernel_ulong_t __sec; +#if defined(__sparc__) && defined(__arch64__) + unsigned int __usec; + unsigned int __pad; +#else + __kernel_ulong_t __usec; +#endif +#define input_event_sec __sec +#define input_event_usec __usec +#endif + __u16 type; + __u16 code; + __s32 value; +}; + +/* + * Protocol version. + */ + +#define EV_VERSION 0x010001 + +/* + * IOCTLs (0x00 - 0x7f) + */ + +struct input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +/** + * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls + * @value: latest reported value for the axis. + * @minimum: specifies minimum value for the axis. + * @maximum: specifies maximum value for the axis. + * @fuzz: specifies fuzz value that is used to filter noise from + * the event stream. + * @flat: values that are within this value will be discarded by + * joydev interface and reported as 0 instead. + * @resolution: specifies resolution for the values reported for + * the axis. + * + * Note that input core does not clamp reported values to the + * [minimum, maximum] limits, such task is left to userspace. + * + * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z, + * ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units + * per millimeter (units/mm), resolution for rotational axes + * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. + * The resolution for the size axes (ABS_MT_TOUCH_MAJOR, + * ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR) + * is reported in units per millimeter (units/mm). + * When INPUT_PROP_ACCELEROMETER is set the resolution changes. + * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in + * units per g (units/g) and in units per degree per second + * (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ). + */ +struct input_absinfo { + __s32 value; + __s32 minimum; + __s32 maximum; + __s32 fuzz; + __s32 flat; + __s32 resolution; +}; + +/** + * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls + * @scancode: scancode represented in machine-endian form. + * @len: length of the scancode that resides in @scancode buffer. + * @index: index in the keymap, may be used instead of scancode + * @flags: allows to specify how kernel should handle the request. For + * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel + * should perform lookup in keymap by @index instead of @scancode + * @keycode: key code assigned to this scancode + * + * The structure is used to retrieve and modify keymap data. Users have + * option of performing lookup either by @scancode itself or by @index + * in keymap entry. EVIOCGKEYCODE will also return scancode or index + * (depending on which element was used to perform lookup). + */ +struct input_keymap_entry { +#define INPUT_KEYMAP_BY_INDEX (1 << 0) + __u8 flags; + __u8 len; + __u16 index; + __u32 keycode; + __u8 scancode[32]; +}; + +struct input_mask { + __u32 type; + __u32 codes_size; + __u64 codes_ptr; +}; + +#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ +#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ +#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ +#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ + +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */ + +/** + * EVIOCGMTSLOTS(len) - get MT slot values + * @len: size of the data buffer in bytes + * + * The ioctl buffer argument should be binary equivalent to + * + * struct input_mt_request_layout { + * __u32 code; + * __s32 values[num_slots]; + * }; + * + * where num_slots is the (arbitrary) number of MT slots to extract. + * + * The ioctl size argument (len) is the size of the buffer, which + * should satisfy len = (num_slots + 1) * sizeof(__s32). If len is + * too small to fit all available slots, the first num_slots are + * returned. + * + * Before the call, code is set to the wanted ABS_MT event type. On + * return, values[] is filled with the slot values for the specified + * ABS_MT code. + * + * If the request code is not an ABS_MT value, -EINVAL is returned. + */ +#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ +#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ + +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ +#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ +#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ + +#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */ +#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ +#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ + +#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ +#define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */ + +/** + * EVIOCGMASK - Retrieve current event mask + * + * This ioctl allows user to retrieve the current event mask for specific + * event type. The argument must be of type "struct input_mask" and + * specifies the event type to query, the address of the receive buffer and + * the size of the receive buffer. + * + * The event mask is a per-client mask that specifies which events are + * forwarded to the client. Each event code is represented by a single bit + * in the event mask. If the bit is set, the event is passed to the client + * normally. Otherwise, the event is filtered and will never be queued on + * the client's receive buffer. + * + * Event masks do not affect global state of the input device. They only + * affect the file descriptor they are applied to. + * + * The default event mask for a client has all bits set, i.e. all events + * are forwarded to the client. If the kernel is queried for an unknown + * event type or if the receive buffer is larger than the number of + * event codes known to the kernel, the kernel returns all zeroes for those + * codes. + * + * At maximum, codes_size bytes are copied. + * + * This ioctl may fail with ENODEV in case the file is revoked, EFAULT + * if the receive-buffer points to invalid memory, or EINVAL if the kernel + * does not implement the ioctl. + */ +#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */ + +/** + * EVIOCSMASK - Set event mask + * + * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the + * current event mask, this changes the client's event mask for a specific + * type. See EVIOCGMASK for a description of event-masks and the + * argument-type. + * + * This ioctl provides full forward compatibility. If the passed event type + * is unknown to the kernel, or if the number of event codes specified in + * the mask is bigger than what is known to the kernel, the ioctl is still + * accepted and applied. However, any unknown codes are left untouched and + * stay cleared. That means, the kernel always filters unknown codes + * regardless of what the client requests. If the new mask doesn't cover + * all known event-codes, all remaining codes are automatically cleared and + * thus filtered. + * + * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is + * returned if the receive-buffer points to invalid memory. EINVAL is returned + * if the kernel does not implement the ioctl. + */ +#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */ + +#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ + +/* + * IDs. + */ + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define BUS_RMI 0x1D +#define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F +#define BUS_AMD_SFH 0x20 +#define BUS_SDW 0x21 + +/* + * MT_TOOL types + */ +#define MT_TOOL_FINGER 0x00 +#define MT_TOOL_PEN 0x01 +#define MT_TOOL_PALM 0x02 +#define MT_TOOL_DIAL 0x0a +#define MT_TOOL_MAX 0x0f + +/* + * Values describing the status of a force-feedback effect + */ +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 + +/* + * Structures used in ioctls to upload effects to a device + * They are pieces of a bigger structure (called ff_effect) + */ + +/* + * All duration values are expressed in ms. Values above 32767 ms (0x7fff) + * should not be used and have unspecified results. + */ + +/** + * struct ff_replay - defines scheduling of the force-feedback effect + * @length: duration of the effect + * @delay: delay before effect should start playing + */ +struct ff_replay { + __u16 length; + __u16 delay; +}; + +/** + * struct ff_trigger - defines what triggers the force-feedback effect + * @button: number of the button triggering the effect + * @interval: controls how soon the effect can be re-triggered + */ +struct ff_trigger { + __u16 button; + __u16 interval; +}; + +/** + * struct ff_envelope - generic force-feedback effect envelope + * @attack_length: duration of the attack (ms) + * @attack_level: level at the beginning of the attack + * @fade_length: duration of fade (ms) + * @fade_level: level at the end of fade + * + * The @attack_level and @fade_level are absolute values; when applying + * envelope force-feedback core will convert to positive/negative + * value based on polarity of the default level of the effect. + * Valid range for the attack and fade levels is 0x0000 - 0x7fff + */ +struct ff_envelope { + __u16 attack_length; + __u16 attack_level; + __u16 fade_length; + __u16 fade_level; +}; + +/** + * struct ff_constant_effect - defines parameters of a constant force-feedback effect + * @level: strength of the effect; may be negative + * @envelope: envelope data + */ +struct ff_constant_effect { + __s16 level; + struct ff_envelope envelope; +}; + +/** + * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect + * @start_level: beginning strength of the effect; may be negative + * @end_level: final strength of the effect; may be negative + * @envelope: envelope data + */ +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; + +/** + * struct ff_condition_effect - defines a spring or friction force-feedback effect + * @right_saturation: maximum level when joystick moved all way to the right + * @left_saturation: same for the left side + * @right_coeff: controls how fast the force grows when the joystick moves + * to the right + * @left_coeff: same for the left side + * @deadband: size of the dead zone, where no force is produced + * @center: position of the dead zone + */ +struct ff_condition_effect { + __u16 right_saturation; + __u16 left_saturation; + + __s16 right_coeff; + __s16 left_coeff; + + __u16 deadband; + __s16 center; +}; + +/** + * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect + * @waveform: kind of the effect (wave) + * @period: period of the wave (ms) + * @magnitude: peak value + * @offset: mean value of the wave (roughly) + * @phase: 'horizontal' shift + * @envelope: envelope data + * @custom_len: number of samples (FF_CUSTOM only) + * @custom_data: buffer of samples (FF_CUSTOM only) + * + * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, + * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined + * for the time being as no driver supports it yet. + * + * Note: the data pointed by custom_data is copied by the driver. + * You can therefore dispose of the memory after the upload/update. + */ +struct ff_periodic_effect { + __u16 waveform; + __u16 period; + __s16 magnitude; + __s16 offset; + __u16 phase; + + struct ff_envelope envelope; + + __u32 custom_len; + __s16 *custom_data; +}; + +/** + * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect + * @strong_magnitude: magnitude of the heavy motor + * @weak_magnitude: magnitude of the light one + * + * Some rumble pads have two motors of different weight. Strong_magnitude + * represents the magnitude of the vibration generated by the heavy one. + */ +struct ff_rumble_effect { + __u16 strong_magnitude; + __u16 weak_magnitude; +}; + +/** + * struct ff_haptic_effect + * @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.) + * @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined range + * @vendor_waveform_page: the vendor waveform page if hid_usage is in the vendor-defined range + * @intensity: strength of the effect as percentage + * @repeat_count: number of times to retrigger effect + * @retrigger_period: time before effect is retriggered (in ms) + */ +struct ff_haptic_effect { + __u16 hid_usage; + __u16 vendor_id; + __u8 vendor_waveform_page; + __u16 intensity; + __u16 repeat_count; + __u16 retrigger_period; +}; + +/** + * struct ff_effect - defines force feedback effect + * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, + * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) + * @id: an unique id assigned to an effect + * @direction: direction of the effect + * @trigger: trigger conditions (struct ff_trigger) + * @replay: scheduling of the effect (struct ff_replay) + * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, + * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further + * defining effect parameters + * + * This structure is sent through ioctl from the application to the driver. + * To create a new effect application should set its @id to -1; the kernel + * will return assigned @id which can later be used to update or delete + * this effect. + * + * Direction of the effect is encoded as follows: + * 0 deg -> 0x0000 (down) + * 90 deg -> 0x4000 (left) + * 180 deg -> 0x8000 (up) + * 270 deg -> 0xC000 (right) + */ +struct ff_effect { + __u16 type; + __s16 id; + __u16 direction; + struct ff_trigger trigger; + struct ff_replay replay; + + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect periodic; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; + struct ff_haptic_effect haptic; + } u; +}; + +/* + * Force feedback effect types + */ + +#define FF_HAPTIC 0x4f +#define FF_RUMBLE 0x50 +#define FF_PERIODIC 0x51 +#define FF_CONSTANT 0x52 +#define FF_SPRING 0x53 +#define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 + +#define FF_EFFECT_MIN FF_HAPTIC +#define FF_EFFECT_MAX FF_RAMP + +/* + * Force feedback periodic effect types + */ + +#define FF_SQUARE 0x58 +#define FF_TRIANGLE 0x59 +#define FF_SINE 0x5a +#define FF_SAW_UP 0x5b +#define FF_SAW_DOWN 0x5c +#define FF_CUSTOM 0x5d + +#define FF_WAVEFORM_MIN FF_SQUARE +#define FF_WAVEFORM_MAX FF_CUSTOM + +/* + * Set ff device properties + */ + +#define FF_GAIN 0x60 +#define FF_AUTOCENTER 0x61 + +/* + * ff->playback(effect_id = FF_GAIN) is the first effect_id to + * cause a collision with another ff method, in this case ff->set_gain(). + * Therefore the greatest safe value for effect_id is FF_GAIN - 1, + * and thus the total number of effects should never exceed FF_GAIN. + */ +#define FF_MAX_EFFECTS FF_GAIN + +#define FF_MAX 0x7f +#define FF_CNT (FF_MAX+1) + +#endif /* _UAPI_INPUT_H */ diff --git a/lib/libevdev/libevdev/config.h b/lib/libevdev/libevdev/config.h new file mode 100644 index 0000000..280c874 --- /dev/null +++ b/lib/libevdev/libevdev/config.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: MIT */ +/* What libevdev's meson.build writes into config.h on Linux. */ +#define _GNU_SOURCE 1 diff --git a/lib/libevdev/libevdev/event-names.h b/lib/libevdev/libevdev/event-names.h new file mode 100644 index 0000000..0230284 --- /dev/null +++ b/lib/libevdev/libevdev/event-names.h @@ -0,0 +1,1692 @@ +/* THIS FILE IS GENERATED, DO NOT EDIT */ + +#ifndef EVENT_NAMES_H +#define EVENT_NAMES_H + +static const char * const ev_map[EV_MAX + 1] = { + [EV_SYN] = "EV_SYN", + [EV_KEY] = "EV_KEY", + [EV_REL] = "EV_REL", + [EV_ABS] = "EV_ABS", + [EV_MSC] = "EV_MSC", + [EV_SW] = "EV_SW", + [EV_LED] = "EV_LED", + [EV_SND] = "EV_SND", + [EV_REP] = "EV_REP", + [EV_FF] = "EV_FF", + [EV_PWR] = "EV_PWR", + [EV_FF_STATUS] = "EV_FF_STATUS", + [EV_MAX] = "EV_MAX", +}; + +static const char * const rel_map[REL_MAX + 1] = { + [REL_X] = "REL_X", + [REL_Y] = "REL_Y", + [REL_Z] = "REL_Z", + [REL_RX] = "REL_RX", + [REL_RY] = "REL_RY", + [REL_RZ] = "REL_RZ", + [REL_HWHEEL] = "REL_HWHEEL", + [REL_DIAL] = "REL_DIAL", + [REL_WHEEL] = "REL_WHEEL", + [REL_MISC] = "REL_MISC", + [REL_RESERVED] = "REL_RESERVED", + [REL_WHEEL_HI_RES] = "REL_WHEEL_HI_RES", + [REL_HWHEEL_HI_RES] = "REL_HWHEEL_HI_RES", + [REL_MAX] = "REL_MAX", +}; + +static const char * const abs_map[ABS_MAX + 1] = { + [ABS_X] = "ABS_X", + [ABS_Y] = "ABS_Y", + [ABS_Z] = "ABS_Z", + [ABS_RX] = "ABS_RX", + [ABS_RY] = "ABS_RY", + [ABS_RZ] = "ABS_RZ", + [ABS_THROTTLE] = "ABS_THROTTLE", + [ABS_RUDDER] = "ABS_RUDDER", + [ABS_WHEEL] = "ABS_WHEEL", + [ABS_GAS] = "ABS_GAS", + [ABS_BRAKE] = "ABS_BRAKE", + [ABS_HAT0X] = "ABS_HAT0X", + [ABS_HAT0Y] = "ABS_HAT0Y", + [ABS_HAT1X] = "ABS_HAT1X", + [ABS_HAT1Y] = "ABS_HAT1Y", + [ABS_HAT2X] = "ABS_HAT2X", + [ABS_HAT2Y] = "ABS_HAT2Y", + [ABS_HAT3X] = "ABS_HAT3X", + [ABS_HAT3Y] = "ABS_HAT3Y", + [ABS_PRESSURE] = "ABS_PRESSURE", + [ABS_DISTANCE] = "ABS_DISTANCE", + [ABS_TILT_X] = "ABS_TILT_X", + [ABS_TILT_Y] = "ABS_TILT_Y", + [ABS_TOOL_WIDTH] = "ABS_TOOL_WIDTH", + [ABS_VOLUME] = "ABS_VOLUME", + [ABS_PROFILE] = "ABS_PROFILE", + [ABS_SND_PROFILE] = "ABS_SND_PROFILE", + [ABS_MISC] = "ABS_MISC", + [ABS_RESERVED] = "ABS_RESERVED", + [ABS_MT_SLOT] = "ABS_MT_SLOT", + [ABS_MT_TOUCH_MAJOR] = "ABS_MT_TOUCH_MAJOR", + [ABS_MT_TOUCH_MINOR] = "ABS_MT_TOUCH_MINOR", + [ABS_MT_WIDTH_MAJOR] = "ABS_MT_WIDTH_MAJOR", + [ABS_MT_WIDTH_MINOR] = "ABS_MT_WIDTH_MINOR", + [ABS_MT_ORIENTATION] = "ABS_MT_ORIENTATION", + [ABS_MT_POSITION_X] = "ABS_MT_POSITION_X", + [ABS_MT_POSITION_Y] = "ABS_MT_POSITION_Y", + [ABS_MT_TOOL_TYPE] = "ABS_MT_TOOL_TYPE", + [ABS_MT_BLOB_ID] = "ABS_MT_BLOB_ID", + [ABS_MT_TRACKING_ID] = "ABS_MT_TRACKING_ID", + [ABS_MT_PRESSURE] = "ABS_MT_PRESSURE", + [ABS_MT_DISTANCE] = "ABS_MT_DISTANCE", + [ABS_MT_TOOL_X] = "ABS_MT_TOOL_X", + [ABS_MT_TOOL_Y] = "ABS_MT_TOOL_Y", + [ABS_MAX] = "ABS_MAX", +}; + +static const char * const key_map[KEY_MAX + 1] = { + [KEY_RESERVED] = "KEY_RESERVED", + [KEY_ESC] = "KEY_ESC", + [KEY_1] = "KEY_1", + [KEY_2] = "KEY_2", + [KEY_3] = "KEY_3", + [KEY_4] = "KEY_4", + [KEY_5] = "KEY_5", + [KEY_6] = "KEY_6", + [KEY_7] = "KEY_7", + [KEY_8] = "KEY_8", + [KEY_9] = "KEY_9", + [KEY_0] = "KEY_0", + [KEY_MINUS] = "KEY_MINUS", + [KEY_EQUAL] = "KEY_EQUAL", + [KEY_BACKSPACE] = "KEY_BACKSPACE", + [KEY_TAB] = "KEY_TAB", + [KEY_Q] = "KEY_Q", + [KEY_W] = "KEY_W", + [KEY_E] = "KEY_E", + [KEY_R] = "KEY_R", + [KEY_T] = "KEY_T", + [KEY_Y] = "KEY_Y", + [KEY_U] = "KEY_U", + [KEY_I] = "KEY_I", + [KEY_O] = "KEY_O", + [KEY_P] = "KEY_P", + [KEY_LEFTBRACE] = "KEY_LEFTBRACE", + [KEY_RIGHTBRACE] = "KEY_RIGHTBRACE", + [KEY_ENTER] = "KEY_ENTER", + [KEY_LEFTCTRL] = "KEY_LEFTCTRL", + [KEY_A] = "KEY_A", + [KEY_S] = "KEY_S", + [KEY_D] = "KEY_D", + [KEY_F] = "KEY_F", + [KEY_G] = "KEY_G", + [KEY_H] = "KEY_H", + [KEY_J] = "KEY_J", + [KEY_K] = "KEY_K", + [KEY_L] = "KEY_L", + [KEY_SEMICOLON] = "KEY_SEMICOLON", + [KEY_APOSTROPHE] = "KEY_APOSTROPHE", + [KEY_GRAVE] = "KEY_GRAVE", + [KEY_LEFTSHIFT] = "KEY_LEFTSHIFT", + [KEY_BACKSLASH] = "KEY_BACKSLASH", + [KEY_Z] = "KEY_Z", + [KEY_X] = "KEY_X", + [KEY_C] = "KEY_C", + [KEY_V] = "KEY_V", + [KEY_B] = "KEY_B", + [KEY_N] = "KEY_N", + [KEY_M] = "KEY_M", + [KEY_COMMA] = "KEY_COMMA", + [KEY_DOT] = "KEY_DOT", + [KEY_SLASH] = "KEY_SLASH", + [KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT", + [KEY_KPASTERISK] = "KEY_KPASTERISK", + [KEY_LEFTALT] = "KEY_LEFTALT", + [KEY_SPACE] = "KEY_SPACE", + [KEY_CAPSLOCK] = "KEY_CAPSLOCK", + [KEY_F1] = "KEY_F1", + [KEY_F2] = "KEY_F2", + [KEY_F3] = "KEY_F3", + [KEY_F4] = "KEY_F4", + [KEY_F5] = "KEY_F5", + [KEY_F6] = "KEY_F6", + [KEY_F7] = "KEY_F7", + [KEY_F8] = "KEY_F8", + [KEY_F9] = "KEY_F9", + [KEY_F10] = "KEY_F10", + [KEY_NUMLOCK] = "KEY_NUMLOCK", + [KEY_SCROLLLOCK] = "KEY_SCROLLLOCK", + [KEY_KP7] = "KEY_KP7", + [KEY_KP8] = "KEY_KP8", + [KEY_KP9] = "KEY_KP9", + [KEY_KPMINUS] = "KEY_KPMINUS", + [KEY_KP4] = "KEY_KP4", + [KEY_KP5] = "KEY_KP5", + [KEY_KP6] = "KEY_KP6", + [KEY_KPPLUS] = "KEY_KPPLUS", + [KEY_KP1] = "KEY_KP1", + [KEY_KP2] = "KEY_KP2", + [KEY_KP3] = "KEY_KP3", + [KEY_KP0] = "KEY_KP0", + [KEY_KPDOT] = "KEY_KPDOT", + [KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU", + [KEY_102ND] = "KEY_102ND", + [KEY_F11] = "KEY_F11", + [KEY_F12] = "KEY_F12", + [KEY_RO] = "KEY_RO", + [KEY_KATAKANA] = "KEY_KATAKANA", + [KEY_HIRAGANA] = "KEY_HIRAGANA", + [KEY_HENKAN] = "KEY_HENKAN", + [KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA", + [KEY_MUHENKAN] = "KEY_MUHENKAN", + [KEY_KPJPCOMMA] = "KEY_KPJPCOMMA", + [KEY_KPENTER] = "KEY_KPENTER", + [KEY_RIGHTCTRL] = "KEY_RIGHTCTRL", + [KEY_KPSLASH] = "KEY_KPSLASH", + [KEY_SYSRQ] = "KEY_SYSRQ", + [KEY_RIGHTALT] = "KEY_RIGHTALT", + [KEY_LINEFEED] = "KEY_LINEFEED", + [KEY_HOME] = "KEY_HOME", + [KEY_UP] = "KEY_UP", + [KEY_PAGEUP] = "KEY_PAGEUP", + [KEY_LEFT] = "KEY_LEFT", + [KEY_RIGHT] = "KEY_RIGHT", + [KEY_END] = "KEY_END", + [KEY_DOWN] = "KEY_DOWN", + [KEY_PAGEDOWN] = "KEY_PAGEDOWN", + [KEY_INSERT] = "KEY_INSERT", + [KEY_DELETE] = "KEY_DELETE", + [KEY_MACRO] = "KEY_MACRO", + [KEY_MUTE] = "KEY_MUTE", + [KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN", + [KEY_VOLUMEUP] = "KEY_VOLUMEUP", + [KEY_POWER] = "KEY_POWER", + [KEY_KPEQUAL] = "KEY_KPEQUAL", + [KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS", + [KEY_PAUSE] = "KEY_PAUSE", + [KEY_SCALE] = "KEY_SCALE", + [KEY_KPCOMMA] = "KEY_KPCOMMA", + [KEY_HANGEUL] = "KEY_HANGEUL", + [KEY_HANJA] = "KEY_HANJA", + [KEY_YEN] = "KEY_YEN", + [KEY_LEFTMETA] = "KEY_LEFTMETA", + [KEY_RIGHTMETA] = "KEY_RIGHTMETA", + [KEY_COMPOSE] = "KEY_COMPOSE", + [KEY_STOP] = "KEY_STOP", + [KEY_AGAIN] = "KEY_AGAIN", + [KEY_PROPS] = "KEY_PROPS", + [KEY_UNDO] = "KEY_UNDO", + [KEY_FRONT] = "KEY_FRONT", + [KEY_COPY] = "KEY_COPY", + [KEY_OPEN] = "KEY_OPEN", + [KEY_PASTE] = "KEY_PASTE", + [KEY_FIND] = "KEY_FIND", + [KEY_CUT] = "KEY_CUT", + [KEY_HELP] = "KEY_HELP", + [KEY_MENU] = "KEY_MENU", + [KEY_CALC] = "KEY_CALC", + [KEY_SETUP] = "KEY_SETUP", + [KEY_SLEEP] = "KEY_SLEEP", + [KEY_WAKEUP] = "KEY_WAKEUP", + [KEY_FILE] = "KEY_FILE", + [KEY_SENDFILE] = "KEY_SENDFILE", + [KEY_DELETEFILE] = "KEY_DELETEFILE", + [KEY_XFER] = "KEY_XFER", + [KEY_PROG1] = "KEY_PROG1", + [KEY_PROG2] = "KEY_PROG2", + [KEY_WWW] = "KEY_WWW", + [KEY_MSDOS] = "KEY_MSDOS", + [KEY_COFFEE] = "KEY_COFFEE", + [KEY_ROTATE_DISPLAY] = "KEY_ROTATE_DISPLAY", + [KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS", + [KEY_MAIL] = "KEY_MAIL", + [KEY_BOOKMARKS] = "KEY_BOOKMARKS", + [KEY_COMPUTER] = "KEY_COMPUTER", + [KEY_BACK] = "KEY_BACK", + [KEY_FORWARD] = "KEY_FORWARD", + [KEY_CLOSECD] = "KEY_CLOSECD", + [KEY_EJECTCD] = "KEY_EJECTCD", + [KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD", + [KEY_NEXTSONG] = "KEY_NEXTSONG", + [KEY_PLAYPAUSE] = "KEY_PLAYPAUSE", + [KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG", + [KEY_STOPCD] = "KEY_STOPCD", + [KEY_RECORD] = "KEY_RECORD", + [KEY_REWIND] = "KEY_REWIND", + [KEY_PHONE] = "KEY_PHONE", + [KEY_ISO] = "KEY_ISO", + [KEY_CONFIG] = "KEY_CONFIG", + [KEY_HOMEPAGE] = "KEY_HOMEPAGE", + [KEY_REFRESH] = "KEY_REFRESH", + [KEY_EXIT] = "KEY_EXIT", + [KEY_MOVE] = "KEY_MOVE", + [KEY_EDIT] = "KEY_EDIT", + [KEY_SCROLLUP] = "KEY_SCROLLUP", + [KEY_SCROLLDOWN] = "KEY_SCROLLDOWN", + [KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN", + [KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN", + [KEY_NEW] = "KEY_NEW", + [KEY_REDO] = "KEY_REDO", + [KEY_F13] = "KEY_F13", + [KEY_F14] = "KEY_F14", + [KEY_F15] = "KEY_F15", + [KEY_F16] = "KEY_F16", + [KEY_F17] = "KEY_F17", + [KEY_F18] = "KEY_F18", + [KEY_F19] = "KEY_F19", + [KEY_F20] = "KEY_F20", + [KEY_F21] = "KEY_F21", + [KEY_F22] = "KEY_F22", + [KEY_F23] = "KEY_F23", + [KEY_F24] = "KEY_F24", + [KEY_PLAYCD] = "KEY_PLAYCD", + [KEY_PAUSECD] = "KEY_PAUSECD", + [KEY_PROG3] = "KEY_PROG3", + [KEY_PROG4] = "KEY_PROG4", + [KEY_ALL_APPLICATIONS] = "KEY_ALL_APPLICATIONS", + [KEY_SUSPEND] = "KEY_SUSPEND", + [KEY_CLOSE] = "KEY_CLOSE", + [KEY_PLAY] = "KEY_PLAY", + [KEY_FASTFORWARD] = "KEY_FASTFORWARD", + [KEY_BASSBOOST] = "KEY_BASSBOOST", + [KEY_PRINT] = "KEY_PRINT", + [KEY_HP] = "KEY_HP", + [KEY_CAMERA] = "KEY_CAMERA", + [KEY_SOUND] = "KEY_SOUND", + [KEY_QUESTION] = "KEY_QUESTION", + [KEY_EMAIL] = "KEY_EMAIL", + [KEY_CHAT] = "KEY_CHAT", + [KEY_SEARCH] = "KEY_SEARCH", + [KEY_CONNECT] = "KEY_CONNECT", + [KEY_FINANCE] = "KEY_FINANCE", + [KEY_SPORT] = "KEY_SPORT", + [KEY_SHOP] = "KEY_SHOP", + [KEY_ALTERASE] = "KEY_ALTERASE", + [KEY_CANCEL] = "KEY_CANCEL", + [KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN", + [KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP", + [KEY_MEDIA] = "KEY_MEDIA", + [KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE", + [KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE", + [KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN", + [KEY_KBDILLUMUP] = "KEY_KBDILLUMUP", + [KEY_SEND] = "KEY_SEND", + [KEY_REPLY] = "KEY_REPLY", + [KEY_FORWARDMAIL] = "KEY_FORWARDMAIL", + [KEY_SAVE] = "KEY_SAVE", + [KEY_DOCUMENTS] = "KEY_DOCUMENTS", + [KEY_BATTERY] = "KEY_BATTERY", + [KEY_BLUETOOTH] = "KEY_BLUETOOTH", + [KEY_WLAN] = "KEY_WLAN", + [KEY_UWB] = "KEY_UWB", + [KEY_UNKNOWN] = "KEY_UNKNOWN", + [KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT", + [KEY_VIDEO_PREV] = "KEY_VIDEO_PREV", + [KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE", + [KEY_BRIGHTNESS_AUTO] = "KEY_BRIGHTNESS_AUTO", + [KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF", + [KEY_WWAN] = "KEY_WWAN", + [KEY_RFKILL] = "KEY_RFKILL", + [KEY_MICMUTE] = "KEY_MICMUTE", + [KEY_OK] = "KEY_OK", + [KEY_SELECT] = "KEY_SELECT", + [KEY_GOTO] = "KEY_GOTO", + [KEY_CLEAR] = "KEY_CLEAR", + [KEY_POWER2] = "KEY_POWER2", + [KEY_OPTION] = "KEY_OPTION", + [KEY_INFO] = "KEY_INFO", + [KEY_TIME] = "KEY_TIME", + [KEY_VENDOR] = "KEY_VENDOR", + [KEY_ARCHIVE] = "KEY_ARCHIVE", + [KEY_PROGRAM] = "KEY_PROGRAM", + [KEY_CHANNEL] = "KEY_CHANNEL", + [KEY_FAVORITES] = "KEY_FAVORITES", + [KEY_EPG] = "KEY_EPG", + [KEY_PVR] = "KEY_PVR", + [KEY_MHP] = "KEY_MHP", + [KEY_LANGUAGE] = "KEY_LANGUAGE", + [KEY_TITLE] = "KEY_TITLE", + [KEY_SUBTITLE] = "KEY_SUBTITLE", + [KEY_ANGLE] = "KEY_ANGLE", + [KEY_FULL_SCREEN] = "KEY_FULL_SCREEN", + [KEY_MODE] = "KEY_MODE", + [KEY_KEYBOARD] = "KEY_KEYBOARD", + [KEY_ASPECT_RATIO] = "KEY_ASPECT_RATIO", + [KEY_PC] = "KEY_PC", + [KEY_TV] = "KEY_TV", + [KEY_TV2] = "KEY_TV2", + [KEY_VCR] = "KEY_VCR", + [KEY_VCR2] = "KEY_VCR2", + [KEY_SAT] = "KEY_SAT", + [KEY_SAT2] = "KEY_SAT2", + [KEY_CD] = "KEY_CD", + [KEY_TAPE] = "KEY_TAPE", + [KEY_RADIO] = "KEY_RADIO", + [KEY_TUNER] = "KEY_TUNER", + [KEY_PLAYER] = "KEY_PLAYER", + [KEY_TEXT] = "KEY_TEXT", + [KEY_DVD] = "KEY_DVD", + [KEY_AUX] = "KEY_AUX", + [KEY_MP3] = "KEY_MP3", + [KEY_AUDIO] = "KEY_AUDIO", + [KEY_VIDEO] = "KEY_VIDEO", + [KEY_DIRECTORY] = "KEY_DIRECTORY", + [KEY_LIST] = "KEY_LIST", + [KEY_MEMO] = "KEY_MEMO", + [KEY_CALENDAR] = "KEY_CALENDAR", + [KEY_RED] = "KEY_RED", + [KEY_GREEN] = "KEY_GREEN", + [KEY_YELLOW] = "KEY_YELLOW", + [KEY_BLUE] = "KEY_BLUE", + [KEY_CHANNELUP] = "KEY_CHANNELUP", + [KEY_CHANNELDOWN] = "KEY_CHANNELDOWN", + [KEY_FIRST] = "KEY_FIRST", + [KEY_LAST] = "KEY_LAST", + [KEY_AB] = "KEY_AB", + [KEY_NEXT] = "KEY_NEXT", + [KEY_RESTART] = "KEY_RESTART", + [KEY_SLOW] = "KEY_SLOW", + [KEY_SHUFFLE] = "KEY_SHUFFLE", + [KEY_BREAK] = "KEY_BREAK", + [KEY_PREVIOUS] = "KEY_PREVIOUS", + [KEY_DIGITS] = "KEY_DIGITS", + [KEY_TEEN] = "KEY_TEEN", + [KEY_TWEN] = "KEY_TWEN", + [KEY_VIDEOPHONE] = "KEY_VIDEOPHONE", + [KEY_GAMES] = "KEY_GAMES", + [KEY_ZOOMIN] = "KEY_ZOOMIN", + [KEY_ZOOMOUT] = "KEY_ZOOMOUT", + [KEY_ZOOMRESET] = "KEY_ZOOMRESET", + [KEY_WORDPROCESSOR] = "KEY_WORDPROCESSOR", + [KEY_EDITOR] = "KEY_EDITOR", + [KEY_SPREADSHEET] = "KEY_SPREADSHEET", + [KEY_GRAPHICSEDITOR] = "KEY_GRAPHICSEDITOR", + [KEY_PRESENTATION] = "KEY_PRESENTATION", + [KEY_DATABASE] = "KEY_DATABASE", + [KEY_NEWS] = "KEY_NEWS", + [KEY_VOICEMAIL] = "KEY_VOICEMAIL", + [KEY_ADDRESSBOOK] = "KEY_ADDRESSBOOK", + [KEY_MESSENGER] = "KEY_MESSENGER", + [KEY_DISPLAYTOGGLE] = "KEY_DISPLAYTOGGLE", + [KEY_SPELLCHECK] = "KEY_SPELLCHECK", + [KEY_LOGOFF] = "KEY_LOGOFF", + [KEY_DOLLAR] = "KEY_DOLLAR", + [KEY_EURO] = "KEY_EURO", + [KEY_FRAMEBACK] = "KEY_FRAMEBACK", + [KEY_FRAMEFORWARD] = "KEY_FRAMEFORWARD", + [KEY_CONTEXT_MENU] = "KEY_CONTEXT_MENU", + [KEY_MEDIA_REPEAT] = "KEY_MEDIA_REPEAT", + [KEY_10CHANNELSUP] = "KEY_10CHANNELSUP", + [KEY_10CHANNELSDOWN] = "KEY_10CHANNELSDOWN", + [KEY_IMAGES] = "KEY_IMAGES", + [KEY_NOTIFICATION_CENTER] = "KEY_NOTIFICATION_CENTER", + [KEY_PICKUP_PHONE] = "KEY_PICKUP_PHONE", + [KEY_HANGUP_PHONE] = "KEY_HANGUP_PHONE", + [KEY_LINK_PHONE] = "KEY_LINK_PHONE", + [KEY_DEL_EOL] = "KEY_DEL_EOL", + [KEY_DEL_EOS] = "KEY_DEL_EOS", + [KEY_INS_LINE] = "KEY_INS_LINE", + [KEY_DEL_LINE] = "KEY_DEL_LINE", + [KEY_FN] = "KEY_FN", + [KEY_FN_ESC] = "KEY_FN_ESC", + [KEY_FN_F1] = "KEY_FN_F1", + [KEY_FN_F2] = "KEY_FN_F2", + [KEY_FN_F3] = "KEY_FN_F3", + [KEY_FN_F4] = "KEY_FN_F4", + [KEY_FN_F5] = "KEY_FN_F5", + [KEY_FN_F6] = "KEY_FN_F6", + [KEY_FN_F7] = "KEY_FN_F7", + [KEY_FN_F8] = "KEY_FN_F8", + [KEY_FN_F9] = "KEY_FN_F9", + [KEY_FN_F10] = "KEY_FN_F10", + [KEY_FN_F11] = "KEY_FN_F11", + [KEY_FN_F12] = "KEY_FN_F12", + [KEY_FN_1] = "KEY_FN_1", + [KEY_FN_2] = "KEY_FN_2", + [KEY_FN_D] = "KEY_FN_D", + [KEY_FN_E] = "KEY_FN_E", + [KEY_FN_F] = "KEY_FN_F", + [KEY_FN_S] = "KEY_FN_S", + [KEY_FN_B] = "KEY_FN_B", + [KEY_FN_RIGHT_SHIFT] = "KEY_FN_RIGHT_SHIFT", + [KEY_BRL_DOT1] = "KEY_BRL_DOT1", + [KEY_BRL_DOT2] = "KEY_BRL_DOT2", + [KEY_BRL_DOT3] = "KEY_BRL_DOT3", + [KEY_BRL_DOT4] = "KEY_BRL_DOT4", + [KEY_BRL_DOT5] = "KEY_BRL_DOT5", + [KEY_BRL_DOT6] = "KEY_BRL_DOT6", + [KEY_BRL_DOT7] = "KEY_BRL_DOT7", + [KEY_BRL_DOT8] = "KEY_BRL_DOT8", + [KEY_BRL_DOT9] = "KEY_BRL_DOT9", + [KEY_BRL_DOT10] = "KEY_BRL_DOT10", + [KEY_NUMERIC_0] = "KEY_NUMERIC_0", + [KEY_NUMERIC_1] = "KEY_NUMERIC_1", + [KEY_NUMERIC_2] = "KEY_NUMERIC_2", + [KEY_NUMERIC_3] = "KEY_NUMERIC_3", + [KEY_NUMERIC_4] = "KEY_NUMERIC_4", + [KEY_NUMERIC_5] = "KEY_NUMERIC_5", + [KEY_NUMERIC_6] = "KEY_NUMERIC_6", + [KEY_NUMERIC_7] = "KEY_NUMERIC_7", + [KEY_NUMERIC_8] = "KEY_NUMERIC_8", + [KEY_NUMERIC_9] = "KEY_NUMERIC_9", + [KEY_NUMERIC_STAR] = "KEY_NUMERIC_STAR", + [KEY_NUMERIC_POUND] = "KEY_NUMERIC_POUND", + [KEY_NUMERIC_A] = "KEY_NUMERIC_A", + [KEY_NUMERIC_B] = "KEY_NUMERIC_B", + [KEY_NUMERIC_C] = "KEY_NUMERIC_C", + [KEY_NUMERIC_D] = "KEY_NUMERIC_D", + [KEY_CAMERA_FOCUS] = "KEY_CAMERA_FOCUS", + [KEY_WPS_BUTTON] = "KEY_WPS_BUTTON", + [KEY_TOUCHPAD_TOGGLE] = "KEY_TOUCHPAD_TOGGLE", + [KEY_TOUCHPAD_ON] = "KEY_TOUCHPAD_ON", + [KEY_TOUCHPAD_OFF] = "KEY_TOUCHPAD_OFF", + [KEY_CAMERA_ZOOMIN] = "KEY_CAMERA_ZOOMIN", + [KEY_CAMERA_ZOOMOUT] = "KEY_CAMERA_ZOOMOUT", + [KEY_CAMERA_UP] = "KEY_CAMERA_UP", + [KEY_CAMERA_DOWN] = "KEY_CAMERA_DOWN", + [KEY_CAMERA_LEFT] = "KEY_CAMERA_LEFT", + [KEY_CAMERA_RIGHT] = "KEY_CAMERA_RIGHT", + [KEY_ATTENDANT_ON] = "KEY_ATTENDANT_ON", + [KEY_ATTENDANT_OFF] = "KEY_ATTENDANT_OFF", + [KEY_ATTENDANT_TOGGLE] = "KEY_ATTENDANT_TOGGLE", + [KEY_LIGHTS_TOGGLE] = "KEY_LIGHTS_TOGGLE", + [KEY_ALS_TOGGLE] = "KEY_ALS_TOGGLE", + [KEY_ROTATE_LOCK_TOGGLE] = "KEY_ROTATE_LOCK_TOGGLE", + [KEY_REFRESH_RATE_TOGGLE] = "KEY_REFRESH_RATE_TOGGLE", + [KEY_BUTTONCONFIG] = "KEY_BUTTONCONFIG", + [KEY_TASKMANAGER] = "KEY_TASKMANAGER", + [KEY_JOURNAL] = "KEY_JOURNAL", + [KEY_CONTROLPANEL] = "KEY_CONTROLPANEL", + [KEY_APPSELECT] = "KEY_APPSELECT", + [KEY_SCREENSAVER] = "KEY_SCREENSAVER", + [KEY_VOICECOMMAND] = "KEY_VOICECOMMAND", + [KEY_ASSISTANT] = "KEY_ASSISTANT", + [KEY_KBD_LAYOUT_NEXT] = "KEY_KBD_LAYOUT_NEXT", + [KEY_EMOJI_PICKER] = "KEY_EMOJI_PICKER", + [KEY_DICTATE] = "KEY_DICTATE", + [KEY_CAMERA_ACCESS_ENABLE] = "KEY_CAMERA_ACCESS_ENABLE", + [KEY_CAMERA_ACCESS_DISABLE] = "KEY_CAMERA_ACCESS_DISABLE", + [KEY_CAMERA_ACCESS_TOGGLE] = "KEY_CAMERA_ACCESS_TOGGLE", + [KEY_ACCESSIBILITY] = "KEY_ACCESSIBILITY", + [KEY_DO_NOT_DISTURB] = "KEY_DO_NOT_DISTURB", + [KEY_BRIGHTNESS_MIN] = "KEY_BRIGHTNESS_MIN", + [KEY_BRIGHTNESS_MAX] = "KEY_BRIGHTNESS_MAX", + [KEY_EPRIVACY_SCREEN_ON] = "KEY_EPRIVACY_SCREEN_ON", + [KEY_EPRIVACY_SCREEN_OFF] = "KEY_EPRIVACY_SCREEN_OFF", + [KEY_ACTION_ON_SELECTION] = "KEY_ACTION_ON_SELECTION", + [KEY_CONTEXTUAL_INSERT] = "KEY_CONTEXTUAL_INSERT", + [KEY_CONTEXTUAL_QUERY] = "KEY_CONTEXTUAL_QUERY", + [KEY_KBDINPUTASSIST_PREV] = "KEY_KBDINPUTASSIST_PREV", + [KEY_KBDINPUTASSIST_NEXT] = "KEY_KBDINPUTASSIST_NEXT", + [KEY_KBDINPUTASSIST_PREVGROUP] = "KEY_KBDINPUTASSIST_PREVGROUP", + [KEY_KBDINPUTASSIST_NEXTGROUP] = "KEY_KBDINPUTASSIST_NEXTGROUP", + [KEY_KBDINPUTASSIST_ACCEPT] = "KEY_KBDINPUTASSIST_ACCEPT", + [KEY_KBDINPUTASSIST_CANCEL] = "KEY_KBDINPUTASSIST_CANCEL", + [KEY_RIGHT_UP] = "KEY_RIGHT_UP", + [KEY_RIGHT_DOWN] = "KEY_RIGHT_DOWN", + [KEY_LEFT_UP] = "KEY_LEFT_UP", + [KEY_LEFT_DOWN] = "KEY_LEFT_DOWN", + [KEY_ROOT_MENU] = "KEY_ROOT_MENU", + [KEY_MEDIA_TOP_MENU] = "KEY_MEDIA_TOP_MENU", + [KEY_NUMERIC_11] = "KEY_NUMERIC_11", + [KEY_NUMERIC_12] = "KEY_NUMERIC_12", + [KEY_AUDIO_DESC] = "KEY_AUDIO_DESC", + [KEY_3D_MODE] = "KEY_3D_MODE", + [KEY_NEXT_FAVORITE] = "KEY_NEXT_FAVORITE", + [KEY_STOP_RECORD] = "KEY_STOP_RECORD", + [KEY_PAUSE_RECORD] = "KEY_PAUSE_RECORD", + [KEY_VOD] = "KEY_VOD", + [KEY_UNMUTE] = "KEY_UNMUTE", + [KEY_FASTREVERSE] = "KEY_FASTREVERSE", + [KEY_SLOWREVERSE] = "KEY_SLOWREVERSE", + [KEY_DATA] = "KEY_DATA", + [KEY_ONSCREEN_KEYBOARD] = "KEY_ONSCREEN_KEYBOARD", + [KEY_PRIVACY_SCREEN_TOGGLE] = "KEY_PRIVACY_SCREEN_TOGGLE", + [KEY_SELECTIVE_SCREENSHOT] = "KEY_SELECTIVE_SCREENSHOT", + [KEY_NEXT_ELEMENT] = "KEY_NEXT_ELEMENT", + [KEY_PREVIOUS_ELEMENT] = "KEY_PREVIOUS_ELEMENT", + [KEY_AUTOPILOT_ENGAGE_TOGGLE] = "KEY_AUTOPILOT_ENGAGE_TOGGLE", + [KEY_MARK_WAYPOINT] = "KEY_MARK_WAYPOINT", + [KEY_SOS] = "KEY_SOS", + [KEY_NAV_CHART] = "KEY_NAV_CHART", + [KEY_FISHING_CHART] = "KEY_FISHING_CHART", + [KEY_SINGLE_RANGE_RADAR] = "KEY_SINGLE_RANGE_RADAR", + [KEY_DUAL_RANGE_RADAR] = "KEY_DUAL_RANGE_RADAR", + [KEY_RADAR_OVERLAY] = "KEY_RADAR_OVERLAY", + [KEY_TRADITIONAL_SONAR] = "KEY_TRADITIONAL_SONAR", + [KEY_CLEARVU_SONAR] = "KEY_CLEARVU_SONAR", + [KEY_SIDEVU_SONAR] = "KEY_SIDEVU_SONAR", + [KEY_NAV_INFO] = "KEY_NAV_INFO", + [KEY_BRIGHTNESS_MENU] = "KEY_BRIGHTNESS_MENU", + [KEY_MACRO1] = "KEY_MACRO1", + [KEY_MACRO2] = "KEY_MACRO2", + [KEY_MACRO3] = "KEY_MACRO3", + [KEY_MACRO4] = "KEY_MACRO4", + [KEY_MACRO5] = "KEY_MACRO5", + [KEY_MACRO6] = "KEY_MACRO6", + [KEY_MACRO7] = "KEY_MACRO7", + [KEY_MACRO8] = "KEY_MACRO8", + [KEY_MACRO9] = "KEY_MACRO9", + [KEY_MACRO10] = "KEY_MACRO10", + [KEY_MACRO11] = "KEY_MACRO11", + [KEY_MACRO12] = "KEY_MACRO12", + [KEY_MACRO13] = "KEY_MACRO13", + [KEY_MACRO14] = "KEY_MACRO14", + [KEY_MACRO15] = "KEY_MACRO15", + [KEY_MACRO16] = "KEY_MACRO16", + [KEY_MACRO17] = "KEY_MACRO17", + [KEY_MACRO18] = "KEY_MACRO18", + [KEY_MACRO19] = "KEY_MACRO19", + [KEY_MACRO20] = "KEY_MACRO20", + [KEY_MACRO21] = "KEY_MACRO21", + [KEY_MACRO22] = "KEY_MACRO22", + [KEY_MACRO23] = "KEY_MACRO23", + [KEY_MACRO24] = "KEY_MACRO24", + [KEY_MACRO25] = "KEY_MACRO25", + [KEY_MACRO26] = "KEY_MACRO26", + [KEY_MACRO27] = "KEY_MACRO27", + [KEY_MACRO28] = "KEY_MACRO28", + [KEY_MACRO29] = "KEY_MACRO29", + [KEY_MACRO30] = "KEY_MACRO30", + [KEY_MACRO_RECORD_START] = "KEY_MACRO_RECORD_START", + [KEY_MACRO_RECORD_STOP] = "KEY_MACRO_RECORD_STOP", + [KEY_MACRO_PRESET_CYCLE] = "KEY_MACRO_PRESET_CYCLE", + [KEY_MACRO_PRESET1] = "KEY_MACRO_PRESET1", + [KEY_MACRO_PRESET2] = "KEY_MACRO_PRESET2", + [KEY_MACRO_PRESET3] = "KEY_MACRO_PRESET3", + [KEY_KBD_LCD_MENU1] = "KEY_KBD_LCD_MENU1", + [KEY_KBD_LCD_MENU2] = "KEY_KBD_LCD_MENU2", + [KEY_KBD_LCD_MENU3] = "KEY_KBD_LCD_MENU3", + [KEY_KBD_LCD_MENU4] = "KEY_KBD_LCD_MENU4", + [KEY_KBD_LCD_MENU5] = "KEY_KBD_LCD_MENU5", + [KEY_PERFORMANCE] = "KEY_PERFORMANCE", + [KEY_MAX] = "KEY_MAX", + [BTN_0] = "BTN_0", + [BTN_1] = "BTN_1", + [BTN_2] = "BTN_2", + [BTN_3] = "BTN_3", + [BTN_4] = "BTN_4", + [BTN_5] = "BTN_5", + [BTN_6] = "BTN_6", + [BTN_7] = "BTN_7", + [BTN_8] = "BTN_8", + [BTN_9] = "BTN_9", + [BTN_LEFT] = "BTN_LEFT", + [BTN_RIGHT] = "BTN_RIGHT", + [BTN_MIDDLE] = "BTN_MIDDLE", + [BTN_SIDE] = "BTN_SIDE", + [BTN_EXTRA] = "BTN_EXTRA", + [BTN_FORWARD] = "BTN_FORWARD", + [BTN_BACK] = "BTN_BACK", + [BTN_TASK] = "BTN_TASK", + [BTN_TRIGGER] = "BTN_TRIGGER", + [BTN_THUMB] = "BTN_THUMB", + [BTN_THUMB2] = "BTN_THUMB2", + [BTN_TOP] = "BTN_TOP", + [BTN_TOP2] = "BTN_TOP2", + [BTN_PINKIE] = "BTN_PINKIE", + [BTN_BASE] = "BTN_BASE", + [BTN_BASE2] = "BTN_BASE2", + [BTN_BASE3] = "BTN_BASE3", + [BTN_BASE4] = "BTN_BASE4", + [BTN_BASE5] = "BTN_BASE5", + [BTN_BASE6] = "BTN_BASE6", + [BTN_DEAD] = "BTN_DEAD", + [BTN_SOUTH] = "BTN_SOUTH", + [BTN_EAST] = "BTN_EAST", + [BTN_C] = "BTN_C", + [BTN_NORTH] = "BTN_NORTH", + [BTN_WEST] = "BTN_WEST", + [BTN_Z] = "BTN_Z", + [BTN_TL] = "BTN_TL", + [BTN_TR] = "BTN_TR", + [BTN_TL2] = "BTN_TL2", + [BTN_TR2] = "BTN_TR2", + [BTN_SELECT] = "BTN_SELECT", + [BTN_START] = "BTN_START", + [BTN_MODE] = "BTN_MODE", + [BTN_THUMBL] = "BTN_THUMBL", + [BTN_THUMBR] = "BTN_THUMBR", + [BTN_TOOL_PEN] = "BTN_TOOL_PEN", + [BTN_TOOL_RUBBER] = "BTN_TOOL_RUBBER", + [BTN_TOOL_BRUSH] = "BTN_TOOL_BRUSH", + [BTN_TOOL_PENCIL] = "BTN_TOOL_PENCIL", + [BTN_TOOL_AIRBRUSH] = "BTN_TOOL_AIRBRUSH", + [BTN_TOOL_FINGER] = "BTN_TOOL_FINGER", + [BTN_TOOL_MOUSE] = "BTN_TOOL_MOUSE", + [BTN_TOOL_LENS] = "BTN_TOOL_LENS", + [BTN_TOOL_QUINTTAP] = "BTN_TOOL_QUINTTAP", + [BTN_STYLUS3] = "BTN_STYLUS3", + [BTN_TOUCH] = "BTN_TOUCH", + [BTN_STYLUS] = "BTN_STYLUS", + [BTN_STYLUS2] = "BTN_STYLUS2", + [BTN_TOOL_DOUBLETAP] = "BTN_TOOL_DOUBLETAP", + [BTN_TOOL_TRIPLETAP] = "BTN_TOOL_TRIPLETAP", + [BTN_TOOL_QUADTAP] = "BTN_TOOL_QUADTAP", + [BTN_GEAR_DOWN] = "BTN_GEAR_DOWN", + [BTN_GEAR_UP] = "BTN_GEAR_UP", + [BTN_DPAD_UP] = "BTN_DPAD_UP", + [BTN_DPAD_DOWN] = "BTN_DPAD_DOWN", + [BTN_DPAD_LEFT] = "BTN_DPAD_LEFT", + [BTN_DPAD_RIGHT] = "BTN_DPAD_RIGHT", + [BTN_GRIPL] = "BTN_GRIPL", + [BTN_GRIPR] = "BTN_GRIPR", + [BTN_GRIPL2] = "BTN_GRIPL2", + [BTN_GRIPR2] = "BTN_GRIPR2", + [BTN_TRIGGER_HAPPY1] = "BTN_TRIGGER_HAPPY1", + [BTN_TRIGGER_HAPPY2] = "BTN_TRIGGER_HAPPY2", + [BTN_TRIGGER_HAPPY3] = "BTN_TRIGGER_HAPPY3", + [BTN_TRIGGER_HAPPY4] = "BTN_TRIGGER_HAPPY4", + [BTN_TRIGGER_HAPPY5] = "BTN_TRIGGER_HAPPY5", + [BTN_TRIGGER_HAPPY6] = "BTN_TRIGGER_HAPPY6", + [BTN_TRIGGER_HAPPY7] = "BTN_TRIGGER_HAPPY7", + [BTN_TRIGGER_HAPPY8] = "BTN_TRIGGER_HAPPY8", + [BTN_TRIGGER_HAPPY9] = "BTN_TRIGGER_HAPPY9", + [BTN_TRIGGER_HAPPY10] = "BTN_TRIGGER_HAPPY10", + [BTN_TRIGGER_HAPPY11] = "BTN_TRIGGER_HAPPY11", + [BTN_TRIGGER_HAPPY12] = "BTN_TRIGGER_HAPPY12", + [BTN_TRIGGER_HAPPY13] = "BTN_TRIGGER_HAPPY13", + [BTN_TRIGGER_HAPPY14] = "BTN_TRIGGER_HAPPY14", + [BTN_TRIGGER_HAPPY15] = "BTN_TRIGGER_HAPPY15", + [BTN_TRIGGER_HAPPY16] = "BTN_TRIGGER_HAPPY16", + [BTN_TRIGGER_HAPPY17] = "BTN_TRIGGER_HAPPY17", + [BTN_TRIGGER_HAPPY18] = "BTN_TRIGGER_HAPPY18", + [BTN_TRIGGER_HAPPY19] = "BTN_TRIGGER_HAPPY19", + [BTN_TRIGGER_HAPPY20] = "BTN_TRIGGER_HAPPY20", + [BTN_TRIGGER_HAPPY21] = "BTN_TRIGGER_HAPPY21", + [BTN_TRIGGER_HAPPY22] = "BTN_TRIGGER_HAPPY22", + [BTN_TRIGGER_HAPPY23] = "BTN_TRIGGER_HAPPY23", + [BTN_TRIGGER_HAPPY24] = "BTN_TRIGGER_HAPPY24", + [BTN_TRIGGER_HAPPY25] = "BTN_TRIGGER_HAPPY25", + [BTN_TRIGGER_HAPPY26] = "BTN_TRIGGER_HAPPY26", + [BTN_TRIGGER_HAPPY27] = "BTN_TRIGGER_HAPPY27", + [BTN_TRIGGER_HAPPY28] = "BTN_TRIGGER_HAPPY28", + [BTN_TRIGGER_HAPPY29] = "BTN_TRIGGER_HAPPY29", + [BTN_TRIGGER_HAPPY30] = "BTN_TRIGGER_HAPPY30", + [BTN_TRIGGER_HAPPY31] = "BTN_TRIGGER_HAPPY31", + [BTN_TRIGGER_HAPPY32] = "BTN_TRIGGER_HAPPY32", + [BTN_TRIGGER_HAPPY33] = "BTN_TRIGGER_HAPPY33", + [BTN_TRIGGER_HAPPY34] = "BTN_TRIGGER_HAPPY34", + [BTN_TRIGGER_HAPPY35] = "BTN_TRIGGER_HAPPY35", + [BTN_TRIGGER_HAPPY36] = "BTN_TRIGGER_HAPPY36", + [BTN_TRIGGER_HAPPY37] = "BTN_TRIGGER_HAPPY37", + [BTN_TRIGGER_HAPPY38] = "BTN_TRIGGER_HAPPY38", + [BTN_TRIGGER_HAPPY39] = "BTN_TRIGGER_HAPPY39", + [BTN_TRIGGER_HAPPY40] = "BTN_TRIGGER_HAPPY40", +}; + +static const char * const led_map[LED_MAX + 1] = { + [LED_NUML] = "LED_NUML", + [LED_CAPSL] = "LED_CAPSL", + [LED_SCROLLL] = "LED_SCROLLL", + [LED_COMPOSE] = "LED_COMPOSE", + [LED_KANA] = "LED_KANA", + [LED_SLEEP] = "LED_SLEEP", + [LED_SUSPEND] = "LED_SUSPEND", + [LED_MUTE] = "LED_MUTE", + [LED_MISC] = "LED_MISC", + [LED_MAIL] = "LED_MAIL", + [LED_CHARGING] = "LED_CHARGING", + [LED_MAX] = "LED_MAX", +}; + +static const char * const snd_map[SND_MAX + 1] = { + [SND_CLICK] = "SND_CLICK", + [SND_BELL] = "SND_BELL", + [SND_TONE] = "SND_TONE", + [SND_MAX] = "SND_MAX", +}; + +static const char * const msc_map[MSC_MAX + 1] = { + [MSC_SERIAL] = "MSC_SERIAL", + [MSC_PULSELED] = "MSC_PULSELED", + [MSC_GESTURE] = "MSC_GESTURE", + [MSC_RAW] = "MSC_RAW", + [MSC_SCAN] = "MSC_SCAN", + [MSC_TIMESTAMP] = "MSC_TIMESTAMP", + [MSC_MAX] = "MSC_MAX", +}; + +static const char * const sw_map[SW_MAX + 1] = { + [SW_LID] = "SW_LID", + [SW_TABLET_MODE] = "SW_TABLET_MODE", + [SW_HEADPHONE_INSERT] = "SW_HEADPHONE_INSERT", + [SW_RFKILL_ALL] = "SW_RFKILL_ALL", + [SW_MICROPHONE_INSERT] = "SW_MICROPHONE_INSERT", + [SW_DOCK] = "SW_DOCK", + [SW_LINEOUT_INSERT] = "SW_LINEOUT_INSERT", + [SW_JACK_PHYSICAL_INSERT] = "SW_JACK_PHYSICAL_INSERT", + [SW_VIDEOOUT_INSERT] = "SW_VIDEOOUT_INSERT", + [SW_CAMERA_LENS_COVER] = "SW_CAMERA_LENS_COVER", + [SW_KEYPAD_SLIDE] = "SW_KEYPAD_SLIDE", + [SW_FRONT_PROXIMITY] = "SW_FRONT_PROXIMITY", + [SW_ROTATE_LOCK] = "SW_ROTATE_LOCK", + [SW_LINEIN_INSERT] = "SW_LINEIN_INSERT", + [SW_MUTE_DEVICE] = "SW_MUTE_DEVICE", + [SW_PEN_INSERTED] = "SW_PEN_INSERTED", + [SW_MACHINE_COVER] = "SW_MACHINE_COVER", + [SW_USB_INSERT] = "SW_USB_INSERT", +}; + +static const char * const ff_map[FF_MAX + 1] = { + [FF_STATUS_STOPPED] = "FF_STATUS_STOPPED", + [FF_STATUS_MAX] = "FF_STATUS_MAX", + [FF_HAPTIC] = "FF_HAPTIC", + [FF_RUMBLE] = "FF_RUMBLE", + [FF_PERIODIC] = "FF_PERIODIC", + [FF_CONSTANT] = "FF_CONSTANT", + [FF_SPRING] = "FF_SPRING", + [FF_FRICTION] = "FF_FRICTION", + [FF_DAMPER] = "FF_DAMPER", + [FF_INERTIA] = "FF_INERTIA", + [FF_RAMP] = "FF_RAMP", + [FF_SQUARE] = "FF_SQUARE", + [FF_TRIANGLE] = "FF_TRIANGLE", + [FF_SINE] = "FF_SINE", + [FF_SAW_UP] = "FF_SAW_UP", + [FF_SAW_DOWN] = "FF_SAW_DOWN", + [FF_CUSTOM] = "FF_CUSTOM", + [FF_GAIN] = "FF_GAIN", + [FF_AUTOCENTER] = "FF_AUTOCENTER", + [FF_MAX] = "FF_MAX", +}; + +static const char * const syn_map[SYN_MAX + 1] = { + [SYN_REPORT] = "SYN_REPORT", + [SYN_CONFIG] = "SYN_CONFIG", + [SYN_MT_REPORT] = "SYN_MT_REPORT", + [SYN_DROPPED] = "SYN_DROPPED", + [SYN_MAX] = "SYN_MAX", +}; + +static const char * const rep_map[REP_MAX + 1] = { + [REP_DELAY] = "REP_DELAY", + [REP_PERIOD] = "REP_PERIOD", +}; + +static const char * const input_prop_map[INPUT_PROP_MAX + 1] = { + [INPUT_PROP_POINTER] = "INPUT_PROP_POINTER", + [INPUT_PROP_DIRECT] = "INPUT_PROP_DIRECT", + [INPUT_PROP_BUTTONPAD] = "INPUT_PROP_BUTTONPAD", + [INPUT_PROP_SEMI_MT] = "INPUT_PROP_SEMI_MT", + [INPUT_PROP_TOPBUTTONPAD] = "INPUT_PROP_TOPBUTTONPAD", + [INPUT_PROP_POINTING_STICK] = "INPUT_PROP_POINTING_STICK", + [INPUT_PROP_ACCELEROMETER] = "INPUT_PROP_ACCELEROMETER", + [INPUT_PROP_PRESSUREPAD] = "INPUT_PROP_PRESSUREPAD", + [INPUT_PROP_MAX] = "INPUT_PROP_MAX", +}; + +static const char * const mt_tool_map[MT_TOOL_MAX + 1] = { + [MT_TOOL_FINGER] = "MT_TOOL_FINGER", + [MT_TOOL_PEN] = "MT_TOOL_PEN", + [MT_TOOL_PALM] = "MT_TOOL_PALM", + [MT_TOOL_DIAL] = "MT_TOOL_DIAL", + [MT_TOOL_MAX] = "MT_TOOL_MAX", +}; + +static const char * const * const event_type_map[EV_MAX + 1] = { + [EV_REL] = rel_map, + [EV_ABS] = abs_map, + [EV_KEY] = key_map, + [EV_LED] = led_map, + [EV_SND] = snd_map, + [EV_MSC] = msc_map, + [EV_SW] = sw_map, + [EV_FF] = ff_map, + [EV_SYN] = syn_map, + [EV_REP] = rep_map, +}; + +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winitializer-overrides" +#elif __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverride-init" +#endif +static const int ev_max[EV_MAX + 1] = { + SYN_MAX, + KEY_MAX, + REL_MAX, + ABS_MAX, + MSC_MAX, + SW_MAX, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + LED_MAX, + SND_MAX, + -1, + REP_MAX, + FF_MAX, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, +}; +#if __clang__ +#pragma clang diagnostic pop /* "-Winitializer-overrides" */ +#elif __GNUC__ +#pragma GCC diagnostic pop /* "-Woverride-init" */ +#endif + +struct name_entry { + const char *name; + unsigned int value; +}; + +static const struct name_entry tool_type_names[] = { + { .name = "MT_TOOL_DIAL", .value = MT_TOOL_DIAL }, + { .name = "MT_TOOL_FINGER", .value = MT_TOOL_FINGER }, + { .name = "MT_TOOL_MAX", .value = MT_TOOL_MAX }, + { .name = "MT_TOOL_PALM", .value = MT_TOOL_PALM }, + { .name = "MT_TOOL_PEN", .value = MT_TOOL_PEN }, +}; + +static const struct name_entry ev_names[] = { + { .name = "EV_ABS", .value = EV_ABS }, + { .name = "EV_FF", .value = EV_FF }, + { .name = "EV_FF_STATUS", .value = EV_FF_STATUS }, + { .name = "EV_KEY", .value = EV_KEY }, + { .name = "EV_LED", .value = EV_LED }, + { .name = "EV_MAX", .value = EV_MAX }, + { .name = "EV_MSC", .value = EV_MSC }, + { .name = "EV_PWR", .value = EV_PWR }, + { .name = "EV_REL", .value = EV_REL }, + { .name = "EV_REP", .value = EV_REP }, + { .name = "EV_SND", .value = EV_SND }, + { .name = "EV_SW", .value = EV_SW }, + { .name = "EV_SYN", .value = EV_SYN }, +}; + +static const struct name_entry code_names[] = { + { .name = "ABS_BRAKE", .value = ABS_BRAKE }, + { .name = "ABS_DISTANCE", .value = ABS_DISTANCE }, + { .name = "ABS_GAS", .value = ABS_GAS }, + { .name = "ABS_HAT0X", .value = ABS_HAT0X }, + { .name = "ABS_HAT0Y", .value = ABS_HAT0Y }, + { .name = "ABS_HAT1X", .value = ABS_HAT1X }, + { .name = "ABS_HAT1Y", .value = ABS_HAT1Y }, + { .name = "ABS_HAT2X", .value = ABS_HAT2X }, + { .name = "ABS_HAT2Y", .value = ABS_HAT2Y }, + { .name = "ABS_HAT3X", .value = ABS_HAT3X }, + { .name = "ABS_HAT3Y", .value = ABS_HAT3Y }, + { .name = "ABS_MAX", .value = ABS_MAX }, + { .name = "ABS_MISC", .value = ABS_MISC }, + { .name = "ABS_MT_BLOB_ID", .value = ABS_MT_BLOB_ID }, + { .name = "ABS_MT_DISTANCE", .value = ABS_MT_DISTANCE }, + { .name = "ABS_MT_ORIENTATION", .value = ABS_MT_ORIENTATION }, + { .name = "ABS_MT_POSITION_X", .value = ABS_MT_POSITION_X }, + { .name = "ABS_MT_POSITION_Y", .value = ABS_MT_POSITION_Y }, + { .name = "ABS_MT_PRESSURE", .value = ABS_MT_PRESSURE }, + { .name = "ABS_MT_SLOT", .value = ABS_MT_SLOT }, + { .name = "ABS_MT_TOOL_TYPE", .value = ABS_MT_TOOL_TYPE }, + { .name = "ABS_MT_TOOL_X", .value = ABS_MT_TOOL_X }, + { .name = "ABS_MT_TOOL_Y", .value = ABS_MT_TOOL_Y }, + { .name = "ABS_MT_TOUCH_MAJOR", .value = ABS_MT_TOUCH_MAJOR }, + { .name = "ABS_MT_TOUCH_MINOR", .value = ABS_MT_TOUCH_MINOR }, + { .name = "ABS_MT_TRACKING_ID", .value = ABS_MT_TRACKING_ID }, + { .name = "ABS_MT_WIDTH_MAJOR", .value = ABS_MT_WIDTH_MAJOR }, + { .name = "ABS_MT_WIDTH_MINOR", .value = ABS_MT_WIDTH_MINOR }, + { .name = "ABS_PRESSURE", .value = ABS_PRESSURE }, + { .name = "ABS_PROFILE", .value = ABS_PROFILE }, + { .name = "ABS_RESERVED", .value = ABS_RESERVED }, + { .name = "ABS_RUDDER", .value = ABS_RUDDER }, + { .name = "ABS_RX", .value = ABS_RX }, + { .name = "ABS_RY", .value = ABS_RY }, + { .name = "ABS_RZ", .value = ABS_RZ }, + { .name = "ABS_SND_PROFILE", .value = ABS_SND_PROFILE }, + { .name = "ABS_THROTTLE", .value = ABS_THROTTLE }, + { .name = "ABS_TILT_X", .value = ABS_TILT_X }, + { .name = "ABS_TILT_Y", .value = ABS_TILT_Y }, + { .name = "ABS_TOOL_WIDTH", .value = ABS_TOOL_WIDTH }, + { .name = "ABS_VOLUME", .value = ABS_VOLUME }, + { .name = "ABS_WHEEL", .value = ABS_WHEEL }, + { .name = "ABS_X", .value = ABS_X }, + { .name = "ABS_Y", .value = ABS_Y }, + { .name = "ABS_Z", .value = ABS_Z }, + { .name = "BTN_0", .value = BTN_0 }, + { .name = "BTN_1", .value = BTN_1 }, + { .name = "BTN_2", .value = BTN_2 }, + { .name = "BTN_3", .value = BTN_3 }, + { .name = "BTN_4", .value = BTN_4 }, + { .name = "BTN_5", .value = BTN_5 }, + { .name = "BTN_6", .value = BTN_6 }, + { .name = "BTN_7", .value = BTN_7 }, + { .name = "BTN_8", .value = BTN_8 }, + { .name = "BTN_9", .value = BTN_9 }, + { .name = "BTN_A", .value = BTN_A }, + { .name = "BTN_B", .value = BTN_B }, + { .name = "BTN_BACK", .value = BTN_BACK }, + { .name = "BTN_BASE", .value = BTN_BASE }, + { .name = "BTN_BASE2", .value = BTN_BASE2 }, + { .name = "BTN_BASE3", .value = BTN_BASE3 }, + { .name = "BTN_BASE4", .value = BTN_BASE4 }, + { .name = "BTN_BASE5", .value = BTN_BASE5 }, + { .name = "BTN_BASE6", .value = BTN_BASE6 }, + { .name = "BTN_C", .value = BTN_C }, + { .name = "BTN_DEAD", .value = BTN_DEAD }, + { .name = "BTN_DPAD_DOWN", .value = BTN_DPAD_DOWN }, + { .name = "BTN_DPAD_LEFT", .value = BTN_DPAD_LEFT }, + { .name = "BTN_DPAD_RIGHT", .value = BTN_DPAD_RIGHT }, + { .name = "BTN_DPAD_UP", .value = BTN_DPAD_UP }, + { .name = "BTN_EAST", .value = BTN_EAST }, + { .name = "BTN_EXTRA", .value = BTN_EXTRA }, + { .name = "BTN_FORWARD", .value = BTN_FORWARD }, + { .name = "BTN_GEAR_DOWN", .value = BTN_GEAR_DOWN }, + { .name = "BTN_GEAR_UP", .value = BTN_GEAR_UP }, + { .name = "BTN_GRIPL", .value = BTN_GRIPL }, + { .name = "BTN_GRIPL2", .value = BTN_GRIPL2 }, + { .name = "BTN_GRIPR", .value = BTN_GRIPR }, + { .name = "BTN_GRIPR2", .value = BTN_GRIPR2 }, + { .name = "BTN_LEFT", .value = BTN_LEFT }, + { .name = "BTN_MIDDLE", .value = BTN_MIDDLE }, + { .name = "BTN_MODE", .value = BTN_MODE }, + { .name = "BTN_NORTH", .value = BTN_NORTH }, + { .name = "BTN_PINKIE", .value = BTN_PINKIE }, + { .name = "BTN_RIGHT", .value = BTN_RIGHT }, + { .name = "BTN_SELECT", .value = BTN_SELECT }, + { .name = "BTN_SIDE", .value = BTN_SIDE }, + { .name = "BTN_SOUTH", .value = BTN_SOUTH }, + { .name = "BTN_START", .value = BTN_START }, + { .name = "BTN_STYLUS", .value = BTN_STYLUS }, + { .name = "BTN_STYLUS2", .value = BTN_STYLUS2 }, + { .name = "BTN_STYLUS3", .value = BTN_STYLUS3 }, + { .name = "BTN_TASK", .value = BTN_TASK }, + { .name = "BTN_THUMB", .value = BTN_THUMB }, + { .name = "BTN_THUMB2", .value = BTN_THUMB2 }, + { .name = "BTN_THUMBL", .value = BTN_THUMBL }, + { .name = "BTN_THUMBR", .value = BTN_THUMBR }, + { .name = "BTN_TL", .value = BTN_TL }, + { .name = "BTN_TL2", .value = BTN_TL2 }, + { .name = "BTN_TOOL_AIRBRUSH", .value = BTN_TOOL_AIRBRUSH }, + { .name = "BTN_TOOL_BRUSH", .value = BTN_TOOL_BRUSH }, + { .name = "BTN_TOOL_DOUBLETAP", .value = BTN_TOOL_DOUBLETAP }, + { .name = "BTN_TOOL_FINGER", .value = BTN_TOOL_FINGER }, + { .name = "BTN_TOOL_LENS", .value = BTN_TOOL_LENS }, + { .name = "BTN_TOOL_MOUSE", .value = BTN_TOOL_MOUSE }, + { .name = "BTN_TOOL_PEN", .value = BTN_TOOL_PEN }, + { .name = "BTN_TOOL_PENCIL", .value = BTN_TOOL_PENCIL }, + { .name = "BTN_TOOL_QUADTAP", .value = BTN_TOOL_QUADTAP }, + { .name = "BTN_TOOL_QUINTTAP", .value = BTN_TOOL_QUINTTAP }, + { .name = "BTN_TOOL_RUBBER", .value = BTN_TOOL_RUBBER }, + { .name = "BTN_TOOL_TRIPLETAP", .value = BTN_TOOL_TRIPLETAP }, + { .name = "BTN_TOP", .value = BTN_TOP }, + { .name = "BTN_TOP2", .value = BTN_TOP2 }, + { .name = "BTN_TOUCH", .value = BTN_TOUCH }, + { .name = "BTN_TR", .value = BTN_TR }, + { .name = "BTN_TR2", .value = BTN_TR2 }, + { .name = "BTN_TRIGGER", .value = BTN_TRIGGER }, + { .name = "BTN_TRIGGER_HAPPY1", .value = BTN_TRIGGER_HAPPY1 }, + { .name = "BTN_TRIGGER_HAPPY10", .value = BTN_TRIGGER_HAPPY10 }, + { .name = "BTN_TRIGGER_HAPPY11", .value = BTN_TRIGGER_HAPPY11 }, + { .name = "BTN_TRIGGER_HAPPY12", .value = BTN_TRIGGER_HAPPY12 }, + { .name = "BTN_TRIGGER_HAPPY13", .value = BTN_TRIGGER_HAPPY13 }, + { .name = "BTN_TRIGGER_HAPPY14", .value = BTN_TRIGGER_HAPPY14 }, + { .name = "BTN_TRIGGER_HAPPY15", .value = BTN_TRIGGER_HAPPY15 }, + { .name = "BTN_TRIGGER_HAPPY16", .value = BTN_TRIGGER_HAPPY16 }, + { .name = "BTN_TRIGGER_HAPPY17", .value = BTN_TRIGGER_HAPPY17 }, + { .name = "BTN_TRIGGER_HAPPY18", .value = BTN_TRIGGER_HAPPY18 }, + { .name = "BTN_TRIGGER_HAPPY19", .value = BTN_TRIGGER_HAPPY19 }, + { .name = "BTN_TRIGGER_HAPPY2", .value = BTN_TRIGGER_HAPPY2 }, + { .name = "BTN_TRIGGER_HAPPY20", .value = BTN_TRIGGER_HAPPY20 }, + { .name = "BTN_TRIGGER_HAPPY21", .value = BTN_TRIGGER_HAPPY21 }, + { .name = "BTN_TRIGGER_HAPPY22", .value = BTN_TRIGGER_HAPPY22 }, + { .name = "BTN_TRIGGER_HAPPY23", .value = BTN_TRIGGER_HAPPY23 }, + { .name = "BTN_TRIGGER_HAPPY24", .value = BTN_TRIGGER_HAPPY24 }, + { .name = "BTN_TRIGGER_HAPPY25", .value = BTN_TRIGGER_HAPPY25 }, + { .name = "BTN_TRIGGER_HAPPY26", .value = BTN_TRIGGER_HAPPY26 }, + { .name = "BTN_TRIGGER_HAPPY27", .value = BTN_TRIGGER_HAPPY27 }, + { .name = "BTN_TRIGGER_HAPPY28", .value = BTN_TRIGGER_HAPPY28 }, + { .name = "BTN_TRIGGER_HAPPY29", .value = BTN_TRIGGER_HAPPY29 }, + { .name = "BTN_TRIGGER_HAPPY3", .value = BTN_TRIGGER_HAPPY3 }, + { .name = "BTN_TRIGGER_HAPPY30", .value = BTN_TRIGGER_HAPPY30 }, + { .name = "BTN_TRIGGER_HAPPY31", .value = BTN_TRIGGER_HAPPY31 }, + { .name = "BTN_TRIGGER_HAPPY32", .value = BTN_TRIGGER_HAPPY32 }, + { .name = "BTN_TRIGGER_HAPPY33", .value = BTN_TRIGGER_HAPPY33 }, + { .name = "BTN_TRIGGER_HAPPY34", .value = BTN_TRIGGER_HAPPY34 }, + { .name = "BTN_TRIGGER_HAPPY35", .value = BTN_TRIGGER_HAPPY35 }, + { .name = "BTN_TRIGGER_HAPPY36", .value = BTN_TRIGGER_HAPPY36 }, + { .name = "BTN_TRIGGER_HAPPY37", .value = BTN_TRIGGER_HAPPY37 }, + { .name = "BTN_TRIGGER_HAPPY38", .value = BTN_TRIGGER_HAPPY38 }, + { .name = "BTN_TRIGGER_HAPPY39", .value = BTN_TRIGGER_HAPPY39 }, + { .name = "BTN_TRIGGER_HAPPY4", .value = BTN_TRIGGER_HAPPY4 }, + { .name = "BTN_TRIGGER_HAPPY40", .value = BTN_TRIGGER_HAPPY40 }, + { .name = "BTN_TRIGGER_HAPPY5", .value = BTN_TRIGGER_HAPPY5 }, + { .name = "BTN_TRIGGER_HAPPY6", .value = BTN_TRIGGER_HAPPY6 }, + { .name = "BTN_TRIGGER_HAPPY7", .value = BTN_TRIGGER_HAPPY7 }, + { .name = "BTN_TRIGGER_HAPPY8", .value = BTN_TRIGGER_HAPPY8 }, + { .name = "BTN_TRIGGER_HAPPY9", .value = BTN_TRIGGER_HAPPY9 }, + { .name = "BTN_WEST", .value = BTN_WEST }, + { .name = "BTN_X", .value = BTN_X }, + { .name = "BTN_Y", .value = BTN_Y }, + { .name = "BTN_Z", .value = BTN_Z }, + { .name = "FF_AUTOCENTER", .value = FF_AUTOCENTER }, + { .name = "FF_CONSTANT", .value = FF_CONSTANT }, + { .name = "FF_CUSTOM", .value = FF_CUSTOM }, + { .name = "FF_DAMPER", .value = FF_DAMPER }, + { .name = "FF_FRICTION", .value = FF_FRICTION }, + { .name = "FF_GAIN", .value = FF_GAIN }, + { .name = "FF_HAPTIC", .value = FF_HAPTIC }, + { .name = "FF_INERTIA", .value = FF_INERTIA }, + { .name = "FF_MAX", .value = FF_MAX }, + { .name = "FF_PERIODIC", .value = FF_PERIODIC }, + { .name = "FF_RAMP", .value = FF_RAMP }, + { .name = "FF_RUMBLE", .value = FF_RUMBLE }, + { .name = "FF_SAW_DOWN", .value = FF_SAW_DOWN }, + { .name = "FF_SAW_UP", .value = FF_SAW_UP }, + { .name = "FF_SINE", .value = FF_SINE }, + { .name = "FF_SPRING", .value = FF_SPRING }, + { .name = "FF_SQUARE", .value = FF_SQUARE }, + { .name = "FF_STATUS_MAX", .value = FF_STATUS_MAX }, + { .name = "FF_STATUS_STOPPED", .value = FF_STATUS_STOPPED }, + { .name = "FF_TRIANGLE", .value = FF_TRIANGLE }, + { .name = "KEY_0", .value = KEY_0 }, + { .name = "KEY_1", .value = KEY_1 }, + { .name = "KEY_102ND", .value = KEY_102ND }, + { .name = "KEY_10CHANNELSDOWN", .value = KEY_10CHANNELSDOWN }, + { .name = "KEY_10CHANNELSUP", .value = KEY_10CHANNELSUP }, + { .name = "KEY_2", .value = KEY_2 }, + { .name = "KEY_3", .value = KEY_3 }, + { .name = "KEY_3D_MODE", .value = KEY_3D_MODE }, + { .name = "KEY_4", .value = KEY_4 }, + { .name = "KEY_5", .value = KEY_5 }, + { .name = "KEY_6", .value = KEY_6 }, + { .name = "KEY_7", .value = KEY_7 }, + { .name = "KEY_8", .value = KEY_8 }, + { .name = "KEY_9", .value = KEY_9 }, + { .name = "KEY_A", .value = KEY_A }, + { .name = "KEY_AB", .value = KEY_AB }, + { .name = "KEY_ACCESSIBILITY", .value = KEY_ACCESSIBILITY }, + { .name = "KEY_ACTION_ON_SELECTION", .value = KEY_ACTION_ON_SELECTION }, + { .name = "KEY_ADDRESSBOOK", .value = KEY_ADDRESSBOOK }, + { .name = "KEY_AGAIN", .value = KEY_AGAIN }, + { .name = "KEY_ALL_APPLICATIONS", .value = KEY_ALL_APPLICATIONS }, + { .name = "KEY_ALS_TOGGLE", .value = KEY_ALS_TOGGLE }, + { .name = "KEY_ALTERASE", .value = KEY_ALTERASE }, + { .name = "KEY_ANGLE", .value = KEY_ANGLE }, + { .name = "KEY_APOSTROPHE", .value = KEY_APOSTROPHE }, + { .name = "KEY_APPSELECT", .value = KEY_APPSELECT }, + { .name = "KEY_ARCHIVE", .value = KEY_ARCHIVE }, + { .name = "KEY_ASPECT_RATIO", .value = KEY_ASPECT_RATIO }, + { .name = "KEY_ASSISTANT", .value = KEY_ASSISTANT }, + { .name = "KEY_ATTENDANT_OFF", .value = KEY_ATTENDANT_OFF }, + { .name = "KEY_ATTENDANT_ON", .value = KEY_ATTENDANT_ON }, + { .name = "KEY_ATTENDANT_TOGGLE", .value = KEY_ATTENDANT_TOGGLE }, + { .name = "KEY_AUDIO", .value = KEY_AUDIO }, + { .name = "KEY_AUDIO_DESC", .value = KEY_AUDIO_DESC }, + { .name = "KEY_AUTOPILOT_ENGAGE_TOGGLE", .value = KEY_AUTOPILOT_ENGAGE_TOGGLE }, + { .name = "KEY_AUX", .value = KEY_AUX }, + { .name = "KEY_B", .value = KEY_B }, + { .name = "KEY_BACK", .value = KEY_BACK }, + { .name = "KEY_BACKSLASH", .value = KEY_BACKSLASH }, + { .name = "KEY_BACKSPACE", .value = KEY_BACKSPACE }, + { .name = "KEY_BASSBOOST", .value = KEY_BASSBOOST }, + { .name = "KEY_BATTERY", .value = KEY_BATTERY }, + { .name = "KEY_BLUE", .value = KEY_BLUE }, + { .name = "KEY_BLUETOOTH", .value = KEY_BLUETOOTH }, + { .name = "KEY_BOOKMARKS", .value = KEY_BOOKMARKS }, + { .name = "KEY_BREAK", .value = KEY_BREAK }, + { .name = "KEY_BRIGHTNESSDOWN", .value = KEY_BRIGHTNESSDOWN }, + { .name = "KEY_BRIGHTNESSUP", .value = KEY_BRIGHTNESSUP }, + { .name = "KEY_BRIGHTNESS_AUTO", .value = KEY_BRIGHTNESS_AUTO }, + { .name = "KEY_BRIGHTNESS_CYCLE", .value = KEY_BRIGHTNESS_CYCLE }, + { .name = "KEY_BRIGHTNESS_MAX", .value = KEY_BRIGHTNESS_MAX }, + { .name = "KEY_BRIGHTNESS_MENU", .value = KEY_BRIGHTNESS_MENU }, + { .name = "KEY_BRIGHTNESS_MIN", .value = KEY_BRIGHTNESS_MIN }, + { .name = "KEY_BRL_DOT1", .value = KEY_BRL_DOT1 }, + { .name = "KEY_BRL_DOT10", .value = KEY_BRL_DOT10 }, + { .name = "KEY_BRL_DOT2", .value = KEY_BRL_DOT2 }, + { .name = "KEY_BRL_DOT3", .value = KEY_BRL_DOT3 }, + { .name = "KEY_BRL_DOT4", .value = KEY_BRL_DOT4 }, + { .name = "KEY_BRL_DOT5", .value = KEY_BRL_DOT5 }, + { .name = "KEY_BRL_DOT6", .value = KEY_BRL_DOT6 }, + { .name = "KEY_BRL_DOT7", .value = KEY_BRL_DOT7 }, + { .name = "KEY_BRL_DOT8", .value = KEY_BRL_DOT8 }, + { .name = "KEY_BRL_DOT9", .value = KEY_BRL_DOT9 }, + { .name = "KEY_BUTTONCONFIG", .value = KEY_BUTTONCONFIG }, + { .name = "KEY_C", .value = KEY_C }, + { .name = "KEY_CALC", .value = KEY_CALC }, + { .name = "KEY_CALENDAR", .value = KEY_CALENDAR }, + { .name = "KEY_CAMERA", .value = KEY_CAMERA }, + { .name = "KEY_CAMERA_ACCESS_DISABLE", .value = KEY_CAMERA_ACCESS_DISABLE }, + { .name = "KEY_CAMERA_ACCESS_ENABLE", .value = KEY_CAMERA_ACCESS_ENABLE }, + { .name = "KEY_CAMERA_ACCESS_TOGGLE", .value = KEY_CAMERA_ACCESS_TOGGLE }, + { .name = "KEY_CAMERA_DOWN", .value = KEY_CAMERA_DOWN }, + { .name = "KEY_CAMERA_FOCUS", .value = KEY_CAMERA_FOCUS }, + { .name = "KEY_CAMERA_LEFT", .value = KEY_CAMERA_LEFT }, + { .name = "KEY_CAMERA_RIGHT", .value = KEY_CAMERA_RIGHT }, + { .name = "KEY_CAMERA_UP", .value = KEY_CAMERA_UP }, + { .name = "KEY_CAMERA_ZOOMIN", .value = KEY_CAMERA_ZOOMIN }, + { .name = "KEY_CAMERA_ZOOMOUT", .value = KEY_CAMERA_ZOOMOUT }, + { .name = "KEY_CANCEL", .value = KEY_CANCEL }, + { .name = "KEY_CAPSLOCK", .value = KEY_CAPSLOCK }, + { .name = "KEY_CD", .value = KEY_CD }, + { .name = "KEY_CHANNEL", .value = KEY_CHANNEL }, + { .name = "KEY_CHANNELDOWN", .value = KEY_CHANNELDOWN }, + { .name = "KEY_CHANNELUP", .value = KEY_CHANNELUP }, + { .name = "KEY_CHAT", .value = KEY_CHAT }, + { .name = "KEY_CLEAR", .value = KEY_CLEAR }, + { .name = "KEY_CLEARVU_SONAR", .value = KEY_CLEARVU_SONAR }, + { .name = "KEY_CLOSE", .value = KEY_CLOSE }, + { .name = "KEY_CLOSECD", .value = KEY_CLOSECD }, + { .name = "KEY_COFFEE", .value = KEY_COFFEE }, + { .name = "KEY_COMMA", .value = KEY_COMMA }, + { .name = "KEY_COMPOSE", .value = KEY_COMPOSE }, + { .name = "KEY_COMPUTER", .value = KEY_COMPUTER }, + { .name = "KEY_CONFIG", .value = KEY_CONFIG }, + { .name = "KEY_CONNECT", .value = KEY_CONNECT }, + { .name = "KEY_CONTEXTUAL_INSERT", .value = KEY_CONTEXTUAL_INSERT }, + { .name = "KEY_CONTEXTUAL_QUERY", .value = KEY_CONTEXTUAL_QUERY }, + { .name = "KEY_CONTEXT_MENU", .value = KEY_CONTEXT_MENU }, + { .name = "KEY_CONTROLPANEL", .value = KEY_CONTROLPANEL }, + { .name = "KEY_COPY", .value = KEY_COPY }, + { .name = "KEY_CUT", .value = KEY_CUT }, + { .name = "KEY_CYCLEWINDOWS", .value = KEY_CYCLEWINDOWS }, + { .name = "KEY_D", .value = KEY_D }, + { .name = "KEY_DATA", .value = KEY_DATA }, + { .name = "KEY_DATABASE", .value = KEY_DATABASE }, + { .name = "KEY_DELETE", .value = KEY_DELETE }, + { .name = "KEY_DELETEFILE", .value = KEY_DELETEFILE }, + { .name = "KEY_DEL_EOL", .value = KEY_DEL_EOL }, + { .name = "KEY_DEL_EOS", .value = KEY_DEL_EOS }, + { .name = "KEY_DEL_LINE", .value = KEY_DEL_LINE }, + { .name = "KEY_DICTATE", .value = KEY_DICTATE }, + { .name = "KEY_DIGITS", .value = KEY_DIGITS }, + { .name = "KEY_DIRECTORY", .value = KEY_DIRECTORY }, + { .name = "KEY_DISPLAYTOGGLE", .value = KEY_DISPLAYTOGGLE }, + { .name = "KEY_DISPLAY_OFF", .value = KEY_DISPLAY_OFF }, + { .name = "KEY_DOCUMENTS", .value = KEY_DOCUMENTS }, + { .name = "KEY_DOLLAR", .value = KEY_DOLLAR }, + { .name = "KEY_DOT", .value = KEY_DOT }, + { .name = "KEY_DOWN", .value = KEY_DOWN }, + { .name = "KEY_DO_NOT_DISTURB", .value = KEY_DO_NOT_DISTURB }, + { .name = "KEY_DUAL_RANGE_RADAR", .value = KEY_DUAL_RANGE_RADAR }, + { .name = "KEY_DVD", .value = KEY_DVD }, + { .name = "KEY_E", .value = KEY_E }, + { .name = "KEY_EDIT", .value = KEY_EDIT }, + { .name = "KEY_EDITOR", .value = KEY_EDITOR }, + { .name = "KEY_EJECTCD", .value = KEY_EJECTCD }, + { .name = "KEY_EJECTCLOSECD", .value = KEY_EJECTCLOSECD }, + { .name = "KEY_EMAIL", .value = KEY_EMAIL }, + { .name = "KEY_EMOJI_PICKER", .value = KEY_EMOJI_PICKER }, + { .name = "KEY_END", .value = KEY_END }, + { .name = "KEY_ENTER", .value = KEY_ENTER }, + { .name = "KEY_EPG", .value = KEY_EPG }, + { .name = "KEY_EPRIVACY_SCREEN_OFF", .value = KEY_EPRIVACY_SCREEN_OFF }, + { .name = "KEY_EPRIVACY_SCREEN_ON", .value = KEY_EPRIVACY_SCREEN_ON }, + { .name = "KEY_EQUAL", .value = KEY_EQUAL }, + { .name = "KEY_ESC", .value = KEY_ESC }, + { .name = "KEY_EURO", .value = KEY_EURO }, + { .name = "KEY_EXIT", .value = KEY_EXIT }, + { .name = "KEY_F", .value = KEY_F }, + { .name = "KEY_F1", .value = KEY_F1 }, + { .name = "KEY_F10", .value = KEY_F10 }, + { .name = "KEY_F11", .value = KEY_F11 }, + { .name = "KEY_F12", .value = KEY_F12 }, + { .name = "KEY_F13", .value = KEY_F13 }, + { .name = "KEY_F14", .value = KEY_F14 }, + { .name = "KEY_F15", .value = KEY_F15 }, + { .name = "KEY_F16", .value = KEY_F16 }, + { .name = "KEY_F17", .value = KEY_F17 }, + { .name = "KEY_F18", .value = KEY_F18 }, + { .name = "KEY_F19", .value = KEY_F19 }, + { .name = "KEY_F2", .value = KEY_F2 }, + { .name = "KEY_F20", .value = KEY_F20 }, + { .name = "KEY_F21", .value = KEY_F21 }, + { .name = "KEY_F22", .value = KEY_F22 }, + { .name = "KEY_F23", .value = KEY_F23 }, + { .name = "KEY_F24", .value = KEY_F24 }, + { .name = "KEY_F3", .value = KEY_F3 }, + { .name = "KEY_F4", .value = KEY_F4 }, + { .name = "KEY_F5", .value = KEY_F5 }, + { .name = "KEY_F6", .value = KEY_F6 }, + { .name = "KEY_F7", .value = KEY_F7 }, + { .name = "KEY_F8", .value = KEY_F8 }, + { .name = "KEY_F9", .value = KEY_F9 }, + { .name = "KEY_FASTFORWARD", .value = KEY_FASTFORWARD }, + { .name = "KEY_FASTREVERSE", .value = KEY_FASTREVERSE }, + { .name = "KEY_FAVORITES", .value = KEY_FAVORITES }, + { .name = "KEY_FILE", .value = KEY_FILE }, + { .name = "KEY_FINANCE", .value = KEY_FINANCE }, + { .name = "KEY_FIND", .value = KEY_FIND }, + { .name = "KEY_FIRST", .value = KEY_FIRST }, + { .name = "KEY_FISHING_CHART", .value = KEY_FISHING_CHART }, + { .name = "KEY_FN", .value = KEY_FN }, + { .name = "KEY_FN_1", .value = KEY_FN_1 }, + { .name = "KEY_FN_2", .value = KEY_FN_2 }, + { .name = "KEY_FN_B", .value = KEY_FN_B }, + { .name = "KEY_FN_D", .value = KEY_FN_D }, + { .name = "KEY_FN_E", .value = KEY_FN_E }, + { .name = "KEY_FN_ESC", .value = KEY_FN_ESC }, + { .name = "KEY_FN_F", .value = KEY_FN_F }, + { .name = "KEY_FN_F1", .value = KEY_FN_F1 }, + { .name = "KEY_FN_F10", .value = KEY_FN_F10 }, + { .name = "KEY_FN_F11", .value = KEY_FN_F11 }, + { .name = "KEY_FN_F12", .value = KEY_FN_F12 }, + { .name = "KEY_FN_F2", .value = KEY_FN_F2 }, + { .name = "KEY_FN_F3", .value = KEY_FN_F3 }, + { .name = "KEY_FN_F4", .value = KEY_FN_F4 }, + { .name = "KEY_FN_F5", .value = KEY_FN_F5 }, + { .name = "KEY_FN_F6", .value = KEY_FN_F6 }, + { .name = "KEY_FN_F7", .value = KEY_FN_F7 }, + { .name = "KEY_FN_F8", .value = KEY_FN_F8 }, + { .name = "KEY_FN_F9", .value = KEY_FN_F9 }, + { .name = "KEY_FN_RIGHT_SHIFT", .value = KEY_FN_RIGHT_SHIFT }, + { .name = "KEY_FN_S", .value = KEY_FN_S }, + { .name = "KEY_FORWARD", .value = KEY_FORWARD }, + { .name = "KEY_FORWARDMAIL", .value = KEY_FORWARDMAIL }, + { .name = "KEY_FRAMEBACK", .value = KEY_FRAMEBACK }, + { .name = "KEY_FRAMEFORWARD", .value = KEY_FRAMEFORWARD }, + { .name = "KEY_FRONT", .value = KEY_FRONT }, + { .name = "KEY_FULL_SCREEN", .value = KEY_FULL_SCREEN }, + { .name = "KEY_G", .value = KEY_G }, + { .name = "KEY_GAMES", .value = KEY_GAMES }, + { .name = "KEY_GOTO", .value = KEY_GOTO }, + { .name = "KEY_GRAPHICSEDITOR", .value = KEY_GRAPHICSEDITOR }, + { .name = "KEY_GRAVE", .value = KEY_GRAVE }, + { .name = "KEY_GREEN", .value = KEY_GREEN }, + { .name = "KEY_H", .value = KEY_H }, + { .name = "KEY_HANGEUL", .value = KEY_HANGEUL }, + { .name = "KEY_HANGUP_PHONE", .value = KEY_HANGUP_PHONE }, + { .name = "KEY_HANJA", .value = KEY_HANJA }, + { .name = "KEY_HELP", .value = KEY_HELP }, + { .name = "KEY_HENKAN", .value = KEY_HENKAN }, + { .name = "KEY_HIRAGANA", .value = KEY_HIRAGANA }, + { .name = "KEY_HOME", .value = KEY_HOME }, + { .name = "KEY_HOMEPAGE", .value = KEY_HOMEPAGE }, + { .name = "KEY_HP", .value = KEY_HP }, + { .name = "KEY_I", .value = KEY_I }, + { .name = "KEY_IMAGES", .value = KEY_IMAGES }, + { .name = "KEY_INFO", .value = KEY_INFO }, + { .name = "KEY_INSERT", .value = KEY_INSERT }, + { .name = "KEY_INS_LINE", .value = KEY_INS_LINE }, + { .name = "KEY_ISO", .value = KEY_ISO }, + { .name = "KEY_J", .value = KEY_J }, + { .name = "KEY_JOURNAL", .value = KEY_JOURNAL }, + { .name = "KEY_K", .value = KEY_K }, + { .name = "KEY_KATAKANA", .value = KEY_KATAKANA }, + { .name = "KEY_KATAKANAHIRAGANA", .value = KEY_KATAKANAHIRAGANA }, + { .name = "KEY_KBDILLUMDOWN", .value = KEY_KBDILLUMDOWN }, + { .name = "KEY_KBDILLUMTOGGLE", .value = KEY_KBDILLUMTOGGLE }, + { .name = "KEY_KBDILLUMUP", .value = KEY_KBDILLUMUP }, + { .name = "KEY_KBDINPUTASSIST_ACCEPT", .value = KEY_KBDINPUTASSIST_ACCEPT }, + { .name = "KEY_KBDINPUTASSIST_CANCEL", .value = KEY_KBDINPUTASSIST_CANCEL }, + { .name = "KEY_KBDINPUTASSIST_NEXT", .value = KEY_KBDINPUTASSIST_NEXT }, + { .name = "KEY_KBDINPUTASSIST_NEXTGROUP", .value = KEY_KBDINPUTASSIST_NEXTGROUP }, + { .name = "KEY_KBDINPUTASSIST_PREV", .value = KEY_KBDINPUTASSIST_PREV }, + { .name = "KEY_KBDINPUTASSIST_PREVGROUP", .value = KEY_KBDINPUTASSIST_PREVGROUP }, + { .name = "KEY_KBD_LAYOUT_NEXT", .value = KEY_KBD_LAYOUT_NEXT }, + { .name = "KEY_KBD_LCD_MENU1", .value = KEY_KBD_LCD_MENU1 }, + { .name = "KEY_KBD_LCD_MENU2", .value = KEY_KBD_LCD_MENU2 }, + { .name = "KEY_KBD_LCD_MENU3", .value = KEY_KBD_LCD_MENU3 }, + { .name = "KEY_KBD_LCD_MENU4", .value = KEY_KBD_LCD_MENU4 }, + { .name = "KEY_KBD_LCD_MENU5", .value = KEY_KBD_LCD_MENU5 }, + { .name = "KEY_KEYBOARD", .value = KEY_KEYBOARD }, + { .name = "KEY_KP0", .value = KEY_KP0 }, + { .name = "KEY_KP1", .value = KEY_KP1 }, + { .name = "KEY_KP2", .value = KEY_KP2 }, + { .name = "KEY_KP3", .value = KEY_KP3 }, + { .name = "KEY_KP4", .value = KEY_KP4 }, + { .name = "KEY_KP5", .value = KEY_KP5 }, + { .name = "KEY_KP6", .value = KEY_KP6 }, + { .name = "KEY_KP7", .value = KEY_KP7 }, + { .name = "KEY_KP8", .value = KEY_KP8 }, + { .name = "KEY_KP9", .value = KEY_KP9 }, + { .name = "KEY_KPASTERISK", .value = KEY_KPASTERISK }, + { .name = "KEY_KPCOMMA", .value = KEY_KPCOMMA }, + { .name = "KEY_KPDOT", .value = KEY_KPDOT }, + { .name = "KEY_KPENTER", .value = KEY_KPENTER }, + { .name = "KEY_KPEQUAL", .value = KEY_KPEQUAL }, + { .name = "KEY_KPJPCOMMA", .value = KEY_KPJPCOMMA }, + { .name = "KEY_KPLEFTPAREN", .value = KEY_KPLEFTPAREN }, + { .name = "KEY_KPMINUS", .value = KEY_KPMINUS }, + { .name = "KEY_KPPLUS", .value = KEY_KPPLUS }, + { .name = "KEY_KPPLUSMINUS", .value = KEY_KPPLUSMINUS }, + { .name = "KEY_KPRIGHTPAREN", .value = KEY_KPRIGHTPAREN }, + { .name = "KEY_KPSLASH", .value = KEY_KPSLASH }, + { .name = "KEY_L", .value = KEY_L }, + { .name = "KEY_LANGUAGE", .value = KEY_LANGUAGE }, + { .name = "KEY_LAST", .value = KEY_LAST }, + { .name = "KEY_LEFT", .value = KEY_LEFT }, + { .name = "KEY_LEFTALT", .value = KEY_LEFTALT }, + { .name = "KEY_LEFTBRACE", .value = KEY_LEFTBRACE }, + { .name = "KEY_LEFTCTRL", .value = KEY_LEFTCTRL }, + { .name = "KEY_LEFTMETA", .value = KEY_LEFTMETA }, + { .name = "KEY_LEFTSHIFT", .value = KEY_LEFTSHIFT }, + { .name = "KEY_LEFT_DOWN", .value = KEY_LEFT_DOWN }, + { .name = "KEY_LEFT_UP", .value = KEY_LEFT_UP }, + { .name = "KEY_LIGHTS_TOGGLE", .value = KEY_LIGHTS_TOGGLE }, + { .name = "KEY_LINEFEED", .value = KEY_LINEFEED }, + { .name = "KEY_LINK_PHONE", .value = KEY_LINK_PHONE }, + { .name = "KEY_LIST", .value = KEY_LIST }, + { .name = "KEY_LOGOFF", .value = KEY_LOGOFF }, + { .name = "KEY_M", .value = KEY_M }, + { .name = "KEY_MACRO", .value = KEY_MACRO }, + { .name = "KEY_MACRO1", .value = KEY_MACRO1 }, + { .name = "KEY_MACRO10", .value = KEY_MACRO10 }, + { .name = "KEY_MACRO11", .value = KEY_MACRO11 }, + { .name = "KEY_MACRO12", .value = KEY_MACRO12 }, + { .name = "KEY_MACRO13", .value = KEY_MACRO13 }, + { .name = "KEY_MACRO14", .value = KEY_MACRO14 }, + { .name = "KEY_MACRO15", .value = KEY_MACRO15 }, + { .name = "KEY_MACRO16", .value = KEY_MACRO16 }, + { .name = "KEY_MACRO17", .value = KEY_MACRO17 }, + { .name = "KEY_MACRO18", .value = KEY_MACRO18 }, + { .name = "KEY_MACRO19", .value = KEY_MACRO19 }, + { .name = "KEY_MACRO2", .value = KEY_MACRO2 }, + { .name = "KEY_MACRO20", .value = KEY_MACRO20 }, + { .name = "KEY_MACRO21", .value = KEY_MACRO21 }, + { .name = "KEY_MACRO22", .value = KEY_MACRO22 }, + { .name = "KEY_MACRO23", .value = KEY_MACRO23 }, + { .name = "KEY_MACRO24", .value = KEY_MACRO24 }, + { .name = "KEY_MACRO25", .value = KEY_MACRO25 }, + { .name = "KEY_MACRO26", .value = KEY_MACRO26 }, + { .name = "KEY_MACRO27", .value = KEY_MACRO27 }, + { .name = "KEY_MACRO28", .value = KEY_MACRO28 }, + { .name = "KEY_MACRO29", .value = KEY_MACRO29 }, + { .name = "KEY_MACRO3", .value = KEY_MACRO3 }, + { .name = "KEY_MACRO30", .value = KEY_MACRO30 }, + { .name = "KEY_MACRO4", .value = KEY_MACRO4 }, + { .name = "KEY_MACRO5", .value = KEY_MACRO5 }, + { .name = "KEY_MACRO6", .value = KEY_MACRO6 }, + { .name = "KEY_MACRO7", .value = KEY_MACRO7 }, + { .name = "KEY_MACRO8", .value = KEY_MACRO8 }, + { .name = "KEY_MACRO9", .value = KEY_MACRO9 }, + { .name = "KEY_MACRO_PRESET1", .value = KEY_MACRO_PRESET1 }, + { .name = "KEY_MACRO_PRESET2", .value = KEY_MACRO_PRESET2 }, + { .name = "KEY_MACRO_PRESET3", .value = KEY_MACRO_PRESET3 }, + { .name = "KEY_MACRO_PRESET_CYCLE", .value = KEY_MACRO_PRESET_CYCLE }, + { .name = "KEY_MACRO_RECORD_START", .value = KEY_MACRO_RECORD_START }, + { .name = "KEY_MACRO_RECORD_STOP", .value = KEY_MACRO_RECORD_STOP }, + { .name = "KEY_MAIL", .value = KEY_MAIL }, + { .name = "KEY_MARK_WAYPOINT", .value = KEY_MARK_WAYPOINT }, + { .name = "KEY_MAX", .value = KEY_MAX }, + { .name = "KEY_MEDIA", .value = KEY_MEDIA }, + { .name = "KEY_MEDIA_REPEAT", .value = KEY_MEDIA_REPEAT }, + { .name = "KEY_MEDIA_TOP_MENU", .value = KEY_MEDIA_TOP_MENU }, + { .name = "KEY_MEMO", .value = KEY_MEMO }, + { .name = "KEY_MENU", .value = KEY_MENU }, + { .name = "KEY_MESSENGER", .value = KEY_MESSENGER }, + { .name = "KEY_MHP", .value = KEY_MHP }, + { .name = "KEY_MICMUTE", .value = KEY_MICMUTE }, + { .name = "KEY_MINUS", .value = KEY_MINUS }, + { .name = "KEY_MODE", .value = KEY_MODE }, + { .name = "KEY_MOVE", .value = KEY_MOVE }, + { .name = "KEY_MP3", .value = KEY_MP3 }, + { .name = "KEY_MSDOS", .value = KEY_MSDOS }, + { .name = "KEY_MUHENKAN", .value = KEY_MUHENKAN }, + { .name = "KEY_MUTE", .value = KEY_MUTE }, + { .name = "KEY_N", .value = KEY_N }, + { .name = "KEY_NAV_CHART", .value = KEY_NAV_CHART }, + { .name = "KEY_NAV_INFO", .value = KEY_NAV_INFO }, + { .name = "KEY_NEW", .value = KEY_NEW }, + { .name = "KEY_NEWS", .value = KEY_NEWS }, + { .name = "KEY_NEXT", .value = KEY_NEXT }, + { .name = "KEY_NEXTSONG", .value = KEY_NEXTSONG }, + { .name = "KEY_NEXT_ELEMENT", .value = KEY_NEXT_ELEMENT }, + { .name = "KEY_NEXT_FAVORITE", .value = KEY_NEXT_FAVORITE }, + { .name = "KEY_NOTIFICATION_CENTER", .value = KEY_NOTIFICATION_CENTER }, + { .name = "KEY_NUMERIC_0", .value = KEY_NUMERIC_0 }, + { .name = "KEY_NUMERIC_1", .value = KEY_NUMERIC_1 }, + { .name = "KEY_NUMERIC_11", .value = KEY_NUMERIC_11 }, + { .name = "KEY_NUMERIC_12", .value = KEY_NUMERIC_12 }, + { .name = "KEY_NUMERIC_2", .value = KEY_NUMERIC_2 }, + { .name = "KEY_NUMERIC_3", .value = KEY_NUMERIC_3 }, + { .name = "KEY_NUMERIC_4", .value = KEY_NUMERIC_4 }, + { .name = "KEY_NUMERIC_5", .value = KEY_NUMERIC_5 }, + { .name = "KEY_NUMERIC_6", .value = KEY_NUMERIC_6 }, + { .name = "KEY_NUMERIC_7", .value = KEY_NUMERIC_7 }, + { .name = "KEY_NUMERIC_8", .value = KEY_NUMERIC_8 }, + { .name = "KEY_NUMERIC_9", .value = KEY_NUMERIC_9 }, + { .name = "KEY_NUMERIC_A", .value = KEY_NUMERIC_A }, + { .name = "KEY_NUMERIC_B", .value = KEY_NUMERIC_B }, + { .name = "KEY_NUMERIC_C", .value = KEY_NUMERIC_C }, + { .name = "KEY_NUMERIC_D", .value = KEY_NUMERIC_D }, + { .name = "KEY_NUMERIC_POUND", .value = KEY_NUMERIC_POUND }, + { .name = "KEY_NUMERIC_STAR", .value = KEY_NUMERIC_STAR }, + { .name = "KEY_NUMLOCK", .value = KEY_NUMLOCK }, + { .name = "KEY_O", .value = KEY_O }, + { .name = "KEY_OK", .value = KEY_OK }, + { .name = "KEY_ONSCREEN_KEYBOARD", .value = KEY_ONSCREEN_KEYBOARD }, + { .name = "KEY_OPEN", .value = KEY_OPEN }, + { .name = "KEY_OPTION", .value = KEY_OPTION }, + { .name = "KEY_P", .value = KEY_P }, + { .name = "KEY_PAGEDOWN", .value = KEY_PAGEDOWN }, + { .name = "KEY_PAGEUP", .value = KEY_PAGEUP }, + { .name = "KEY_PASTE", .value = KEY_PASTE }, + { .name = "KEY_PAUSE", .value = KEY_PAUSE }, + { .name = "KEY_PAUSECD", .value = KEY_PAUSECD }, + { .name = "KEY_PAUSE_RECORD", .value = KEY_PAUSE_RECORD }, + { .name = "KEY_PC", .value = KEY_PC }, + { .name = "KEY_PERFORMANCE", .value = KEY_PERFORMANCE }, + { .name = "KEY_PHONE", .value = KEY_PHONE }, + { .name = "KEY_PICKUP_PHONE", .value = KEY_PICKUP_PHONE }, + { .name = "KEY_PLAY", .value = KEY_PLAY }, + { .name = "KEY_PLAYCD", .value = KEY_PLAYCD }, + { .name = "KEY_PLAYER", .value = KEY_PLAYER }, + { .name = "KEY_PLAYPAUSE", .value = KEY_PLAYPAUSE }, + { .name = "KEY_POWER", .value = KEY_POWER }, + { .name = "KEY_POWER2", .value = KEY_POWER2 }, + { .name = "KEY_PRESENTATION", .value = KEY_PRESENTATION }, + { .name = "KEY_PREVIOUS", .value = KEY_PREVIOUS }, + { .name = "KEY_PREVIOUSSONG", .value = KEY_PREVIOUSSONG }, + { .name = "KEY_PREVIOUS_ELEMENT", .value = KEY_PREVIOUS_ELEMENT }, + { .name = "KEY_PRINT", .value = KEY_PRINT }, + { .name = "KEY_PRIVACY_SCREEN_TOGGLE", .value = KEY_PRIVACY_SCREEN_TOGGLE }, + { .name = "KEY_PROG1", .value = KEY_PROG1 }, + { .name = "KEY_PROG2", .value = KEY_PROG2 }, + { .name = "KEY_PROG3", .value = KEY_PROG3 }, + { .name = "KEY_PROG4", .value = KEY_PROG4 }, + { .name = "KEY_PROGRAM", .value = KEY_PROGRAM }, + { .name = "KEY_PROPS", .value = KEY_PROPS }, + { .name = "KEY_PVR", .value = KEY_PVR }, + { .name = "KEY_Q", .value = KEY_Q }, + { .name = "KEY_QUESTION", .value = KEY_QUESTION }, + { .name = "KEY_R", .value = KEY_R }, + { .name = "KEY_RADAR_OVERLAY", .value = KEY_RADAR_OVERLAY }, + { .name = "KEY_RADIO", .value = KEY_RADIO }, + { .name = "KEY_RECORD", .value = KEY_RECORD }, + { .name = "KEY_RED", .value = KEY_RED }, + { .name = "KEY_REDO", .value = KEY_REDO }, + { .name = "KEY_REFRESH", .value = KEY_REFRESH }, + { .name = "KEY_REFRESH_RATE_TOGGLE", .value = KEY_REFRESH_RATE_TOGGLE }, + { .name = "KEY_REPLY", .value = KEY_REPLY }, + { .name = "KEY_RESERVED", .value = KEY_RESERVED }, + { .name = "KEY_RESTART", .value = KEY_RESTART }, + { .name = "KEY_REWIND", .value = KEY_REWIND }, + { .name = "KEY_RFKILL", .value = KEY_RFKILL }, + { .name = "KEY_RIGHT", .value = KEY_RIGHT }, + { .name = "KEY_RIGHTALT", .value = KEY_RIGHTALT }, + { .name = "KEY_RIGHTBRACE", .value = KEY_RIGHTBRACE }, + { .name = "KEY_RIGHTCTRL", .value = KEY_RIGHTCTRL }, + { .name = "KEY_RIGHTMETA", .value = KEY_RIGHTMETA }, + { .name = "KEY_RIGHTSHIFT", .value = KEY_RIGHTSHIFT }, + { .name = "KEY_RIGHT_DOWN", .value = KEY_RIGHT_DOWN }, + { .name = "KEY_RIGHT_UP", .value = KEY_RIGHT_UP }, + { .name = "KEY_RO", .value = KEY_RO }, + { .name = "KEY_ROOT_MENU", .value = KEY_ROOT_MENU }, + { .name = "KEY_ROTATE_DISPLAY", .value = KEY_ROTATE_DISPLAY }, + { .name = "KEY_ROTATE_LOCK_TOGGLE", .value = KEY_ROTATE_LOCK_TOGGLE }, + { .name = "KEY_S", .value = KEY_S }, + { .name = "KEY_SAT", .value = KEY_SAT }, + { .name = "KEY_SAT2", .value = KEY_SAT2 }, + { .name = "KEY_SAVE", .value = KEY_SAVE }, + { .name = "KEY_SCALE", .value = KEY_SCALE }, + { .name = "KEY_SCREENSAVER", .value = KEY_SCREENSAVER }, + { .name = "KEY_SCROLLDOWN", .value = KEY_SCROLLDOWN }, + { .name = "KEY_SCROLLLOCK", .value = KEY_SCROLLLOCK }, + { .name = "KEY_SCROLLUP", .value = KEY_SCROLLUP }, + { .name = "KEY_SEARCH", .value = KEY_SEARCH }, + { .name = "KEY_SELECT", .value = KEY_SELECT }, + { .name = "KEY_SELECTIVE_SCREENSHOT", .value = KEY_SELECTIVE_SCREENSHOT }, + { .name = "KEY_SEMICOLON", .value = KEY_SEMICOLON }, + { .name = "KEY_SEND", .value = KEY_SEND }, + { .name = "KEY_SENDFILE", .value = KEY_SENDFILE }, + { .name = "KEY_SETUP", .value = KEY_SETUP }, + { .name = "KEY_SHOP", .value = KEY_SHOP }, + { .name = "KEY_SHUFFLE", .value = KEY_SHUFFLE }, + { .name = "KEY_SIDEVU_SONAR", .value = KEY_SIDEVU_SONAR }, + { .name = "KEY_SINGLE_RANGE_RADAR", .value = KEY_SINGLE_RANGE_RADAR }, + { .name = "KEY_SLASH", .value = KEY_SLASH }, + { .name = "KEY_SLEEP", .value = KEY_SLEEP }, + { .name = "KEY_SLOW", .value = KEY_SLOW }, + { .name = "KEY_SLOWREVERSE", .value = KEY_SLOWREVERSE }, + { .name = "KEY_SOS", .value = KEY_SOS }, + { .name = "KEY_SOUND", .value = KEY_SOUND }, + { .name = "KEY_SPACE", .value = KEY_SPACE }, + { .name = "KEY_SPELLCHECK", .value = KEY_SPELLCHECK }, + { .name = "KEY_SPORT", .value = KEY_SPORT }, + { .name = "KEY_SPREADSHEET", .value = KEY_SPREADSHEET }, + { .name = "KEY_STOP", .value = KEY_STOP }, + { .name = "KEY_STOPCD", .value = KEY_STOPCD }, + { .name = "KEY_STOP_RECORD", .value = KEY_STOP_RECORD }, + { .name = "KEY_SUBTITLE", .value = KEY_SUBTITLE }, + { .name = "KEY_SUSPEND", .value = KEY_SUSPEND }, + { .name = "KEY_SWITCHVIDEOMODE", .value = KEY_SWITCHVIDEOMODE }, + { .name = "KEY_SYSRQ", .value = KEY_SYSRQ }, + { .name = "KEY_T", .value = KEY_T }, + { .name = "KEY_TAB", .value = KEY_TAB }, + { .name = "KEY_TAPE", .value = KEY_TAPE }, + { .name = "KEY_TASKMANAGER", .value = KEY_TASKMANAGER }, + { .name = "KEY_TEEN", .value = KEY_TEEN }, + { .name = "KEY_TEXT", .value = KEY_TEXT }, + { .name = "KEY_TIME", .value = KEY_TIME }, + { .name = "KEY_TITLE", .value = KEY_TITLE }, + { .name = "KEY_TOUCHPAD_OFF", .value = KEY_TOUCHPAD_OFF }, + { .name = "KEY_TOUCHPAD_ON", .value = KEY_TOUCHPAD_ON }, + { .name = "KEY_TOUCHPAD_TOGGLE", .value = KEY_TOUCHPAD_TOGGLE }, + { .name = "KEY_TRADITIONAL_SONAR", .value = KEY_TRADITIONAL_SONAR }, + { .name = "KEY_TUNER", .value = KEY_TUNER }, + { .name = "KEY_TV", .value = KEY_TV }, + { .name = "KEY_TV2", .value = KEY_TV2 }, + { .name = "KEY_TWEN", .value = KEY_TWEN }, + { .name = "KEY_U", .value = KEY_U }, + { .name = "KEY_UNDO", .value = KEY_UNDO }, + { .name = "KEY_UNKNOWN", .value = KEY_UNKNOWN }, + { .name = "KEY_UNMUTE", .value = KEY_UNMUTE }, + { .name = "KEY_UP", .value = KEY_UP }, + { .name = "KEY_UWB", .value = KEY_UWB }, + { .name = "KEY_V", .value = KEY_V }, + { .name = "KEY_VCR", .value = KEY_VCR }, + { .name = "KEY_VCR2", .value = KEY_VCR2 }, + { .name = "KEY_VENDOR", .value = KEY_VENDOR }, + { .name = "KEY_VIDEO", .value = KEY_VIDEO }, + { .name = "KEY_VIDEOPHONE", .value = KEY_VIDEOPHONE }, + { .name = "KEY_VIDEO_NEXT", .value = KEY_VIDEO_NEXT }, + { .name = "KEY_VIDEO_PREV", .value = KEY_VIDEO_PREV }, + { .name = "KEY_VOD", .value = KEY_VOD }, + { .name = "KEY_VOICECOMMAND", .value = KEY_VOICECOMMAND }, + { .name = "KEY_VOICEMAIL", .value = KEY_VOICEMAIL }, + { .name = "KEY_VOLUMEDOWN", .value = KEY_VOLUMEDOWN }, + { .name = "KEY_VOLUMEUP", .value = KEY_VOLUMEUP }, + { .name = "KEY_W", .value = KEY_W }, + { .name = "KEY_WAKEUP", .value = KEY_WAKEUP }, + { .name = "KEY_WLAN", .value = KEY_WLAN }, + { .name = "KEY_WORDPROCESSOR", .value = KEY_WORDPROCESSOR }, + { .name = "KEY_WPS_BUTTON", .value = KEY_WPS_BUTTON }, + { .name = "KEY_WWAN", .value = KEY_WWAN }, + { .name = "KEY_WWW", .value = KEY_WWW }, + { .name = "KEY_X", .value = KEY_X }, + { .name = "KEY_XFER", .value = KEY_XFER }, + { .name = "KEY_Y", .value = KEY_Y }, + { .name = "KEY_YELLOW", .value = KEY_YELLOW }, + { .name = "KEY_YEN", .value = KEY_YEN }, + { .name = "KEY_Z", .value = KEY_Z }, + { .name = "KEY_ZENKAKUHANKAKU", .value = KEY_ZENKAKUHANKAKU }, + { .name = "KEY_ZOOMIN", .value = KEY_ZOOMIN }, + { .name = "KEY_ZOOMOUT", .value = KEY_ZOOMOUT }, + { .name = "KEY_ZOOMRESET", .value = KEY_ZOOMRESET }, + { .name = "LED_CAPSL", .value = LED_CAPSL }, + { .name = "LED_CHARGING", .value = LED_CHARGING }, + { .name = "LED_COMPOSE", .value = LED_COMPOSE }, + { .name = "LED_KANA", .value = LED_KANA }, + { .name = "LED_MAIL", .value = LED_MAIL }, + { .name = "LED_MAX", .value = LED_MAX }, + { .name = "LED_MISC", .value = LED_MISC }, + { .name = "LED_MUTE", .value = LED_MUTE }, + { .name = "LED_NUML", .value = LED_NUML }, + { .name = "LED_SCROLLL", .value = LED_SCROLLL }, + { .name = "LED_SLEEP", .value = LED_SLEEP }, + { .name = "LED_SUSPEND", .value = LED_SUSPEND }, + { .name = "MSC_GESTURE", .value = MSC_GESTURE }, + { .name = "MSC_MAX", .value = MSC_MAX }, + { .name = "MSC_PULSELED", .value = MSC_PULSELED }, + { .name = "MSC_RAW", .value = MSC_RAW }, + { .name = "MSC_SCAN", .value = MSC_SCAN }, + { .name = "MSC_SERIAL", .value = MSC_SERIAL }, + { .name = "MSC_TIMESTAMP", .value = MSC_TIMESTAMP }, + { .name = "REL_DIAL", .value = REL_DIAL }, + { .name = "REL_HWHEEL", .value = REL_HWHEEL }, + { .name = "REL_HWHEEL_HI_RES", .value = REL_HWHEEL_HI_RES }, + { .name = "REL_MAX", .value = REL_MAX }, + { .name = "REL_MISC", .value = REL_MISC }, + { .name = "REL_RESERVED", .value = REL_RESERVED }, + { .name = "REL_RX", .value = REL_RX }, + { .name = "REL_RY", .value = REL_RY }, + { .name = "REL_RZ", .value = REL_RZ }, + { .name = "REL_WHEEL", .value = REL_WHEEL }, + { .name = "REL_WHEEL_HI_RES", .value = REL_WHEEL_HI_RES }, + { .name = "REL_X", .value = REL_X }, + { .name = "REL_Y", .value = REL_Y }, + { .name = "REL_Z", .value = REL_Z }, + { .name = "REP_DELAY", .value = REP_DELAY }, + { .name = "REP_MAX", .value = REP_MAX }, + { .name = "REP_PERIOD", .value = REP_PERIOD }, + { .name = "SND_BELL", .value = SND_BELL }, + { .name = "SND_CLICK", .value = SND_CLICK }, + { .name = "SND_MAX", .value = SND_MAX }, + { .name = "SND_TONE", .value = SND_TONE }, + { .name = "SW_CAMERA_LENS_COVER", .value = SW_CAMERA_LENS_COVER }, + { .name = "SW_DOCK", .value = SW_DOCK }, + { .name = "SW_FRONT_PROXIMITY", .value = SW_FRONT_PROXIMITY }, + { .name = "SW_HEADPHONE_INSERT", .value = SW_HEADPHONE_INSERT }, + { .name = "SW_JACK_PHYSICAL_INSERT", .value = SW_JACK_PHYSICAL_INSERT }, + { .name = "SW_KEYPAD_SLIDE", .value = SW_KEYPAD_SLIDE }, + { .name = "SW_LID", .value = SW_LID }, + { .name = "SW_LINEIN_INSERT", .value = SW_LINEIN_INSERT }, + { .name = "SW_LINEOUT_INSERT", .value = SW_LINEOUT_INSERT }, + { .name = "SW_MACHINE_COVER", .value = SW_MACHINE_COVER }, + { .name = "SW_MAX", .value = SW_MAX }, + { .name = "SW_MICROPHONE_INSERT", .value = SW_MICROPHONE_INSERT }, + { .name = "SW_MUTE_DEVICE", .value = SW_MUTE_DEVICE }, + { .name = "SW_PEN_INSERTED", .value = SW_PEN_INSERTED }, + { .name = "SW_RFKILL_ALL", .value = SW_RFKILL_ALL }, + { .name = "SW_ROTATE_LOCK", .value = SW_ROTATE_LOCK }, + { .name = "SW_TABLET_MODE", .value = SW_TABLET_MODE }, + { .name = "SW_USB_INSERT", .value = SW_USB_INSERT }, + { .name = "SW_VIDEOOUT_INSERT", .value = SW_VIDEOOUT_INSERT }, + { .name = "SYN_CONFIG", .value = SYN_CONFIG }, + { .name = "SYN_DROPPED", .value = SYN_DROPPED }, + { .name = "SYN_MAX", .value = SYN_MAX }, + { .name = "SYN_MT_REPORT", .value = SYN_MT_REPORT }, + { .name = "SYN_REPORT", .value = SYN_REPORT }, +}; + +static const struct name_entry prop_names[] = { + { .name = "INPUT_PROP_ACCELEROMETER", .value = INPUT_PROP_ACCELEROMETER }, + { .name = "INPUT_PROP_BUTTONPAD", .value = INPUT_PROP_BUTTONPAD }, + { .name = "INPUT_PROP_DIRECT", .value = INPUT_PROP_DIRECT }, + { .name = "INPUT_PROP_MAX", .value = INPUT_PROP_MAX }, + { .name = "INPUT_PROP_POINTER", .value = INPUT_PROP_POINTER }, + { .name = "INPUT_PROP_POINTING_STICK", .value = INPUT_PROP_POINTING_STICK }, + { .name = "INPUT_PROP_PRESSUREPAD", .value = INPUT_PROP_PRESSUREPAD }, + { .name = "INPUT_PROP_SEMI_MT", .value = INPUT_PROP_SEMI_MT }, + { .name = "INPUT_PROP_TOPBUTTONPAD", .value = INPUT_PROP_TOPBUTTONPAD }, +}; + +#endif /* EVENT_NAMES_H */ diff --git a/lib/libevdev/libevdev/libevdev-int.h b/lib/libevdev/libevdev/libevdev-int.h new file mode 100644 index 0000000..8e2518e --- /dev/null +++ b/lib/libevdev/libevdev/libevdev-int.h @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013 Red Hat, Inc. + */ + +#ifndef LIBEVDEV_INT_H +#define LIBEVDEV_INT_H + +#include "config.h" +#include +#include +#include +#include +#include "libevdev.h" +#include "libevdev-util.h" + +#define MAX_NAME 256 +#define ABS_MT_MIN ABS_MT_SLOT +#define ABS_MT_MAX ABS_MT_TOOL_Y +#define ABS_MT_CNT (ABS_MT_MAX - ABS_MT_MIN + 1) +#define LIBEVDEV_EXPORT __attribute__((visibility("default"))) +#define ALIAS(_to) __attribute__((alias(#_to))) + +/** + * Sync state machine: + * default state: SYNC_NONE + * + * SYNC_NONE → SYN_DROPPED or forced sync → SYNC_NEEDED + * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC) → SYNC_IN_PROGRESS + * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE + * SYNC_IN_PROGRESS → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE + * SYNC_IN_PROGRESS → no sync events left → SYNC_NONE + * + */ +enum SyncState { + SYNC_NONE, + SYNC_NEEDED, + SYNC_IN_PROGRESS, +}; + +/** + * Internal only: log data used to send messages to the respective log + * handler. We re-use the same struct for a global and inside + * struct libevdev. + * For the global, device_handler is NULL, for per-device instance + * global_handler is NULL. + */ +struct logdata { + enum libevdev_log_priority priority; /** minimum logging priority */ + libevdev_log_func_t global_handler; /** global handler function */ + libevdev_device_log_func_t device_handler; /** per-device handler function */ + void *userdata; /** user-defined data pointer */ +}; + +struct libevdev { + int fd; + bool initialized; + char *name; + char *phys; + char *uniq; + struct input_id ids; + int driver_version; + unsigned long bits[NLONGS(EV_CNT)]; + unsigned long props[NLONGS(INPUT_PROP_CNT)]; + unsigned long key_bits[NLONGS(KEY_CNT)]; + unsigned long rel_bits[NLONGS(REL_CNT)]; + unsigned long abs_bits[NLONGS(ABS_CNT)]; + unsigned long led_bits[NLONGS(LED_CNT)]; + unsigned long msc_bits[NLONGS(MSC_CNT)]; + unsigned long sw_bits[NLONGS(SW_CNT)]; + unsigned long rep_bits[NLONGS(REP_CNT)]; /* convenience, always 1 */ + unsigned long ff_bits[NLONGS(FF_CNT)]; + unsigned long snd_bits[NLONGS(SND_CNT)]; + unsigned long key_values[NLONGS(KEY_CNT)]; + unsigned long led_values[NLONGS(LED_CNT)]; + unsigned long sw_values[NLONGS(SW_CNT)]; + struct input_absinfo abs_info[ABS_CNT]; + int *mt_slot_vals; /* [num_slots * ABS_MT_CNT] */ + int num_slots; /**< valid slots in mt_slot_vals */ + int current_slot; + int rep_values[REP_CNT]; + + enum SyncState sync_state; + enum libevdev_grab_mode grabbed; + + struct input_event *queue; + size_t queue_size; /**< size of queue in elements */ + size_t queue_next; /**< next event index */ + size_t queue_nsync; /**< number of sync events */ + + struct timeval last_event_time; + + struct logdata log; +}; + +#define log_msg_cond(dev, priority, ...) \ + do { \ + if (_libevdev_log_priority(dev) >= priority) \ + _libevdev_log_msg(dev, priority, __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } while(0) + +#define log_error(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, __VA_ARGS__) +#define log_info(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_INFO, __VA_ARGS__) +#define log_dbg(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_DEBUG, __VA_ARGS__) +#define log_bug(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, "BUG: "__VA_ARGS__) + +extern void +_libevdev_log_msg(const struct libevdev *dev, + enum libevdev_log_priority priority, + const char *file, int line, const char *func, + const char *format, ...) LIBEVDEV_ATTRIBUTE_PRINTF(6, 7); +extern enum libevdev_log_priority +_libevdev_log_priority(const struct libevdev *dev); + +static inline void +init_event(struct libevdev *dev, struct input_event *ev, int type, int code, int value) +{ + ev->input_event_sec = dev->last_event_time.tv_sec; + ev->input_event_usec = dev->last_event_time.tv_usec; + ev->type = type; + ev->code = code; + ev->value = value; +} + +/** + * @return a pointer to the next element in the queue, or NULL if the queue + * is full. + */ +static inline struct input_event* +queue_push(struct libevdev *dev) +{ + if (dev->queue_next >= dev->queue_size) + return NULL; + + return &dev->queue[dev->queue_next++]; +} + +static inline bool +queue_push_event(struct libevdev *dev, unsigned int type, + unsigned int code, int value) +{ + struct input_event *ev = queue_push(dev); + + if (ev) + init_event(dev, ev, type, code, value); + + return ev != NULL; +} + +/** + * Set ev to the last element in the queue, removing it from the queue. + * + * @return 0 on success, 1 if the queue is empty. + */ +static inline int +queue_pop(struct libevdev *dev, struct input_event *ev) +{ + if (dev->queue_next == 0) + return 1; + + *ev = dev->queue[--dev->queue_next]; + + return 0; +} + +static inline int +queue_peek(struct libevdev *dev, size_t idx, struct input_event *ev) +{ + if (dev->queue_next == 0 || idx > dev->queue_next) + return 1; + *ev = dev->queue[idx]; + return 0; +} + +/** + * Shift the first n elements into ev and return the number of elements + * shifted. + * ev must be large enough to store n elements. + * + * @param ev The buffer to copy into, or NULL + * @return The number of elements in ev. + */ +static inline int +queue_shift_multiple(struct libevdev *dev, size_t n, struct input_event *ev) +{ + size_t remaining; + + if (dev->queue_next == 0) + return 0; + + remaining = dev->queue_next; + n = min(n, remaining); + remaining -= n; + + if (ev) + memcpy(ev, dev->queue, n * sizeof(*ev)); + + memmove(dev->queue, &dev->queue[n], remaining * sizeof(*dev->queue)); + + dev->queue_next = remaining; + return n; +} + +/** + * Set ev to the first element in the queue, shifting everything else + * forward by one. + * + * @return 0 on success, 1 if the queue is empty. + */ +static inline int +queue_shift(struct libevdev *dev, struct input_event *ev) +{ + return queue_shift_multiple(dev, 1, ev) == 1 ? 0 : 1; +} + +static inline int +queue_alloc(struct libevdev *dev, size_t size) +{ + if (size == 0) + return -ENOMEM; + + dev->queue = calloc(size, sizeof(struct input_event)); + if (!dev->queue) + return -ENOMEM; + + dev->queue_size = size; + dev->queue_next = 0; + return 0; +} + +static inline void +queue_free(struct libevdev *dev) +{ + free(dev->queue); + dev->queue_size = 0; + dev->queue_next = 0; +} + +static inline size_t +queue_num_elements(struct libevdev *dev) +{ + return dev->queue_next; +} + +static inline size_t +queue_size(struct libevdev *dev) +{ + return dev->queue_size; +} + +static inline size_t +queue_num_free_elements(struct libevdev *dev) +{ + if (dev->queue_size == 0) + return 0; + + return dev->queue_size - dev->queue_next; +} + +static inline struct input_event * +queue_next_element(struct libevdev *dev) +{ + if (dev->queue_next == dev->queue_size) + return NULL; + + return &dev->queue[dev->queue_next]; +} + +static inline int +queue_set_num_elements(struct libevdev *dev, size_t nelem) +{ + if (nelem > dev->queue_size) + return 1; + + dev->queue_next = nelem; + + return 0; +} + +#define max_mask(uc, lc) \ + case EV_##uc: \ + *mask = dev->lc##_bits; \ + max = libevdev_event_type_get_max(type); \ + break; + +static inline int +type_to_mask_const(const struct libevdev *dev, unsigned int type, const unsigned long **mask) +{ + int max; + + switch(type) { + max_mask(ABS, abs); + max_mask(REL, rel); + max_mask(KEY, key); + max_mask(LED, led); + max_mask(MSC, msc); + max_mask(SW, sw); + max_mask(FF, ff); + max_mask(REP, rep); + max_mask(SND, snd); + default: + max = -1; + break; + } + + return max; +} + +static inline int +type_to_mask(struct libevdev *dev, unsigned int type, unsigned long **mask) +{ + int max; + + switch(type) { + max_mask(ABS, abs); + max_mask(REL, rel); + max_mask(KEY, key); + max_mask(LED, led); + max_mask(MSC, msc); + max_mask(SW, sw); + max_mask(FF, ff); + max_mask(REP, rep); + max_mask(SND, snd); + default: + max = -1; + break; + } + + return max; +} + +#undef max_mask +#endif diff --git a/lib/libevdev/libevdev/libevdev-names.c b/lib/libevdev/libevdev/libevdev-names.c new file mode 100644 index 0000000..82329c3 --- /dev/null +++ b/lib/libevdev/libevdev/libevdev-names.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013 David Herrmann + */ + +#include "config.h" +#include +#include +#include +#include + +#include "libevdev-int.h" +#include "libevdev-util.h" +#include "libevdev.h" + +#include "event-names.h" + +struct name_lookup { + const char *name; + size_t len; +}; + +static int cmp_entry(const void *vlookup, const void *ventry) +{ + const struct name_lookup *lookup = vlookup; + const struct name_entry *entry = ventry; + int r; + + r = strncmp(lookup->name, entry->name, lookup->len); + if (!r) { + if (entry->name[lookup->len]) + r = -1; + else + r = 0; + } + + return r; +} + +static const struct name_entry* +lookup_name(const struct name_entry *array, size_t asize, + struct name_lookup *lookup) +{ + const struct name_entry *entry; + + entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry); + if (!entry) + return NULL; + + return entry; +} + +LIBEVDEV_EXPORT int +libevdev_event_type_from_name(const char *name) +{ + return libevdev_event_type_from_name_n(name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_event_type_from_name_n(const char *name, size_t len) +{ + struct name_lookup lookup; + const struct name_entry *entry; + + lookup.name = name; + lookup.len = len; + + entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup); + + return entry ? (int)entry->value : -1; +} + +static int type_from_prefix(const char *name, ssize_t len) +{ + const char *e; + size_t i; + ssize_t l; + + /* MAX_ is not allowed, even though EV_MAX exists */ + if (startswith(name, len, "MAX_", 4)) + return -1; + /* BTN_ is special as there is no EV_BTN type */ + if (startswith(name, len, "BTN_", 4)) + return EV_KEY; + /* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */ + if (startswith(name, len, "FF_STATUS_", 10)) + return EV_FF_STATUS; + + for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) { + /* skip EV_ prefix so @e is suffix of [EV_]XYZ */ + e = &ev_names[i].name[3]; + l = strlen(e); + + /* compare prefix and test for trailing _ */ + if (len > l && startswith(name, len, e, l) && name[l] == '_') + return ev_names[i].value; + } + + return -1; +} + +LIBEVDEV_EXPORT int +libevdev_event_code_from_name(unsigned int type, const char *name) +{ + return libevdev_event_code_from_name_n(type, name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len) +{ + struct name_lookup lookup; + const struct name_entry *entry; + int real_type; + + /* verify that @name is really of type @type */ + real_type = type_from_prefix(name, len); + if (real_type < 0 || (unsigned int)real_type != type) + return -1; + + /* now look up the name @name and return the constant */ + lookup.name = name; + lookup.len = len; + + entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup); + + return entry ? (int)entry->value : -1; +} + +LIBEVDEV_EXPORT int +libevdev_event_value_from_name(unsigned int type, unsigned int code, const char *name) +{ + return libevdev_event_value_from_name_n(type, code, name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_event_value_from_name_n(unsigned int type, unsigned int code, const char *name, size_t len) +{ + struct name_lookup lookup; + const struct name_entry *entry; + + if (type != EV_ABS || code != ABS_MT_TOOL_TYPE) + return -1; + + lookup.name = name; + lookup.len = len; + + entry = lookup_name(tool_type_names, ARRAY_LENGTH(tool_type_names), &lookup); + + return entry ? (int)entry->value : -1; +} + +LIBEVDEV_EXPORT int +libevdev_property_from_name(const char *name) +{ + return libevdev_property_from_name_n(name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_property_from_name_n(const char *name, size_t len) +{ + struct name_lookup lookup; + const struct name_entry *entry; + + lookup.name = name; + lookup.len = len; + + entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup); + + return entry ? (int)entry->value : -1; +} + +LIBEVDEV_EXPORT int +libevdev_event_code_from_code_name(const char *name) +{ + return libevdev_event_code_from_code_name_n(name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_event_code_from_code_name_n(const char *name, size_t len) +{ + const struct name_entry *entry; + struct name_lookup lookup; + + /* now look up the name @name and return the constant */ + lookup.name = name; + lookup.len = len; + + entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup); + + return entry ? (int)entry->value : -1; +} + +LIBEVDEV_EXPORT int +libevdev_event_type_from_code_name(const char *name) +{ + return libevdev_event_type_from_code_name_n(name, strlen(name)); +} + +LIBEVDEV_EXPORT int +libevdev_event_type_from_code_name_n(const char *name, size_t len) +{ + const struct name_entry *entry; + struct name_lookup lookup; + + /* First look up if the name exists, we dont' want to return a valid + * type for an invalid code name */ + lookup.name = name; + lookup.len = len; + + entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup); + + return entry ? type_from_prefix(name, len) : -1; +} diff --git a/lib/libevdev/libevdev/libevdev-util.h b/lib/libevdev/libevdev/libevdev-util.h new file mode 100644 index 0000000..cab8067 --- /dev/null +++ b/lib/libevdev/libevdev/libevdev-util.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013 Red Hat, Inc. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include "config.h" +#include +#include + +#define LONG_BITS (sizeof(long) * 8) +#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) +#define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0]))) +#define unlikely(x) (__builtin_expect(!!(x),0)) + +#undef min +#undef max +#ifdef __GNUC__ +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _b : _a; \ + }) +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; \ + }) +#else +#define min(a,b) ((a) > (b) ? (b) : (a)) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +static inline bool +startswith(const char *str, size_t len, const char *prefix, size_t plen) +{ + return len >= plen && !strncmp(str, prefix, plen); +} + +static inline int +bit_is_set(const unsigned long *array, int bit) +{ + return !!(array[bit / LONG_BITS] & (1ULL << (bit % LONG_BITS))); +} + +static inline void +set_bit(unsigned long *array, int bit) +{ + array[bit / LONG_BITS] |= (1ULL << (bit % LONG_BITS)); +} + +static inline void +clear_bit(unsigned long *array, int bit) +{ + array[bit / LONG_BITS] &= ~(1ULL << (bit % LONG_BITS)); +} + +static inline void +set_bit_state(unsigned long *array, int bit, int state) +{ + if (state) + set_bit(array, bit); + else + clear_bit(array, bit); +} + +#endif diff --git a/lib/libevdev/libevdev/libevdev.c b/lib/libevdev/libevdev/libevdev.c new file mode 100644 index 0000000..e1c33ea --- /dev/null +++ b/lib/libevdev/libevdev/libevdev.c @@ -0,0 +1,1912 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013 Red Hat, Inc. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libevdev-int.h" +#include "libevdev-util.h" +#include "libevdev.h" + +#include "event-names.h" + +#define MAXEVENTS 64 +#define MAX_SLOTS 256 + +enum event_filter_status { + EVENT_FILTER_NONE, /**< Event untouched by filters */ + EVENT_FILTER_MODIFIED, /**< Event was modified */ + EVENT_FILTER_DISCARD, /**< Discard current event */ +}; + +/* Keeps a record of touches during SYN_DROPPED */ +enum touch_state { + TOUCH_OFF, + TOUCH_STARTED, /* Started during SYN_DROPPED */ + TOUCH_STOPPED, /* Stopped during SYN_DROPPED */ + TOUCH_ONGOING, /* Existed before, still have same tracking ID */ + TOUCH_CHANGED, /* Existed before but have new tracking ID now, so + stopped + started in that slot */ +}; + +struct slot_change_state { + enum touch_state state; + unsigned long axes[NLONGS(ABS_CNT)]; /* bitmask for updated axes */ +}; + +static int sync_mt_state(struct libevdev *dev, + struct slot_change_state changes_out[dev->num_slots]); + +static int +update_key_state(struct libevdev *dev, const struct input_event *e); + +static inline int* +slot_value(const struct libevdev *dev, int slot, int axis) +{ + if (unlikely(slot >= dev->num_slots)) { + log_bug(dev, "Slot %d exceeds number of slots (%d)\n", slot, dev->num_slots); + slot = 0; + } + if (unlikely(axis < ABS_MT_MIN || axis > ABS_MT_MAX)) { + log_bug(dev, "MT axis %d is outside the valid range [%d,%d]\n", + axis, ABS_MT_MIN, ABS_MT_MAX); + axis = ABS_MT_MIN; + } + return &dev->mt_slot_vals[slot * ABS_MT_CNT + axis - ABS_MT_MIN]; +} + +static int +init_event_queue(struct libevdev *dev) +{ + const int MIN_QUEUE_SIZE = 256; + int nevents = 1; /* terminating SYN_REPORT */ + int nslots; + unsigned int type, code; + + /* count the number of axes, keys, etc. to get a better idea at how + many events per EV_SYN we could possibly get. That's the max we + may get during SYN_DROPPED too. Use double that, just so we have + room for events while syncing a device. + */ + for (type = EV_KEY; type < EV_MAX; type++) { + int max = libevdev_event_type_get_max(type); + for (code = 0; max > 0 && code < (unsigned int) max; code++) { + if (libevdev_has_event_code(dev, type, code)) + nevents++; + } + } + + nslots = libevdev_get_num_slots(dev); + if (nslots > 1) { + int num_mt_axes = 0; + + for (code = ABS_MT_SLOT; code <= ABS_MAX; code++) { + if (libevdev_has_event_code(dev, EV_ABS, code)) + num_mt_axes++; + } + + /* We already counted the first slot in the initial count */ + nevents += num_mt_axes * (nslots - 1); + } + + return queue_alloc(dev, max(MIN_QUEUE_SIZE, nevents * 2)); +} + +static void +libevdev_dflt_log_func(enum libevdev_log_priority priority, + void *data, + const char *file, int line, const char *func, + const char *format, va_list args) +{ + const char *prefix; + switch(priority) { + case LIBEVDEV_LOG_ERROR: prefix = "libevdev error"; break; + case LIBEVDEV_LOG_INFO: prefix = "libevdev info"; break; + case LIBEVDEV_LOG_DEBUG: + prefix = "libevdev debug"; + break; + default: + prefix = "libevdev INVALID LOG PRIORITY"; + break; + } + /* default logging format: + libevev error in libevdev_some_func: blah blah + libevev info in libevdev_some_func: blah blah + libevev debug in file.c:123:libevdev_some_func: blah blah + */ + + fprintf(stderr, "%s in ", prefix); + if (priority == LIBEVDEV_LOG_DEBUG) + fprintf(stderr, "%s:%d:", file, line); + fprintf(stderr, "%s: ", func); + vfprintf(stderr, format, args); +} + +static void +fix_invalid_absinfo(const struct libevdev *dev, + int axis, + struct input_absinfo* abs_info) +{ + /* + * The reported absinfo for ABS_MT_TRACKING_ID is sometimes + * uninitialized for certain mtk-soc, due to init code mangling + * in the vendor kernel. + */ + if (axis == ABS_MT_TRACKING_ID && + abs_info->maximum == abs_info->minimum) { + abs_info->minimum = -1; + abs_info->maximum = 0xFFFF; + log_bug(dev, + "Device \"%s\" has invalid ABS_MT_TRACKING_ID range", + dev->name); + } +} + +/* + * Global logging settings. + */ +static struct logdata log_data = { + .priority = LIBEVDEV_LOG_INFO, + .global_handler = libevdev_dflt_log_func, + .userdata = NULL, +}; + +void +_libevdev_log_msg(const struct libevdev *dev, + enum libevdev_log_priority priority, + const char *file, int line, const char *func, + const char *format, ...) +{ + va_list args; + + if (dev && dev->log.device_handler) { + /** + * if both global handler and device handler are set + * we've set up the handlers wrong. And that means we'll + * likely get the printf args wrong and cause all sorts of + * mayhem. Seppuku is called for. + */ + if (unlikely(dev->log.global_handler)) + abort(); + + if (priority > dev->log.priority) + return; + } else if (!log_data.global_handler || priority > log_data.priority) { + return; + } else if (unlikely(log_data.device_handler)) { + abort(); /* Seppuku, see above */ + } + + va_start(args, format); + if (dev && dev->log.device_handler) + dev->log.device_handler(dev, priority, dev->log.userdata, file, line, func, format, args); + else + log_data.global_handler(priority, log_data.userdata, file, line, func, format, args); + va_end(args); +} + +static void +libevdev_reset(struct libevdev *dev) +{ + enum libevdev_log_priority pri = dev->log.priority; + libevdev_device_log_func_t handler = dev->log.device_handler; + + free(dev->name); + free(dev->phys); + free(dev->uniq); + free(dev->mt_slot_vals); + memset(dev, 0, sizeof(*dev)); + dev->fd = -1; + dev->initialized = false; + dev->num_slots = -1; + dev->current_slot = -1; + dev->grabbed = LIBEVDEV_UNGRAB; + dev->sync_state = SYNC_NONE; + dev->log.priority = pri; + dev->log.device_handler = handler; + libevdev_enable_event_type(dev, EV_SYN); +} + +LIBEVDEV_EXPORT struct libevdev* +libevdev_new(void) +{ + struct libevdev *dev; + + dev = calloc(1, sizeof(*dev)); + if (!dev) + return NULL; + + libevdev_reset(dev); + + return dev; +} + +LIBEVDEV_EXPORT int +libevdev_new_from_fd(int fd, struct libevdev **dev) +{ + struct libevdev *d; + int rc; + + d = libevdev_new(); + if (!d) + return -ENOMEM; + + rc = libevdev_set_fd(d, fd); + if (rc < 0) + libevdev_free(d); + else + *dev = d; + return rc; +} + +LIBEVDEV_EXPORT void +libevdev_free(struct libevdev *dev) +{ + if (!dev) + return; + + queue_free(dev); + libevdev_reset(dev); + free(dev); +} + +LIBEVDEV_EXPORT void +libevdev_set_log_function(libevdev_log_func_t logfunc, void *data) +{ + log_data.global_handler = logfunc; + log_data.userdata = data; +} + +LIBEVDEV_EXPORT void +libevdev_set_log_priority(enum libevdev_log_priority priority) +{ + if (priority > LIBEVDEV_LOG_DEBUG) + priority = LIBEVDEV_LOG_DEBUG; + log_data.priority = priority; +} + +LIBEVDEV_EXPORT enum libevdev_log_priority +libevdev_get_log_priority(void) +{ + return log_data.priority; +} + +LIBEVDEV_EXPORT void +libevdev_set_device_log_function(struct libevdev *dev, + libevdev_device_log_func_t logfunc, + enum libevdev_log_priority priority, + void *data) +{ + if (!dev) { + log_bug(NULL, "device must not be NULL\n"); + return; + } + + dev->log.priority = priority; + dev->log.device_handler = logfunc; + dev->log.userdata = data; +} + +enum libevdev_log_priority +_libevdev_log_priority(const struct libevdev *dev) +{ + if (dev && dev->log.device_handler) + return dev->log.priority; + return libevdev_get_log_priority(); +} + +LIBEVDEV_EXPORT int +libevdev_change_fd(struct libevdev *dev, int fd) +{ + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -1; + } + dev->fd = fd; + dev->grabbed = LIBEVDEV_UNGRAB; + return 0; +} + +static void +reset_tracking_ids(struct libevdev *dev) +{ + if (dev->num_slots == -1 || + !libevdev_has_event_code(dev, EV_ABS, ABS_MT_TRACKING_ID)) + return; + + for (int slot = 0; slot < dev->num_slots; slot++) + libevdev_set_slot_value(dev, slot, ABS_MT_TRACKING_ID, -1); +} + +static inline void +free_slots(struct libevdev *dev) +{ + dev->num_slots = -1; + free(dev->mt_slot_vals); + dev->mt_slot_vals = NULL; +} + +static int +init_slots(struct libevdev *dev) +{ + const struct input_absinfo *abs_info; + int rc = 0; + + free(dev->mt_slot_vals); + dev->mt_slot_vals = NULL; + + /* devices with ABS_RESERVED aren't MT devices, + see the documentation for multitouch-related + functions for more details */ + if (libevdev_has_event_code(dev, EV_ABS, ABS_RESERVED) || + !libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) { + if (dev->num_slots != -1) { + free_slots(dev); + } + return rc; + } + + abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT); + + free_slots(dev); + dev->num_slots = abs_info->maximum + 1; + if (dev->num_slots > MAX_SLOTS) { + rc = -ENOMEM; + goto out; + } + + dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int)); + if (!dev->mt_slot_vals) { + rc = -ENOMEM; + goto out; + } + dev->current_slot = abs_info->value; + + reset_tracking_ids(dev); +out: + return rc; +} + +LIBEVDEV_EXPORT int +libevdev_set_fd(struct libevdev* dev, int fd) +{ + int rc; + int i; + char buf[256]; + + if (dev->initialized) { + log_bug(dev, "device already initialized.\n"); + return -EBADF; + } + + if (fd < 0) { + return -EBADF; + } + + libevdev_reset(dev); + + rc = ioctl(fd, EVIOCGBIT(0, sizeof(dev->bits)), dev->bits); + if (rc < 0) + goto out; + + memset(buf, 0, sizeof(buf)); + rc = ioctl(fd, EVIOCGNAME(sizeof(buf) - 1), buf); + if (rc < 0) + goto out; + + free(dev->name); + dev->name = strdup(buf); + if (!dev->name) { + errno = ENOMEM; + goto out; + } + + free(dev->phys); + dev->phys = NULL; + memset(buf, 0, sizeof(buf)); + rc = ioctl(fd, EVIOCGPHYS(sizeof(buf) - 1), buf); + if (rc < 0) { + /* uinput has no phys */ + if (errno != ENOENT) + goto out; + } else { + dev->phys = strdup(buf); + if (!dev->phys) { + errno = ENOMEM; + goto out; + } + } + + free(dev->uniq); + dev->uniq = NULL; + memset(buf, 0, sizeof(buf)); + rc = ioctl(fd, EVIOCGUNIQ(sizeof(buf) - 1), buf); + if (rc < 0) { + if (errno != ENOENT) + goto out; + } else { + dev->uniq = strdup(buf); + if (!dev->uniq) { + errno = ENOMEM; + goto out; + } + } + + rc = ioctl(fd, EVIOCGID, &dev->ids); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGVERSION, &dev->driver_version); + if (rc < 0) + goto out; + + /* Built on a kernel with props, running against a kernel without property + support. This should not be a fatal case, we'll be missing properties but other + than that everything is as expected. + */ + rc = ioctl(fd, EVIOCGPROP(sizeof(dev->props)), dev->props); + if (rc < 0 && errno != EINVAL) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_REL, sizeof(dev->rel_bits)), dev->rel_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(dev->abs_bits)), dev->abs_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(dev->led_bits)), dev->led_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(dev->key_bits)), dev->key_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_SW, sizeof(dev->sw_bits)), dev->sw_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_MSC, sizeof(dev->msc_bits)), dev->msc_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_FF, sizeof(dev->ff_bits)), dev->ff_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGBIT(EV_SND, sizeof(dev->snd_bits)), dev->snd_bits); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGKEY(sizeof(dev->key_values)), dev->key_values); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGLED(sizeof(dev->led_values)), dev->led_values); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGSW(sizeof(dev->sw_values)), dev->sw_values); + if (rc < 0) + goto out; + + /* rep is a special case, always set it to 1 for both values if EV_REP is set */ + if (bit_is_set(dev->bits, EV_REP)) { + for (i = 0; i < REP_CNT; i++) + set_bit(dev->rep_bits, i); + rc = ioctl(fd, EVIOCGREP, dev->rep_values); + if (rc < 0) + goto out; + } + + for (i = ABS_X; i <= ABS_MAX; i++) { + if (bit_is_set(dev->abs_bits, i)) { + struct input_absinfo abs_info; + rc = ioctl(fd, EVIOCGABS(i), &abs_info); + if (rc < 0) + goto out; + + fix_invalid_absinfo(dev, i, &abs_info); + + dev->abs_info[i] = abs_info; + } + } + + dev->fd = fd; + + rc = init_slots(dev); + if (rc != 0) + goto out; + + if (dev->num_slots != -1) { + struct slot_change_state unused[dev->num_slots]; + sync_mt_state(dev, unused); + } + + rc = init_event_queue(dev); + if (rc < 0) { + dev->fd = -1; + return -rc; + } + + /* not copying key state because we won't know when we'll start to + * use this fd and key's are likely to change state by then. + * Same with the valuators, really, but they may not change. + */ + + dev->initialized = true; +out: + if (rc) + libevdev_reset(dev); + return rc ? -errno : 0; +} + +LIBEVDEV_EXPORT int +libevdev_get_fd(const struct libevdev* dev) +{ + return dev->fd; +} + +LIBEVDEV_EXPORT int +libevdev_upload_ff_effect(struct libevdev *dev, struct ff_effect *effect) +{ + if (!libevdev_has_event_type(dev, EV_FF)) + return -EINVAL; + + if (ioctl(libevdev_get_fd(dev), EVIOCSFF, effect) < 0) + return -errno; + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_remove_ff_effect(struct libevdev *dev, short effect_id) +{ + if (!libevdev_has_event_type(dev, EV_FF)) + return -EINVAL; + + if (ioctl(libevdev_get_fd(dev), EVIOCRMFF, effect_id) < 0) + return -errno; + + return 0; +} + +static int +sync_key_state(struct libevdev *dev) +{ + int rc; + int i; + unsigned long keystate[NLONGS(KEY_CNT)] = {0}; + + rc = ioctl(dev->fd, EVIOCGKEY(sizeof(keystate)), keystate); + if (rc < 0) + goto out; + + for (i = 0; i < KEY_CNT; i++) { + int old, new; + old = bit_is_set(dev->key_values, i); + new = bit_is_set(keystate, i); + if (old ^ new) + queue_push_event(dev, EV_KEY, i, new ? 1 : 0); + } + + memcpy(dev->key_values, keystate, rc); + + rc = 0; +out: + return rc ? -errno : 0; +} + +static int +sync_sw_state(struct libevdev *dev) +{ + int rc; + int i; + unsigned long swstate[NLONGS(SW_CNT)] = {0}; + + rc = ioctl(dev->fd, EVIOCGSW(sizeof(swstate)), swstate); + if (rc < 0) + goto out; + + for (i = 0; i < SW_CNT; i++) { + int old, new; + old = bit_is_set(dev->sw_values, i); + new = bit_is_set(swstate, i); + if (old ^ new) + queue_push_event(dev, EV_SW, i, new ? 1 : 0); + } + + memcpy(dev->sw_values, swstate, rc); + + rc = 0; +out: + return rc ? -errno : 0; +} + +static int +sync_led_state(struct libevdev *dev) +{ + int rc; + int i; + unsigned long ledstate[NLONGS(LED_CNT)] = {0}; + + rc = ioctl(dev->fd, EVIOCGLED(sizeof(ledstate)), ledstate); + if (rc < 0) + goto out; + + for (i = 0; i < LED_CNT; i++) { + int old, new; + old = bit_is_set(dev->led_values, i); + new = bit_is_set(ledstate, i); + if (old ^ new) { + queue_push_event(dev, EV_LED, i, new ? 1 : 0); + } + } + + memcpy(dev->led_values, ledstate, rc); + + rc = 0; +out: + return rc ? -errno : 0; +} +static int +sync_abs_state(struct libevdev *dev) +{ + int rc; + int i; + + for (i = ABS_X; i < ABS_CNT; i++) { + struct input_absinfo abs_info; + + if (i >= ABS_MT_MIN && i <= ABS_MT_MAX) + continue; + + if (!bit_is_set(dev->abs_bits, i)) + continue; + + rc = ioctl(dev->fd, EVIOCGABS(i), &abs_info); + if (rc < 0) + goto out; + + if (dev->abs_info[i].value != abs_info.value) { + queue_push_event(dev, EV_ABS, i, abs_info.value); + dev->abs_info[i].value = abs_info.value; + } + } + + rc = 0; +out: + return rc ? -errno : 0; +} + +static int +sync_mt_state(struct libevdev *dev, + struct slot_change_state changes_out[dev->num_slots]) +{ + int rc = 0; + struct slot_change_state changes[MAX_SLOTS] = {0}; + unsigned int nslots = min(MAX_SLOTS, dev->num_slots); + + for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) { + /* EVIOCGMTSLOTS required format */ + struct mt_sync_state { + uint32_t code; + int32_t val[MAX_SLOTS]; + } mt_state; + + if (axis == ABS_MT_SLOT || + !libevdev_has_event_code(dev, EV_ABS, axis)) + continue; + + mt_state.code = axis; + rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(mt_state)), &mt_state); + if (rc < 0) + goto out; + + for (unsigned int slot = 0; slot < nslots; slot++) { + int val_before = *slot_value(dev, slot, axis), + val_after = mt_state.val[slot]; + + if (axis == ABS_MT_TRACKING_ID) { + if (val_before == -1 && val_after != -1) { + changes[slot].state = TOUCH_STARTED; + } else if (val_before != -1 && val_after == -1) { + changes[slot].state = TOUCH_STOPPED; + } else if (val_before != -1 && val_after != -1 && + val_before == val_after) { + changes[slot].state = TOUCH_ONGOING; + } else if (val_before != -1 && val_after != -1 && + val_before != val_after) { + changes[slot].state = TOUCH_CHANGED; + } else { + changes[slot].state = TOUCH_OFF; + } + } + + if (val_before == val_after) + continue; + + *slot_value(dev, slot, axis) = val_after; + + set_bit(changes[slot].axes, axis); + /* note that this slot has updates */ + set_bit(changes[slot].axes, ABS_MT_SLOT); + } + } + + if (dev->num_slots > MAX_SLOTS) + memset(changes_out, 0, sizeof(*changes) * dev->num_slots); + + memcpy(changes_out, changes, sizeof(*changes) * nslots); +out: + return rc; +} + +static void +terminate_slots(struct libevdev *dev, + const struct slot_change_state changes[dev->num_slots], + int *last_reported_slot) +{ + const unsigned int map[] = {BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, + BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP, + BTN_TOOL_QUINTTAP}; + bool touches_stopped = false; + int ntouches_before = 0, ntouches_after = 0; + + /* For BTN_TOOL_* emulation, we need to know how many touches we had + * before and how many we have left once we terminate all the ones + * that changed and all the ones that stopped. + */ + for (int slot = 0; slot < dev->num_slots; slot++) { + switch(changes[slot].state) { + case TOUCH_OFF: + break; + case TOUCH_CHANGED: + case TOUCH_STOPPED: + queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot); + queue_push_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + + *last_reported_slot = slot; + touches_stopped = true; + ntouches_before++; + break; + case TOUCH_ONGOING: + ntouches_before++; + ntouches_after++; + break; + case TOUCH_STARTED: + break; + } + } + + /* If any of the touches stopped, we need to split the sync state + into two frames - one with all the stopped touches, one with the + new touches starting (if any) */ + if (touches_stopped) { + /* Send through the required BTN_TOOL_ 0 and 1 events for + * the previous and current number of fingers. And update + * our own key state accordingly, so that during the second + * sync event frame sync_key_state() sets everything correctly + * for the *real* number of touches. + */ + if (ntouches_before > 0 && ntouches_before <= 5) { + struct input_event ev = { + .type = EV_KEY, + .code = map[ntouches_before - 1], + .value = 0, + }; + queue_push_event(dev, ev.type, ev.code, ev.value); + update_key_state(dev, &ev); + } + + if (ntouches_after > 0 && ntouches_after <= 5) { + struct input_event ev = { + .type = EV_KEY, + .code = map[ntouches_after - 1], + .value = 1, + }; + queue_push_event(dev, ev.type, ev.code, ev.value); + update_key_state(dev, &ev); + } + + queue_push_event(dev, EV_SYN, SYN_REPORT, 0); + } +} + +static int +push_mt_sync_events(struct libevdev *dev, + const struct slot_change_state changes[dev->num_slots], + int last_reported_slot) +{ + struct input_absinfo abs_info; + int rc; + + for (int slot = 0; slot < dev->num_slots; slot++) { + bool have_slot_event = false; + + if (!bit_is_set(changes[slot].axes, ABS_MT_SLOT)) + continue; + + for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) { + if (axis == ABS_MT_SLOT || + !libevdev_has_event_code(dev, EV_ABS, axis)) + continue; + + if (bit_is_set(changes[slot].axes, axis)) { + /* We already sent the tracking id -1 in + * terminate_slots so don't do that again. There + * may be other axes like ABS_MT_TOOL_TYPE that + * need to be synced despite no touch being active */ + if (axis == ABS_MT_TRACKING_ID && + *slot_value(dev, slot, axis) == -1) + continue; + + if (!have_slot_event) { + queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot); + last_reported_slot = slot; + have_slot_event = true; + } + + queue_push_event(dev, EV_ABS, axis, + *slot_value(dev, slot, axis)); + } + } + } + + /* add one last slot event to make sure the client is on the same + slot as the kernel */ + + rc = ioctl(dev->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); + if (rc < 0) + goto out; + + dev->current_slot = abs_info.value; + + if (dev->current_slot != last_reported_slot) + queue_push_event(dev, EV_ABS, ABS_MT_SLOT, dev->current_slot); + + rc = 0; +out: + return rc ? -errno : 0; +} + +static int +read_more_events(struct libevdev *dev) +{ + int free_elem; + int len; + struct input_event *next; + + free_elem = queue_num_free_elements(dev); + if (free_elem <= 0) + return 0; + + next = queue_next_element(dev); + len = read(dev->fd, next, free_elem * sizeof(struct input_event)); + if (len < 0) + return -errno; + + if (len > 0 && len % sizeof(struct input_event) != 0) + return -EINVAL; + + if (len > 0) { + int nev = len/sizeof(struct input_event); + queue_set_num_elements(dev, queue_num_elements(dev) + nev); + } + + return 0; +} + +static inline void +drain_events(struct libevdev *dev) +{ + int rc; + size_t nelem; + int iterations = 0; + const int max_iterations = 8; /* EVDEV_BUF_PACKETS in + kernel/drivers/input/evedev.c */ + + queue_shift_multiple(dev, queue_num_elements(dev), NULL); + + do { + rc = read_more_events(dev); + if (rc == -EAGAIN) + return; + + if (rc < 0) { + log_error(dev, "Failed to drain events before sync.\n"); + return; + } + + nelem = queue_num_elements(dev); + queue_shift_multiple(dev, nelem, NULL); + } while (iterations++ < max_iterations && nelem >= queue_size(dev)); + + /* Our buffer should be roughly the same or bigger than the kernel + buffer in most cases, so we usually don't expect to recurse. If + we do, make sure we stop after max_iterations and proceed with + what we have. This could happen if events queue up faster than + we can drain them. + */ + if (iterations >= max_iterations) + log_info(dev, "Unable to drain events, buffer size mismatch.\n"); +} + +static int +sync_state(struct libevdev *dev) +{ + int rc = 0; + bool want_mt_sync = false; + int last_reported_slot = 0; + struct slot_change_state changes[dev->num_slots > 0 ? dev->num_slots : 1]; + + memset(changes, 0, sizeof(changes)); + + /* see section "Discarding events before synchronizing" in + * libevdev/libevdev.h */ + drain_events(dev); + + /* We generate one or two event frames during sync. + * The first one (if it exists) terminates all slots that have + * either terminated during SYN_DROPPED or changed their tracking + * ID. + * + * The second frame syncs everything up to the current state of the + * device - including re-starting those slots that have a changed + * tracking id. + */ + if (dev->num_slots > -1 && + libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) { + want_mt_sync = true; + rc = sync_mt_state(dev, changes); + if (rc == 0) + terminate_slots(dev, changes, &last_reported_slot); + else + want_mt_sync = false; + } + + if (libevdev_has_event_type(dev, EV_KEY)) + rc = sync_key_state(dev); + if (libevdev_has_event_type(dev, EV_LED)) + rc = sync_led_state(dev); + if (libevdev_has_event_type(dev, EV_SW)) + rc = sync_sw_state(dev); + if (rc == 0 && libevdev_has_event_type(dev, EV_ABS)) + rc = sync_abs_state(dev); + if (rc == 0 && want_mt_sync) + push_mt_sync_events(dev, changes, last_reported_slot); + + dev->queue_nsync = queue_num_elements(dev); + + if (dev->queue_nsync > 0) { + queue_push_event(dev, EV_SYN, SYN_REPORT, 0); + dev->queue_nsync++; + } + + return rc; +} + +static int +update_key_state(struct libevdev *dev, const struct input_event *e) +{ + if (!libevdev_has_event_type(dev, EV_KEY)) + return 1; + + if (e->code > KEY_MAX) + return 1; + + set_bit_state(dev->key_values, e->code, e->value != 0); + + return 0; +} + +static int +update_mt_state(struct libevdev *dev, const struct input_event *e) +{ + if (e->code == ABS_MT_SLOT && dev->num_slots > -1) { + int i; + dev->current_slot = e->value; + /* sync abs_info with the current slot values */ + for (i = ABS_MT_SLOT + 1; i <= ABS_MT_MAX; i++) { + if (libevdev_has_event_code(dev, EV_ABS, i)) + dev->abs_info[i].value = *slot_value(dev, dev->current_slot, i); + } + + return 0; + } + + if (dev->current_slot == -1) + return 1; + + *slot_value(dev, dev->current_slot, e->code) = e->value; + + return 0; +} + +static int +update_abs_state(struct libevdev *dev, const struct input_event *e) +{ + if (!libevdev_has_event_type(dev, EV_ABS)) + return 1; + + if (e->code > ABS_MAX) + return 1; + + if (e->code >= ABS_MT_MIN && e->code <= ABS_MT_MAX) + update_mt_state(dev, e); + + dev->abs_info[e->code].value = e->value; + + return 0; +} + +static int +update_led_state(struct libevdev *dev, const struct input_event *e) +{ + if (!libevdev_has_event_type(dev, EV_LED)) + return 1; + + if (e->code > LED_MAX) + return 1; + + set_bit_state(dev->led_values, e->code, e->value != 0); + + return 0; +} + +static int +update_sw_state(struct libevdev *dev, const struct input_event *e) +{ + if (!libevdev_has_event_type(dev, EV_SW)) + return 1; + + if (e->code > SW_MAX) + return 1; + + set_bit_state(dev->sw_values, e->code, e->value != 0); + + return 0; +} + +static int +update_state(struct libevdev *dev, const struct input_event *e) +{ + int rc = 0; + + switch(e->type) { + case EV_SYN: + case EV_REL: + break; + case EV_KEY: + rc = update_key_state(dev, e); + break; + case EV_ABS: + rc = update_abs_state(dev, e); + break; + case EV_LED: + rc = update_led_state(dev, e); + break; + case EV_SW: + rc = update_sw_state(dev, e); + break; + } + + dev->last_event_time.tv_sec = e->input_event_sec; + dev->last_event_time.tv_usec = e->input_event_usec; + + return rc; +} + +/** + * Sanitize/modify events where needed. + */ +static inline enum event_filter_status +sanitize_event(const struct libevdev *dev, + struct input_event *ev, + enum SyncState sync_state) +{ + if (!libevdev_has_event_code(dev, ev->type, ev->code)) + return EVENT_FILTER_DISCARD; + + if (unlikely(dev->num_slots > -1 && + libevdev_event_is_code(ev, EV_ABS, ABS_MT_SLOT) && + (ev->value < 0 || ev->value >= dev->num_slots))) { + log_bug(dev, "Device \"%s\" received an invalid slot index %d." + "Capping to announced max slot number %d.\n", + dev->name, ev->value, dev->num_slots - 1); + ev->value = dev->num_slots - 1; + return EVENT_FILTER_MODIFIED; + + /* Drop any invalid tracking IDs, they are only supposed to go from + N to -1 or from -1 to N. Never from -1 to -1, or N to M. Very + unlikely to ever happen from a real device. + */ + } + + if (unlikely(sync_state == SYNC_NONE && + dev->num_slots > -1 && + libevdev_event_is_code(ev, EV_ABS, ABS_MT_TRACKING_ID) && + ((ev->value == -1 && + *slot_value(dev, dev->current_slot, ABS_MT_TRACKING_ID) == -1) || + (ev->value != -1 && + *slot_value(dev, dev->current_slot, ABS_MT_TRACKING_ID) != -1)))) { + log_bug(dev, "Device \"%s\" received a double tracking ID %d in slot %d.\n", + dev->name, ev->value, dev->current_slot); + return EVENT_FILTER_DISCARD; + } + + return EVENT_FILTER_NONE; +} + +LIBEVDEV_EXPORT int +libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev) +{ + int rc = LIBEVDEV_READ_STATUS_SUCCESS; + enum event_filter_status filter_status; + const unsigned int valid_flags = LIBEVDEV_READ_FLAG_NORMAL | + LIBEVDEV_READ_FLAG_SYNC | + LIBEVDEV_READ_FLAG_FORCE_SYNC | + LIBEVDEV_READ_FLAG_BLOCKING; + + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + if ((flags & valid_flags) == 0) { + log_bug(dev, "invalid flags %#x.\n", flags); + return -EINVAL; + } + + if (flags & LIBEVDEV_READ_FLAG_SYNC) { + if (dev->sync_state == SYNC_NEEDED) { + rc = sync_state(dev); + if (rc != 0) + return rc; + dev->sync_state = SYNC_IN_PROGRESS; + } + + if (dev->queue_nsync == 0) { + dev->sync_state = SYNC_NONE; + return -EAGAIN; + } + + } else if (dev->sync_state != SYNC_NONE) { + struct input_event e; + + /* call update_state for all events here, otherwise the library has the wrong view + of the device too */ + while (queue_shift(dev, &e) == 0) { + dev->queue_nsync--; + if (sanitize_event(dev, &e, dev->sync_state) != EVENT_FILTER_DISCARD) + update_state(dev, &e); + } + + dev->sync_state = SYNC_NONE; + } + + /* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED, + worst case we don't read fast enough and end up with SYN_DROPPED anyway. + + Except if the fd is in blocking mode and we still have events from the last read, don't + read in any more. + */ + do { + if (queue_num_elements(dev) == 0) { + rc = read_more_events(dev); + if (rc < 0 && rc != -EAGAIN) + goto out; + } + + if (flags & LIBEVDEV_READ_FLAG_FORCE_SYNC) { + dev->sync_state = SYNC_NEEDED; + rc = LIBEVDEV_READ_STATUS_SYNC; + goto out; + } + + if (queue_shift(dev, ev) != 0) + return -EAGAIN; + + filter_status = sanitize_event(dev, ev, dev->sync_state); + if (filter_status != EVENT_FILTER_DISCARD) + update_state(dev, ev); + + /* if we disabled a code, get the next event instead */ + } while(filter_status == EVENT_FILTER_DISCARD || + !libevdev_has_event_code(dev, ev->type, ev->code)); + + rc = LIBEVDEV_READ_STATUS_SUCCESS; + if (ev->type == EV_SYN && ev->code == SYN_DROPPED) { + dev->sync_state = SYNC_NEEDED; + rc = LIBEVDEV_READ_STATUS_SYNC; + } + + if (flags & LIBEVDEV_READ_FLAG_SYNC && dev->queue_nsync > 0) { + dev->queue_nsync--; + rc = LIBEVDEV_READ_STATUS_SYNC; + if (dev->queue_nsync == 0) + dev->sync_state = SYNC_NONE; + } + +out: + return rc; +} + +LIBEVDEV_EXPORT int +libevdev_has_event_pending(struct libevdev *dev) +{ + struct pollfd fds = { dev->fd, POLLIN, 0 }; + int rc; + + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + if (queue_num_elements(dev) != 0) + return 1; + + rc = poll(&fds, 1, 0); + return (rc >= 0) ? rc : -errno; +} + +LIBEVDEV_EXPORT const char * +libevdev_get_name(const struct libevdev *dev) +{ + return dev->name ? dev->name : ""; +} + +LIBEVDEV_EXPORT const char * +libevdev_get_phys(const struct libevdev *dev) +{ + return dev->phys; +} + +LIBEVDEV_EXPORT const char * +libevdev_get_uniq(const struct libevdev *dev) +{ + return dev->uniq; +} + +#define STRING_SETTER(field) \ +LIBEVDEV_EXPORT void libevdev_set_##field(struct libevdev *dev, const char *field) \ +{ \ + if (field == NULL) \ + return; \ + free(dev->field); \ + dev->field = strdup(field); \ +} + +STRING_SETTER(name) +STRING_SETTER(phys) +STRING_SETTER(uniq) + +#define PRODUCT_GETTER(name) \ +LIBEVDEV_EXPORT int libevdev_get_id_##name(const struct libevdev *dev) \ +{ \ + return dev->ids.name; \ +} + +PRODUCT_GETTER(product) +PRODUCT_GETTER(vendor) +PRODUCT_GETTER(bustype) +PRODUCT_GETTER(version) + +#define PRODUCT_SETTER(field) \ +LIBEVDEV_EXPORT void libevdev_set_id_##field(struct libevdev *dev, int field) \ +{ \ + dev->ids.field = field;\ +} + +PRODUCT_SETTER(product) +PRODUCT_SETTER(vendor) +PRODUCT_SETTER(bustype) +PRODUCT_SETTER(version) + +LIBEVDEV_EXPORT int +libevdev_get_driver_version(const struct libevdev *dev) +{ + return dev->driver_version; +} + +LIBEVDEV_EXPORT int +libevdev_has_property(const struct libevdev *dev, unsigned int prop) +{ + return (prop <= INPUT_PROP_MAX) && bit_is_set(dev->props, prop); +} + +LIBEVDEV_EXPORT int +libevdev_enable_property(struct libevdev *dev, unsigned int prop) +{ + if (prop > INPUT_PROP_MAX) + return -1; + + set_bit(dev->props, prop); + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_disable_property(struct libevdev *dev, unsigned int prop) +{ + if (prop > INPUT_PROP_MAX) + return -1; + + clear_bit(dev->props, prop); + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_has_event_type(const struct libevdev *dev, unsigned int type) +{ + return type == EV_SYN ||(type <= EV_MAX && bit_is_set(dev->bits, type)); +} + +LIBEVDEV_EXPORT int +libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code) +{ + const unsigned long *mask = NULL; + int max; + + if (!libevdev_has_event_type(dev, type)) + return 0; + + if (type == EV_SYN) + return 1; + + max = type_to_mask_const(dev, type, &mask); + + if (max == -1 || code > (unsigned int)max) + return 0; + + return bit_is_set(mask, code); +} + +LIBEVDEV_EXPORT int +libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code) +{ + int value = 0; + + if (!libevdev_has_event_type(dev, type) || !libevdev_has_event_code(dev, type, code)) + return 0; + + switch (type) { + case EV_ABS: value = dev->abs_info[code].value; break; + case EV_KEY: value = bit_is_set(dev->key_values, code); break; + case EV_LED: value = bit_is_set(dev->led_values, code); break; + case EV_SW: value = bit_is_set(dev->sw_values, code); break; + case EV_REP: + switch(code) { + case REP_DELAY: + libevdev_get_repeat(dev, &value, NULL); + break; + case REP_PERIOD: + libevdev_get_repeat(dev, NULL, &value); + break; + default: + value = 0; + break; + } + break; + default: + value = 0; + break; + } + + return value; +} + +LIBEVDEV_EXPORT int +libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int code, int value) +{ + int rc = 0; + struct input_event e; + + if (!libevdev_has_event_type(dev, type) || !libevdev_has_event_code(dev, type, code)) + return -1; + + e.type = type; + e.code = code; + e.value = value; + + if (sanitize_event(dev, &e, SYNC_NONE) != EVENT_FILTER_NONE) + return -1; + + switch(type) { + case EV_ABS: rc = update_abs_state(dev, &e); break; + case EV_KEY: rc = update_key_state(dev, &e); break; + case EV_LED: rc = update_led_state(dev, &e); break; + case EV_SW: rc = update_sw_state(dev, &e); break; + default: + rc = -1; + break; + } + + return rc; +} + +LIBEVDEV_EXPORT int +libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value) +{ + if (libevdev_has_event_type(dev, type) && + libevdev_has_event_code(dev, type, code)) { + *value = libevdev_get_event_value(dev, type, code); + return 1; + } + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code) +{ + if (!libevdev_has_event_type(dev, EV_ABS) || !libevdev_has_event_code(dev, EV_ABS, code)) + return 0; + + if (dev->num_slots < 0 || slot >= (unsigned int)dev->num_slots) + return 0; + + if (code > ABS_MT_MAX || code < ABS_MT_MIN) + return 0; + + return *slot_value(dev, slot, code); +} + +LIBEVDEV_EXPORT int +libevdev_set_slot_value(struct libevdev *dev, unsigned int slot, unsigned int code, int value) +{ + if (!libevdev_has_event_type(dev, EV_ABS) || !libevdev_has_event_code(dev, EV_ABS, code)) + return -1; + + if (dev->num_slots == -1 || slot >= (unsigned int)dev->num_slots) + return -1; + + if (code > ABS_MT_MAX || code < ABS_MT_MIN) + return -1; + + if (code == ABS_MT_SLOT) { + if (value < 0 || value >= libevdev_get_num_slots(dev)) + return -1; + dev->current_slot = value; + } + + *slot_value(dev, slot, code) = value; + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code, int *value) +{ + if (libevdev_has_event_type(dev, EV_ABS) && + libevdev_has_event_code(dev, EV_ABS, code) && + dev->num_slots >= 0 && + slot < (unsigned int)dev->num_slots) { + *value = libevdev_get_slot_value(dev, slot, code); + return 1; + } + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_get_num_slots(const struct libevdev *dev) +{ + return dev->num_slots; +} + +LIBEVDEV_EXPORT int +libevdev_get_current_slot(const struct libevdev *dev) +{ + return dev->current_slot; +} + +LIBEVDEV_EXPORT const struct input_absinfo* +libevdev_get_abs_info(const struct libevdev *dev, unsigned int code) +{ + if (!libevdev_has_event_type(dev, EV_ABS) || + !libevdev_has_event_code(dev, EV_ABS, code)) + return NULL; + + return &dev->abs_info[code]; +} + +#define ABS_GETTER(name) \ +LIBEVDEV_EXPORT int libevdev_get_abs_##name(const struct libevdev *dev, unsigned int code) \ +{ \ + const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code); \ + return absinfo ? absinfo->name : 0; \ +} + +ABS_GETTER(maximum) +ABS_GETTER(minimum) +ABS_GETTER(fuzz) +ABS_GETTER(flat) +ABS_GETTER(resolution) + +#define ABS_SETTER(field) \ +LIBEVDEV_EXPORT void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \ +{ \ + if (!libevdev_has_event_code(dev, EV_ABS, code)) \ + return; \ + dev->abs_info[code].field = val; \ +} + +ABS_SETTER(maximum) +ABS_SETTER(minimum) +ABS_SETTER(fuzz) +ABS_SETTER(flat) +ABS_SETTER(resolution) + +LIBEVDEV_EXPORT void +libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs) +{ + if (!libevdev_has_event_code(dev, EV_ABS, code)) + return; + + dev->abs_info[code] = *abs; +} + +LIBEVDEV_EXPORT int +libevdev_enable_event_type(struct libevdev *dev, unsigned int type) +{ + int max; + + if (type > EV_MAX) + return -1; + + if (libevdev_has_event_type(dev, type)) + return 0; + + max = libevdev_event_type_get_max(type); + if (max == -1) + return -1; + + set_bit(dev->bits, type); + + if (type == EV_REP) { + int delay = 0, period = 0; + libevdev_enable_event_code(dev, EV_REP, REP_DELAY, &delay); + libevdev_enable_event_code(dev, EV_REP, REP_PERIOD, &period); + } + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_disable_event_type(struct libevdev *dev, unsigned int type) +{ + int max; + + if (type > EV_MAX || type == EV_SYN) + return -1; + + max = libevdev_event_type_get_max(type); + if (max == -1) + return -1; + + clear_bit(dev->bits, type); + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_enable_event_code(struct libevdev *dev, unsigned int type, + unsigned int code, const void *data) +{ + unsigned int max; + unsigned long *mask = NULL; + + if (libevdev_enable_event_type(dev, type)) + return -1; + + switch(type) { + case EV_SYN: + return 0; + case EV_ABS: + case EV_REP: + if (data == NULL) + return -1; + break; + default: + if (data != NULL) + return -1; + break; + } + + max = type_to_mask(dev, type, &mask); + + if (code > max || (int)max == -1) + return -1; + + set_bit(mask, code); + + if (type == EV_ABS) { + const struct input_absinfo *abs = data; + dev->abs_info[code] = *abs; + if (code == ABS_MT_SLOT) { + if (init_slots(dev) != 0) + return -1; + } else if (code == ABS_MT_TRACKING_ID) { + reset_tracking_ids(dev); + } + } else if (type == EV_REP) { + const int *value = data; + dev->rep_values[code] = *value; + } + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code) +{ + unsigned int max; + unsigned long *mask = NULL; + + if (type > EV_MAX || type == EV_SYN) + return -1; + + max = type_to_mask(dev, type, &mask); + + if (code > max || (int)max == -1) + return -1; + + clear_bit(mask, code); + + if (type == EV_ABS) { + if (code == ABS_MT_SLOT) { + if (init_slots(dev) != 0) + return -1; + } else if (code == ABS_MT_TRACKING_ID) { + reset_tracking_ids(dev); + } + } + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs) +{ + int rc; + + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + if (code > ABS_MAX) + return -EINVAL; + + rc = ioctl(dev->fd, EVIOCSABS(code), abs); + if (rc < 0) + rc = -errno; + else + rc = libevdev_enable_event_code(dev, EV_ABS, code, abs); + + return rc; +} + +LIBEVDEV_EXPORT int +libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab) +{ + int rc = 0; + + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB) { + log_bug(dev, "invalid grab parameter %#x\n", grab); + return -EINVAL; + } + + if (grab == dev->grabbed) + return 0; + + if (grab == LIBEVDEV_GRAB) + rc = ioctl(dev->fd, EVIOCGRAB, (void *)1); + else if (grab == LIBEVDEV_UNGRAB) + rc = ioctl(dev->fd, EVIOCGRAB, (void *)0); + + if (rc == 0) + dev->grabbed = grab; + + return rc < 0 ? -errno : 0; +} + +LIBEVDEV_EXPORT int +libevdev_event_is_type(const struct input_event *ev, unsigned int type) +{ + return type < EV_CNT && ev->type == type; +} + +LIBEVDEV_EXPORT int +libevdev_event_is_code(const struct input_event *ev, unsigned int type, unsigned int code) +{ + int max; + + if (!libevdev_event_is_type(ev, type)) + return 0; + + max = libevdev_event_type_get_max(type); + return (max > -1 && code <= (unsigned int)max && ev->code == code); +} + +LIBEVDEV_EXPORT const char* +libevdev_event_type_get_name(unsigned int type) +{ + if (type > EV_MAX) + return NULL; + + return ev_map[type]; +} + +LIBEVDEV_EXPORT const char* +libevdev_event_code_get_name(unsigned int type, unsigned int code) +{ + int max = libevdev_event_type_get_max(type); + + if (max == -1 || code > (unsigned int)max) + return NULL; + + return event_type_map[type][code]; +} + +LIBEVDEV_EXPORT const char * +libevdev_event_value_get_name(unsigned int type, + unsigned int code, + int value) +{ + /* This is a simplified version because nothing else + is an enum like ABS_MT_TOOL_TYPE so we don't need + a generic lookup */ + if (type != EV_ABS || code != ABS_MT_TOOL_TYPE) + return NULL; + + if (value < 0 || value > MT_TOOL_MAX) + return NULL; + + return mt_tool_map[value]; +} + +LIBEVDEV_EXPORT const char* +libevdev_property_get_name(unsigned int prop) +{ + if (prop > INPUT_PROP_MAX) + return NULL; + + return input_prop_map[prop]; +} + +LIBEVDEV_EXPORT int +libevdev_event_type_get_max(unsigned int type) +{ + if (type > EV_MAX) + return -1; + + return ev_max[type]; +} + +LIBEVDEV_EXPORT int +libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period) +{ + if (!libevdev_has_event_type(dev, EV_REP)) + return -1; + + if (delay != NULL) + *delay = dev->rep_values[REP_DELAY]; + if (period != NULL) + *period = dev->rep_values[REP_PERIOD]; + + return 0; +} + +LIBEVDEV_EXPORT int +libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum libevdev_led_value value) +{ + return libevdev_kernel_set_led_values(dev, code, value, -1); +} + +LIBEVDEV_EXPORT int +libevdev_kernel_set_led_values(struct libevdev *dev, ...) +{ + struct input_event ev[LED_MAX + 1]; + enum libevdev_led_value val; + va_list args; + int code; + int rc = 0; + size_t nleds = 0; + + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + memset(ev, 0, sizeof(ev)); + + va_start(args, dev); + code = va_arg(args, unsigned int); + while (code != -1) { + if (code > LED_MAX) { + rc = -EINVAL; + break; + } + val = va_arg(args, enum libevdev_led_value); + if (val != LIBEVDEV_LED_ON && val != LIBEVDEV_LED_OFF) { + rc = -EINVAL; + break; + } + + if (libevdev_has_event_code(dev, EV_LED, code)) { + struct input_event *e = ev; + + while (e->type > 0 && e->code != code) + e++; + + if (e->type == 0) + nleds++; + e->type = EV_LED; + e->code = code; + e->value = (val == LIBEVDEV_LED_ON); + } + code = va_arg(args, unsigned int); + } + va_end(args); + + if (rc == 0 && nleds > 0) { + ev[nleds].type = EV_SYN; + ev[nleds++].code = SYN_REPORT; + + rc = write(libevdev_get_fd(dev), ev, nleds * sizeof(ev[0])); + if (rc > 0) { + nleds--; /* last is EV_SYN */ + while (nleds--) + update_led_state(dev, &ev[nleds]); + } + rc = (rc != -1) ? 0 : -errno; + } + + return rc; +} + +LIBEVDEV_EXPORT int +libevdev_set_clock_id(struct libevdev *dev, int clockid) +{ + if (!dev->initialized) { + log_bug(dev, "device not initialized. call libevdev_set_fd() first\n"); + return -EBADF; + } + + if (dev->fd < 0) + return -EBADF; + + return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0; +} diff --git a/lib/libevdev/libevdev/libevdev.h b/lib/libevdev/libevdev/libevdev.h new file mode 100644 index 0000000..1f23f6c --- /dev/null +++ b/lib/libevdev/libevdev/libevdev.h @@ -0,0 +1,2404 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2013 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifndef LIBEVDEV_H +#define LIBEVDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define LIBEVDEV_ATTRIBUTE_PRINTF(_format, _args) __attribute__ ((format (printf, _format, _args))) + +/** + * @mainpage + * + * **libevdev** is a library for handling evdev kernel devices. It abstracts + * the \ref ioctls through type-safe interfaces and provides functions to change + * the appearance of the device. + * + * Development + * =========== + * The git repository is available here: + * + * - https://gitlab.freedesktop.org/libevdev/libevdev + * + * Development of libevdev is discussed on + * [input-tools@lists.freedesktop.org](http://lists.freedesktop.org/mailman/listinfo/input-tools). + * Please submit patches, questions or general comments there. + * + * Handling events and SYN_DROPPED + * =============================== + * + * libevdev provides an interface for handling events, including most notably + * `SYN_DROPPED` events. `SYN_DROPPED` events are sent by the kernel when the + * process does not read events fast enough and the kernel is forced to drop + * some events. This causes the device to get out of sync with the process' + * view of it. libevdev handles this by telling the caller that a * `SYN_DROPPED` + * has been received and that the state of the device is different to what is + * to be expected. It then provides the delta between the previous state and + * the actual state of the device as a set of events. See + * libevdev_next_event() and @ref syn_dropped for more information on how + * `SYN_DROPPED` is handled. + * + * Signal safety + * ============= + * + * libevdev is signal-safe for the majority of its operations, i.e. many of + * its functions are safe to be called from within a signal handler. + * Check the API documentation to make sure, unless explicitly stated a call + * is not signal safe. + * + * Device handling + * =============== + * + * A libevdev context is valid for a given file descriptor and its + * duration. Closing the file descriptor will not destroy the libevdev device + * but libevdev will not be able to read further events. + * + * libevdev does not attempt duplicate detection. Initializing two libevdev + * devices for the same fd is valid and behaves the same as for two different + * devices. + * + * libevdev does not handle the file descriptors directly, it merely uses + * them. The caller is responsible for opening the file descriptors, setting + * them to `O_NONBLOCK` and handling permissions. A caller should drain any + * events pending on the file descriptor before passing it to libevdev. + * + * Where does libevdev sit? + * ======================== + * + * libevdev is essentially a `read(2)` on steroids for `/dev/input/eventX` + * devices. It sits below the process that handles input events, in between + * the kernel and that process. In the simplest case, e.g. an evtest-like tool + * the stack would look like this: + * + * kernel → libevdev → evtest + * + * For X.Org input modules, the stack would look like this: + * + * kernel → libevdev → xf86-input-evdev → X server → X client + * + * For anything using libinput (e.g. most Wayland compositors), the stack + * the stack would look like this: + * + * kernel → libevdev → libinput → Compositor → Wayland client + * + * libevdev does **not** have knowledge of X clients or Wayland clients, it is + * too low in the stack. + * + * Example + * ======= + * Below is a simple example that shows how libevdev could be used. This example + * opens a device, checks for relative axes and a left mouse button and if it + * finds them monitors the device to print the event. + * + * @code + * struct libevdev *dev = NULL; + * int fd; + * int rc = 1; + * + * fd = open("/dev/input/event0", O_RDONLY|O_NONBLOCK); + * rc = libevdev_new_from_fd(fd, &dev); + * if (rc < 0) { + * fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc)); + * exit(1); + * } + * printf("Input device name: \"%s\"\n", libevdev_get_name(dev)); + * printf("Input device ID: bus %#x vendor %#x product %#x\n", + * libevdev_get_id_bustype(dev), + * libevdev_get_id_vendor(dev), + * libevdev_get_id_product(dev)); + * if (!libevdev_has_event_type(dev, EV_REL) || + * !libevdev_has_event_code(dev, EV_KEY, BTN_LEFT)) { + * printf("This device does not look like a mouse\n"); + * exit(1); + * } + * + * do { + * struct input_event ev; + * rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); + * if (rc == 0) + * printf("Event: %s %s %d\n", + * libevdev_event_type_get_name(ev.type), + * libevdev_event_code_get_name(ev.type, ev.code), + * ev.value); + * } while (rc == 1 || rc == 0 || rc == -EAGAIN); + * @endcode + * + * A more complete example is available with the libevdev-events tool here: + * https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c + * + * Backwards compatibility with older kernel + * ========================================= + * libevdev attempts to build and run correctly on a number of kernel versions. + * If features required are not available, libevdev attempts to work around them + * in the most reasonable way. For more details see \ref backwardscompatibility. + * + * License information + * =================== + * libevdev is licensed under the + * [MIT license](http://cgit.freedesktop.org/libevdev/tree/COPYING). + * + * Bindings + * =================== + * - Python: https://gitlab.freedesktop.org/libevdev/python-libevdev + * - Haskell: http://hackage.haskell.org/package/evdev + * - Rust: https://crates.io/crates/evdev-rs + * + * Reporting bugs + * ============== + * Please report bugs in the freedesktop.org GitLab instance: + * https://gitlab.freedesktop.org/libevdev/libevdev/issues/ + */ + +/** + * @page syn_dropped SYN_DROPPED handling + * + * This page describes how libevdev handles `SYN_DROPPED` events. + * + * Receiving `SYN_DROPPED` events + * ============================== + * + * The kernel sends evdev events separated by an event of type `EV_SYN` and + * code `SYN_REPORT`. Such an event marks the end of a frame of hardware + * events. The number of events between `SYN_REPORT` events is arbitrary and + * depends on the hardware. An example event sequence may look like this: + * @code + * EV_ABS ABS_X 9 + * EV_ABS ABS_Y 8 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_ABS ABS_X 10 + * EV_ABS ABS_Y 10 + * EV_KEY BTN_TOUCH 1 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_ABS ABS_X 11 + * EV_SYN SYN_REPORT 0 + * @endcode + * + * Events are handed to the client buffer as they appear, the kernel adjusts + * the buffer size to handle at least one full event. In the normal case, + * the client reads the event and the kernel can place the next event in the + * buffer. If the client is not fast enough, the kernel places an event of + * type `EV_SYN` and code `SYN_DROPPED` into the buffer, effectively notifying + * the client that some events were lost. The above example event sequence + * may look like this (note the missing/repeated events): + * @code + * EV_ABS ABS_X 9 + * EV_ABS ABS_Y 8 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_ABS ABS_X 10 + * EV_ABS ABS_Y 10 + * EV_SYN SYN_DROPPED 0 + * EV_ABS ABS_Y 15 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_ABS ABS_X 11 + * EV_KEY BTN_TOUCH 0 + * EV_SYN SYN_REPORT 0 + * @endcode + * + * A `SYN_DROPPED` event may be recieved at any time in the event sequence. + * When a `SYN_DROPPED` event is received, the client must: + * * discard all events since the last `SYN_REPORT` + * * discard all events until including the next `SYN_REPORT` + * These event are part of incomplete event frames. + * + * Synchronizing the state of the device + * ===================================== + * + * The handling of the device after a `SYN_DROPPED` depends on the available + * event codes. For all event codes of type `EV_REL`, no handling is + * necessary, there is no state attached. For all event codes of type + * `EV_KEY`, `EV_SW`, `EV_LED` and `EV_SND`, the matching @ref ioctls retrieve the + * current state. The caller must then compare the last-known state to the + * retrieved state and handle the deltas accordingly. + * libevdev simplifies this approach: if the state of the device has + * changed, libevdev generates an event for each code with the new value and + * passes it to the caller during libevdev_next_event() if + * @ref LIBEVDEV_READ_FLAG_SYNC is set. + * + * For events of type `EV_ABS` and an event code less than `ABS_MT_SLOT`, the + * handling of state changes is as described above. For events between + * `ABS_MT_SLOT` and `ABS_MAX`, the event handling differs. + * Slots are the vehicles to transport information for multiple simultaneous + * touchpoints on a device. Slots are re-used once a touchpoint has ended. + * The kernel sends an `ABS_MT_SLOT` event whenever the current slot + * changes; any event in the above axis range applies only to the currently + * active slot. + * Thus, an event sequence from a slot-capable device may look like this: + * @code + * EV_ABS ABS_MT_POSITION_Y 10 + * EV_ABS ABS_MT_SLOT 1 + * EV_ABS ABS_MT_POSITION_X 100 + * EV_ABS ABS_MT_POSITION_Y 80 + * EV_SYN SYN_REPORT 0 + * @endcode + * Note the lack of `ABS_MT_SLOT`: the first `ABS_MT_POSITION_Y` applies to + * a slot opened previously, and is the only axis that changed for that + * slot. The touchpoint in slot 1 now has position `100/80`. + * The kernel does not provide events if a value does not change, and does + * not send `ABS_MT_SLOT` events if the slot does not change, or none of the + * values within a slot changes. A client must thus keep the state for each + * slot. + * + * If a `SYN_DROPPED` is received, the client must sync all slots + * individually and update its internal state. libevdev simplifies this by + * generating multiple events: + * * for each slot on the device, libevdev generates an + * `ABS_MT_SLOT` event with the value set to the slot number + * * for each event code between `ABS_MT_SLOT + 1` and `ABS_MAX` that changed + * state for this slot, libevdev generates an event for the new state + * * libevdev sends a final `ABS_MT_SLOT` event for the current slot as + * seen by the kernel + * * libevdev terminates this sequence with an `EV_SYN SYN_REPORT` event + * + * An example event sequence for such a sync may look like this: + * @code + * EV_ABS ABS_MT_SLOT 0 + * EV_ABS ABS_MT_POSITION_Y 10 + * EV_ABS ABS_MT_SLOT 1 + * EV_ABS ABS_MT_POSITION_X 100 + * EV_ABS ABS_MT_POSITION_Y 80 + * EV_ABS ABS_MT_SLOT 2 + * EV_ABS ABS_MT_POSITION_Y 8 + * EV_ABS ABS_MT_PRESSURE 12 + * EV_ABS ABS_MT_SLOT 1 + * EV_SYN SYN_REPORT 0 + * @endcode + * Note the terminating `ABS_MT_SLOT` event, this indicates that the kernel + * currently has slot 1 active. + * + * Synchronizing ABS_MT_TRACKING_ID + * ================================ + * + * The event code `ABS_MT_TRACKING_ID` is used to denote the start and end of + * a touch point within a slot. An `ABS_MT_TRACKING_ID` of zero or greater + * denotes the start of a touchpoint, an `ABS_MT_TRACKING_ID` of -1 denotes + * the end of a touchpoint within this slot. During `SYN_DROPPED`, a touch + * point may have ended and re-started within a slot - a client must check + * the `ABS_MT_TRACKING_ID`. libevdev simplifies this by emulating extra + * events if the `ABS_MT_TRACKING_ID` has changed: + * * if the `ABS_MT_TRACKING_ID` was valid and is -1, libevdev enqueues an + * `ABS_MT_TRACKING_ID` event with value -1. + * * if the `ABS_MT_TRACKING_ID` was -1 and is now a valid ID, libevdev + * enqueues an `ABS_MT_TRACKING_ID` event with the current value. + * * if the `ABS_MT_TRACKING_ID` was a valid ID and is now a different valid + * ID, libevev enqueues an `ABS_MT_TRACKING_ID` event with value -1 and + * another `ABS_MT_TRACKING_ID` event with the new value. + * + * An example event sequence for such a sync may look like this: + * @code + * EV_ABS ABS_MT_SLOT 0 + * EV_ABS ABS_MT_TRACKING_ID -1 + * EV_ABS ABS_MT_SLOT 2 + * EV_ABS ABS_MT_TRACKING_ID -1 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_ABS ABS_MT_SLOT 1 + * EV_ABS ABS_MT_POSITION_X 100 + * EV_ABS ABS_MT_POSITION_Y 80 + * EV_ABS ABS_MT_SLOT 2 + * EV_ABS ABS_MT_TRACKING_ID 45 + * EV_ABS ABS_MT_POSITION_Y 8 + * EV_ABS ABS_MT_PRESSURE 12 + * EV_ABS ABS_MT_SLOT 1 + * EV_SYN SYN_REPORT 0 + * @endcode + * Note how the touchpoint in slot 0 was terminated, the touchpoint in slot + * 2 was terminated and then started with a new `ABS_MT_TRACKING_ID`. The touchpoint + * in slot 1 maintained the same `ABS_MT_TRACKING_ID` and only updated the + * coordinates. Slot 1 is the currently active slot. + * + * In the case of a `SYN_DROPPED` event, a touch point may be invisible to a + * client if it started after `SYN_DROPPED` and finished before the client + * handles events again. The below example shows an example event sequence + * and what libevdev sees in the case of a `SYN_DROPPED` event: + * @code + * + * kernel | userspace + * | + * EV_ABS ABS_MT_SLOT 0 | EV_ABS ABS_MT_SLOT 0 + * EV_ABS ABS_MT_TRACKING_ID -1 | EV_ABS ABS_MT_TRACKING_ID -1 + * EV_SYN SYN_REPORT 0 | EV_SYN SYN_REPORT 0 + * ------------------------ | ------------------------ + * EV_ABS ABS_MT_TRACKING_ID 30 | + * EV_ABS ABS_MT_POSITION_X 100 | + * EV_ABS ABS_MT_POSITION_Y 80 | + * EV_SYN SYN_REPORT 0 | SYN_DROPPED + * ------------------------ | + * EV_ABS ABS_MT_TRACKING_ID -1 | + * EV_SYN SYN_REPORT 0 | + * ------------------------ | ------------------------ + * EV_ABS ABS_MT_SLOT 1 | EV_ABS ABS_MT_SLOT 1 + * EV_ABS ABS_MT_POSITION_X 90 | EV_ABS ABS_MT_POSITION_X 90 + * EV_ABS ABS_MT_POSITION_Y 10 | EV_ABS ABS_MT_POSITION_Y 10 + * EV_SYN SYN_REPORT 0 | EV_SYN SYN_REPORT 0 + * @endcode + * If such an event sequence occurs, libevdev will send all updated axes + * during the sync process. Axis events may thus be generated for devices + * without a currently valid `ABS_MT_TRACKING_ID`. Specifically for the above + * example, the client would receive the following event sequence: + * @code + * EV_ABS ABS_MT_SLOT 0 ← LIBEVDEV_READ_FLAG_NORMAL + * EV_ABS ABS_MT_TRACKING_ID -1 + * EV_SYN SYN_REPORT 0 + * ------------------------ + * EV_SYN SYN_DROPPED 0 → LIBEVDEV_READ_STATUS_SYNC + * ------------------------ + * EV_ABS ABS_MT_POSITION_X 100 ← LIBEVDEV_READ_FLAG_SYNC + * EV_ABS ABS_MT_POSITION_Y 80 + * EV_SYN SYN_REPORT 0 + * ----------------------------- → -EGAIN + * EV_ABS ABS_MT_SLOT 1 ← LIBEVDEV_READ_FLAG_NORMAL + * EV_ABS ABS_MT_POSITION_X 90 + * EV_ABS ABS_MT_POSITION_Y 10 + * EV_SYN SYN_REPORT 0 + * ------------------- + * @endcode + * The axis events do not reflect the position of a current touch point, a + * client must take care not to generate a new touch point based on those + * updates. + * + * Discarding events before synchronizing + * ===================================== + * + * The kernel implements the client buffer as a ring buffer. `SYN_DROPPED` + * events are handled when the buffer is full and a new event is received + * from a device. All existing events are discarded, a `SYN_DROPPED` is added + * to the buffer followed by the actual device event. Further events will be + * appended to the buffer until it is either read by the client, or filled + * again, at which point the sequence repeats. + * + * When the client reads the buffer, the buffer will thus always consist of + * exactly one `SYN_DROPPED` event followed by an unspecified number of real + * events. The data the ioctls return is the current state of the device, + * i.e. the state after all these events have been processed. For example, + * assume the buffer contains the following sequence: + * + * @code + * EV_SYN SYN_DROPPED + * EV_ABS ABS_X 1 + * EV_SYN SYN_REPORT 0 + * EV_ABS ABS_X 2 + * EV_SYN SYN_REPORT 0 + * EV_ABS ABS_X 3 + * EV_SYN SYN_REPORT 0 + * EV_ABS ABS_X 4 + * EV_SYN SYN_REPORT 0 + * EV_ABS ABS_X 5 + * EV_SYN SYN_REPORT 0 + * EV_ABS ABS_X 6 + * EV_SYN SYN_REPORT 0 + * @endcode + * An ioctl at any time in this sequence will return a value of 6 for ABS_X. + * + * libevdev discards all events after a `SYN_DROPPED` to ensure the events + * during @ref LIBEVDEV_READ_FLAG_SYNC represent the last known state of the + * device. This loses some granularity of the events especially as the time + * between the `SYN_DROPPED` and the sync process increases. It does however + * avoid spurious cursor movements. In the above example, the event sequence + * by libevdev is: + * @code + * EV_SYN SYN_DROPPED + * EV_ABS ABS_X 6 + * EV_SYN SYN_REPORT 0 + * @endcode + */ + +/** + * @page backwardscompatibility Compatibility and Behavior across kernel versions + * + * This page describes libevdev's behavior when the build-time kernel and the + * run-time kernel differ in their feature set. + * + * With the exception of event names, libevdev defines features that may be + * missing on older kernels and building on such kernels will not disable + * features. Running libevdev on a kernel that is missing some feature will + * change libevdev's behavior. In most cases, the new behavior should be + * obvious, but it is spelled out below in detail. + * + * Minimum requirements + * ==================== + * libevdev requires a 2.6.36 kernel as minimum. Specifically, it requires + * kernel-support for `ABS_MT_SLOT`. + * + * Event and input property names + * ============================== + * Event names and input property names are defined at build-time by the + * linux/input.h shipped with libevdev. + * The list of event names is compiled at build-time, any events not defined + * at build time will not resolve. Specifically, + * libevdev_event_code_get_name() for an undefined type or code will + * always return `NULL`. Likewise, libevdev_property_get_name() will return NULL + * for properties undefined at build-time. + * + * Input properties + * ================ + * If the kernel does not support input properties, specifically the + * `EVIOCGPROPS` ioctl, libevdev does not expose input properties to the caller. + * Specifically, libevdev_has_property() will always return 0 unless the + * property has been manually set with libevdev_enable_property(). + * + * This also applies to the libevdev-uinput code. If uinput does not honor + * `UI_SET_PROPBIT`, libevdev will continue without setting the properties on + * the device. + * + * MT slot behavior + * ================= + * If the kernel does not support the `EVIOCGMTSLOTS` ioctl, libevdev + * assumes all values in all slots are 0 and continues without an error. + * + * SYN_DROPPED behavior + * ==================== + * A kernel without `SYN_DROPPED` won't send such an event. libevdev_next_event() + * will never require the switch to sync mode. + */ + +/** + * @page ioctls evdev ioctls + * + * This page lists the status of the evdev-specific ioctls in libevdev. + * + *
+ *
EVIOCGVERSION:
+ *
supported, see libevdev_get_driver_version()
+ *
EVIOCGID:
+ *
supported, see libevdev_get_id_product(), libevdev_get_id_vendor(), + * libevdev_get_id_bustype(), libevdev_get_id_version()
+ *
EVIOCGREP:
+ *
supported, see libevdev_get_event_value())
+ *
EVIOCSREP:
+ *
supported, see libevdev_enable_event_code()
+ *
EVIOCGKEYCODE:
+ *
currently not supported
+ *
EVIOCSKEYCODE:
+ *
currently not supported
+ *
EVIOCGKEYCODE_V2:
+ *
currently not supported
+ *
EVIOCSKEYCODE_V2:
+ *
currently not supported
+ *
EVIOCGNAME:
+ *
supported, see libevdev_get_name()
+ *
EVIOCGPHYS:
+ *
supported, see libevdev_get_phys()
+ *
EVIOCGUNIQ:
+ *
supported, see libevdev_get_uniq()
+ *
EVIOCGPROP:
+ *
supported, see libevdev_has_property()
+ *
EVIOCGMTSLOTS:
+ *
supported, see libevdev_get_num_slots(), libevdev_get_slot_value()
+ *
EVIOCGKEY:
+ *
supported, see libevdev_has_event_code(), libevdev_get_event_value()
+ *
EVIOCGLED:
+ *
supported, see libevdev_has_event_code(), libevdev_get_event_value()
+ *
EVIOCGSND:
+ *
currently not supported
+ *
EVIOCGSW:
+ *
supported, see libevdev_has_event_code(), libevdev_get_event_value()
+ *
EVIOCGBIT:
+ *
supported, see libevdev_has_event_code(), libevdev_get_event_value()
+ *
EVIOCGABS:
+ *
supported, see libevdev_has_event_code(), libevdev_get_event_value(), + * libevdev_get_abs_info()
+ *
EVIOCSABS:
+ *
supported, see libevdev_kernel_set_abs_info()
+ *
EVIOCSFF:
+ *
supported, see libevdev_upload_ff_effect()
+ *
EVIOCRMFF:
+ *
supported, see libevdev_remove_ff_effect()
+ *
EVIOCGEFFECTS:
+ *
currently not supported
+ *
EVIOCGRAB:
+ *
supported, see libevdev_grab()
+ *
EVIOCSCLOCKID:
+ *
supported, see libevdev_set_clock_id()
+ *
EVIOCREVOKE:
+ *
currently not supported, see + * http://lists.freedesktop.org/archives/input-tools/2014-January/000688.html
+ *
EVIOCGMASK:
+ *
currently not supported
+ *
EVIOCSMASK:
+ *
currently not supported
+ *
+ * + */ + +/** + * @page kernel_header Kernel header + * + * libevdev provides its own copy of the Linux kernel header file and + * compiles against the definitions define here. Event type and event code + * names, etc. are taken from the file below: + * @include linux/input.h + */ + +/** + * @page static_linking Statically linking libevdev + * + * Statically linking libevdev.a is not recommended. Symbol visibility is + * difficult to control in a static library, so extra care must be taken to + * only use symbols that are explicitly exported. libevdev's API stability + * guarantee only applies to those symbols. + * + * If you do link libevdev statically, note that in addition to the exported + * symbols, libevdev reserves the _libevdev_* namespace. Do not use + * or create symbols with that prefix, they are subject to change at any + * time. + */ + +/** + * @page testing libevdev-internal test suite + * + * libevdev's internal test suite uses the + * [Check unit testing framework](http://check.sourceforge.net/). Tests are + * divided into test suites and test cases. Most tests create a uinput device, + * so you'll need to run as root, and your kernel must have + * `CONFIG_INPUT_UINPUT` enabled. + * + * To run a specific suite only: + * + * export CK_RUN_SUITE="suite name" + * + * To run a specific test case only: + * + * export CK_RUN_TEST="test case name" + * + * To get a list of all suites or tests: + * + * git grep "suite_create" + * git grep "tcase_create" + * + * By default, Check forks, making debugging harder. The test suite tries to detect + * if it is running inside gdb and disable forking. If that doesn't work for + * some reason, run gdb as below to avoid forking. + * + * sudo CK_FORK=no CK_RUN_TEST="test case name" gdb ./test/test-libevdev + * + * A special target `make gcov-report.txt` exists that runs gcov and leaves a + * `libevdev.c.gcov` file. Check that for test coverage. + * + * `make check` is hooked up to run the test and gcov (again, needs root). + * + * The test suite creates a lot of devices, very quickly. Add the following + * xorg.conf.d snippet to avoid the devices being added as X devices (at the + * time of writing, mutter can't handle these devices and exits after getting + * a BadDevice error). + * + * $ cat /etc/X11/xorg.conf.d/99-ignore-libevdev-devices.conf + * Section "InputClass" + * Identifier "Ignore libevdev test devices" + * MatchProduct "libevdev test device" + * Option "Ignore" "on" + * EndSection + * + */ + +/** + * @defgroup init Initialization and setup + * + * Initialization, initial setup and file descriptor handling. + * These functions are the main entry points for users of libevdev, usually a + * caller will use this series of calls: + * + * @code + * struct libevdev *dev; + * int err; + * + * dev = libevdev_new(); + * if (!dev) + * return ENOMEM; + * + * err = libevdev_set_fd(dev, fd); + * if (err < 0) + * printf("Failed (errno %d): %s\n", -err, strerror(-err)); + * + * libevdev_free(dev); + * @endcode + * + * libevdev_set_fd() is the central call and initializes the internal structs + * for the device at the given fd. libevdev functions will fail if called + * before libevdev_set_fd() unless documented otherwise. + */ + +/** + * @defgroup logging Library logging facilities + * + * libevdev provides two methods of logging library-internal messages. The + * old method is to provide a global log handler in + * libevdev_set_log_function(). The new method is to provide a per-context + * log handler in libevdev_set_device_log_function(). Developers are encouraged + * to use the per-context logging facilities over the global log handler as + * it provides access to the libevdev instance that caused a message, and is + * more flexible when libevdev is used from within a shared library. + * + * If a caller sets both the global log handler and a per-context log + * handler, each device with a per-context log handler will only invoke that + * log handler. + * + * @note To set a context-specific log handler, a context is needed. + * Thus developers are discouraged from using libevdev_new_from_fd() as + * important messages from the device initialization process may get lost. + * + * @note A context-specific handler cannot be used for libevdev's uinput + * devices. @ref uinput must use the global log handler. + */ + +/** + * @defgroup bits Querying device capabilities + * + * Abstraction functions to handle device capabilities, specifically + * device properties such as the name of the device and the bits + * representing the events supported by this device. + * + * The logical state returned may lag behind the physical state of the device. + * libevdev queries the device state on libevdev_set_fd() and then relies on + * the caller to parse events through libevdev_next_event(). If a caller does not + * use libevdev_next_event(), libevdev will not update the internal state of the + * device and thus returns outdated values. + */ + +/** + * @defgroup mt Multi-touch related functions + * Functions for querying multi-touch-related capabilities. MT devices + * following the kernel protocol B (using `ABS_MT_SLOT`) provide multiple touch + * points through so-called slots on the same axis. The slots are enumerated, + * a client reading from the device will first get an ABS_MT_SLOT event, then + * the values of axes changed in this slot. Multiple slots may be provided in + * before an `EV_SYN` event. + * + * As with @ref bits, the logical state of the device as seen by the library + * depends on the caller using libevdev_next_event(). + * + * The Linux kernel requires all axes on a device to have a semantic + * meaning, matching the axis names in linux/input.h. Some devices merely + * export a number of axes beyond the available axis list. For those + * devices, the multitouch information is invalid. Specifically, if a device + * provides the `ABS_MT_SLOT` axis AND also the `ABS_RESERVED` axis, the + * device is not treated as multitouch device. No slot information is + * available and the `ABS_MT` axis range for these devices is treated as all + * other `EV_ABS` axes. + * + * Note that because of limitations in the kernel API, such fake multitouch + * devices can not be reliably synced after a `SYN_DROPPED` event. libevdev + * ignores all `ABS_MT` axis values during the sync process and instead + * relies on the device to send the current axis value with the first event + * after `SYN_DROPPED`. + */ + +/** + * @defgroup kernel Modifying the appearance or capabilities of the device + * + * Modifying the set of events reported by this device. By default, the + * libevdev device mirrors the kernel device, enabling only those bits + * exported by the kernel. This set of functions enable or disable bits as + * seen from the caller. + * + * Enabling an event type or code does not affect event reporting - a + * software-enabled event will not be generated by the physical hardware. + * Disabling an event will prevent libevdev from routing such events to the + * caller. Enabling and disabling event types and codes is at the library + * level and thus only affects the caller. + * + * If an event type or code is enabled at kernel-level, future users of this + * device will see this event enabled. Currently there is no option of + * disabling an event type or code at kernel-level. + */ + +/** + * @defgroup misc Miscellaneous helper functions + * + * Functions for printing or querying event ranges. The list of names is + * compiled into libevdev and is independent of the run-time kernel. + * Likewise, the max for each event type is compiled in and does not check + * the kernel at run-time. + */ + +/** + * @defgroup events Event handling + * + * Functions to handle events and fetch the current state of the event. + * libevdev updates its internal state as the event is processed and forwarded + * to the caller. Thus, the libevdev state of the device should always be identical + * to the caller's state. It may however lag behind the actual state of the device. + */ + +/** + * @ingroup init + * + * Opaque struct representing an evdev device. + */ +struct libevdev; + +/** + * @ingroup events + */ +enum libevdev_read_flag { + LIBEVDEV_READ_FLAG_SYNC = 1, /**< Process data in sync mode */ + LIBEVDEV_READ_FLAG_NORMAL = 2, /**< Process data in normal mode */ + LIBEVDEV_READ_FLAG_FORCE_SYNC = 4, /**< Pretend the next event is a SYN_DROPPED and + require the caller to sync */ + LIBEVDEV_READ_FLAG_BLOCKING = 8 /**< The fd is not in O_NONBLOCK and a read may block */ +}; + +/** + * @ingroup init + * + * Initialize a new libevdev device. This function only allocates the + * required memory and initializes the struct to sane default values. + * To actually hook up the device to a kernel device, use + * libevdev_set_fd(). + * + * Memory allocated through libevdev_new() must be released by the + * caller with libevdev_free(). + * + * @see libevdev_set_fd + * @see libevdev_free + */ +struct libevdev* libevdev_new(void); + +/** + * @ingroup init + * + * Initialize a new libevdev device from the given fd. + * + * This is a shortcut for + * + * @code + * int err; + * struct libevdev *dev = libevdev_new(); + * err = libevdev_set_fd(dev, fd); + * @endcode + * + * @param fd A file descriptor to the device in O_RDWR or O_RDONLY mode. + * @param[out] dev The newly initialized evdev device. + * + * @return On success, 0 is returned and dev is set to the newly + * allocated struct. On failure, a negative errno is returned and the value + * of dev is undefined. + * + * @see libevdev_free + */ +int libevdev_new_from_fd(int fd, struct libevdev **dev); + +/** + * @ingroup init + * + * Clean up and free the libevdev struct. After completion, the struct + * libevdev is invalid and must not be used. + * + * Note that calling libevdev_free() does not close the file descriptor + * currently associated with this instance. + * + * @param dev The evdev device + * + * @note This function may be called before libevdev_set_fd(). + */ +void libevdev_free(struct libevdev *dev); + +/** + * @ingroup logging + */ +enum libevdev_log_priority { + LIBEVDEV_LOG_ERROR = 10, /**< critical errors and application bugs */ + LIBEVDEV_LOG_INFO = 20, /**< informational messages */ + LIBEVDEV_LOG_DEBUG = 30 /**< debug information */ +}; + +/** + * @ingroup logging + * + * Logging function called by library-internal logging. + * This function is expected to treat its input like printf would. + * + * @param priority Log priority of this message + * @param data User-supplied data pointer (see libevdev_set_log_function()) + * @param file libevdev source code file generating this message + * @param line libevdev source code line generating this message + * @param func libevdev source code function generating this message + * @param format printf-style format string + * @param args List of arguments + * + * @see libevdev_set_log_function + */ +typedef void (*libevdev_log_func_t)(enum libevdev_log_priority priority, + void *data, + const char *file, int line, + const char *func, + const char *format, va_list args) + LIBEVDEV_ATTRIBUTE_PRINTF(6, 0); + +/** + * @ingroup logging + * + * Set a printf-style logging handler for library-internal logging. The default + * logging function is to stdout. + * + * @note The global log handler is only called if no context-specific log + * handler has been set with libevdev_set_device_log_function(). + * + * @param logfunc The logging function for this device. If NULL, the current + * logging function is unset and no logging is performed. + * @param data User-specific data passed to the log handler. + * + * @note This function may be called before libevdev_set_fd(). + * + * @deprecated Use per-context logging instead, see + * libevdev_set_device_log_function(). + */ +void libevdev_set_log_function(libevdev_log_func_t logfunc, void *data); + +/** + * @ingroup logging + * + * Define the minimum level to be printed to the log handler. + * Messages higher than this level are printed, others are discarded. This + * is a global setting and applies to any future logging messages. + * + * @param priority Minimum priority to be printed to the log. + * + * @deprecated Use per-context logging instead, see + * libevdev_set_device_log_function(). + */ +void libevdev_set_log_priority(enum libevdev_log_priority priority); + +/** + * @ingroup logging + * + * Return the current log priority level. Messages higher than this level + * are printed, others are discarded. This is a global setting. + * + * @return the current log level + * + * @deprecated Use per-context logging instead, see + * libevdev_set_device_log_function(). + */ +enum libevdev_log_priority libevdev_get_log_priority(void); + +/** + * @ingroup logging + * + * Logging function called by library-internal logging for a specific + * libevdev context. This function is expected to treat its input like + * printf would. + * + * @param dev The evdev device + * @param priority Log priority of this message + * @param data User-supplied data pointer (see libevdev_set_log_function()) + * @param file libevdev source code file generating this message + * @param line libevdev source code line generating this message + * @param func libevdev source code function generating this message + * @param format printf-style format string + * @param args List of arguments + * + * @see libevdev_set_log_function + * @since 1.3 + */ +typedef void (*libevdev_device_log_func_t)(const struct libevdev *dev, + enum libevdev_log_priority priority, + void *data, + const char *file, int line, + const char *func, + const char *format, va_list args) + LIBEVDEV_ATTRIBUTE_PRINTF(7, 0); + +/** + * @ingroup logging + * + * Set a printf-style logging handler for library-internal logging for this + * device context. The default logging function is NULL, i.e. the global log + * handler is invoked. If a context-specific log handler is set, the global + * log handler is not invoked for this device. + * + * @note This log function applies for this device context only, even if + * another context exists for the same fd. + * + * @param dev The evdev device + * @param logfunc The logging function for this device. If NULL, the current + * logging function is unset and logging falls back to the global log + * handler, if any. + * @param priority Minimum priority to be printed to the log. + * @param data User-specific data passed to the log handler. + * + * @note This function may be called before libevdev_set_fd(). + * @since 1.3 + */ +void libevdev_set_device_log_function(struct libevdev *dev, + libevdev_device_log_func_t logfunc, + enum libevdev_log_priority priority, + void *data); + +/** + * @ingroup init + */ +enum libevdev_grab_mode { + LIBEVDEV_GRAB = 3, /**< Grab the device if not currently grabbed */ + LIBEVDEV_UNGRAB = 4 /**< Ungrab the device if currently grabbed */ +}; + +/** + * @ingroup init + * + * Grab or ungrab the device through a kernel EVIOCGRAB. This prevents other + * clients (including kernel-internal ones such as rfkill) from receiving + * events from this device. + * + * This is generally a bad idea. Don't do this. + * + * Grabbing an already grabbed device, or ungrabbing an ungrabbed device is + * a noop and always succeeds. + * + * A grab is an operation tied to a file descriptor, not a device. If a + * client changes the file descriptor with libevdev_change_fd(), it must + * also re-issue a grab with libevdev_grab(). + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param grab If true, grab the device. Otherwise ungrab the device. + * + * @return 0 if the device was successfully grabbed or ungrabbed, or a + * negative errno in case of failure. + */ +int libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab); + +/** + * @ingroup init + * + * Set the fd for this struct and initialize internal data. + * The fd must be in O_RDONLY or O_RDWR mode. + * + * This function may only be called once per device. If the device changed and + * you need to re-read a device, use libevdev_free() and libevdev_new(). If + * you need to change the fd after closing and re-opening the same device, use + * libevdev_change_fd(). + * + * A caller should ensure that any events currently pending on the fd are + * drained before the file descriptor is passed to libevdev for + * initialization. Due to how the kernel's ioctl handling works, the initial + * device state will reflect the current device state *after* applying all + * events currently pending on the fd. Thus, if the fd is not drained, the + * state visible to the caller will be inconsistent with the events + * immediately available on the device. This does not affect state-less + * events like EV_REL. + * + * Unless otherwise specified, libevdev function behavior is undefined until + * a successful call to libevdev_set_fd(). + * + * @param dev The evdev device + * @param fd The file descriptor for the device + * + * @return 0 on success, or a negative errno on failure + * + * @see libevdev_change_fd + * @see libevdev_new + * @see libevdev_free + */ +int libevdev_set_fd(struct libevdev* dev, int fd); + +/** + * @ingroup init + * + * Change the fd for this device, without re-reading the actual device. If the fd + * changes after initializing the device, for example after a VT-switch in the + * X.org X server, this function updates the internal fd to the newly opened. + * No check is made that new fd points to the same device. If the device has + * changed, libevdev's behavior is undefined. + * + * libevdev does not sync itself after changing the fd and keeps the current + * device state. Use libevdev_next_event with the + * @ref LIBEVDEV_READ_FLAG_FORCE_SYNC flag to force a re-sync. + * + * The example code below illustrates how to force a re-sync of the + * library-internal state. Note that this code doesn't handle the events in + * the caller, it merely forces an update of the internal library state. + * @code + * struct input_event ev; + * libevdev_change_fd(dev, new_fd); + * libevdev_next_event(dev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev); + * while (libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev) == LIBEVDEV_READ_STATUS_SYNC) + * ; // noop + * @endcode + * + * The fd may be open in O_RDONLY or O_RDWR. + * + * After changing the fd, the device is assumed ungrabbed and a caller must + * call libevdev_grab() again. + * + * It is an error to call this function before calling libevdev_set_fd(). + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param fd The new fd + * + * @return 0 on success, or -1 on failure. + * + * @see libevdev_set_fd + */ +int libevdev_change_fd(struct libevdev* dev, int fd); + +/** + * @ingroup init + * + * @param dev The evdev device + * + * @return The previously set fd, or -1 if none had been set previously. + * @note This function may be called before libevdev_set_fd(). + */ +int libevdev_get_fd(const struct libevdev* dev); + +/** + * @ingroup kernel + * + * Uploads a force feedback effect to the given device. The kernel assigns + * an ID for this effect (`struct ff_effect->id`) - this id can be used + * to remove the effect later. + * + * @param dev The evdev device + * @param effect The struct containing the force feedback effect to upload + * + * @return 0 on success, negative error code on failure + */ +int libevdev_upload_ff_effect(struct libevdev *dev, struct ff_effect *effect); + +/** + * @ingroup kernel + * + * Removes the force feedback effect from the given device + * + * @param dev The evdev device + * @param effect_id the id of the effect to remove + * + * @return 0 on success, negative error code on failure + */ +int libevdev_remove_ff_effect(struct libevdev *dev, short effect_id); + +/** + * @ingroup events + */ +enum libevdev_read_status { + /** + * libevdev_next_event() has finished without an error + * and an event is available for processing. + * + * @see libevdev_next_event + */ + LIBEVDEV_READ_STATUS_SUCCESS = 0, + /** + * Depending on the libevdev_next_event() read flag: + * * libevdev received a SYN_DROPPED from the device, and the caller should + * now resync the device, or, + * * an event has been read in sync mode. + * + * @see libevdev_next_event + */ + LIBEVDEV_READ_STATUS_SYNC = 1 +}; + +/** + * @ingroup events + * + * Get the next event from the device. This function operates in two different + * modes: normal mode or sync mode. + * + * In normal mode (when flags has @ref LIBEVDEV_READ_FLAG_NORMAL set), this + * function returns @ref LIBEVDEV_READ_STATUS_SUCCESS and returns the event + * in the argument @p ev. If no events are available at this + * time, it returns -EAGAIN and ev is undefined. + * + * If the current event is an EV_SYN SYN_DROPPED event, this function returns + * @ref LIBEVDEV_READ_STATUS_SYNC and ev is set to the EV_SYN event. + * The caller should now call this function with the + * @ref LIBEVDEV_READ_FLAG_SYNC flag set, to get the set of events that make up the + * device state delta. This function returns @ref LIBEVDEV_READ_STATUS_SYNC for + * each event part of that delta, until it returns -EAGAIN once all events + * have been synced. For more details on what libevdev does to sync after a + * SYN_DROPPED event, see @ref syn_dropped. + * + * If a device needs to be synced by the caller but the caller does not call + * with the @ref LIBEVDEV_READ_FLAG_SYNC flag set, all events from the diff are + * dropped after libevdev updates its internal state and event processing + * continues as normal. Note that the current slot and the state of touch + * points may have updated during the SYN_DROPPED event, it is strongly + * recommended that a caller ignoring all sync events calls + * libevdev_get_current_slot() and checks the ABS_MT_TRACKING_ID values for + * all slots. + * + * If a device has changed state without events being enqueued in libevdev, + * e.g. after changing the file descriptor, use the @ref + * LIBEVDEV_READ_FLAG_FORCE_SYNC flag. This triggers an internal sync of the + * device and libevdev_next_event() returns @ref LIBEVDEV_READ_STATUS_SYNC. + * Any state changes are available as events as described above. If + * @ref LIBEVDEV_READ_FLAG_FORCE_SYNC is set, the value of ev is undefined. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param flags Set of flags to determine behaviour. If @ref LIBEVDEV_READ_FLAG_NORMAL + * is set, the next event is read in normal mode. If @ref LIBEVDEV_READ_FLAG_SYNC is + * set, the next event is read in sync mode. + * @param ev On success, set to the current event. + * @return On failure, a negative errno is returned. + * @retval LIBEVDEV_READ_STATUS_SUCCESS One or more events were read of the + * device and ev points to the next event in the queue + * @retval -EAGAIN No events are currently available on the device + * @retval LIBEVDEV_READ_STATUS_SYNC A SYN_DROPPED event was received, or a + * synced event was returned and ev points to the SYN_DROPPED event + * + * @note This function is signal-safe. + */ +int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev); + +/** + * @ingroup events + * + * Check if there are events waiting for us. This function does not read an + * event off the fd and may not access the fd at all. If there are events + * queued internally this function will return non-zero. If the internal + * queue is empty, this function will poll the file descriptor for data. + * + * This is a convenience function for simple processes, most complex programs + * are expected to use select(2) or poll(2) on the file descriptor. The kernel + * guarantees that if data is available, it is a multiple of sizeof(struct + * input_event), and thus calling libevdev_next_event() when select(2) or + * poll(2) return is safe. You do not need libevdev_has_event_pending() if + * you're using select(2) or poll(2). + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @return On failure, a negative errno is returned. + * @retval 0 No event is currently available + * @retval 1 One or more events are available on the fd + * + * @note This function is signal-safe. + */ +int libevdev_has_event_pending(struct libevdev *dev); + +/** + * @ingroup bits + * + * Retrieve the device's name, either as set by the caller or as read from + * the kernel. The string returned is valid until libevdev_free() or until + * libevdev_set_name(), whichever comes earlier. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The device name as read off the kernel device. The name is never + * NULL but it may be the empty string. + * + * @note This function is signal-safe. + */ +const char* libevdev_get_name(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * Change the device's name as returned by libevdev_get_name(). This + * function destroys the string previously returned by libevdev_get_name(), + * a caller must take care that no references are kept. + * + * @param dev The evdev device + * @param name The new, non-NULL, name to assign to this device. + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. + */ +void libevdev_set_name(struct libevdev *dev, const char *name); + +/** + * @ingroup bits + * + * Retrieve the device's physical location, either as set by the caller or + * as read from the kernel. The string returned is valid until + * libevdev_free() or until libevdev_set_phys(), whichever comes earlier. + * + * Virtual devices such as uinput devices have no phys location. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The physical location of this device, or NULL if there is none + * + * @note This function is signal safe. + */ +const char * libevdev_get_phys(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * Change the device's physical location as returned by libevdev_get_phys(). + * This function destroys the string previously returned by + * libevdev_get_phys(), a caller must take care that no references are kept. + * + * @param dev The evdev device + * @param phys The new phys to assign to this device. + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. + */ +void libevdev_set_phys(struct libevdev *dev, const char *phys); + +/** + * @ingroup bits + * + * Retrieve the device's unique identifier, either as set by the caller or + * as read from the kernel. The string returned is valid until + * libevdev_free() or until libevdev_set_uniq(), whichever comes earlier. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The unique identifier for this device, or NULL if there is none + * + * @note This function is signal safe. + */ +const char * libevdev_get_uniq(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * Change the device's unique identifier as returned by libevdev_get_uniq(). + * This function destroys the string previously returned by + * libevdev_get_uniq(), a caller must take care that no references are kept. + * + * @param dev The evdev device + * @param uniq The new uniq to assign to this device. + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. + */ +void libevdev_set_uniq(struct libevdev *dev, const char *uniq); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The device's product ID + * + * @note This function is signal-safe. + */ +int libevdev_get_id_product(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param product_id The product ID to assign to this device + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. Even though + * the function accepts an int for product_id the value is truncated at 16 + * bits. + */ +void libevdev_set_id_product(struct libevdev *dev, int product_id); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The device's vendor ID + * + * @note This function is signal-safe. + */ +int libevdev_get_id_vendor(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param vendor_id The vendor ID to assign to this device + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. Even though + * the function accepts an int for vendor_id the value is truncated at 16 + * bits. + */ +void libevdev_set_id_vendor(struct libevdev *dev, int vendor_id); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The device's bus type + * + * @note This function is signal-safe. + */ +int libevdev_get_id_bustype(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param bustype The bustype to assign to this device + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. Even though + * the function accepts an int for bustype the value is truncated at 16 + * bits. + */ +void libevdev_set_id_bustype(struct libevdev *dev, int bustype); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The device's firmware version + * + * @note This function is signal-safe. + */ +int libevdev_get_id_version(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param version The version to assign to this device + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. Even though + * the function accepts an int for version the value is truncated at 16 + * bits. + */ +void libevdev_set_id_version(struct libevdev *dev, int version); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The driver version for this device + * + * @note This function is signal-safe. + */ +int libevdev_get_driver_version(const struct libevdev *dev); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param prop The input property to query for, one of INPUT_PROP_... + * + * @return 1 if the device provides this input property, or 0 otherwise. + * + * @note This function is signal-safe + */ +int libevdev_has_property(const struct libevdev *dev, unsigned int prop); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param prop The input property to enable, one of INPUT_PROP_... + * + * @return 0 on success or -1 on failure + * + * @note This function may be called before libevdev_set_fd(). A call to + * libevdev_set_fd() will overwrite any previously set value. + */ +int libevdev_enable_property(struct libevdev *dev, unsigned int prop); + +/** + * @ingroup kernel + * + * @param dev The evdev device + * @param prop The input property to disable, one of INPUT_PROP_... + * + * @return 0 on success or -1 on failure + */ +int libevdev_disable_property(struct libevdev *dev, unsigned int prop); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type to query for, one of EV_SYN, EV_REL, etc. + * + * @return 1 if the device supports this event type, or 0 otherwise. + * + * @note This function is signal-safe. + */ +int libevdev_has_event_type(const struct libevdev *dev, unsigned int type); + +/** + * @ingroup bits + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to query for, one of ABS_X, REL_X, etc. + * + * @return 1 if the device supports this event type and code, or 0 otherwise. + * + * @note This function is signal-safe. + */ +int libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code); + +/** + * @ingroup bits + * + * Get the minimum axis value for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return axis minimum for the given axis or 0 if the axis is invalid + * + * @note This function is signal-safe. + */ +int libevdev_get_abs_minimum(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Get the maximum axis value for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return axis maximum for the given axis or 0 if the axis is invalid + * + * @note This function is signal-safe. + */ +int libevdev_get_abs_maximum(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Get the axis fuzz for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return axis fuzz for the given axis or 0 if the axis is invalid + * + * @note This function is signal-safe. + */ +int libevdev_get_abs_fuzz(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Get the axis flat for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return axis flat for the given axis or 0 if the axis is invalid + * + * @note This function is signal-safe. + */ +int libevdev_get_abs_flat(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Get the axis resolution for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return axis resolution for the given axis or 0 if the axis is invalid + * + * @note This function is signal-safe. + */ +int libevdev_get_abs_resolution(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Get the axis info for the given axis, as advertised by the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to query for, one of ABS_X, ABS_Y, etc. + * + * @return The input_absinfo for the given code, or NULL if the device does + * not support this event code. + * + * @note This function is signal-safe. + */ +const struct input_absinfo* libevdev_get_abs_info(const struct libevdev *dev, unsigned int code); + +/** + * @ingroup bits + * + * Behaviour of this function is undefined if the device does not provide + * the event. + * + * If the device supports ABS_MT_SLOT, the value returned for any ABS_MT_* + * event code is undefined. Use libevdev_get_slot_value() instead. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to query for, one of ABS_X, REL_X, etc. + * + * @return The current value of the event. + * + * @note This function is signal-safe. + * @note The value for ABS_MT_ events is undefined, use + * libevdev_get_slot_value() instead + * + * @see libevdev_get_slot_value + */ +int libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code); + +/** + * @ingroup kernel + * + * Set the value for a given event type and code. This only makes sense for + * some event types, e.g. setting the value for EV_REL is pointless. + * + * This is a local modification only affecting only this representation of + * this device. A future call to libevdev_get_event_value() will return this + * value, unless the value was overwritten by an event. + * + * If the device supports ABS_MT_SLOT, the value set for any ABS_MT_* + * event code is the value of the currently active slot. You should use + * libevdev_set_slot_value() instead. + * + * If the device supports ABS_MT_SLOT and the type is EV_ABS and the code is + * ABS_MT_SLOT, the value must be a positive number less then the number of + * slots on the device. Otherwise, libevdev_set_event_value() returns -1. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to set the value for, one of ABS_X, LED_NUML, etc. + * @param value The new value to set + * + * @return 0 on success, or -1 on failure. + * @retval -1 + * - the device does not have the event type or code enabled, or + * - the code is outside the allowed limits for the given type, or + * - the type cannot be set, or + * - the value is not permitted for the given code. + * + * @see libevdev_set_slot_value + * @see libevdev_get_event_value + */ +int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int code, int value); + +/** + * @ingroup bits + * + * Fetch the current value of the event type. This is a shortcut for + * + * @code + * if (libevdev_has_event_type(dev, t) && libevdev_has_event_code(dev, t, c)) + * val = libevdev_get_event_value(dev, t, c); + * @endcode + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to query for, one of ABS_X, REL_X, etc. + * @param[out] value The current value of this axis returned. + * + * @return If the device supports this event type and code, the return value is + * non-zero and value is set to the current value of this axis. Otherwise, + * 0 is returned and value is unmodified. + * + * @note This function is signal-safe. + * @note The value for ABS_MT_ events is undefined, use + * libevdev_fetch_slot_value() instead + * + * @see libevdev_fetch_slot_value + */ +int libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value); + +/** + * @ingroup mt + * + * Return the current value of the code for the given slot. + * + * The return value is undefined for a slot exceeding the available slots on + * the device, for a code that is not in the permitted ABS_MT range or for a + * device that does not have slots. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param slot The numerical slot number, must be smaller than the total number + * of slots on this device + * @param code The event code to query for, one of ABS_MT_POSITION_X, etc. + * + * @note This function is signal-safe. + * @note The value for events other than ABS_MT_ is undefined, use + * libevdev_fetch_value() instead + * + * @see libevdev_get_event_value + */ +int libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code); + +/** + * @ingroup kernel + * + * Set the value for a given code for the given slot. + * + * This is a local modification only affecting only this representation of + * this device. A future call to libevdev_get_slot_value() will return this + * value, unless the value was overwritten by an event. + * + * This function does not set event values for axes outside the ABS_MT range, + * use libevdev_set_event_value() instead. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param slot The numerical slot number, must be smaller than the total number + * of slots on this device + * @param code The event code to set the value for, one of ABS_MT_POSITION_X, etc. + * @param value The new value to set + * + * @return 0 on success, or -1 on failure. + * @retval -1 + * - the device does not have the event code enabled, or + * - the code is outside the allowed limits for multitouch events, or + * - the slot number is outside the limits for this device, or + * - the device does not support multitouch events. + * + * @see libevdev_set_event_value + * @see libevdev_get_slot_value + */ +int libevdev_set_slot_value(struct libevdev *dev, unsigned int slot, unsigned int code, int value); + +/** + * @ingroup mt + * + * Fetch the current value of the code for the given slot. This is a shortcut for + * + * @code + * if (libevdev_has_event_type(dev, EV_ABS) && + * libevdev_has_event_code(dev, EV_ABS, c) && + * slot < device->number_of_slots) + * val = libevdev_get_slot_value(dev, slot, c); + * @endcode + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param slot The numerical slot number, must be smaller than the total number + * of slots on this * device + * @param[out] value The current value of this axis returned. + * + * @param code The event code to query for, one of ABS_MT_POSITION_X, etc. + * @return If the device supports this event code, the return value is + * non-zero and value is set to the current value of this axis. Otherwise, or + * if the event code is not an ABS_MT_* event code, 0 is returned and value + * is unmodified. + * + * @note This function is signal-safe. + */ +int libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code, int *value); + +/** + * @ingroup mt + * + * Get the number of slots supported by this device. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return The number of slots supported, or -1 if the device does not provide + * any slots + * + * @note A device may provide ABS_MT_SLOT but a total number of 0 slots. Hence + * the return value of -1 for "device does not provide slots at all" + */ +int libevdev_get_num_slots(const struct libevdev *dev); + +/** + * @ingroup mt + * + * Get the currently active slot. This may differ from the value + * an ioctl may return at this time as events may have been read off the fd + * since changing the slot value but those events are still in the buffer + * waiting to be processed. The returned value is the value a caller would + * see if it were to process events manually one-by-one. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * + * @return the currently active slot (logically) + * + * @note This function is signal-safe. + */ +int libevdev_get_current_slot(const struct libevdev *dev); + +/** + * @ingroup kernel + * + * Change the minimum for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param val The new minimum for this axis + */ +void libevdev_set_abs_minimum(struct libevdev *dev, unsigned int code, int val); + +/** + * @ingroup kernel + * + * Change the maximum for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param val The new maxium for this axis + */ +void libevdev_set_abs_maximum(struct libevdev *dev, unsigned int code, int val); + +/** + * @ingroup kernel + * + * Change the fuzz for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param val The new fuzz for this axis + */ +void libevdev_set_abs_fuzz(struct libevdev *dev, unsigned int code, int val); + +/** + * @ingroup kernel + * + * Change the flat for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param val The new flat for this axis + */ +void libevdev_set_abs_flat(struct libevdev *dev, unsigned int code, int val); + +/** + * @ingroup kernel + * + * Change the resolution for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param val The new axis resolution + */ +void libevdev_set_abs_resolution(struct libevdev *dev, unsigned int code, int val); + +/** + * @ingroup kernel + * + * Change the abs info for the given EV_ABS event code, if the code exists. + * This function has no effect if libevdev_has_event_code() returns false for + * this code. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code One of ABS_X, ABS_Y, ... + * @param abs The new absolute axis data (min, max, fuzz, flat, resolution) + */ +void libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs); + +/** + * @ingroup kernel + * + * Forcibly enable an event type on this device, even if the underlying + * device does not support it. While this cannot make the device actually + * report such events, it will now return true for libevdev_has_event_type(). + * + * This is a local modification only affecting only this representation of + * this device. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type to enable (EV_ABS, EV_KEY, ...) + * + * @return 0 on success or -1 otherwise + * + * @see libevdev_has_event_type + */ +int libevdev_enable_event_type(struct libevdev *dev, unsigned int type); + +/** + * @ingroup kernel + * + * Forcibly disable an event type on this device, even if the underlying + * device provides it. This effectively mutes the respective set of + * events. libevdev will filter any events matching this type and none will + * reach the caller. libevdev_has_event_type() will return false for this + * type. + * + * In most cases, a caller likely only wants to disable a single code, not + * the whole type. Use libevdev_disable_event_code() for that. + * + * Disabling EV_SYN will not work. Don't shoot yourself in the foot. + * It hurts. + * + * This is a local modification only affecting only this representation of + * this device. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type to disable (EV_ABS, EV_KEY, ...) + * + * @return 0 on success or -1 otherwise + * + * @see libevdev_has_event_type + * @see libevdev_disable_event_type + */ +int libevdev_disable_event_type(struct libevdev *dev, unsigned int type); + +/** + * @ingroup kernel + * + * Forcibly enable an event code on this device, even if the underlying + * device does not support it. While this cannot make the device actually + * report such events, it will now return true for libevdev_has_event_code(). + * + * The last argument depends on the type and code: + * - If type is EV_ABS, data must be a pointer to a struct input_absinfo + * containing the data for this axis. + * - If type is EV_REP, data must be a pointer to a int containing the data + * for this axis + * - For all other types, the argument must be NULL. + * + * This function calls libevdev_enable_event_type() if necessary. + * + * This is a local modification only affecting only this representation of + * this device. + * + * If this function is called with a type of EV_ABS and EV_REP on a device + * that already has the given event code enabled, the values in data + * overwrite the previous values. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type to enable (EV_ABS, EV_KEY, ...) + * @param code The event code to enable (ABS_X, REL_X, etc.) + * @param data If type is EV_ABS, data points to a struct input_absinfo. If type is EV_REP, data + * points to an integer. Otherwise, data must be NULL. + * + * @return 0 on success or -1 otherwise + * + * @see libevdev_enable_event_type + */ +int libevdev_enable_event_code(struct libevdev *dev, unsigned int type, unsigned int code, const void *data); + +/** + * @ingroup kernel + * + * Forcibly disable an event code on this device, even if the underlying + * device provides it. This effectively mutes the respective set of + * events. libevdev will filter any events matching this type and code and + * none will reach the caller. libevdev_has_event_code() will return false for + * this code. + * + * Disabling all event codes for a given type will not disable the event + * type. Use libevdev_disable_event_type() for that. + * + * This is a local modification only affecting only this representation of + * this device. + * + * Disabling codes of type EV_SYN will not work. Don't shoot yourself in the + * foot. It hurts. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type to disable (EV_ABS, EV_KEY, ...) + * @param code The event code to disable (ABS_X, REL_X, etc.) + * + * @return 0 on success or -1 otherwise + * + * @see libevdev_has_event_code + * @see libevdev_disable_event_type + */ +int libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code); + +/** + * @ingroup kernel + * + * Set the device's EV_ABS axis to the value defined in the abs + * parameter. This will be written to the kernel. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_ABS event code to modify, one of ABS_X, ABS_Y, etc. + * @param abs Axis info to set the kernel axis to + * + * @return 0 on success, or a negative errno on failure + * + * @see libevdev_enable_event_code + */ +int libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs); + +/** + * @ingroup kernel + */ +enum libevdev_led_value { + LIBEVDEV_LED_ON = 3, /**< Turn the LED on */ + LIBEVDEV_LED_OFF = 4 /**< Turn the LED off */ +}; + +/** + * @ingroup kernel + * + * Turn an LED on or off. Convenience function, if you need to modify multiple + * LEDs simultaneously, use libevdev_kernel_set_led_values() instead. + * + * @note enabling an LED requires write permissions on the device's file descriptor. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_LED event code to modify, one of LED_NUML, LED_CAPSL, ... + * @param value Specifies whether to turn the LED on or off + * @return 0 on success, or a negative errno on failure + */ +int libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum libevdev_led_value value); + +/** + * @ingroup kernel + * + * Turn multiple LEDs on or off simultaneously. This function expects a pair + * of LED codes and values to set them to, terminated by a -1. For example, to + * switch the NumLock LED on but the CapsLock LED off, use: + * + * @code + * libevdev_kernel_set_led_values(dev, LED_NUML, LIBEVDEV_LED_ON, + * LED_CAPSL, LIBEVDEV_LED_OFF, + * -1); + * @endcode + * + * If any LED code or value is invalid, this function returns -EINVAL and no + * LEDs are modified. + * + * @note enabling an LED requires write permissions on the device's file descriptor. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param ... A pair of LED_* event codes and libevdev_led_value_t, followed by + * -1 to terminate the list. + * @return 0 on success, or a negative errno on failure + */ +int libevdev_kernel_set_led_values(struct libevdev *dev, ...); + +/** + * @ingroup kernel + * + * Set the clock ID to be used for timestamps. Further events from this device + * will report an event time based on the given clock. + * + * This is a modification only affecting this representation of + * this device. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param clockid The clock to use for future events. Permitted values + * are CLOCK_MONOTONIC and CLOCK_REALTIME (the default). + * @return 0 on success, or a negative errno on failure + */ +int libevdev_set_clock_id(struct libevdev *dev, int clockid); + +/** + * @ingroup misc + * + * Helper function to check if an event is of a specific type. This is + * virtually the same as: + * + * ev->type == type + * + * with the exception that some sanity checks are performed to ensure type + * is valid. + * + * @note The ranges for types are compiled into libevdev. If the kernel + * changes the max value, libevdev will not automatically pick these up. + * + * @param ev The input event to check + * @param type Input event type to compare the event against (EV_REL, EV_ABS, + * etc.) + * + * @return 1 if the event type matches the given type, 0 otherwise (or if + * type is invalid) + */ +int libevdev_event_is_type(const struct input_event *ev, unsigned int type); + +/** + * @ingroup misc + * + * Helper function to check if an event is of a specific type and code. This + * is virtually the same as: + * + * ev->type == type && ev->code == code + * + * with the exception that some sanity checks are performed to ensure type and + * code are valid. + * + * @note The ranges for types and codes are compiled into libevdev. If the kernel + * changes the max value, libevdev will not automatically pick these up. + * + * @param ev The input event to check + * @param type Input event type to compare the event against (EV_REL, EV_ABS, + * etc.) + * @param code Input event code to compare the event against (ABS_X, REL_X, + * etc.) + * + * @return 1 if the event type matches the given type and code, 0 otherwise + * (or if type/code are invalid) + */ +int libevdev_event_is_code(const struct input_event *ev, unsigned int type, unsigned int code); + +/** + * @ingroup misc + * + * @param type The event type to return the name for. + * + * @return The name of the given event type (e.g. EV_ABS) or NULL for an + * invalid type + * + * @note The list of names is compiled into libevdev. If the kernel adds new + * defines for new event types, libevdev will not automatically pick these up. + */ +const char * libevdev_event_type_get_name(unsigned int type); +/** + * @ingroup misc + * + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to return the name for (e.g. ABS_X) + * + * @return The name of the given event code (e.g. ABS_X) or NULL for an + * invalid type or code + * + * @note The list of names is compiled into libevdev. If the kernel adds new + * defines for new event codes, libevdev will not automatically pick these up. + */ +const char * libevdev_event_code_get_name(unsigned int type, unsigned int code); + +/** + * @ingroup misc + * + * This function resolves the event value for a code. + * + * For almost all event codes this will return NULL as the value is just a + * numerical value. As of kernel 4.17, the only event code that will return + * a non-NULL value is EV_ABS/ABS_MT_TOOL_TYPE. + * + * @param type The event type for the value to query (EV_ABS, etc.) + * @param code The event code for the value to query (e.g. ABS_MT_TOOL_TYPE) + * @param value The event value to return the name for (e.g. MT_TOOL_PALM) + * + * @return The name of the given event value (e.g. MT_TOOL_PALM) or NULL for + * an invalid type or code or NULL for an axis that has numerical values + * only. + * + * @note The list of names is compiled into libevdev. If the kernel adds new + * defines for new event values, libevdev will not automatically pick these up. + */ +const char * libevdev_event_value_get_name(unsigned int type, + unsigned int code, + int value); +/** + * @ingroup misc + * + * @param prop The input prop to return the name for (e.g. INPUT_PROP_BUTTONPAD) + * + * @return The name of the given input prop (e.g. INPUT_PROP_BUTTONPAD) or NULL for an + * invalid property + * + * @note The list of names is compiled into libevdev. If the kernel adds new + * defines for new properties libevdev will not automatically pick these up. + * @note On older kernels input properties may not be defined and + * libevdev_property_get_name() will always return NULL + */ +const char* libevdev_property_get_name(unsigned int prop); + +/** + * @ingroup misc + * + * @param type The event type to return the maximum for (EV_ABS, EV_REL, etc.). No max is defined for + * EV_SYN. + * + * @return The max value defined for the given event type, e.g. ABS_MAX for a type of EV_ABS, or -1 + * for an invalid type. + * + * @note The max value is compiled into libevdev. If the kernel changes the + * max value, libevdev will not automatically pick these up. + */ +int libevdev_event_type_get_max(unsigned int type); + +/** + * @ingroup misc + * + * Look up an event-type by its name. Event-types start with "EV_" followed by + * the name (eg., "EV_ABS"). The "EV_" prefix must be included in the name. It + * returns the constant assigned to the event-type or -1 if not found. + * + * @param name A non-NULL string describing an input-event type ("EV_KEY", + * "EV_ABS", ...), zero-terminated. + * + * @return The given type constant for the passed name or -1 if not found. + * + * @note EV_MAX is also recognized. + */ +int libevdev_event_type_from_name(const char *name); + +/** + * @ingroup misc + * + * Look up an event-type by its name. Event-types start with "EV_" followed by + * the name (eg., "EV_ABS"). The "EV_" prefix must be included in the name. It + * returns the constant assigned to the event-type or -1 if not found. + * + * @param name A non-NULL string describing an input-event type ("EV_KEY", + * "EV_ABS", ...). + * @param len The length of the passed string excluding any terminating 0 + * character. + * + * @return The given type constant for the passed name or -1 if not found. + * + * @note EV_MAX is also recognized. + */ +int libevdev_event_type_from_name_n(const char *name, size_t len); + +/** + * @ingroup misc + * + * Look up an event code by its type and name. Event codes start with a fixed + * prefix followed by their name (eg., "ABS_X"). The prefix must be included in + * the name. It returns the constant assigned to the event code or -1 if not + * found. + * + * You have to pass the event type where to look for the name. For instance, to + * resolve "ABS_X" you need to pass EV_ABS as type and "ABS_X" as string. + * Supported event codes are codes starting with SYN_, KEY_, BTN_, REL_, ABS_, + * MSC_, SND_, SW_, LED_, REP_, FF_. + * + * @param type The event type (EV_* constant) where to look for the name. + * @param name A non-NULL string describing an input-event code ("KEY_A", + * "ABS_X", "BTN_Y", ...), zero-terminated. + * + * @return The given code constant for the passed name or -1 if not found. + */ +int libevdev_event_code_from_name(unsigned int type, const char *name); + +/** + * @ingroup misc + * + * Look up an event code by its type and name. Event codes start with a fixed + * prefix followed by their name (eg., "ABS_X"). The prefix must be included in + * the name. It returns the constant assigned to the event code or -1 if not + * found. + * + * You have to pass the event type where to look for the name. For instance, to + * resolve "ABS_X" you need to pass EV_ABS as type and "ABS_X" as string. + * Supported event codes are codes starting with SYN_, KEY_, BTN_, REL_, ABS_, + * MSC_, SND_, SW_, LED_, REP_, FF_. + * + * @param type The event type (EV_* constant) where to look for the name. + * @param name A non-NULL string describing an input-event code ("KEY_A", + * "ABS_X", "BTN_Y", ...). + * @param len The length of the string in @p name excluding any terminating 0 + * character. + * + * @return The given code constant for the name or -1 if not found. + */ +int libevdev_event_code_from_name_n(unsigned int type, const char *name, + size_t len); + +/** + * @ingroup misc + * + * Look up an event value by its type, code and name. Event values start + * with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The + * prefix must be included in the name. It returns the constant assigned + * to the event code or -1 if not found. + * + * You have to pass the event type and code where to look for the name. For + * instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type, + * ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string. + * + * As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution. + * + * @param type The event type (EV_* constant) where to look for the name. + * @param code The event code (ABS_* constant) where to look for the name. + * @param name A non-NULL string describing an input-event value + * ("MT_TOOL_TYPE", ...) + * + * @return The given value constant for the name or -1 if not found. + */ +int libevdev_event_value_from_name(unsigned int type, unsigned int code, + const char *name); + +/** + * @ingroup misc + * + * Look up an event type for a event code name. For example, the name + * "ABS_Y" returns EV_ABS. For the lookup to succeed, the name must be + * unique, which is the case for all defines as of kernel 5.0 and likely to + * be the case in the future. + * + * This is equivalent to libevdev_event_type_from_name() but takes the code + * name instead of the type name. + * + * @param name A non-NULL string describing an input-event value + * ("ABS_X", "REL_Y", "KEY_A", ...) + * + * @return The given event code for the name or -1 if not found. + */ +int +libevdev_event_type_from_code_name(const char *name); + +/** + * @ingroup misc + * + * Look up an event type for a event code name. For example, the name + * "ABS_Y" returns EV_ABS. For the lookup to succeed, the name must be + * unique, which is the case for all defines as of kernel 5.0 and likely to + * be the case in the future. + * + * This is equivalent to libevdev_event_type_from_name_n() but takes the code + * name instead of the type name. + * + * @param name A non-NULL string describing an input-event value + * ("ABS_X", "REL_Y", "KEY_A", ...) + * @param len The length of the passed string excluding any terminating 0 + * character. + * + * @return The given event code for the name or -1 if not found. + */ +int +libevdev_event_type_from_code_name_n(const char *name, size_t len); + +/** + * @ingroup misc + * + * Look up an event code by its name. For example, the name "ABS_Y" + * returns 1. For the lookup to succeed, the name must be unique, which is + * the case for all defines as of kernel 5.0 and likely to be the case in + * the future. + * + * This is equivalent to libevdev_event_code_from_name() without the need + * for knowing the event type. + * + * @param name A non-NULL string describing an input-event value + * ("ABS_X", "REL_Y", "KEY_A", ...) + * + * @return The given event code for the name or -1 if not found. + */ +int +libevdev_event_code_from_code_name(const char *name); + +/** + * @ingroup misc + * + * Look up an event code by its name. For example, the name "ABS_Y" + * returns 1. For the lookup to succeed, the name must be unique, which is + * the case for all defines as of kernel 5.0 and likely to be the case in + * the future. + * + * This is equivalent to libevdev_event_code_from_name_n() without the need + * for knowing the event type. + * + * @param name A non-NULL string describing an input-event value + * ("ABS_X", "REL_Y", "KEY_A", ...) + * @param len The length of the passed string excluding any terminating 0 + * character. + * + * @return The given event code for the name or -1 if not found. + */ +int +libevdev_event_code_from_code_name_n(const char *name, size_t len); + +/** + * @ingroup misc + * + * Look up an event value by its type, code and name. Event values start + * with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The + * prefix must be included in the name. It returns the constant assigned + * to the event code or -1 if not found. + * + * You have to pass the event type and code where to look for the name. For + * instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type, + * ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string. + * + * As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution. + * + * @param type The event type (EV_* constant) where to look for the name. + * @param code The event code (ABS_* constant) where to look for the name. + * @param name A non-NULL string describing an input-event value + * ("MT_TOOL_TYPE", ...) + * @param len The length of the string in @p name excluding any terminating 0 + * character. + * + * @return The given value constant for the name or -1 if not found. + */ +int libevdev_event_value_from_name_n(unsigned int type, unsigned int code, + const char *name, size_t len); + +/** + * @ingroup misc + * + * Look up an input property by its name. Properties start with the fixed + * prefix "INPUT_PROP_" followed by their name (eg., "INPUT_PROP_POINTER"). + * The prefix must be included in the name. It returns the constant assigned + * to the property or -1 if not found. + * + * @param name A non-NULL string describing an input property + * + * @return The given code constant for the name or -1 if not found. + */ +int libevdev_property_from_name(const char *name); + +/** + * @ingroup misc + * + * Look up an input property by its name. Properties start with the fixed + * prefix "INPUT_PROP_" followed by their name (eg., "INPUT_PROP_POINTER"). + * The prefix must be included in the name. It returns the constant assigned + * to the property or -1 if not found. + * + * @param name A non-NULL string describing an input property + * @param len The length of the string in @p name excluding any terminating 0 + * character. + * + * @return The given code constant for the name or -1 if not found. + */ +int libevdev_property_from_name_n(const char *name, size_t len); + +/** + * @ingroup bits + * + * Get the repeat delay and repeat period values for this device. This + * function is a convenience function only, EV_REP is supported by + * libevdev_get_event_value(). + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param delay If not null, set to the repeat delay value + * @param period If not null, set to the repeat period value + * + * @return 0 on success, -1 if this device does not have repeat settings. + * + * @note This function is signal-safe + * + * @see libevdev_get_event_value + */ +int libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period); + +/********* DEPRECATED SECTION *********/ +#if defined(__GNUC__) && __GNUC__ >= 4 +#define LIBEVDEV_DEPRECATED __attribute__ ((deprecated)) +#else +#define LIBEVDEV_DEPRECATED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LIBEVDEV_H */ diff --git a/lib/libevdev/libevdev/make-event-names.py b/lib/libevdev/libevdev/make-event-names.py new file mode 100755 index 0000000..e5b3f05 --- /dev/null +++ b/lib/libevdev/libevdev/make-event-names.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python3 +# +# Parses linux/input.h scanning for #define KEY_FOO 134 +# Prints C header files or Python files that can be used as +# mapping and lookup tables. +# + +import re +import sys + + +class Bits(object): + def __init__(self): + self.max_codes = {} + + +prefixes = [ + "EV_", + "REL_", + "ABS_", + "KEY_", + "BTN_", + "LED_", + "SND_", + "MSC_", + "SW_", + "FF_", + "SYN_", + "REP_", + "INPUT_PROP_", + "MT_TOOL_", +] + +duplicates = [ + "EV_VERSION", + "BTN_MISC", + "BTN_MOUSE", + "BTN_JOYSTICK", + "BTN_GAMEPAD", + "BTN_DIGI", + "BTN_WHEEL", + "BTN_TRIGGER_HAPPY", + "SW_MAX", + "REP_MAX", +] + +ignore_prefixes = [ + "SND_PROFILE_", +] + +btn_additional = [ + [0, "BTN_A"], + [0, "BTN_B"], + [0, "BTN_X"], + [0, "BTN_Y"], +] + +code_prefixes = [ + "REL_", + "ABS_", + "KEY_", + "BTN_", + "LED_", + "SND_", + "MSC_", + "SW_", + "FF_", + "SYN_", + "REP_", +] + + +def print_bits(bits, prefix): + if not hasattr(bits, prefix): + return + print("static const char * const %s_map[%s_MAX + 1] = {" % (prefix, prefix.upper())) + for val, name in sorted(list(getattr(bits, prefix).items())): + print(" [%s] = \"%s\"," % (name, name)) + if prefix == "key": + for val, name in sorted(list(getattr(bits, "btn").items())): + print(" [%s] = \"%s\"," % (name, name)) + print("};") + print("") + + +def print_map(bits): + print("static const char * const * const event_type_map[EV_MAX + 1] = {") + + for prefix in prefixes: + if prefix in ["BTN_", "EV_", "INPUT_PROP_", "MT_TOOL_"]: + continue + print(" [EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower())) + + print("};") + print("") + + print("#if __clang__") + print("#pragma clang diagnostic push") + print("#pragma clang diagnostic ignored \"-Winitializer-overrides\"") + print("#elif __GNUC__") + print("#pragma GCC diagnostic push") + print("#pragma GCC diagnostic ignored \"-Woverride-init\"") + print("#endif") + print("static const int ev_max[EV_MAX + 1] = {") + for val in range(bits.max_codes["EV_MAX"] + 1): + if val in bits.ev: + prefix = bits.ev[val][3:] + if prefix + "_" in prefixes: + print(" %s_MAX," % prefix) + continue + print(" -1,") + print("};") + print("#if __clang__") + print("#pragma clang diagnostic pop /* \"-Winitializer-overrides\" */") + print("#elif __GNUC__") + print("#pragma GCC diagnostic pop /* \"-Woverride-init\" */") + print("#endif") + print("") + + +def print_lookup(bits, prefix): + if not hasattr(bits, prefix): + return + + names = sorted(list(getattr(bits, prefix).items())) + if prefix == "btn": + names = names + btn_additional + + # We need to manually add the _MAX codes because some are + # duplicates + maxname = "%s_MAX" % (prefix.upper()) + if maxname in duplicates: + names.append((bits.max_codes[maxname], maxname)) + + for val, name in sorted(names, key=lambda e: e[1]): + print(" { .name = \"%s\", .value = %s }," % (name, name)) + + +def print_lookup_table(bits): + print("struct name_entry {") + print(" const char *name;") + print(" unsigned int value;") + print("};") + print("") + print("static const struct name_entry tool_type_names[] = {") + print_lookup(bits, "mt_tool") + print("};") + print("") + print("static const struct name_entry ev_names[] = {") + print_lookup(bits, "ev") + print("};") + print("") + + print("static const struct name_entry code_names[] = {") + for prefix in sorted(code_prefixes, key=lambda e: e): + print_lookup(bits, prefix[:-1].lower()) + print("};") + print("") + print("static const struct name_entry prop_names[] = {") + print_lookup(bits, "input_prop") + print("};") + print("") + + +def print_mapping_table(bits): + print("/* THIS FILE IS GENERATED, DO NOT EDIT */") + print("") + print("#ifndef EVENT_NAMES_H") + print("#define EVENT_NAMES_H") + print("") + + for prefix in prefixes: + if prefix == "BTN_": + continue + print_bits(bits, prefix[:-1].lower()) + + print_map(bits) + print_lookup_table(bits) + + print("#endif /* EVENT_NAMES_H */") + + +def parse_define(bits, line): + m = re.match(r"^#define\s+(\w+)\s+(\w+)", line) + if m is None: + return + + name = m.group(1) + + try: + value = int(m.group(2), 0) + except ValueError: + return + + for prefix in prefixes: + if not name.startswith(prefix) or any(name.startswith(p) for p in ignore_prefixes): + continue + + if name.endswith("_MAX"): + bits.max_codes[name] = value + + if name in duplicates: + return + + attrname = prefix[:-1].lower() + + if not hasattr(bits, attrname): + setattr(bits, attrname, {}) + b = getattr(bits, attrname) + b[value] = name + + +def parse(lines): + bits = Bits() + for line in lines: + if not line.startswith("#define"): + continue + parse_define(bits, line) + + return bits + + +def usage(prog): + print("Usage: %s ".format(prog)) + + +if __name__ == "__main__": + if len(sys.argv) <= 1: + usage(sys.argv[0]) + sys.exit(2) + + from itertools import chain + lines = chain(*[open(f).readlines() for f in sys.argv[1:]]) + bits = parse(lines) + print_mapping_table(bits) diff --git a/project.cpp b/project.cpp index 643a44e..7d7ae4f 100644 --- a/project.cpp +++ b/project.cpp @@ -80,11 +80,42 @@ extern "C" Configuration CrafterBuildProject(std::span a cfg.linkFlags.push_back("-lwayland-client"); cfg.linkFlags.push_back("-lxkbcommon"); // Gamepad: libudev for hot-plug + device enumeration; libevdev - // for event parsing + axis calibration. libevdev ships its headers - // under a versioned dir (libevdev-1.0/) so the -I is mandatory. + // for event parsing + axis calibration. cfg.linkFlags.push_back("-ludev"); - cfg.linkFlags.push_back("-levdev"); - cfg.compileFlags.push_back("-I/usr/include/libevdev-1.0"); + + // libevdev is vendored in lib/libevdev rather than linked from the + // system: the Flatpak SDK crafter-build runs in ships no libevdev + // headers, and a vendored copy cross-builds like everything else. It + // is its own static library so it compiles once, not again in every + // test configuration (they copy cfg.cFiles). One per call, since each + // distinct argument list loads this project separately; it lives for + // the whole build like a GitProject's configuration. Its paths are + // absolute because Crafter.Build only resolves the returned + // configuration's paths against this project's root, and this + // project.cpp runs with that root as cwd. + static std::deque libevdevConfigs; + Configuration& libevdev = libevdevConfigs.emplace_back(); + libevdev.path = fs::absolute(cfg.path); + libevdev.name = "Crafter.Graphics-libevdev"; + libevdev.outputName = "Crafter.Graphics-libevdev"; + libevdev.type = ConfigurationType::LibraryStatic; + libevdev.target = cfg.target; + libevdev.march = cfg.march; + libevdev.mtune = cfg.mtune; + libevdev.debug = cfg.debug; + libevdev.sysroot = cfg.sysroot; + libevdev.cFiles = { + fs::absolute("lib/libevdev/libevdev/libevdev"), + fs::absolute("lib/libevdev/libevdev/libevdev-names"), + }; + // Its generated event-names.h names every input code by macro, so it + // compiles against the kernel headers that table was generated from + // rather than the target's. + libevdev.compileFlags.push_back(std::format("-I{}", fs::absolute("lib/libevdev/kernel-headers").string())); + cfg.dependencies.push_back(&libevdev); + // For Gamepad's #include . + cfg.compileFlags.push_back(std::format("-I{}", fs::absolute("lib/libevdev").string())); + cfg.cFiles.push_back("lib/xdg-shell-protocol"); cfg.cFiles.push_back("lib/wayland-xdg-decoration-unstable-v1-client-protocol"); cfg.cFiles.push_back("lib/fractional-scale-v1");