blob: e68ad7c4394eb0252a1ca8543284687b7d8c0305 [file] [log] [blame]
Brad Bishop8a502f52017-06-14 23:46:15 -04001#pragma once
2
3#include <fcntl.h>
4#include <libevdev/libevdev.h>
Matthew Barth11fc0a72020-05-26 10:55:54 -05005#include <unistd.h>
6
Brad Bishop8a502f52017-06-14 23:46:15 -04007#include <phosphor-logging/elog-errors.hpp>
Matthew Barth11fc0a72020-05-26 10:55:54 -05008#include <phosphor-logging/elog.hpp>
Anwaar Hadi32c4fef2025-04-02 16:08:27 +00009#include <phosphor-logging/lg2.hpp>
Matthew Barth11fc0a72020-05-26 10:55:54 -050010#include <xyz/openbmc_project/Common/error.hpp>
11
12#include <memory>
Brad Bishop8a502f52017-06-14 23:46:15 -040013#include <string>
14#include <tuple>
Brad Bishop8a502f52017-06-14 23:46:15 -040015
16namespace evdevpp
17{
18namespace evdev
19{
20
21using EvDevPtr = libevdev*;
22
23namespace details
24{
25
26/** @brief unique_ptr functor to release an evdev reference. */
27struct EvDevDeleter
28{
29 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. */
38using EvDev = std::unique_ptr<libevdev, EvDevDeleter>;
39
40} // namespace details
41
Marri Devender Rao60885582017-11-07 04:58:14 -060042using namespace phosphor::logging;
Brad Bishop8a502f52017-06-14 23:46:15 -040043/** @class EvDev
44 * @brief Provides C++ bindings to the libevdev C API.
45 */
46class EvDev
47{
Matthew Barth11fc0a72020-05-26 10:55:54 -050048 private:
49 using InternalFailure =
50 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Brad Bishop8a502f52017-06-14 23:46:15 -040051
Matthew Barth11fc0a72020-05-26 10:55:54 -050052 public:
53 /* Define all of the basic class operations:
54 * Not allowed:
55 * - Default constructor to avoid nullptrs.
56 * - Copy operations due to internal unique_ptr.
57 * Allowed:
58 * - Move operations.
59 * - Destructor.
60 */
61 EvDev() = delete;
62 EvDev(const EvDev&) = delete;
63 EvDev& operator=(const EvDev&) = delete;
64 EvDev(EvDev&&) = default;
65 EvDev& operator=(EvDev&&) = default;
66 ~EvDev() = default;
Brad Bishop8a502f52017-06-14 23:46:15 -040067
Matthew Barth11fc0a72020-05-26 10:55:54 -050068 /** @brief Conversion constructor from evdev. */
Patrick Williams61b73292023-05-10 07:50:12 -050069 explicit EvDev(EvDevPtr ptr) : evdev(ptr) {}
Brad Bishop8a502f52017-06-14 23:46:15 -040070
Matthew Barth11fc0a72020-05-26 10:55:54 -050071 /** @brief Get the current event state. */
72 auto fetch(unsigned int type, unsigned int code)
73 {
74 int val;
75 auto rc = libevdev_fetch_event_value(evdev.get(), type, code, &val);
76 if (!rc)
Brad Bishop8a502f52017-06-14 23:46:15 -040077 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +000078 lg2::error(
79 "Error in call to libevdev_fetch_event_value, Type={TYPE}, Code={CODE}",
80 "TYPE", type, "CODE", code);
Matthew Barth11fc0a72020-05-26 10:55:54 -050081 elog<InternalFailure>();
82 }
83
84 return val;
85 }
86
87 /** @brief Get the next event. */
88 auto next()
89 {
90 struct input_event ev;
91 while (true)
92 {
93 auto rc = libevdev_next_event(evdev.get(),
94 LIBEVDEV_READ_FLAG_NORMAL, &ev);
95 if (rc < 0)
Brad Bishop8a502f52017-06-14 23:46:15 -040096 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +000097 lg2::error("Error in call to libevdev_next_event, RC={RC}",
98 "RC", rc);
Marri Devender Rao60885582017-11-07 04:58:14 -060099 elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -0400100 }
101
Matthew Barth11fc0a72020-05-26 10:55:54 -0500102 if (ev.type == EV_SYN && ev.code == SYN_REPORT)
103 continue;
104
105 break;
Brad Bishop8a502f52017-06-14 23:46:15 -0400106 }
Matthew Barth11fc0a72020-05-26 10:55:54 -0500107 return std::make_tuple(ev.type, ev.code, ev.value);
108 }
Brad Bishop8a502f52017-06-14 23:46:15 -0400109
Matthew Barth11fc0a72020-05-26 10:55:54 -0500110 private:
111 EvDevPtr get()
112 {
113 return evdev.get();
114 }
Brad Bishop8a502f52017-06-14 23:46:15 -0400115
Matthew Barth11fc0a72020-05-26 10:55:54 -0500116 details::EvDev evdev;
Brad Bishop8a502f52017-06-14 23:46:15 -0400117};
118
119inline auto newFromFD(int fd)
120{
Matthew Barth11fc0a72020-05-26 10:55:54 -0500121 using InternalFailure =
122 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Brad Bishop8a502f52017-06-14 23:46:15 -0400123
124 EvDevPtr dev = nullptr;
125 auto rc = libevdev_new_from_fd(fd, &dev);
126
127 if (rc)
128 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +0000129 lg2::error("Error in call to libevdev_new_from_fd, RC={RC}, FD={FD}",
130 "RC", rc, "FD", fd);
Marri Devender Rao60885582017-11-07 04:58:14 -0600131 elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -0400132 }
133
134 return EvDev(dev);
135}
136} // namespace evdev
137} // namespace evdevpp