mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-01 21:56:43 +08:00
Basically, the implementation uses the API described in the kernel documentation. It listens for new events that come from the device. It also supports joystick hotplugging. * https://www.kernel.org/doc/Documentation/input/joystick-api.txt
216 lines
6.7 KiB
C++
216 lines
6.7 KiB
C++
/* Copyright (C) 2013 VATSIM Community / contributors
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "keyboard_linux.h"
|
|
#include "keymapping_linux.h"
|
|
#include <QDebug>
|
|
#include <QFileSystemWatcher>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QSocketNotifier>
|
|
#include <linux/input.h>
|
|
#include <fcntl.h>
|
|
|
|
using namespace BlackMisc::Hardware;
|
|
|
|
namespace BlackInput
|
|
{
|
|
CKeyboardLinux::CKeyboardLinux(QObject *parent) :
|
|
IKeyboard(parent),
|
|
m_ignoreNextKey(false),
|
|
m_mode(Mode_Nominal)
|
|
{
|
|
}
|
|
|
|
CKeyboardLinux::~CKeyboardLinux()
|
|
{
|
|
}
|
|
|
|
bool CKeyboardLinux::init()
|
|
{
|
|
QString dir = QLatin1String("/dev/input");
|
|
m_devInputWatcher = new QFileSystemWatcher(QStringList(dir), this);
|
|
connect(m_devInputWatcher, &QFileSystemWatcher::directoryChanged, this, &CKeyboardLinux::deviceDirectoryChanged);
|
|
deviceDirectoryChanged(dir);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CKeyboardLinux::setKeysToMonitor(const CKeyboardKeyList &keylist)
|
|
{
|
|
m_listMonitoredKeys = keylist;
|
|
}
|
|
|
|
void CKeyboardLinux::startCapture(bool ignoreNextKey)
|
|
{
|
|
m_mode = Mode_Capture;
|
|
m_ignoreNextKey = ignoreNextKey;
|
|
m_pressedKey.setKeyObject(CKeyboardKey());
|
|
}
|
|
|
|
void CKeyboardLinux::triggerKey(const CKeyboardKey &key, bool isPressed)
|
|
{
|
|
if(!isPressed) emit keyUp(key);
|
|
else emit keyDown(key);
|
|
}
|
|
|
|
void CKeyboardLinux::deviceDirectoryChanged(const QString &dir)
|
|
{
|
|
QDir eventFiles(dir, QLatin1String("event*"), 0, QDir::System);
|
|
|
|
foreach (QFileInfo fileInfo, eventFiles.entryInfoList())
|
|
{
|
|
QString path = fileInfo.absoluteFilePath();
|
|
if (!m_hashInputDevices.contains(path))
|
|
addRawInputDevice(path);
|
|
}
|
|
}
|
|
|
|
void CKeyboardLinux::inputReadyRead(int)
|
|
{
|
|
struct input_event eventInput;
|
|
|
|
QFile *fileInput=qobject_cast<QFile *>(sender()->parent());
|
|
if (!fileInput)
|
|
return;
|
|
|
|
bool found = false;
|
|
|
|
while (fileInput->read(reinterpret_cast<char *>(&eventInput), sizeof(eventInput)) == sizeof(eventInput))
|
|
{
|
|
found = true;
|
|
if (eventInput.type != EV_KEY)
|
|
continue;
|
|
bool isPressed = false;
|
|
switch (eventInput.value)
|
|
{
|
|
case 0:
|
|
isPressed = false;
|
|
break;
|
|
case 1:
|
|
isPressed = true;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
int keyCode = eventInput.code;
|
|
keyEvent(keyCode, isPressed);
|
|
}
|
|
|
|
if (!found) {
|
|
int fd = fileInput->handle();
|
|
int version = 0;
|
|
if ((ioctl(fd, EVIOCGVERSION, &version) < 0) || (((version >> 16) & 0xFF) < 1)) {
|
|
qWarning("CKeyboardLinux: Removing dead input device %s", qPrintable(fileInput->fileName()));
|
|
m_hashInputDevices.remove(fileInput->fileName());
|
|
fileInput->deleteLater();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CKeyboardLinux::sendCaptureNotification(const CKeyboardKey &key, bool isFinished)
|
|
{
|
|
if (isFinished)
|
|
emit keySelectionFinished(key);
|
|
else
|
|
emit keySelectionChanged(key);
|
|
}
|
|
|
|
#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
|
|
|
|
void CKeyboardLinux::addRawInputDevice(const QString &filePath)
|
|
{
|
|
QFile *inputFile = new QFile(filePath, this);
|
|
if (inputFile->open(QIODevice::ReadOnly))
|
|
{
|
|
int fd = inputFile->handle();
|
|
int version;
|
|
char name[256];
|
|
quint8 events[EV_MAX/8 + 1];
|
|
memset(events, 0, sizeof(events));
|
|
|
|
if ((ioctl(fd, EVIOCGVERSION, &version) >= 0) && (ioctl(fd, EVIOCGNAME(sizeof(name)), name)>=0) && (ioctl(fd, EVIOCGBIT(0,sizeof(events)), &events) >= 0) && test_bit(EV_KEY, events) && !test_bit(EV_SYN, events) && (((version >> 16) & 0xFF) > 0)) {
|
|
name[255]=0;
|
|
qDebug() << "CKeyboardLinux: " << qPrintable(inputFile->fileName()) << " " << name;
|
|
// Is it grabbed by someone else?
|
|
if ((ioctl(fd, EVIOCGRAB, 1) < 0)) {
|
|
qWarning("CKeyboardLinux: Device exclusively grabbed by someone else (X11 using exclusive-mode evdev?)");
|
|
inputFile->deleteLater();
|
|
} else {
|
|
ioctl(fd, EVIOCGRAB, 0);
|
|
|
|
fcntl(inputFile->handle(), F_SETFL, O_NONBLOCK);
|
|
connect(new QSocketNotifier(inputFile->handle(), QSocketNotifier::Read, inputFile), SIGNAL(activated(int)), this, SLOT(inputReadyRead(int)));
|
|
|
|
m_hashInputDevices.insert(inputFile->fileName(), inputFile);
|
|
}
|
|
}
|
|
else
|
|
inputFile->deleteLater();
|
|
}
|
|
else
|
|
inputFile->deleteLater();
|
|
}
|
|
|
|
void CKeyboardLinux::keyEvent(int virtualKeyCode, bool isPressed)
|
|
{
|
|
if (CKeyMappingLinux::isMouseButton(virtualKeyCode))
|
|
return;
|
|
|
|
BlackMisc::Hardware::CKeyboardKey lastPressedKey = m_pressedKey;
|
|
if (m_ignoreNextKey)
|
|
{
|
|
m_ignoreNextKey = false;
|
|
return;
|
|
}
|
|
|
|
bool isFinished = false;
|
|
if (isPressed)
|
|
{
|
|
if (CKeyMappingLinux::isModifier(virtualKeyCode))
|
|
m_pressedKey.addModifier(CKeyMappingLinux::convertToModifier(virtualKeyCode));
|
|
else
|
|
{
|
|
m_pressedKey.setKey(CKeyMappingLinux::convertToKey(virtualKeyCode));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CKeyMappingLinux::isModifier(virtualKeyCode))
|
|
m_pressedKey.removeModifier(CKeyMappingLinux::convertToModifier(virtualKeyCode));
|
|
else
|
|
{
|
|
m_pressedKey.setKey(Qt::Key_unknown);
|
|
}
|
|
|
|
isFinished = true;
|
|
}
|
|
|
|
if (lastPressedKey == m_pressedKey)
|
|
return;
|
|
|
|
#ifdef DEBUG_KEYBOARD
|
|
qDebug() << "Virtual key: " << virtualKeyCode;
|
|
#endif
|
|
if (m_mode == Mode_Capture)
|
|
{
|
|
if (isFinished)
|
|
{
|
|
sendCaptureNotification(lastPressedKey, true);
|
|
m_mode = Mode_Nominal;
|
|
}
|
|
else
|
|
{
|
|
sendCaptureNotification(m_pressedKey, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_listMonitoredKeys.contains(lastPressedKey)) emit keyUp(lastPressedKey);
|
|
if (m_listMonitoredKeys.contains(m_pressedKey)) emit keyDown(m_pressedKey);
|
|
}
|
|
}
|
|
}
|