blob: 4c4441fa56b3487c41910ea9860ba1eb86a7819d [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
42/** @class EvDev
43 * @brief Provides C++ bindings to the libevdev C API.
44 */
45class EvDev
46{
Matthew Barth11fc0a72020-05-26 10:55:54 -050047 private:
48 using InternalFailure =
49 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Brad Bishop8a502f52017-06-14 23:46:15 -040050
Matthew Barth11fc0a72020-05-26 10:55:54 -050051 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;
Brad Bishop8a502f52017-06-14 23:46:15 -040066
Matthew Barth11fc0a72020-05-26 10:55:54 -050067 /** @brief Conversion constructor from evdev. */
Patrick Williams61b73292023-05-10 07:50:12 -050068 explicit EvDev(EvDevPtr ptr) : evdev(ptr) {}
Brad Bishop8a502f52017-06-14 23:46:15 -040069
Matthew Barth11fc0a72020-05-26 10:55:54 -050070 /** @brief Get the current event state. */
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)
Brad Bishop8a502f52017-06-14 23:46:15 -040076 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +000077 lg2::error(
78 "Error in call to libevdev_fetch_event_value, Type={TYPE}, Code={CODE}",
79 "TYPE", type, "CODE", code);
Anwaar Hadi9d533802025-04-09 19:08:51 +000080 phosphor::logging::elog<InternalFailure>();
Matthew Barth11fc0a72020-05-26 10:55:54 -050081 }
82
83 return val;
84 }
85
86 /** @brief Get the next event. */
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)
Brad Bishop8a502f52017-06-14 23:46:15 -040095 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +000096 lg2::error("Error in call to libevdev_next_event, RC={RC}",
97 "RC", rc);
Anwaar Hadi9d533802025-04-09 19:08:51 +000098 phosphor::logging::elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -040099 }
100
Matthew Barth11fc0a72020-05-26 10:55:54 -0500101 if (ev.type == EV_SYN && ev.code == SYN_REPORT)
102 continue;
103
104 break;
Brad Bishop8a502f52017-06-14 23:46:15 -0400105 }
Matthew Barth11fc0a72020-05-26 10:55:54 -0500106 return std::make_tuple(ev.type, ev.code, ev.value);
107 }
Brad Bishop8a502f52017-06-14 23:46:15 -0400108
Matthew Barth11fc0a72020-05-26 10:55:54 -0500109 private:
110 EvDevPtr get()
111 {
112 return evdev.get();
113 }
Brad Bishop8a502f52017-06-14 23:46:15 -0400114
Matthew Barth11fc0a72020-05-26 10:55:54 -0500115 details::EvDev evdev;
Brad Bishop8a502f52017-06-14 23:46:15 -0400116};
117
118inline auto newFromFD(int fd)
119{
Matthew Barth11fc0a72020-05-26 10:55:54 -0500120 using InternalFailure =
121 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Brad Bishop8a502f52017-06-14 23:46:15 -0400122
123 EvDevPtr dev = nullptr;
124 auto rc = libevdev_new_from_fd(fd, &dev);
125
126 if (rc)
127 {
Anwaar Hadi32c4fef2025-04-02 16:08:27 +0000128 lg2::error("Error in call to libevdev_new_from_fd, RC={RC}, FD={FD}",
129 "RC", rc, "FD", fd);
Anwaar Hadi9d533802025-04-09 19:08:51 +0000130 phosphor::logging::elog<InternalFailure>();
Brad Bishop8a502f52017-06-14 23:46:15 -0400131 }
132
133 return EvDev(dev);
134}
135} // namespace evdev
136} // namespace evdevpp