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 /** @brief Get the current event state. */ 71 auto fetch(unsigned int type, unsigned int code) 72 { 73 int val; 74 auto rc = libevdev_fetch_event_value(evdev.get(), type, code, &val); 75 if (!rc) 76 { 77 log<level::ERR>("Error in call to libevdev_fetch_event_value", 78 entry("TYPE=%d", type), entry("CODE=%d", code)); 79 elog<InternalFailure>(); 80 } 81 82 return val; 83 } 84 85 /** @brief Get the next event. */ 86 auto next() 87 { 88 struct input_event ev; 89 while (true) 90 { 91 auto rc = libevdev_next_event(evdev.get(), 92 LIBEVDEV_READ_FLAG_NORMAL, &ev); 93 if (rc < 0) 94 { 95 log<level::ERR>("Error in call to libevdev_next_event", 96 entry("RC=%d", rc)); 97 elog<InternalFailure>(); 98 } 99 100 if (ev.type == EV_SYN && ev.code == SYN_REPORT) 101 continue; 102 103 break; 104 } 105 return std::make_tuple(ev.type, ev.code, ev.value); 106 } 107 108 private: 109 EvDevPtr get() 110 { 111 return evdev.get(); 112 } 113 114 details::EvDev evdev; 115 }; 116 117 inline auto newFromFD(int fd) 118 { 119 using InternalFailure = 120 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 121 122 EvDevPtr dev = nullptr; 123 auto rc = libevdev_new_from_fd(fd, &dev); 124 125 if (rc) 126 { 127 log<level::ERR>("Error in call to libevdev_new_from_fd", 128 entry("RC=%d", rc), entry("FD=%d", fd)); 129 elog<InternalFailure>(); 130 } 131 132 return EvDev(dev); 133 } 134 } // namespace evdev 135 } // namespace evdevpp 136