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