diff --git a/README.md b/README.md index 642c626..be5aeb8 100644 --- a/README.md +++ b/README.md @@ -41,23 +41,15 @@ shaded through an intersection shader with an any-hit cut-out. > reads no descriptor), and `RTPass` supplies the address as push data. > Shaders and example code are unchanged, and it's a single fenced block > gated on `Device::workaroundDescriptorHeapAS`, removable once a fixed -> driver ships. **Still present on `615.78.08`**: with the rewrite off, -> `traceRayEXT` still loses the device and an inline ray query renders -> nothing. `tests/HeapASRead` covers the engine path; run -> `HeapASRead --no-workaround` to check a newer driver (it tries both paths -> with the rewrite off). Any app runs with the rewrite off while -> `CRAFTER_GRAPHICS_NO_AS_WORKAROUND` is set, to any value. See +> driver ships. See > [examples/VulkanTriangle/README.md](examples/VulkanTriangle/README.md) > for the full investigation. WebGPU RT is unaffected. -> **Native RT limitation (fixed in NVIDIA `615.78.08`) — dynamic -> `descriptor_heap` indexing in hit shaders:** on NVIDIA `610.43.02`, indexing -> a `descriptor_heap` array with a **runtime (non-constant)** index inside a -> ray-tracing **hit** shader also device-losts (`VK_ERROR_DEVICE_LOST`), for -> plain SSBO **and** sampled-image descriptors. On `615.78.08` it works: -> `tests/HeapDynamicIndexHit` picks a buffer and a texture by a runtime index -> in a closest-hit, including different descriptors in neighbouring lanes of -> a wave. The rest of this note applies to the older drivers. A **constant / spec-constant** +> **Native RT limitation — dynamic `descriptor_heap` indexing in hit +> shaders:** on the same NVIDIA driver, indexing a `descriptor_heap` +> array with a **runtime (non-constant)** index inside a ray-tracing +> **hit** shader also device-losts (`VK_ERROR_DEVICE_LOST`), for plain +> SSBO **and** sampled-image descriptors. A **constant / spec-constant** > index is fine (that's why [Sponza](examples/Sponza/README.md)'s > closest-hit reads `albedo[albedoSlot]` through a spec constant), and > the identical dynamic pattern works in fragment shaders (the UI @@ -137,8 +129,7 @@ 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 (libevdev is vendored in - `lib/libevdev`) and WGI on Windows; the DOM + Gamepad uses libudev+libevdev on Linux 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/examples/Sponza/README.md b/examples/Sponza/README.md index f7a198d..7ba3d7c 100644 --- a/examples/Sponza/README.md +++ b/examples/Sponza/README.md @@ -20,11 +20,6 @@ below. ## Native RT limitation: dynamic `descriptor_heap` indexing in hit shaders -Fixed in NVIDIA `615.78.08`: `tests/HeapDynamicIndexHit` selects buffers and -textures with a runtime index in a closest-hit, including different -descriptors in neighbouring lanes of a wave. This example still uses the -spec-constant pattern below, which also runs on the older drivers. - On NVIDIA driver `610.43.02` (Vulkan 1.4), indexing a `layout(descriptor_heap)` array with a **runtime (non-constant)** index inside a ray-tracing **hit** shader aborts the device with @@ -127,6 +122,8 @@ This is precisely what the WebGPU path already does — bucketed texture arrays plus a single geometry buffer — so it is a proven, cross-backend pattern, and it sidesteps the NVIDIA RT fault on the native path. +Remove this section once a fixed NVIDIA driver ships and dynamic +`descriptor_heap` indexing in hit shaders stops faulting. ## Asset fetch diff --git a/examples/SponzaBench/README.md b/examples/SponzaBench/README.md index 1b79677..fdf3426 100644 --- a/examples/SponzaBench/README.md +++ b/examples/SponzaBench/README.md @@ -20,8 +20,8 @@ exits. `Window::Render()`, reporting per-frame wall-clock stats and throughput. Unlike the interactive Sponza example — which is single-material on native -because of the hit-shader dynamic-`descriptor_heap`-index driver fault, fixed -in NVIDIA `615.78.08` (see `examples/Sponza/README.md`) — SponzaBench's closest-hit shades from +because of the hit-shader dynamic-`descriptor_heap`-index driver fault +(see `examples/Sponza/README.md`) — SponzaBench's closest-hit shades from barycentric coordinates and samples **no** texture, so it can build the **full multi-mesh atrium** (25 mesh groups, ~262 k triangles) as one multi-instance TLAS. The albedo is still decompressed and uploaded during diff --git a/examples/VulkanTriangle/README.md b/examples/VulkanTriangle/README.md index 6201ff7..45f9fd7 100644 --- a/examples/VulkanTriangle/README.md +++ b/examples/VulkanTriangle/README.md @@ -58,17 +58,6 @@ every other driver the workaround is inert. It's gated on `interfaces/Crafter.Graphics-ShaderVulkan.cppm` so it can be deleted wholesale once a fixed NVIDIA driver ships. -### Status on later drivers - -On `615.78.08` the fault is still there. With the rewrite off -(`CRAFTER_GRAPHICS_NO_AS_WORKAROUND` set), `traceRayEXT` still loses the device, -and an inline ray query that reads the TLAS from the heap no longer faults but -renders nothing. Mesa's llvmpipe now advertises `VK_EXT_descriptor_heap` too -and renders the plain heap read correctly, which is a second implementation -backing the conclusion below. `tests/HeapASRead` renders this triangle through -both paths and checks the pixels; `HeapASRead --no-workaround` is the quick -check for a new driver, reporting each path on its own. - ### The underlying fault (#7) The fault was traced to the **acceleration-structure read through @@ -94,10 +83,9 @@ The fault was traced to the **acceleration-structure read through - The fault reproduces even with the AS descriptor written at heap byte 0 and read at shader index 0 (no descriptor offset/stride ambiguity), and is unaffected by the `pAddressRange` size. -- `VK_EXT_descriptor_heap` is brand new; at the time NVIDIA was the only - implementation on this machine that advertised it (llvmpipe did not), so - there was no second conformant implementation to cross-check against. - Mesa's llvmpipe has it now; see "Status on later drivers" above. +- `VK_EXT_descriptor_heap` is brand new; on this machine NVIDIA is the only + implementation that advertises it (llvmpipe does not), so there is no + second conformant implementation to cross-check against. **Conclusion:** this is a driver-side fault in NVIDIA's `VK_EXT_descriptor_heap` acceleration-structure path, not an engine bug, and diff --git a/implementations/Crafter.Graphics-Device.cpp b/implementations/Crafter.Graphics-Device.cpp index 613c4ce..f9414c6 100644 --- a/implementations/Crafter.Graphics-Device.cpp +++ b/implementations/Crafter.Graphics-Device.cpp @@ -1061,12 +1061,9 @@ void Device::Initialize() { // the heap, so it is off whenever the heap is: otherwise a forced-fallback // run on NVIDIA would still rewrite SPIR-V, enable shaderInt64 and push the // TLAS address through vkCmdPushDataEXT, none of which a real heap-less - // driver does. Still needed on 615.78.08. CRAFTER_GRAPHICS_NO_AS_WORKAROUND, - // set to any value like the other CRAFTER_GRAPHICS_* switches, turns it off, - // which is how a new driver gets checked (tests/HeapASRead --no-workaround). + // driver does. workaroundDescriptorHeapAS = descriptorHeapSupported - && driverProperties.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY - && std::getenv("CRAFTER_GRAPHICS_NO_AS_WORKAROUND") == nullptr; + && driverProperties.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY; // Sanity-gate: GDeflate 1.0 must actually be in the supported method set. if (memoryDecompressionSupported && diff --git a/implementations/Crafter.Graphics-RenderingElement3D.cpp b/implementations/Crafter.Graphics-RenderingElement3D.cpp index 21359d8..9622c94 100644 --- a/implementations/Crafter.Graphics-RenderingElement3D.cpp +++ b/implementations/Crafter.Graphics-RenderingElement3D.cpp @@ -119,15 +119,10 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTB // (no-op when the chosen type is coherent — the previous behaviour), // and the queue submit carries the host-write -> shader-read ordering as // it always has. - // - // At least one slot each: a TLAS built before anything is in the scene - // has zero instances, and a zero-size buffer is invalid (NVIDIA fails - // the allocation). The empty build reads no instance anyway. if (tlas.instanceBuffer.buffer == VK_NULL_HANDLE || primitiveCount > tlas.instanceBuffer.size / sizeof(VkAccelerationStructureInstanceKHR)) { - const std::uint32_t capacity = std::max(primitiveCount, 1u); - tlas.instanceBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, capacity, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - tlas.metadataBuffer.Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, capacity, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + tlas.instanceBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, primitiveCount, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + tlas.metadataBuffer.Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, primitiveCount, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } // A topology change reshuffles which element occupies each slot (a count @@ -255,9 +250,7 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTB // Scratch buffer must hold at least max(buildScratchSize, updateScratchSize). // Sizing for buildScratchSize covers both — refit is always smaller. - // An empty TLAS may need no scratch at all, but the buffer can't be - // zero-size. - tlas.scratchBuffer.Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, std::max(tlasBuildSizes.buildScratchSize, 1)); + tlas.scratchBuffer.Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tlasBuildSizes.buildScratchSize); tlas.buffer.Resize(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tlasBuildSizes.accelerationStructureSize); // Destroy the previous AS handle before creating a new one — the @@ -302,6 +295,13 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTB VkAccelerationStructureBuildRangeInfoKHR* tlasRangeInfoPP = &tlasRangeInfo; Device::vkCmdBuildAccelerationStructuresKHR(cmd, 1, &tlasBuildGeometryInfo, &tlasRangeInfoPP); - const TlasReadBarrier readBarrier = BuildTlasReadBarrier(); - vkCmdPipelineBarrier(cmd, readBarrier.srcStage, readBarrier.dstStage, 0, 1, &readBarrier.memory, 0, nullptr, 0, nullptr); + vkCmdPipelineBarrier( + cmd, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 0, nullptr + ); } \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-Device.cppm b/interfaces/Crafter.Graphics-Device.cppm index ffca74e..30e7959 100644 --- a/interfaces/Crafter.Graphics-Device.cppm +++ b/interfaces/Crafter.Graphics-Device.cppm @@ -281,11 +281,8 @@ export namespace Crafter { // VK_ERROR_DEVICE_LOST (a brand-new-extension driver fault, verified // engine-clean in #7). When set, VulkanShader rewrites heap AS reads // into a TLAS-device-address + OpConvertUToAccelerationStructureKHR - // path and RTPass pushes the active TLAS address as push data. Still - // needed on 615.78.08. CRAFTER_GRAPHICS_NO_AS_WORKAROUND, set to any - // value, turns it off to check a newer driver (tests/HeapASRead - // --no-workaround). Delete this flag and everything keyed on it once a - // fixed driver ships. + // path and RTPass pushes the active TLAS address as push data. Delete + // this flag and everything keyed on it once a fixed driver ships. inline static bool workaroundDescriptorHeapAS = false; // Count of ERROR-severity validation messages seen by the debug diff --git a/interfaces/Crafter.Graphics-RenderingElement3D.cppm b/interfaces/Crafter.Graphics-RenderingElement3D.cppm index 576736a..f350aa3 100644 --- a/interfaces/Crafter.Graphics-RenderingElement3D.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement3D.cppm @@ -115,14 +115,7 @@ export namespace Crafter { inline static std::uint64_t hostDataVersionCounter = 0; static std::vector elements; - // Never destroyed, like Device::device. As a plain static its - // destructor would run at process exit after the Vulkan driver and - // layers, which are loaded during Device::Initialize (after this was - // constructed), have torn down their own state, and destroying the - // buffers would call into that freed state: the validation layer - // segfaults on it. Exit reclaims them instead. - inline static std::array& tlases = - *new std::array(); + inline static TlasWithBuffer tlases[Window::numFrames]; // Build (or in-place refit) the TLAS for frame `index`. `preference` // maps onto the FAST_TRACE/FAST_BUILD bits exactly as Mesh::Build // does for a BLAS: FastTrace (the default) spends more build time for @@ -141,29 +134,6 @@ export namespace Crafter { static void Add(RenderingElement3D* e); static void Remove(RenderingElement3D* e); }; - - // The dependency BuildTLAS records after its build, ordering it before - // the shaders that read the TLAS later in the same command buffer: - // traceRayEXT in a ray-tracing pass, rayQueryEXT in a compute pass. It - // has to carry the acceleration-structure memory dependency; ordering - // execution alone never makes the build's writes visible to those reads. - struct TlasReadBarrier { - VkPipelineStageFlags srcStage; - VkPipelineStageFlags dstStage; - VkMemoryBarrier memory; - }; - - inline TlasReadBarrier BuildTlasReadBarrier() { - return { - .srcStage = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - .dstStage = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - .memory = { - .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, - .dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, - }, - }; - } } #endif // !CRAFTER_GRAPHICS_WINDOW_DOM diff --git a/lib/libevdev/COPYING b/lib/libevdev/COPYING deleted file mode 100644 index 1974905..0000000 --- a/lib/libevdev/COPYING +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 2876434..0000000 --- a/lib/libevdev/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# 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 deleted file mode 100644 index 3528168..0000000 --- a/lib/libevdev/kernel-headers/linux/input-event-codes.h +++ /dev/null @@ -1,1016 +0,0 @@ -/* 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 deleted file mode 100644 index 5285f88..0000000 --- a/lib/libevdev/kernel-headers/linux/input.h +++ /dev/null @@ -1,539 +0,0 @@ -/* 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 deleted file mode 100644 index 280c874..0000000 --- a/lib/libevdev/libevdev/config.h +++ /dev/null @@ -1,3 +0,0 @@ -/* 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 deleted file mode 100644 index 0230284..0000000 --- a/lib/libevdev/libevdev/event-names.h +++ /dev/null @@ -1,1692 +0,0 @@ -/* 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 deleted file mode 100644 index 8e2518e..0000000 --- a/lib/libevdev/libevdev/libevdev-int.h +++ /dev/null @@ -1,333 +0,0 @@ -// 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 deleted file mode 100644 index 82329c3..0000000 --- a/lib/libevdev/libevdev/libevdev-names.c +++ /dev/null @@ -1,213 +0,0 @@ -// 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 deleted file mode 100644 index cab8067..0000000 --- a/lib/libevdev/libevdev/libevdev-util.h +++ /dev/null @@ -1,69 +0,0 @@ -// 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 deleted file mode 100644 index e1c33ea..0000000 --- a/lib/libevdev/libevdev/libevdev.c +++ /dev/null @@ -1,1912 +0,0 @@ -// 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 deleted file mode 100644 index 1f23f6c..0000000 --- a/lib/libevdev/libevdev/libevdev.h +++ /dev/null @@ -1,2404 +0,0 @@ -/* 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 deleted file mode 100755 index e5b3f05..0000000 --- a/lib/libevdev/libevdev/make-event-names.py +++ /dev/null @@ -1,235 +0,0 @@ -#!/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 c445d25..643a44e 100644 --- a/project.cpp +++ b/project.cpp @@ -80,42 +80,11 @@ 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. + // for event parsing + axis calibration. libevdev ships its headers + // under a versioned dir (libevdev-1.0/) so the -I is mandatory. cfg.linkFlags.push_back("-ludev"); - - // 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.linkFlags.push_back("-levdev"); + cfg.compileFlags.push_back("-I/usr/include/libevdev-1.0"); 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"); @@ -439,69 +408,6 @@ extern "C" Configuration CrafterBuildProject(std::span a parityImpls.emplace_back("tests/UIFallbackParity/main"); up.GetInterfacesAndImplementations(ifaces, parityImpls); cfg.tests.push_back(std::move(parityTest)); - - // Reading the TLAS from the descriptor heap (#7/#15): renders a - // triangle through traceRayEXT and an inline ray query and checks - // the read-back pixels, through the engine's normal path (so on - // NVIDIA through the SPIR-V rewrite). `HeapASRead --no-workaround` - // is the manual probe for whether a driver still has the fault. - // Needs the Wayland backend, a real compositor and an RT device - // (skips without RT). - Test heapAsTest; - Configuration& ha = heapAsTest.config; - ha.path = cfg.path; - ha.name = "HeapASRead"; - ha.outputName = "HeapASRead"; - ha.type = ConfigurationType::Executable; - ha.target = cfg.target; - ha.march = cfg.march; - ha.mtune = cfg.mtune; - ha.debug = cfg.debug; - ha.sysroot = cfg.sysroot; - ha.dependencies = cfg.dependencies; - ha.externalDependencies = cfg.externalDependencies; - ha.compileFlags = cfg.compileFlags; - ha.linkFlags = cfg.linkFlags; - ha.defines = cfg.defines; - ha.cFiles = cfg.cFiles; - ha.shaders.emplace_back(fs::path("tests/HeapASRead/heapas-raygen.glsl"), std::string("main"), ShaderType::RayGen); - ha.shaders.emplace_back(fs::path("tests/HeapASRead/heapas-closesthit.glsl"), std::string("main"), ShaderType::ClosestHit); - ha.shaders.emplace_back(fs::path("tests/HeapASRead/heapas-miss.glsl"), std::string("main"), ShaderType::Miss); - std::vector heapAsImpls(impls.begin(), impls.end()); - heapAsImpls.emplace_back("tests/HeapASRead/main"); - ha.GetInterfacesAndImplementations(ifaces, heapAsImpls); - cfg.tests.push_back(std::move(heapAsTest)); - - // Dynamic descriptor-heap indexing in a hit shader: a closest-hit - // picks a storage buffer and a sampled image by a runtime index - // (the same across a wave on one instance, different between - // neighbouring lanes on the other), which lost the device on - // NVIDIA 610.43.02; skips on NVIDIA drivers older than 615.78.08. - // Same requirements as HeapASRead. - Test dynIndexTest; - Configuration& di = dynIndexTest.config; - di.path = cfg.path; - di.name = "HeapDynamicIndexHit"; - di.outputName = "HeapDynamicIndexHit"; - di.type = ConfigurationType::Executable; - di.target = cfg.target; - di.march = cfg.march; - di.mtune = cfg.mtune; - di.debug = cfg.debug; - di.sysroot = cfg.sysroot; - di.dependencies = cfg.dependencies; - di.externalDependencies = cfg.externalDependencies; - di.compileFlags = cfg.compileFlags; - di.linkFlags = cfg.linkFlags; - di.defines = cfg.defines; - di.cFiles = cfg.cFiles; - di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-raygen.glsl"), std::string("main"), ShaderType::RayGen); - di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-closesthit.glsl"), std::string("main"), ShaderType::ClosestHit); - di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-miss.glsl"), std::string("main"), ShaderType::Miss); - std::vector dynIndexImpls(impls.begin(), impls.end()); - dynIndexImpls.emplace_back("tests/HeapDynamicIndexHit/main"); - di.GetInterfacesAndImplementations(ifaces, dynIndexImpls); - cfg.tests.push_back(std::move(dynIndexTest)); } // Issue #36: BLAS build options. Drives the real hardware AS-build @@ -565,58 +471,6 @@ extern "C" Configuration CrafterBuildProject(std::span a tlc.GetInterfacesAndImplementations(ifaces, tlasImpls); cfg.tests.push_back(std::move(tlasTest)); - // The barrier BuildTLAS records after the build carries the - // acceleration-structure memory dependency to the shaders that read - // the TLAS, not just execution order. BuildTlasReadBarrier is pure - // CPU logic, so no GPU device is needed at runtime. - Test tlasBarrierTest; - Configuration& tbc = tlasBarrierTest.config; - tbc.path = cfg.path; - tbc.name = "TLASBuildBarrier"; - tbc.outputName = "TLASBuildBarrier"; - tbc.type = ConfigurationType::Executable; - tbc.target = cfg.target; - tbc.march = cfg.march; - tbc.mtune = cfg.mtune; - tbc.debug = cfg.debug; - tbc.sysroot = cfg.sysroot; - tbc.dependencies = cfg.dependencies; - tbc.externalDependencies = cfg.externalDependencies; - tbc.compileFlags = cfg.compileFlags; - tbc.linkFlags = cfg.linkFlags; - tbc.defines = cfg.defines; - tbc.cFiles = cfg.cFiles; - std::vector tlasBarrierImpls(impls.begin(), impls.end()); - tlasBarrierImpls.emplace_back("tests/TLASBuildBarrier/main"); - tbc.GetInterfacesAndImplementations(ifaces, tlasBarrierImpls); - cfg.tests.push_back(std::move(tlasBarrierTest)); - - // BuildTLAS on an empty scene (no elements registered yet) builds a - // valid empty TLAS instead of creating zero-size buffers, and adding - // and removing instances afterwards still rebuilds it. Needs a Vulkan - // RT device at runtime, like TLASHighWaterMark. - Test tlasEmptyTest; - Configuration& tec = tlasEmptyTest.config; - tec.path = cfg.path; - tec.name = "TLASEmptyBuild"; - tec.outputName = "TLASEmptyBuild"; - tec.type = ConfigurationType::Executable; - tec.target = cfg.target; - tec.march = cfg.march; - tec.mtune = cfg.mtune; - tec.debug = cfg.debug; - tec.sysroot = cfg.sysroot; - tec.dependencies = cfg.dependencies; - tec.externalDependencies = cfg.externalDependencies; - tec.compileFlags = cfg.compileFlags; - tec.linkFlags = cfg.linkFlags; - tec.defines = cfg.defines; - tec.cFiles = cfg.cFiles; - std::vector tlasEmptyImpls(impls.begin(), impls.end()); - tlasEmptyImpls.emplace_back("tests/TLASEmptyBuild/main"); - tec.GetInterfacesAndImplementations(ifaces, tlasEmptyImpls); - cfg.tests.push_back(std::move(tlasEmptyTest)); - // Issue #118: the per-frame TLAS instance+metadata host rebuild copies // (and flushes) only the slots whose element's host-authored data // changed, tracked via RenderingElement3D::hostDataVersion against the diff --git a/shaders/ui-shared.glsl b/shaders/ui-shared.glsl index ace325d..2157978 100644 --- a/shaders/ui-shared.glsl +++ b/shaders/ui-shared.glsl @@ -99,6 +99,49 @@ layout(UI_HEAP_BUFFERS, std430) readonly buffer UICircleBuf { CircleItem items[] layout(UI_HEAP_BUFFERS, std430) readonly buffer UIImageBuf { ImageItem items[]; } uiImageHeap[]; layout(UI_HEAP_BUFFERS, std430) readonly buffer UIGlyphBuf { GlyphItem items[]; } uiGlyphHeap[]; + +// ──── Driver workaround: per-member SSBO load ──────────────────────────── +// `UIItem it = itemHeap[idx].items[i]` emits an OpLoad of a composite type +// from a descriptor-heap'd SSBO, which crashes the GPU on the NVIDIA +// VK_EXT_descriptor_heap path (verified with a 1-float struct repro). +// Reading individual members works (each becomes OpAccessChain + scalar +// OpLoad). LoadItem reassembles the struct member-by-member into a local; +// the rest of the shader then operates on a regular local var. + +ImageItem LoadImageItem(uint heap, uint i) { + ImageItem it; + it.rect = uiImageHeap[heap].items[i].rect; + it.uv = uiImageHeap[heap].items[i].uv; + it.tint = uiImageHeap[heap].items[i].tint; + it.slots = uiImageHeap[heap].items[i].slots; + return it; +} + +GlyphItem LoadGlpyhtem(uint heap, uint i) { + GlyphItem it; + it.rect = uiGlyphHeap[heap].items[i].rect; + it.uv = uiGlyphHeap[heap].items[i].uv; + it.color = uiGlyphHeap[heap].items[i].color; + return it; +} + +CircleItem LoadCircleItem(uint heap, uint i) { + CircleItem it; + it.centerRadius = uiCircleHeap[heap].items[i].centerRadius; + it.color = uiCircleHeap[heap].items[i].color; + it.outline = uiCircleHeap[heap].items[i].outline; + return it; +} + +QuadItem LoadQuadItem(uint heap, uint i) { + QuadItem it; + it.rect = uiQuadHeap[heap].items[i].rect; + it.color = uiQuadHeap[heap].items[i].color; + it.corners = uiQuadHeap[heap].items[i].corners; + it.outline = uiQuadHeap[heap].items[i].outline; + return it; +} + // ─── pixel-tile dispatch model ───────────────────────────────────────── // Standard shaders dispatch one workgroup per 8×8 screen tile. Each thread // owns ONE pixel and iterates ALL items in order, accumulating the result diff --git a/tests/HeapASRead/heapas-closesthit.glsl b/tests/HeapASRead/heapas-closesthit.glsl deleted file mode 100644 index dd3fa18..0000000 --- a/tests/HeapASRead/heapas-closesthit.glsl +++ /dev/null @@ -1,11 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable - -layout(location = 0) rayPayloadInEXT vec3 hitValue; - -void main() { - hitValue = vec3(0.0, 1.0, 0.0); -} diff --git a/tests/HeapASRead/heapas-miss.glsl b/tests/HeapASRead/heapas-miss.glsl deleted file mode 100644 index 4a686d4..0000000 --- a/tests/HeapASRead/heapas-miss.glsl +++ /dev/null @@ -1,11 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable - -layout(location = 0) rayPayloadInEXT vec3 hitValue; - -void main() { - hitValue = vec3(0.5); -} diff --git a/tests/HeapASRead/heapas-raygen.glsl b/tests/HeapASRead/heapas-raygen.glsl deleted file mode 100644 index 01c875b..0000000 --- a/tests/HeapASRead/heapas-raygen.glsl +++ /dev/null @@ -1,51 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_ray_query : enable -#extension GL_EXT_shader_image_load_formatted : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable -#extension GL_EXT_descriptor_heap : enable -#extension GL_EXT_nonuniform_qualifier : enable - -// Reads the TLAS straight out of the descriptor heap through traceRayEXT and -// through an inline ray query: the two AS-read paths that lost the device on -// NVIDIA 610.43.02 (#7). `path` picks which: 0 traces the left half of the -// frame and ray queries the right half, 1 only traces, 2 only ray queries. -layout(constant_id = 0) const uint16_t bufferStart = 0us; -layout(constant_id = 1) const uint path = 0u; -layout(descriptor_heap) uniform accelerationStructureEXT topLevelAS[]; -layout(descriptor_heap) uniform writeonly image2D image[]; - -layout(location = 0) rayPayloadEXT vec3 hitValue; - -void main() { - uvec2 pixel = gl_LaunchIDEXT.xy; - uvec2 resolution = gl_LaunchSizeEXT.xy; - vec2 ndc = (vec2(pixel) + 0.5) / vec2(resolution) * 2.0 - 1.0; - - // Same pinhole camera as examples/VulkanTriangle, facing +Z. - vec3 origin = vec3(0.0, 0.0, -300.0); - float aspect = float(resolution.x) / float(resolution.y); - float tanHalfFov = tan(radians(60.0) * 0.5); - vec3 direction = normalize(vec3(ndc.x * aspect * tanHalfFov, -ndc.y * tanHalfFov, 1.0)); - - bool trace = path == 1u || (path == 0u && pixel.x < resolution.x / 2); - vec3 colour; - if (trace) { - // Closest-hit writes green, miss writes grey. - traceRayEXT(topLevelAS[bufferStart], gl_RayFlagsNoneEXT, 0xff, 0, 0, 0, - origin, 0.001, direction, 10000.0, 0); - colour = hitValue; - } else { - rayQueryEXT query; - rayQueryInitializeEXT(query, topLevelAS[bufferStart], gl_RayFlagsOpaqueEXT, 0xff, - origin, 0.001, direction, 10000.0); - while (rayQueryProceedEXT(query)) {} - bool hit = rayQueryGetIntersectionTypeEXT(query, true) == gl_RayQueryCommittedIntersectionTriangleEXT; - // White for a hit, the miss shader's grey otherwise. - colour = hit ? vec3(1.0) : vec3(0.5); - } - imageStore(image[0], ivec2(pixel), vec4(colour, 1.0)); -} diff --git a/tests/HeapASRead/main.cpp b/tests/HeapASRead/main.cpp deleted file mode 100644 index 68ab572..0000000 --- a/tests/HeapASRead/main.cpp +++ /dev/null @@ -1,344 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// Regression test for reading an acceleration structure out of a -// VK_EXT_descriptor_heap heap (#7, worked around on NVIDIA in #15). It renders -// examples/VulkanTriangle's triangle, tracing the left half of the frame with -// traceRayEXT and ray querying the right half, then reads the frame back and -// checks both halves hit the triangle where it is and miss around it. As run -// by the test runner it goes through the engine's normal path, so on NVIDIA it -// covers the SPIR-V rewrite too; a CRAFTER_GRAPHICS_NO_AS_WORKAROUND inherited -// from the environment is cleared so the rewrite can't be switched off. -// -// `HeapASRead --no-workaround` instead probes whether the driver still has the -// fault: it renders each path on its own in a child process with the rewrite -// off and validation off (GPU-assisted validation instruments the shaders), -// and reports per path whether it works, renders wrong or loses the device. -// It exits 0 only when both work. On 610.43.02 both paths lost the device; on -// 615.78.08 traceRayEXT still does, and the ray query renders nothing. -// -// The validation check only means something with CRAFTER_GRAPHICS_VALIDATION -// set. Needs a live Wayland compositor and a Vulkan RT device; without RT it -// skips. - -#include "vulkan/vulkan.h" -#include -#include -#include - -// PNG decode for the read-back frame. The library only compiles the writer -// (Window::SaveFrame); STB_IMAGE_STATIC keeps the reader private to this file. -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_STATIC -#define STBI_ONLY_PNG -#include "../../lib/stb_image.h" - -import Crafter.Graphics; -import Crafter.Event; -import Crafter.Math; -import std; - -using namespace Crafter; -namespace fs = std::filesystem; - -namespace { - -int failures = 0; - -void Check(bool ok, std::string_view what) { - std::println("{} {}", ok ? "PASS" : "FAIL", what); - // Flushed per line: a driver with the fault aborts the process from - // inside Render(), and the checks before it should still show. - std::fflush(stdout); - if (!ok) ++failures; -} - -// The build places the compiled shaders next to the test binary, and the -// test runner's working directory is not that directory. -fs::path ExeDir() { - return fs::read_symlink("/proc/self/exe").parent_path(); -} - -int RunCommand(const std::string& cmd) { - int status = std::system(cmd.c_str()); - if (status == -1) return -1; - return (status & 0x7f) == 0 ? ((status >> 8) & 0xff) : 128 + (status & 0x7f); -} - -struct Frame { - int width = 0; - int height = 0; - std::vector rgba; - - std::array At(int x, int y) const { - const std::size_t i = (static_cast(y) * width + x) * 4; - return { rgba[i], rgba[i + 1], rgba[i + 2] }; - } -}; - -Frame LoadFrame(const fs::path& path) { - Frame frame; - int channels = 0; - stbi_uc* pixels = stbi_load(path.string().c_str(), &frame.width, &frame.height, &channels, STBI_rgb_alpha); - if (pixels != nullptr) { - frame.rgba.assign(pixels, pixels + static_cast(frame.width) * frame.height * 4); - stbi_image_free(pixels); - } - return frame; -} - -bool Near(std::array pixel, std::array expected) { - for (std::size_t c = 0; c < 3; ++c) { - if (std::abs(static_cast(pixel[c]) - static_cast(expected[c])) > 8) return false; - } - return true; -} - -void CheckPixel(const Frame& frame, float fx, float fy, std::array expected, std::string_view what) { - const int x = static_cast(fx * static_cast(frame.width)); - const int y = static_cast(fy * static_cast(frame.height)); - const std::array pixel = frame.At(x, y); - Check(Near(pixel, expected), std::format("{} at ({}, {}) is ({}, {}, {}), expected ({}, {}, {})", - what, x, y, pixel[0], pixel[1], pixel[2], expected[0], expected[1], expected[2])); -} - -// Matches `path` in heapas-raygen.glsl. -enum class Path : std::uint32_t { Both = 0, Trace = 1, Query = 2 }; - -// Spec constants of the raygen, matching heapas-raygen.glsl. -struct RaygenConstants { - std::uint16_t bufferStart; - std::uint16_t pad; - std::uint32_t path; -}; - -constexpr std::array traceHit = {0, 255, 0}; -constexpr std::array queryHit = {255, 255, 255}; -constexpr std::array miss = {128, 128, 128}; - -// Renders the triangle through `path` into `out` and checks the pixels. -// Returns the exit code. -int Render(Path path, const fs::path& out) { - Device::Initialize(); - if (!Device::rayTracingSupported) { - std::println("SKIP no Vulkan ray-tracing device"); - return 77; - } - Device::validationErrorCount = 0; - if (path != Path::Both) { - Check(!Device::workaroundDescriptorHeapAS, "the AS workaround is off for the probe"); - } - - Window window(640, 360, "HeapASRead test"); - VkCommandBuffer cmd = window.StartInit(); - - DescriptorHeapVulkan descriptorHeap; - descriptorHeap.Initialize(1, 1, 0); - - RaygenConstants raygenConstants = { - .bufferStart = descriptorHeap.bufferStartElement, - .pad = 0, - .path = static_cast(path), - }; - std::array raygenEntries {{ - { .constantID = 0, .offset = offsetof(RaygenConstants, bufferStart), .size = sizeof(std::uint16_t) }, - { .constantID = 1, .offset = offsetof(RaygenConstants, path), .size = sizeof(std::uint32_t) }, - }}; - VkSpecializationInfo raygenSpec = { - .mapEntryCount = static_cast(raygenEntries.size()), - .pMapEntries = raygenEntries.data(), - .dataSize = sizeof(RaygenConstants), - .pData = &raygenConstants, - }; - - const fs::path dir = ExeDir(); - std::array shaders{{ - {dir / "heapas-raygen.spv", "main", VK_SHADER_STAGE_RAYGEN_BIT_KHR, &raygenSpec}, - {dir / "heapas-miss.spv", "main", VK_SHADER_STAGE_MISS_BIT_KHR, nullptr}, - {dir / "heapas-closesthit.spv", "main", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, nullptr}, - }}; - ShaderBindingTableVulkan shaderTable; - shaderTable.Init(shaders); - - std::array raygenGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, - .generalShader = 0, .closestHitShader = VK_SHADER_UNUSED_KHR, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - std::array missGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, - .generalShader = 1, .closestHitShader = VK_SHADER_UNUSED_KHR, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - std::array hitGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, - .generalShader = VK_SHADER_UNUSED_KHR, .closestHitShader = 2, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - PipelineRTVulkan pipeline; - pipeline.Init(cmd, raygenGroups, missGroups, hitGroups, shaderTable); - - Mesh triangleMesh; - std::array, 3> verts {{{-150, -150, 100}, {0, 150, 100}, {150, -150, 100}}}; - std::array index {{2, 1, 0}}; - triangleMesh.Build(verts, index, cmd); - - RenderingElement3D renderer; - renderer.instance = { - .instanceCustomIndex = 0, - .mask = 0xFF, - .instanceShaderBindingTableRecordOffset = 0, - .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - .accelerationStructureReference = triangleMesh.blasAddr, - }; - MatrixRowMajor::Identity().Store(reinterpret_cast(renderer.instance.transform.matrix)); - RenderingElement3D::Add(&renderer); - for (std::uint32_t f = 0; f < Window::numFrames; ++f) RenderingElement3D::BuildTLAS(cmd, f); - - window.FinishInit(); - - // Per frame: the TLAS at buffer slot 0 and that frame's swapchain image at - // image slot 0, each in its own copy of the heap. Written again whenever - // the swapchain is recreated, since the image descriptors point at its - // images. - auto imgSlots = descriptorHeap.AllocateImageSlots(1); - auto bufSlots = descriptorHeap.AllocateBufferSlots(1); - auto writeDescriptors = [&] { - std::array tlasRanges{}; - std::array imageInfos{}; - std::vector resources; - std::vector destinations; - for (std::uint32_t f = 0; f < Window::numFrames; ++f) { - tlasRanges[f] = { .address = RenderingElement3D::tlases[f].address }; - imageInfos[f] = { - .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, - .pView = &window.imageViews[f], - .layout = VK_IMAGE_LAYOUT_GENERAL, - }; - resources.push_back({ - .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, - .data = { .pAddressRange = &tlasRanges[f] }, - }); - destinations.push_back({ - .address = descriptorHeap.resourceHeap[f].value + descriptorHeap.BufferByteOffset(bufSlots.firstElement), - .size = Device::descriptorHeapProperties.bufferDescriptorSize, - }); - resources.push_back({ - .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .data = { .pImage = &imageInfos[f] }, - }); - destinations.push_back({ - .address = descriptorHeap.resourceHeap[f].value + descriptorHeap.ImageByteOffset(imgSlots.firstElement), - .size = Device::descriptorHeapProperties.imageDescriptorSize, - }); - } - Device::vkWriteResourceDescriptorsEXT(Device::device, static_cast(resources.size()), - resources.data(), destinations.data()); - for (auto& heap : descriptorHeap.resourceHeap) heap.FlushDevice(); - }; - writeDescriptors(); - EventListener resizeListener(&window.onResize, writeDescriptors); - - window.descriptorHeap = &descriptorHeap; - RTPass rtPass(&pipeline); - window.passes.push_back(&rtPass); - - // More frames than are in flight, so every per-frame heap copy and TLAS - // is read at least once. A device loss here throws out of Render(). - for (int i = 0; i < Window::numFrames * 2; ++i) window.Render(); - Device::CheckVkResult(vkQueueWaitIdle(Device::queue)); - - // Counted before the capture: SaveFrame reads back an image that has - // already been handed to the presentation engine, which the validation - // layer reports on its own. - if (std::getenv("CRAFTER_GRAPHICS_VALIDATION") != nullptr) { - Check(Device::validationErrorCount == 0, - std::format("no Vulkan validation errors while rendering ({} seen)", Device::validationErrorCount)); - } - - window.SaveFrame(out); - Device::CheckVkResult(vkQueueWaitIdle(Device::queue)); - const Frame frame = LoadFrame(out); - Check(!frame.rgba.empty(), "the frame was read back"); - if (!frame.rgba.empty()) { - switch (path) { - case Path::Both: - // The triangle covers the middle of the frame at any aspect - // ratio; 5% either side of the centre line is inside it. - CheckPixel(frame, 0.45f, 0.5f, traceHit, "traceRayEXT hit"); - CheckPixel(frame, 0.55f, 0.5f, queryHit, "rayQueryEXT hit"); - CheckPixel(frame, 0.05f, 0.1f, miss, "traceRayEXT miss"); - CheckPixel(frame, 0.95f, 0.1f, miss, "rayQueryEXT miss"); - break; - case Path::Trace: - CheckPixel(frame, 0.5f, 0.5f, traceHit, "traceRayEXT hit"); - CheckPixel(frame, 0.05f, 0.1f, miss, "traceRayEXT miss"); - break; - case Path::Query: - CheckPixel(frame, 0.5f, 0.5f, queryHit, "rayQueryEXT hit"); - CheckPixel(frame, 0.05f, 0.1f, miss, "rayQueryEXT miss"); - break; - } - } - RenderingElement3D::Remove(&renderer); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} - -// A fresh directory for the read-back frames, so a frame left by an earlier -// run can't stand in for one this run failed to write. -fs::path OutputDir() { - const fs::path dir = fs::temp_directory_path() / "crafter-heap-as-read"; - std::error_code ec; - fs::remove_all(dir, ec); - fs::create_directories(dir); - return dir; -} - -// --no-workaround: renders each path in its own child process, so a device -// loss on one doesn't hide the other. -int Probe() { - const fs::path exe = fs::read_symlink("/proc/self/exe"); - const fs::path dir = OutputDir(); - bool allWork = true; - for (const auto& [name, arg] : {std::pair{"traceRayEXT", "trace"}, std::pair{"rayQueryEXT", "query"}}) { - const int exit = RunCommand(std::format( - "env -u CRAFTER_GRAPHICS_VALIDATION CRAFTER_GRAPHICS_NO_AS_WORKAROUND=1 '{}' --probe {} '{}'", - exe.string(), arg, (dir / std::format("{}.png", arg)).string())); - const std::string verdict = - exit == 0 ? std::string("works") : - exit == 77 ? std::string("skipped (no RT device)") : - exit == 1 ? std::string("renders wrong") : - std::format("loses the device or crashes (exit {})", exit); - std::println("PROBE {} reading the TLAS from the heap: {}", name, verdict); - if (exit != 0) allWork = false; - } - std::println("{}", allWork ? "the driver reads the TLAS from the heap on both paths" - : "the driver still needs the workaround"); - return allWork ? EXIT_SUCCESS : EXIT_FAILURE; -} - -} // namespace - -int main(int argc, char** argv) { - if (argc == 2 && std::string_view(argv[1]) == "--no-workaround") { - return Probe(); - } - if (argc == 4 && std::string_view(argv[1]) == "--probe") { - const Path path = std::string_view(argv[2]) == "trace" ? Path::Trace : Path::Query; - return Render(path, argv[3]); - } - - unsetenv("CRAFTER_GRAPHICS_NO_AS_WORKAROUND"); - const int result = Render(Path::Both, OutputDir() / "both.png"); - if (result == 77) return result; - Check(Device::workaroundDescriptorHeapAS - == (Device::descriptorHeapSupported && Device::driverProperties.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY), - "the AS workaround is on exactly where the driver needs it"); - std::println("{}", failures == 0 ? "all checks passed" : "check(s) failed"); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/tests/HeapDynamicIndexHit/dynidx-closesthit.glsl b/tests/HeapDynamicIndexHit/dynidx-closesthit.glsl deleted file mode 100644 index b4d95f3..0000000 --- a/tests/HeapDynamicIndexHit/dynidx-closesthit.glsl +++ /dev/null @@ -1,35 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable -#extension GL_EXT_descriptor_heap : enable -#extension GL_EXT_nonuniform_qualifier : enable - -// Picks a storage buffer and a sampled image out of the descriptor heap by a -// runtime index. Instance 0 uses descriptor set 0 everywhere, so the index is -// the same across each wave. Instance 1 alternates between sets 1 and 0 from -// one pixel column to the next, so neighbouring lanes of every wave over it -// pick different descriptors. On NVIDIA 610.43.02 a runtime index here lost the -// device, for both descriptor kinds, which is why the engine's examples select -// hit-shader descriptors through spec constants. -layout(constant_id = 0) const uint16_t bufferStart = 0us; -layout(constant_id = 1) const uint textureBase = 0u; -layout(constant_id = 2) const uint colourBase = 0u; - -layout(descriptor_heap, std430) readonly buffer Colour { vec4 value; } colours[]; -layout(descriptor_heap) uniform texture2D textures[]; -layout(descriptor_heap) uniform sampler samplers[]; - -layout(location = 0) rayPayloadInEXT vec3 hitValue; - -void main() { - uint set = gl_InstanceCustomIndexEXT == 0u ? 0u : 1u - (gl_LaunchIDEXT.x & 1u); - vec4 colour = colours[nonuniformEXT(uint(bufferStart) + colourBase + set)].value; - vec4 texel = textureLod(sampler2D(textures[nonuniformEXT(textureBase + set)], samplers[0]), - vec2(0.5), 0.0); - // Red from the buffer, green from the texture, so each descriptor kind - // is checked separately. - hitValue = vec3(colour.r, texel.g, 0.0); -} diff --git a/tests/HeapDynamicIndexHit/dynidx-miss.glsl b/tests/HeapDynamicIndexHit/dynidx-miss.glsl deleted file mode 100644 index 783417e..0000000 --- a/tests/HeapDynamicIndexHit/dynidx-miss.glsl +++ /dev/null @@ -1,11 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable - -layout(location = 0) rayPayloadInEXT vec3 hitValue; - -void main() { - hitValue = vec3(0.0, 0.0, 1.0); -} diff --git a/tests/HeapDynamicIndexHit/dynidx-raygen.glsl b/tests/HeapDynamicIndexHit/dynidx-raygen.glsl deleted file mode 100644 index e835e90..0000000 --- a/tests/HeapDynamicIndexHit/dynidx-raygen.glsl +++ /dev/null @@ -1,31 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -#version 460 -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_shader_image_load_formatted : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable -#extension GL_EXT_descriptor_heap : enable -#extension GL_EXT_nonuniform_qualifier : enable - -layout(constant_id = 0) const uint16_t bufferStart = 0us; -layout(descriptor_heap) uniform accelerationStructureEXT topLevelAS[]; -layout(descriptor_heap) uniform writeonly image2D image[]; - -layout(location = 0) rayPayloadEXT vec3 hitValue; - -void main() { - uvec2 pixel = gl_LaunchIDEXT.xy; - uvec2 resolution = gl_LaunchSizeEXT.xy; - vec2 ndc = (vec2(pixel) + 0.5) / vec2(resolution) * 2.0 - 1.0; - - // Same pinhole camera as examples/VulkanTriangle, facing +Z. - vec3 origin = vec3(0.0, 0.0, -300.0); - float aspect = float(resolution.x) / float(resolution.y); - float tanHalfFov = tan(radians(60.0) * 0.5); - vec3 direction = normalize(vec3(ndc.x * aspect * tanHalfFov, -ndc.y * tanHalfFov, 1.0)); - - traceRayEXT(topLevelAS[bufferStart], gl_RayFlagsNoneEXT, 0xff, 0, 0, 0, - origin, 0.001, direction, 10000.0, 0); - imageStore(image[0], ivec2(pixel), vec4(hitValue, 1.0)); -} diff --git a/tests/HeapDynamicIndexHit/main.cpp b/tests/HeapDynamicIndexHit/main.cpp deleted file mode 100644 index 057d289..0000000 --- a/tests/HeapDynamicIndexHit/main.cpp +++ /dev/null @@ -1,415 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// Regression test for dynamic descriptor-heap indexing in ray-tracing hit -// shaders. On NVIDIA 610.43.02, selecting a VK_EXT_descriptor_heap descriptor -// with a runtime index inside a hit shader lost the device, for storage -// buffers and sampled images alike (README, "Native RT limitation"), so the -// examples select hit-shader descriptors through spec constants. This renders -// two instances of one triangle whose closest-hit picks a storage buffer and a -// texture by a runtime index: instance 0 the same set everywhere, instance 1 a -// different set in every other pixel column, so neighbouring lanes of a wave -// select different descriptors. It reads the frame back and checks every -// pixel got its own set's buffer red and texture green. -// -// The fault fixed in NVIDIA 615.78.08, so on older NVIDIA drivers the test -// skips instead of aborting the suite. GPU-assisted validation hides the -// fault (examples/Sponza/README.md), so with CRAFTER_GRAPHICS_VALIDATION set -// the scene is also rendered in a child process with validation off; the -// validation check only means something with it set. Needs a live Wayland -// compositor and a Vulkan RT device; without RT it skips. - -#include "vulkan/vulkan.h" -#include -#include -#include - -// PNG decode for the read-back frame. The library only compiles the writer -// (Window::SaveFrame); STB_IMAGE_STATIC keeps the reader private to this file. -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_STATIC -#define STBI_ONLY_PNG -#include "../../lib/stb_image.h" - -import Crafter.Graphics; -import Crafter.Event; -import Crafter.Math; -import std; - -using namespace Crafter; -namespace fs = std::filesystem; - -namespace { - -int failures = 0; - -void Check(bool ok, std::string_view what) { - std::println("{} {}", ok ? "PASS" : "FAIL", what); - // Flushed per line: a driver with the fault aborts the process from - // inside Render(), and the checks before it should still show. - std::fflush(stdout); - if (!ok) ++failures; -} - -// The build places the compiled shaders next to the test binary, and the -// test runner's working directory is not that directory. -fs::path ExeDir() { - return fs::read_symlink("/proc/self/exe").parent_path(); -} - -int RunCommand(const std::string& cmd) { - int status = std::system(cmd.c_str()); - if (status == -1) return -1; - return (status & 0x7f) == 0 ? ((status >> 8) & 0xff) : 128 + (status & 0x7f); -} - -struct RGBA8 { std::uint8_t r, g, b, a; }; - -struct Frame { - int width = 0; - int height = 0; - std::vector rgba; - - std::array At(int x, int y) const { - const std::size_t i = (static_cast(y) * width + x) * 4; - return { rgba[i], rgba[i + 1], rgba[i + 2] }; - } -}; - -Frame LoadFrame(const fs::path& path) { - Frame frame; - int channels = 0; - stbi_uc* pixels = stbi_load(path.string().c_str(), &frame.width, &frame.height, &channels, STBI_rgb_alpha); - if (pixels != nullptr) { - frame.rgba.assign(pixels, pixels + static_cast(frame.width) * frame.height * 4); - stbi_image_free(pixels); - } - return frame; -} - -bool Near(std::array pixel, std::array expected) { - for (std::size_t c = 0; c < 3; ++c) { - if (std::abs(static_cast(pixel[c]) - static_cast(expected[c])) > 8) return false; - } - return true; -} - -void CheckPixel(const Frame& frame, int x, int y, std::array expected, std::string_view what) { - const std::array pixel = frame.At(x, y); - Check(Near(pixel, expected), std::format("{} at ({}, {}) is ({}, {}, {}), expected ({}, {}, {})", - what, x, y, pixel[0], pixel[1], pixel[2], expected[0], expected[1], expected[2])); -} - -// The pixel column world x on the triangles' plane (z = 100, 400 in front of -// the camera) lands in, for the raygen's 60° vertical field of view. -int FrameX(float worldX, const Frame& frame) { - const float aspect = static_cast(frame.width) / static_cast(frame.height); - const float ndc = worldX / (400.0f * aspect * std::tan(std::numbers::pi_v / 6.0f)); - return static_cast((0.5f + ndc * 0.5f) * static_cast(frame.width)); -} - -// Spec constants of the closest-hit, matching dynidx-closesthit.glsl. -struct HitConstants { - std::uint16_t bufferStart; - std::uint16_t pad; - std::uint32_t textureBase; - std::uint32_t colourBase; -}; - -// What each descriptor set holds: the red its buffer gives and the green its -// texture gives. -constexpr std::array bufferRed = {1.0f, 0.5f}; -constexpr std::array textureGreen = {64, 191}; -constexpr std::array, 2> setColour = {{{255, 64, 0}, {128, 191, 0}}}; - -// NVIDIA's proprietary driver packs its version into 10.8.8.6 bits. -std::tuple NvidiaVersion() { - const std::uint32_t v = Device::deviceProperties.driverVersion; - return {(v >> 22) & 0x3ff, (v >> 14) & 0xff, (v >> 6) & 0xff}; -} - -// Renders the scene into `out` and checks the pixels. Device::Initialize has -// already run. Returns the number of failed checks. -int RenderScene(const fs::path& out) { - const int failuresBefore = failures; - Device::validationErrorCount = 0; - - Window window(640, 360, "HeapDynamicIndexHit test"); - VkCommandBuffer cmd = window.StartInit(); - - // Image slots: 0 = the frame's swapchain image, 1-2 = the textures. - // Buffer slots: 0 = the TLAS, 1-2 = the colour buffers. Sampler slot 0. - DescriptorHeapVulkan descriptorHeap; - descriptorHeap.Initialize(3, 3, 1); - - VkSpecializationMapEntry raygenEntry = { .constantID = 0, .offset = 0, .size = sizeof(std::uint16_t) }; - VkSpecializationInfo raygenSpec = { - .mapEntryCount = 1, - .pMapEntries = &raygenEntry, - .dataSize = sizeof(std::uint16_t), - .pData = &descriptorHeap.bufferStartElement, - }; - HitConstants hitConstants = { - .bufferStart = descriptorHeap.bufferStartElement, - .pad = 0, - .textureBase = 1, - .colourBase = 1, - }; - std::array hitEntries {{ - { .constantID = 0, .offset = offsetof(HitConstants, bufferStart), .size = sizeof(std::uint16_t) }, - { .constantID = 1, .offset = offsetof(HitConstants, textureBase), .size = sizeof(std::uint32_t) }, - { .constantID = 2, .offset = offsetof(HitConstants, colourBase), .size = sizeof(std::uint32_t) }, - }}; - VkSpecializationInfo hitSpec = { - .mapEntryCount = static_cast(hitEntries.size()), - .pMapEntries = hitEntries.data(), - .dataSize = sizeof(HitConstants), - .pData = &hitConstants, - }; - - const fs::path dir = ExeDir(); - std::array shaders{{ - {dir / "dynidx-raygen.spv", "main", VK_SHADER_STAGE_RAYGEN_BIT_KHR, &raygenSpec}, - {dir / "dynidx-miss.spv", "main", VK_SHADER_STAGE_MISS_BIT_KHR, nullptr}, - {dir / "dynidx-closesthit.spv", "main", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, &hitSpec}, - }}; - ShaderBindingTableVulkan shaderTable; - shaderTable.Init(shaders); - - std::array raygenGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, - .generalShader = 0, .closestHitShader = VK_SHADER_UNUSED_KHR, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - std::array missGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, - .generalShader = 1, .closestHitShader = VK_SHADER_UNUSED_KHR, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - std::array hitGroups {{ { - .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, - .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, - .generalShader = VK_SHADER_UNUSED_KHR, .closestHitShader = 2, - .anyHitShader = VK_SHADER_UNUSED_KHR, .intersectionShader = VK_SHADER_UNUSED_KHR, - } }}; - PipelineRTVulkan pipeline; - pipeline.Init(cmd, raygenGroups, missGroups, hitGroups, shaderTable); - - // One triangle, two instances 100 units either side of the centre line. - Mesh triangleMesh; - std::array, 3> verts {{{-75, -75, 100}, {0, 75, 100}, {75, -75, 100}}}; - std::array index {{2, 1, 0}}; - triangleMesh.Build(verts, index, cmd); - - std::array renderers{}; - for (std::uint32_t i = 0; i < renderers.size(); ++i) { - renderers[i].instance = { - .instanceCustomIndex = i, - .mask = 0xFF, - .instanceShaderBindingTableRecordOffset = 0, - .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - .accelerationStructureReference = triangleMesh.blasAddr, - }; - MatrixRowMajor::Translation(i == 0 ? -100.0f : 100.0f, 0.0f, 0.0f) - .Store(reinterpret_cast(renderers[i].instance.transform.matrix)); - RenderingElement3D::Add(&renderers[i]); - } - for (std::uint32_t f = 0; f < Window::numFrames; ++f) RenderingElement3D::BuildTLAS(cmd, f); - - // Per descriptor set: a 2x2 texture whose green the hit shader reads, and - // a one-vec4 buffer whose red it reads. - std::array, 2> textures; - std::array, 2> colourBuffers; - for (std::size_t i = 0; i < textures.size(); ++i) { - textures[i].Create(2, 2, 1, cmd, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - for (std::size_t p = 0; p < 4; ++p) textures[i].buffer.value[p] = {0, textureGreen[i], 0, 255}; - textures[i].Update(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - colourBuffers[i].Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 4); - colourBuffers[i].value[0] = bufferRed[i]; - colourBuffers[i].value[1] = 0.0f; - colourBuffers[i].value[2] = 0.0f; - colourBuffers[i].value[3] = 1.0f; - colourBuffers[i].FlushDevice(); - } - - window.FinishInit(); - - auto imgSlots = descriptorHeap.AllocateImageSlots(3); - auto bufSlots = descriptorHeap.AllocateBufferSlots(3); - auto samplerSlots = descriptorHeap.AllocateSamplerSlots(1); - - std::array textureViews{}; - std::array textureInfos{}; - std::array colourRanges{}; - for (std::size_t i = 0; i < 2; ++i) { - textureViews[i] = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = textures[i].image, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, - .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1 }, - }; - textureInfos[i] = { - .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, - .pView = &textureViews[i], - .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - }; - colourRanges[i] = { .address = colourBuffers[i].address, .size = 4 * sizeof(float) }; - } - - // Written again whenever the swapchain is recreated, since the output - // image descriptors point at its images. - auto writeDescriptors = [&] { - std::array tlasRanges{}; - std::array outInfos{}; - std::vector resources; - std::vector destinations; - auto add = [&](std::uint32_t f, VkResourceDescriptorInfoEXT resource, std::uint32_t offset, std::uint32_t size) { - resources.push_back(resource); - destinations.push_back({ .address = descriptorHeap.resourceHeap[f].value + offset, .size = size }); - }; - const std::uint32_t imageSize = Device::descriptorHeapProperties.imageDescriptorSize; - const std::uint32_t bufferSize = Device::descriptorHeapProperties.bufferDescriptorSize; - for (std::uint32_t f = 0; f < Window::numFrames; ++f) { - tlasRanges[f] = { .address = RenderingElement3D::tlases[f].address }; - outInfos[f] = { - .sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT, - .pView = &window.imageViews[f], - .layout = VK_IMAGE_LAYOUT_GENERAL, - }; - add(f, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, - .data = { .pAddressRange = &tlasRanges[f] } }, - descriptorHeap.BufferByteOffset(bufSlots.firstElement), bufferSize); - add(f, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .data = { .pImage = &outInfos[f] } }, - descriptorHeap.ImageByteOffset(imgSlots.firstElement), imageSize); - for (std::uint16_t i = 0; i < 2; ++i) { - add(f, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .data = { .pImage = &textureInfos[i] } }, - descriptorHeap.ImageByteOffset(imgSlots.firstElement + 1 + i), imageSize); - add(f, { .sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT, - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .data = { .pAddressRange = &colourRanges[i] } }, - descriptorHeap.BufferByteOffset(bufSlots.firstElement + 1 + i), bufferSize); - } - } - Device::vkWriteResourceDescriptorsEXT(Device::device, static_cast(resources.size()), - resources.data(), destinations.data()); - for (auto& heap : descriptorHeap.resourceHeap) heap.FlushDevice(); - }; - writeDescriptors(); - EventListener resizeListener(&window.onResize, writeDescriptors); - - VkSamplerCreateInfo samplerInfo = { - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .magFilter = VK_FILTER_NEAREST, - .minFilter = VK_FILTER_NEAREST, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, - .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .maxLod = VK_LOD_CLAMP_NONE, - }; - std::array samplerInfos{}; - std::array samplerDestinations{}; - for (std::uint32_t f = 0; f < Window::numFrames; ++f) { - samplerInfos[f] = samplerInfo; - samplerDestinations[f] = { - .address = descriptorHeap.samplerHeap[f].value + descriptorHeap.SamplerByteOffset(samplerSlots.firstElement), - .size = Device::descriptorHeapProperties.samplerDescriptorSize, - }; - } - Device::vkWriteSamplerDescriptorsEXT(Device::device, Window::numFrames, samplerInfos.data(), samplerDestinations.data()); - for (auto& heap : descriptorHeap.samplerHeap) heap.FlushDevice(); - - window.descriptorHeap = &descriptorHeap; - RTPass rtPass(&pipeline); - window.passes.push_back(&rtPass); - - // More frames than are in flight, so every per-frame heap copy is read at - // least once. A device loss here throws out of Render(). - for (int i = 0; i < Window::numFrames * 2; ++i) window.Render(); - Device::CheckVkResult(vkQueueWaitIdle(Device::queue)); - - // Counted before the capture: SaveFrame reads back an image that has - // already been handed to the presentation engine, which the validation - // layer reports on its own. - if (std::getenv("CRAFTER_GRAPHICS_VALIDATION") != nullptr) { - Check(Device::validationErrorCount == 0, - std::format("no Vulkan validation errors while rendering ({} seen)", Device::validationErrorCount)); - } - - window.SaveFrame(out); - Device::CheckVkResult(vkQueueWaitIdle(Device::queue)); - const Frame frame = LoadFrame(out); - Check(!frame.rgba.empty(), "the frame was read back"); - if (!frame.rgba.empty()) { - const int y = frame.height / 2; - // An even column then the odd one next to it, in each triangle. - const int left = FrameX(-100.0f, frame) & ~1; - const int right = FrameX(100.0f, frame) & ~1; - CheckPixel(frame, left, y, setColour[0], "instance 0, even column (set 0)"); - CheckPixel(frame, left + 1, y, setColour[0], "instance 0, odd column (set 0)"); - CheckPixel(frame, right, y, setColour[1], "instance 1, even column (set 1)"); - CheckPixel(frame, right + 1, y, setColour[0], "instance 1, odd column (set 0)"); - CheckPixel(frame, frame.width / 2, y, {0, 0, 255}, "miss between the triangles"); - CheckPixel(frame, frame.width / 20, frame.height / 10, {0, 0, 255}, "miss in the corner"); - } - - for (RenderingElement3D& renderer : renderers) RenderingElement3D::Remove(&renderer); - return failures - failuresBefore; -} - -// A fresh directory for the read-back frames, so a frame left by an earlier -// run can't stand in for one this run failed to write. -fs::path OutputDir() { - const fs::path dir = fs::temp_directory_path() / "crafter-heap-dynamic-index-hit"; - std::error_code ec; - fs::remove_all(dir, ec); - fs::create_directories(dir); - return dir; -} - -} // namespace - -int main(int argc, char** argv) { - Device::Initialize(); - if (!Device::rayTracingSupported) { - std::println("SKIP no Vulkan ray-tracing device"); - return 77; - } - if (Device::driverProperties.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY - && NvidiaVersion() < std::tuple(615u, 78u, 8u)) { - const auto [major, minor, patch] = NvidiaVersion(); - std::println("SKIP NVIDIA {}.{:02}.{:02} loses the device on this (fixed in 615.78.08)", major, minor, patch); - return 77; - } - - // `--render `: the child run, rendering as configured. - if (argc == 3 && std::string_view(argv[1]) == "--render") { - RenderScene(argv[2]); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; - } - - const fs::path dir = OutputDir(); - if (std::getenv("CRAFTER_GRAPHICS_VALIDATION") != nullptr) { - const fs::path exe = fs::read_symlink("/proc/self/exe"); - const int exit = RunCommand(std::format("env -u CRAFTER_GRAPHICS_VALIDATION '{}' --render '{}'", - exe.string(), (dir / "unvalidated.png").string())); - Check(exit == 0, std::format("the scene renders with validation off (exit {})", exit)); - } - RenderScene(dir / "frame.png"); - - std::println("{}", failures == 0 ? "all checks passed" : "check(s) failed"); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/tests/TLASBuildBarrier/main.cpp b/tests/TLASBuildBarrier/main.cpp deleted file mode 100644 index f57b8e2..0000000 --- a/tests/TLASBuildBarrier/main.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// The dependency RenderingElement3D::BuildTLAS records after its build, which -// orders the build before the shaders that read the TLAS: traceRayEXT in a -// ray-tracing pass, rayQueryEXT in a compute pass, recorded after it in the -// same command buffer (BuildTLAS in onUpdate, then RTPass, is the documented -// per-frame flow). It used to be an execution-only barrier with no memory -// barrier, which orders the commands but never makes the build's -// acceleration-structure writes available and visible to those reads. The -// dependency is built by BuildTlasReadBarrier, pure CPU logic that this test -// drives directly with no GPU device, like SwapchainBarrierScope. - -#include -#include "vulkan/vulkan.h" - -import Crafter.Graphics; -import std; - -using namespace Crafter; - -namespace { - -int failures = 0; - -void Check(bool ok, std::string_view what) { - std::println("{} {}", ok ? "PASS" : "FAIL", what); - if (!ok) ++failures; -} - -} // namespace - -int main() { - const TlasReadBarrier barrier = BuildTlasReadBarrier(); - - Check(barrier.srcStage == VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - "the dependency starts at the acceleration-structure build"); - Check((barrier.dstStage & VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR) != 0, - "it reaches ray-tracing shaders (traceRayEXT)"); - Check((barrier.dstStage & VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT) != 0, - "it reaches compute shaders (rayQueryEXT)"); - - Check(barrier.memory.sType == VK_STRUCTURE_TYPE_MEMORY_BARRIER, "it carries a memory barrier"); - Check((barrier.memory.srcAccessMask & VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR) != 0, - "the build's acceleration-structure writes are made available"); - Check((barrier.memory.dstAccessMask & VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) != 0, - "and visible to acceleration-structure reads"); - - std::println("{}", failures == 0 ? "all checks passed" : "check(s) failed"); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/tests/TLASEmptyBuild/main.cpp b/tests/TLASEmptyBuild/main.cpp deleted file mode 100644 index 94e9595..0000000 --- a/tests/TLASEmptyBuild/main.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0-only -//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// RenderingElement3D::BuildTLAS with no elements registered, i.e. an app that -// builds its TLAS before the scene has anything in it. The TLAS instance and -// metadata buffers used to be sized to the instance count, so the first build -// of an empty scene created zero-size buffers: invalid usage, which NVIDIA -// answers with VK_ERROR_OUT_OF_DEVICE_MEMORY, so BuildTLAS threw. An empty -// TLAS is valid to trace against (every ray misses), so it has to build, and -// adding and removing instances afterwards has to keep working. -// -// Needs a Vulkan RT device, like BLASBuildOptions; without RT it skips. - -#include -#include "vulkan/vulkan.h" - -import Crafter.Graphics; -import Crafter.Math; -import std; - -using namespace Crafter; - -namespace { - -int failures = 0; - -void Check(bool ok, std::string_view what) { - std::println("{} {}", ok ? "PASS" : "FAIL", what); - if (!ok) ++failures; -} - -// One-time command buffer helpers: record a build, submit, block. -VkCommandBuffer BeginCmd() { - VkCommandBufferAllocateInfo allocInfo { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = Device::commandPool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - VkCommandBuffer cmd = VK_NULL_HANDLE; - Device::CheckVkResult(vkAllocateCommandBuffers(Device::device, &allocInfo, &cmd)); - VkCommandBufferBeginInfo beginInfo { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, - }; - Device::CheckVkResult(vkBeginCommandBuffer(cmd, &beginInfo)); - return cmd; -} - -void SubmitWait(VkCommandBuffer cmd) { - Device::CheckVkResult(vkEndCommandBuffer(cmd)); - VkSubmitInfo submitInfo { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &cmd, - }; - Device::CheckVkResult(vkQueueSubmit(Device::queue, 1, &submitInfo, VK_NULL_HANDLE)); - Device::CheckVkResult(vkQueueWaitIdle(Device::queue)); - vkFreeCommandBuffers(Device::device, Device::commandPool, 1, &cmd); -} - -// Builds frame 0's TLAS from whatever is registered; false if it threw. -bool BuildFrame0() { - VkCommandBuffer cmd = BeginCmd(); - try { - RenderingElement3D::BuildTLAS(cmd, 0); - } catch (const std::exception& e) { - std::println(" BuildTLAS threw: {}", e.what()); - vkEndCommandBuffer(cmd); - vkFreeCommandBuffers(Device::device, Device::commandPool, 1, &cmd); - return false; - } - SubmitWait(cmd); - return true; -} - -} // namespace - -int main() { - Device::Initialize(); - if (!Device::rayTracingSupported) { - std::println("SKIP no Vulkan ray-tracing device"); - return 77; - } - Device::validationErrorCount = 0; - const TlasWithBuffer& tlas = RenderingElement3D::tlases[0]; - - Check(RenderingElement3D::elements.empty(), "the scene starts empty"); - if (!BuildFrame0()) { - Check(false, "an empty scene's TLAS builds"); - std::println("check(s) failed"); - return EXIT_FAILURE; - } - Check(true, "an empty scene's TLAS builds"); - Check(tlas.accelerationStructure != VK_NULL_HANDLE && tlas.address != 0, - "it is a real acceleration structure with a device address"); - Check(tlas.builtInstanceCount == 0, "built for zero instances"); - - // One instance added to the scene afterwards. - Mesh triangle; - { - VkCommandBuffer cmd = BeginCmd(); - std::array, 3> verts {{{-1, -1, 0}, {0, 1, 0}, {1, -1, 0}}}; - std::array index {{2, 1, 0}}; - triangle.Build(verts, index, cmd); - SubmitWait(cmd); - } - RenderingElement3D element; - element.instance = { - .instanceCustomIndex = 0, - .mask = 0xFF, - .instanceShaderBindingTableRecordOffset = 0, - .flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - .accelerationStructureReference = triangle.blasAddr, - }; - MatrixRowMajor::Identity().Store(reinterpret_cast(element.instance.transform.matrix)); - RenderingElement3D::Add(&element); - Check(BuildFrame0(), "the TLAS rebuilds once an instance is added"); - Check(tlas.builtInstanceCount == 1, "built for one instance"); - - // And back to empty. - RenderingElement3D::Remove(&element); - Check(BuildFrame0(), "the TLAS rebuilds once the scene is empty again"); - Check(tlas.builtInstanceCount == 0, "built for zero instances again"); - - if (std::getenv("CRAFTER_GRAPHICS_VALIDATION") != nullptr) { - Check(Device::validationErrorCount == 0, - std::format("no Vulkan validation errors ({} seen)", Device::validationErrorCount)); - } - - std::println("{}", failures == 0 ? "all checks passed" : "check(s) failed"); - return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/tests/TLASHighWaterMark/main.cpp b/tests/TLASHighWaterMark/main.cpp index 746a66e..99174f4 100644 --- a/tests/TLASHighWaterMark/main.cpp +++ b/tests/TLASHighWaterMark/main.cpp @@ -351,6 +351,22 @@ int main() { Check(Device::validationErrorCount == 0, std::format("no Vulkan validation errors ({} seen)", Device::validationErrorCount)); + // Tear down the frame-0 TLAS while the Vulkan device is still alive. The + // static tlases[] array is destroyed at process exit, by which point the + // device (also static) may already be gone — so its VulkanBuffer + // destructors would fault. Releasing here keeps the exit path clean. + { + auto& t0 = RenderingElement3D::tlases[0]; + if (t0.accelerationStructure != VK_NULL_HANDLE) { + Device::vkDestroyAccelerationStructureKHR(Device::device, t0.accelerationStructure, nullptr); + t0.accelerationStructure = VK_NULL_HANDLE; + } + if (t0.instanceBuffer.buffer != VK_NULL_HANDLE) t0.instanceBuffer.Clear(); + if (t0.metadataBuffer.buffer != VK_NULL_HANDLE) t0.metadataBuffer.Clear(); + if (t0.scratchBuffer.buffer != VK_NULL_HANDLE) t0.scratchBuffer.Clear(); + if (t0.buffer.buffer != VK_NULL_HANDLE) t0.buffer.Clear(); + } + if (failures != 0) { std::println("{} check(s) failed", failures); return EXIT_FAILURE; diff --git a/tests/TLASInstanceDirtyTracking/main.cpp b/tests/TLASInstanceDirtyTracking/main.cpp index b2526fc..4ba711a 100644 --- a/tests/TLASInstanceDirtyTracking/main.cpp +++ b/tests/TLASInstanceDirtyTracking/main.cpp @@ -213,6 +213,20 @@ int main() { Check(Device::validationErrorCount == 0, std::format("no Vulkan validation errors ({} seen)", Device::validationErrorCount)); + // Tear down the frame-0 TLAS while the device is still alive (same rationale + // as TLASHighWaterMark — the static tlases[] outlive the static device). + { + auto& t0 = RenderingElement3D::tlases[0]; + if (t0.accelerationStructure != VK_NULL_HANDLE) { + Device::vkDestroyAccelerationStructureKHR(Device::device, t0.accelerationStructure, nullptr); + t0.accelerationStructure = VK_NULL_HANDLE; + } + if (t0.instanceBuffer.buffer != VK_NULL_HANDLE) t0.instanceBuffer.Clear(); + if (t0.metadataBuffer.buffer != VK_NULL_HANDLE) t0.metadataBuffer.Clear(); + if (t0.scratchBuffer.buffer != VK_NULL_HANDLE) t0.scratchBuffer.Clear(); + if (t0.buffer.buffer != VK_NULL_HANDLE) t0.buffer.Clear(); + } + if (failures != 0) { std::println("{} check(s) failed", failures); return EXIT_FAILURE;