blob: b0ba06e1443bea906161e04812ac9d0f61d3b72c [file] [log] [blame]
Brad Bishop8a502f52017-06-14 23:46:15 -04001#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
13namespace evdevpp
14{
15namespace evdev
16{
17
18using EvDevPtr = libevdev*;
19
20namespace details
21{
22
23/** @brief unique_ptr functor to release an evdev reference. */
24struct 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. */
35using EvDev = std::unique_ptr<libevdev, EvDevDeleter>;
36
37} // namespace details
38
Marri Devender Rao60885582017-11-07 04:58:14 -060039using namespace phosphor::logging;
Brad Bishop8a502f52017-06-14 23:46:15 -040040/** @class EvDev
41 * @brief Provides C++ bindings to the libevdev C API.
42 */
43class 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 {
Marri Devender Rao60885582017-11-07 04:58:14 -060076 log<level::ERR>("Error in call to libevdev_fetch_event_value",
77 entry("TYPE=%d", type),
78 entry("CODE=%d", code));
79 elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -040080 }
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 {
Marri Devender Rao60885582017-11-07 04:58:14 -060095 log<level::ERR>("Error in call to libevdev_next_event",
96 entry("RC=%d", rc));
97 elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -040098 }
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
117inline 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 {
Marri Devender Rao60885582017-11-07 04:58:14 -0600127 log<level::ERR>("Error in call to libevdev_new_from_fd",
128 entry("RC=%d", rc),
129 entry("FD=%d", fd));
130 elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -0400131 }
132
133 return EvDev(dev);
134}
135} // namespace evdev
136} // namespace evdevpp