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 {
operator ()evdevpp::evdev::details::EvDevDeleter28 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. */
EvDev(EvDevPtr ptr)68 explicit EvDev(EvDevPtr ptr) : evdev(ptr) {}
69
70 /** @brief Get the current event state. */
fetch(unsigned int type,unsigned int code)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. */
next()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:
get()109 EvDevPtr get()
110 {
111 return evdev.get();
112 }
113
114 details::EvDev evdev;
115 };
116
newFromFD(int fd)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