1 #pragma once 2 3 #include <fcntl.h> 4 #include <libevdev/libevdev.h> 5 #include <memory> 6 #include <phosphor-logging/elog.hpp> 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <string> 9 #include <tuple> 10 #include <unistd.h> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 13 namespace evdevpp 14 { 15 namespace evdev 16 { 17 18 using EvDevPtr = libevdev*; 19 20 namespace details 21 { 22 23 /** @brief unique_ptr functor to release an evdev reference. */ 24 struct EvDevDeleter 25 { 26 void operator()(libevdev* ptr) const 27 { 28 deleter(ptr); 29 } 30 31 decltype(&libevdev_free) deleter = libevdev_free; 32 }; 33 34 /* @brief Alias evdev to a unique_ptr type for auto-release. */ 35 using EvDev = std::unique_ptr<libevdev, EvDevDeleter>; 36 37 } // namespace details 38 39 /** @class EvDev 40 * @brief Provides C++ bindings to the libevdev C API. 41 */ 42 class EvDev 43 { 44 private: 45 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 46 Error::InternalFailure; 47 48 public: 49 /* Define all of the basic class operations: 50 * Not allowed: 51 * - Default constructor to avoid nullptrs. 52 * - Copy operations due to internal unique_ptr. 53 * Allowed: 54 * - Move operations. 55 * - Destructor. 56 */ 57 EvDev() = delete; 58 EvDev(const EvDev&) = delete; 59 EvDev& operator=(const EvDev&) = delete; 60 EvDev(EvDev&&) = default; 61 EvDev& operator=(EvDev&&) = default; 62 ~EvDev() = default; 63 64 /** @brief Conversion constructor from evdev. */ 65 explicit EvDev(EvDevPtr ptr) : evdev(ptr) {} 66 67 /** @brief Get the current event state. */ 68 auto fetch(unsigned int type, unsigned int code) 69 { 70 int val; 71 auto rc = libevdev_fetch_event_value( 72 evdev.get(), type, code, &val); 73 if (!rc) 74 { 75 phosphor::logging::elog<InternalFailure>(); 76 } 77 78 return val; 79 } 80 81 /** @brief Get the next event. */ 82 auto next() 83 { 84 struct input_event ev; 85 while (true) 86 { 87 auto rc = libevdev_next_event( 88 evdev.get(), LIBEVDEV_READ_FLAG_NORMAL, &ev); 89 if (rc < 0) 90 { 91 phosphor::logging::elog<InternalFailure>(); 92 } 93 94 if (ev.type == EV_SYN && ev.code == SYN_REPORT) 95 continue; 96 97 break; 98 } 99 return std::make_tuple(ev.type, ev.code, ev.value); 100 } 101 102 private: 103 EvDevPtr get() 104 { 105 return evdev.get(); 106 } 107 108 details::EvDev evdev; 109 }; 110 111 inline auto newFromFD(int fd) 112 { 113 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 114 Error::InternalFailure; 115 116 EvDevPtr dev = nullptr; 117 auto rc = libevdev_new_from_fd(fd, &dev); 118 119 if (rc) 120 { 121 phosphor::logging::elog<InternalFailure>(); 122 } 123 124 return EvDev(dev); 125 } 126 } // namespace evdev 127 } // namespace evdevpp 128