Lomiri
Loading...
Searching...
No Matches
uinput.cpp
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "uinput.h"
18
19#include <QFile>
20#include <QDebug>
21#include <QDateTime>
22
23#include <unistd.h>
24#include <time.h>
25
26UInput::UInput(QObject *parent) :
27 QObject(parent)
28{
29 m_devName = QByteArrayLiteral("lomiri-simulated-mouse");
30 m_uinput.setFileName(QStringLiteral("/dev/uinput"));
31
32 memset(&m_uinput_mouse_dev, 0, sizeof(m_uinput_mouse_dev));
33 m_uinput_mouse_dev.id.bustype = BUS_USB;
34 m_uinput_mouse_dev.id.version = 1;
35 strncpy(m_uinput_mouse_dev.name, m_devName.constData(), m_devName.length());
36}
37
38UInput::~UInput()
39{
40 if (m_mouseCreated) {
41 removeMouse();
42 }
43}
44
45void UInput::createMouse()
46{
47 if (m_mouseCreated) {
48 qDebug() << "Already have a virtual device. Not creating another one.";
49 return;
50 }
51
52 if (!m_uinput.isOpen() && !m_uinput.open(QFile::WriteOnly)) {
53 return;
54 }
55
56 ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_REL);
57 ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_X);
58 ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_Y);
59 ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_HWHEEL);
60 ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_WHEEL);
61
62 ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_KEY);
63 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_MOUSE);
64 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_LEFT);
65 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_MIDDLE);
66 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_RIGHT);
67 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_FORWARD);
68 ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_BACK);
69
70 ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_SYN);
71
72 int len = write(m_uinput.handle(), &m_uinput_mouse_dev, sizeof(m_uinput_mouse_dev));
73 if (len <= 0) {
74 qWarning() << "Failed to write to uinput. Cannot create virtual uinput mouse.";
75 return;
76 }
77
78 int err = ioctl(m_uinput.handle(), UI_DEV_CREATE);
79 if (err != 0) {
80 qWarning() << "Cannot create virtual uinput device. Create ioctl failed:" << err;
81 return;
82 }
83 m_mouseCreated = true;
84 qDebug() << "Virtual uinput mouse device created.";
85}
86
87void UInput::removeMouse()
88{
89 if (!m_mouseCreated) {
90 return;
91 }
92
93 if (!m_uinput.isOpen() && !m_uinput.open(QFile::WriteOnly)) {
94 qWarning() << "cannot open uinput... ";
95 return;
96 }
97
98 int err = ioctl(m_uinput.handle(), UI_DEV_DESTROY);
99 if (err != 0) {
100 qWarning() << "Failed to destroy virtual uinput device. Destroy ioctl failed:" << err;
101 } else {
102 qDebug() << "Virtual uinput mouse device removed.";
103 }
104 m_uinput.close();
105 m_mouseCreated = false;
106}
107
108void UInput::moveMouse(int dx, int dy)
109{
110 struct input_event event;
111 struct timespec time;
112 memset(&event, 0, sizeof(event));
113 clock_gettime(CLOCK_MONOTONIC, &time);
114 event.input_event_sec = time.tv_sec;
115 event.input_event_usec = time.tv_nsec / 1000;
116 event.type = EV_REL;
117 event.code = REL_X;
118 event.value = dx;
119 write(m_uinput.handle(), &event, sizeof(event));
120
121 event.code = REL_Y;
122 event.value = dy;
123 write(m_uinput.handle(), &event, sizeof(event));
124
125 event.type = EV_SYN;
126 event.code = SYN_REPORT;
127 event.value = 0;
128 write(m_uinput.handle(), &event, sizeof(event));
129}
130
131void UInput::pressMouse(Button button)
132{
133 injectMouse(button, 1);
134}
135
136void UInput::releaseMouse(Button button)
137{
138 injectMouse(button, 0);
139}
140
141void UInput::scrollMouse(int dh, int dv)
142{
143 struct input_event event;
144 struct timespec time;
145 memset(&event, 0, sizeof(event));
146 clock_gettime(CLOCK_MONOTONIC, &time);
147 event.input_event_sec = time.tv_sec;
148 event.input_event_usec = time.tv_nsec / 1000;
149 event.type = EV_REL;
150 event.code = REL_HWHEEL;
151 event.value = dh;
152 write(m_uinput.handle(), &event, sizeof(event));
153
154 event.code = REL_WHEEL;
155 event.value = dv;
156 write(m_uinput.handle(), &event, sizeof(event));
157
158 event.type = EV_SYN;
159 event.code = SYN_REPORT;
160 event.value = 0;
161 write(m_uinput.handle(), &event, sizeof(event));
162}
163
164void UInput::injectMouse(Button button, int down)
165{
166 struct input_event event;
167 struct timespec time;
168 memset(&event, 0, sizeof(event));
169 clock_gettime(CLOCK_MONOTONIC, &time);
170 event.input_event_sec = time.tv_sec;
171 event.input_event_usec = time.tv_nsec / 1000;
172 event.type = EV_KEY;
173 switch (button) {
174 case ButtonLeft:
175 event.code = BTN_LEFT;
176 break;
177 case ButtonRight:
178 event.code = BTN_RIGHT;
179 break;
180 case ButtonMiddle:
181 event.code = BTN_MIDDLE;
182 break;
183 }
184 event.value = down;
185 write(m_uinput.handle(), &event, sizeof(event));
186
187 event.type = EV_SYN;
188 event.code = SYN_REPORT;
189 event.value = 0;
190 write(m_uinput.handle(), &event, sizeof(event));
191}