/*
* Copyright (C) 2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "uinput.h"
#include
#include
#include
#include
#include
UInput::UInput(QObject *parent) :
QObject(parent)
{
m_devName = QByteArrayLiteral("unity8-simulated-mouse");
m_uinput.setFileName(QStringLiteral("/dev/uinput"));
memset(&m_uinput_mouse_dev, 0, sizeof(m_uinput_mouse_dev));
m_uinput_mouse_dev.id.bustype = BUS_USB;
m_uinput_mouse_dev.id.version = 1;
strncpy(m_uinput_mouse_dev.name, m_devName.constData(), m_devName.length());
}
UInput::~UInput()
{
if (m_mouseCreated) {
removeMouse();
}
}
void UInput::createMouse()
{
if (m_mouseCreated) {
qDebug() << "Already have a virtual device. Not creating another one.";
return;
}
if (!m_uinput.isOpen() && !m_uinput.open(QFile::WriteOnly)) {
return;
}
ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_REL);
ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_X);
ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_Y);
ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_HWHEEL);
ioctl(m_uinput.handle(), UI_SET_RELBIT, REL_WHEEL);
ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_KEY);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_MOUSE);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_LEFT);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_MIDDLE);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_RIGHT);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_FORWARD);
ioctl(m_uinput.handle(), UI_SET_KEYBIT, BTN_BACK);
ioctl(m_uinput.handle(), UI_SET_EVBIT, EV_SYN);
int len = write(m_uinput.handle(), &m_uinput_mouse_dev, sizeof(m_uinput_mouse_dev));
if (len <= 0) {
qWarning() << "Failed to write to uinput. Cannot create virtual uinput mouse.";
return;
}
int err = ioctl(m_uinput.handle(), UI_DEV_CREATE);
if (err != 0) {
qWarning() << "Cannot create virtual uinput device. Create ioctl failed:" << err;
return;
}
m_mouseCreated = true;
qDebug() << "Virtual uinput mouse device created.";
}
void UInput::removeMouse()
{
if (!m_mouseCreated) {
return;
}
if (!m_uinput.isOpen() && !m_uinput.open(QFile::WriteOnly)) {
qWarning() << "cannot open uinput... ";
return;
}
int err = ioctl(m_uinput.handle(), UI_DEV_DESTROY);
if (err != 0) {
qWarning() << "Failed to destroy virtual uinput device. Destroy ioctl failed:" << err;
} else {
qDebug() << "Virtual uinput mouse device removed.";
}
m_uinput.close();
m_mouseCreated = false;
}
void UInput::moveMouse(int dx, int dy)
{
struct input_event event;
memset(&event, 0, sizeof(event));
clock_gettime(CLOCK_MONOTONIC, (timespec*)&event.time);
event.type = EV_REL;
event.code = REL_X;
event.value = dx;
write(m_uinput.handle(), &event, sizeof(event));
event.code = REL_Y;
event.value = dy;
write(m_uinput.handle(), &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(m_uinput.handle(), &event, sizeof(event));
}
void UInput::pressMouse(Button button)
{
injectMouse(button, 1);
}
void UInput::releaseMouse(Button button)
{
injectMouse(button, 0);
}
void UInput::scrollMouse(int dh, int dv)
{
struct input_event event;
memset(&event, 0, sizeof(event));
clock_gettime(CLOCK_MONOTONIC, (timespec*)&event.time);
event.type = EV_REL;
event.code = REL_HWHEEL;
event.value = dh;
write(m_uinput.handle(), &event, sizeof(event));
event.code = REL_WHEEL;
event.value = dv;
write(m_uinput.handle(), &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(m_uinput.handle(), &event, sizeof(event));
}
void UInput::injectMouse(Button button, int down)
{
struct input_event event;
memset(&event, 0, sizeof(event));
clock_gettime(CLOCK_MONOTONIC, (timespec*)&event.time);
event.type = EV_KEY;
switch (button) {
case ButtonLeft:
event.code = BTN_LEFT;
break;
case ButtonRight:
event.code = BTN_RIGHT;
break;
case ButtonMiddle:
event.code = BTN_MIDDLE;
break;
}
event.value = down;
write(m_uinput.handle(), &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(m_uinput.handle(), &event, sizeof(event));
}