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 using namespace phosphor::logging; 40 /** @class EvDev 41 * @brief Provides C++ bindings to the libevdev C API. 42 */ 43 class EvDev 44 { 45 private: 46 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 47 Error::InternalFailure; 48 49 public: 50 /* Define all of the basic class operations: 51 * Not allowed: 52 * - Default constructor to avoid nullptrs. 53 * - Copy operations due to internal unique_ptr. 54 * Allowed: 55 * - Move operations. 56 * - Destructor. 57 */ 58 EvDev() = delete; 59 EvDev(const EvDev&) = delete; 60 EvDev& operator=(const EvDev&) = delete; 61 EvDev(EvDev&&) = default; 62 EvDev& operator=(EvDev&&) = default; 63 ~EvDev() = default; 64 65 /** @brief Conversion constructor from evdev. */ 66 explicit EvDev(EvDevPtr ptr) : evdev(ptr) {} 67 68 /** @brief Get the current event state. */ 69 auto fetch(unsigned int type, unsigned int code) 70 { 71 int val; 72 auto rc = libevdev_fetch_event_value( 73 evdev.get(), type, code, &val); 74 if (!rc) 75 { 76 log<level::ERR>("Error in call to libevdev_fetch_event_value", 77 entry("TYPE=%d", type), 78 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( 92 evdev.get(), 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 = sdbusplus::xyz::openbmc_project::Common:: 120 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), 129 entry("FD=%d", fd)); 130 elog<InternalFailure>(); 131 } 132 133 return EvDev(dev); 134 } 135 } // namespace evdev 136 } // namespace evdevpp 137