summaryrefslogtreecommitdiffstats
path: root/evdevpp/evdev.hpp
blob: b0ba06e1443bea906161e04812ac9d0f61d3b72c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#pragma once

#include <fcntl.h>
#include <libevdev/libevdev.h>
#include <memory>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <string>
#include <tuple>
#include <unistd.h>
#include <xyz/openbmc_project/Common/error.hpp>

namespace evdevpp
{
namespace evdev
{

using EvDevPtr = libevdev*;

namespace details
{

/** @brief unique_ptr functor to release an evdev reference. */
struct EvDevDeleter
{
    void operator()(libevdev* ptr) const
    {
        deleter(ptr);
    }

    decltype(&libevdev_free) deleter = libevdev_free;
};

/* @brief Alias evdev to a unique_ptr type for auto-release. */
using EvDev = std::unique_ptr<libevdev, EvDevDeleter>;

} // namespace details

using namespace phosphor::logging;
/** @class EvDev
 *  @brief Provides C++ bindings to the libevdev C API.
 */
class EvDev
{
    private:
        using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
            Error::InternalFailure;

    public:
        /* Define all of the basic class operations:
         *     Not allowed:
         *         - Default constructor to avoid nullptrs.
         *         - Copy operations due to internal unique_ptr.
         *     Allowed:
         *         - Move operations.
         *         - Destructor.
         */
        EvDev() = delete;
        EvDev(const EvDev&) = delete;
        EvDev& operator=(const EvDev&) = delete;
        EvDev(EvDev&&) = default;
        EvDev& operator=(EvDev&&) = default;
        ~EvDev() = default;

        /** @brief Conversion constructor from evdev. */
        explicit EvDev(EvDevPtr ptr) : evdev(ptr) {}

        /** @brief Get the current event state. */
        auto fetch(unsigned int type, unsigned int code)
        {
            int val;
            auto rc = libevdev_fetch_event_value(
                    evdev.get(), type, code, &val);
            if (!rc)
            {
                log<level::ERR>("Error in call to libevdev_fetch_event_value",
                        entry("TYPE=%d", type),
                        entry("CODE=%d", code));
                elog<InternalFailure>();
            }

            return val;
        }

        /** @brief Get the next event. */
        auto next()
        {
            struct input_event ev;
            while (true)
            {
                auto rc = libevdev_next_event(
                        evdev.get(), LIBEVDEV_READ_FLAG_NORMAL, &ev);
                if (rc < 0)
                {
                    log<level::ERR>("Error in call to libevdev_next_event",
                            entry("RC=%d", rc));
                    elog<InternalFailure>();
                }

                if (ev.type == EV_SYN && ev.code == SYN_REPORT)
                    continue;

                break;
            }
            return std::make_tuple(ev.type, ev.code, ev.value);
        }

    private:
        EvDevPtr get()
        {
            return evdev.get();
        }

        details::EvDev evdev;
};

inline auto newFromFD(int fd)
{
    using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
        Error::InternalFailure;

    EvDevPtr dev = nullptr;
    auto rc = libevdev_new_from_fd(fd, &dev);

    if (rc)
    {
        log<level::ERR>("Error in call to libevdev_new_from_fd",
                entry("RC=%d", rc),
                entry("FD=%d", fd));
        elog<InternalFailure>();
    }

    return EvDev(dev);
}
} // namespace evdev
} // namespace evdevpp
OpenPOWER on IntegriCloud