mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-02 15:15:50 +08:00
refs #265 Linux raw input handling
This commit is contained in:
@@ -4,7 +4,14 @@
|
||||
* 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;
|
||||
|
||||
@@ -12,6 +19,7 @@ namespace BlackInput
|
||||
{
|
||||
CKeyboardLinux::CKeyboardLinux(QObject *parent) :
|
||||
IKeyboard(parent),
|
||||
m_ignoreNextKey(false),
|
||||
m_mode(Mode_Nominal)
|
||||
{
|
||||
}
|
||||
@@ -22,6 +30,11 @@ namespace BlackInput
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -63,6 +76,10 @@ namespace BlackInput
|
||||
if (receiver == nullptr)
|
||||
return handle;
|
||||
|
||||
// FIXME. Remove virtual key code, because the one we receive from Qt is different to the linux native code.
|
||||
// If we don't remove it, the hash lookup fails later.
|
||||
key.setNativeVirtualKey(0);
|
||||
|
||||
handle.m_key = key;
|
||||
handle.m_receiver = receiver;
|
||||
handle.function = function;
|
||||
@@ -87,6 +104,60 @@ namespace BlackInput
|
||||
m_registeredFunctions.clear();
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -107,4 +178,101 @@ namespace BlackInput
|
||||
functionHandle.function(isPressed);
|
||||
}
|
||||
}
|
||||
|
||||
#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) && (((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));
|
||||
m_pressedKey.setNativeVirtualKey(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CKeyMappingLinux::isModifier(virtualKeyCode))
|
||||
m_pressedKey.removeModifier(CKeyMappingLinux::convertToModifier(virtualKeyCode));
|
||||
else
|
||||
{
|
||||
m_pressedKey.setKey(Qt::Key_unknown);
|
||||
m_pressedKey.setNativeVirtualKey(0);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
callFunctionsBy(lastPressedKey, false);
|
||||
callFunctionsBy(m_pressedKey, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user