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 <phosphor-logging/lg2.hpp>
10 #include <xyz/openbmc_project/Common/error.hpp>
11
12 #include <memory>
13 #include <string>
14 #include <tuple>
15
16 namespace evdevpp
17 {
18 namespace evdev
19 {
20
21 using EvDevPtr = libevdev*;
22
23 namespace details
24 {
25
26 /** @brief unique_ptr functor to release an evdev reference. */
27 struct EvDevDeleter
28 {
operator ()evdevpp::evdev::details::EvDevDeleter29 void operator()(libevdev* ptr) const
30 {
31 deleter(ptr);
32 }
33
34 decltype(&libevdev_free) deleter = libevdev_free;
35 };
36
37 /* @brief Alias evdev to a unique_ptr type for auto-release. */
38 using EvDev = std::unique_ptr<libevdev, EvDevDeleter>;
39
40 } // namespace details
41
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 lg2::error(
78 "Error in call to libevdev_fetch_event_value, Type={TYPE}, Code={CODE}",
79 "TYPE", type, "CODE", code);
80 phosphor::logging::elog<InternalFailure>();
81 }
82
83 return val;
84 }
85
86 /** @brief Get the next event. */
next()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 lg2::error("Error in call to libevdev_next_event, RC={RC}",
97 "RC", rc);
98 phosphor::logging::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:
get()110 EvDevPtr get()
111 {
112 return evdev.get();
113 }
114
115 details::EvDev evdev;
116 };
117
newFromFD(int fd)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 lg2::error("Error in call to libevdev_new_from_fd, RC={RC}, FD={FD}",
129 "RC", rc, "FD", fd);
130 phosphor::logging::elog<InternalFailure>();
131 }
132
133 return EvDev(dev);
134 }
135 } // namespace evdev
136 } // namespace evdevpp
137