~benklop/+junk/libcec-daemon

« back to all changes in this revision

Viewing changes to src/uinput.cpp

  • Committer: Ben Klopfenstein
  • Date: 2016-10-02 07:42:53 UTC
  • Revision ID: ben@klopnet.com-20161002074253-umxla9914gyv967v
Tags: upstream-0.9
ImportĀ upstreamĀ versionĀ 0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "uinput.h"
 
2
 
 
3
#include <cstring>
 
4
#include <stdexcept>
 
5
 
 
6
#include <errno.h>
 
7
#include <fcntl.h>
 
8
#include <linux/uinput.h>
 
9
#include <unistd.h>
 
10
 
 
11
#include <log4cplus/logger.h>
 
12
#include <log4cplus/loggingmacros.h>
 
13
 
 
14
using namespace log4cplus;
 
15
 
 
16
// Various uinput files we try and open
 
17
static const char *uinput_filename[] = {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput"};
 
18
 
 
19
static Logger logger = Logger::getInstance("uinput");
 
20
 
 
21
UInput::UInput(const char *dev_name, const std::vector< std::list<__u16> > & keys) : fd(-1) {
 
22
        openAll();
 
23
        setup(dev_name, keys);
 
24
        create();
 
25
}
 
26
 
 
27
UInput::~UInput() {
 
28
        destroy();
 
29
}
 
30
 
 
31
int UInput::open(const char *uinput_path) {
 
32
        this->fd = ::open(uinput_path, O_WRONLY | O_NONBLOCK);
 
33
        if(this->fd < 0) {
 
34
                return errno;
 
35
        }
 
36
        return 0;
 
37
}
 
38
 
 
39
/**
 
40
 * Try each uinput until one works
 
41
 */
 
42
void UInput::openAll() {
 
43
        int ret = ENOENT;
 
44
        for (int i = 0; i < 3; i++) {
 
45
                ret = open(uinput_filename[i]);
 
46
 
 
47
                // If all things worked, then bail
 
48
                if (ret == 0) {
 
49
                        LOG4CPLUS_INFO(logger, "Opened " << uinput_filename[i]);
 
50
                        break;
 
51
                }
 
52
 
 
53
                // If the device isn't found, try the next one
 
54
                if (ret == ENOENT)
 
55
                        continue;
 
56
 
 
57
                if (ret == EACCES) {
 
58
                        LOG4CPLUS_ERROR(logger, "Permission denied. Check you have permission to uinput.");
 
59
                } else {
 
60
                        LOG4CPLUS_ERROR(logger, errno << " " << strerror(errno));
 
61
                }
 
62
 
 
63
                throw std::runtime_error("Failed to open uinput");
 
64
        }
 
65
 
 
66
        if (ret != 0) {
 
67
                LOG4CPLUS_ERROR(logger, "uinput was not found. Is the uinput module loaded?");
 
68
                throw std::runtime_error("Failed to open uinput");
 
69
        }
 
70
}
 
71
 
 
72
void UInput::setup(const char *dev_name, const std::vector< std::list<__u16> > & keys) {
 
73
 
 
74
        int ret;
 
75
        struct uinput_user_dev uidev;
 
76
        memset(&uidev, 0, sizeof(uidev));
 
77
 
 
78
        strncpy(uidev.name, dev_name, UINPUT_MAX_NAME_SIZE);
 
79
        uidev.id.bustype = BUS_USB;
 
80
        uidev.id.vendor  = 1337;
 
81
        uidev.id.product = 1337;
 
82
        uidev.id.version = 1337;
 
83
 
 
84
        ret = write(this->fd, &uidev, sizeof(uidev));
 
85
        if (ret != sizeof(uidev)) {
 
86
                throw std::runtime_error("Failed to setup uinput");
 
87
                //cerr << "Failed to setup uinput: " << errno << " " << strerror(errno) << endl;
 
88
        }
 
89
 
 
90
        // We only want to send keypresses
 
91
        ret  = ioctl(this->fd, UI_SET_EVBIT, EV_KEY);
 
92
 
 
93
        // Add all the keys we might use
 
94
        for (std::vector< std::list<__u16> >::const_iterator i = keys.begin(); i != keys.end(); ++i) {
 
95
                const std::list<__u16> & kk = *i;
 
96
                for (std::list<__u16>::const_iterator k = kk.begin(); k != kk.end(); ++k) {
 
97
                        __u16 ukey = *k;
 
98
                        if (ukey != KEY_RESERVED)
 
99
                                ret |= ioctl(this->fd, UI_SET_KEYBIT, ukey);
 
100
                }
 
101
        }
 
102
 
 
103
        if (ret) {
 
104
        throw std::runtime_error("Failed to setup uinput");
 
105
                //cerr << "Failed to setup uinput" " << errno << " " << strerror(errno) << endl;
 
106
        }
 
107
}
 
108
 
 
109
void UInput::create() {
 
110
        int ret = ioctl(this->fd, UI_DEV_CREATE);
 
111
        if (ret) {
 
112
                throw std::runtime_error("Failed to create uinput");
 
113
        }
 
114
 
 
115
        LOG4CPLUS_INFO(logger, "Created uinput device");
 
116
 
 
117
        // This sleep is here, because (for some reason) you need to wait before
 
118
        // sending you first uinput event.
 
119
        sleep(1);
 
120
}
 
121
 
 
122
void UInput::send_event(__u16 type, __u16 code, __s32 value) const {
 
123
        struct input_event ev;
 
124
        memset(&ev, 0, sizeof(ev));
 
125
 
 
126
        ev.type  = type;
 
127
        ev.code  = code;
 
128
        ev.value = value;
 
129
 
 
130
        int ret = write(this->fd, &ev, sizeof(ev));
 
131
        if (ret != sizeof(ev)) {
 
132
                throw std::runtime_error("Failed to send_event");
 
133
        }
 
134
}
 
135
 
 
136
void UInput::sync() const {
 
137
        send_event(EV_SYN, SYN_REPORT, 0);
 
138
}
 
139
 
 
140
 
 
141
void UInput::destroy() {
 
142
        ioctl(this->fd, UI_DEV_DESTROY);
 
143
        close(this->fd);
 
144
 
 
145
        this->fd = -1;
 
146
}