From 30417ccf20b5ed04ea0ff3f2a72516257fd0ed6d Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Sat, 20 Jan 2024 22:46:24 -0700 Subject: [PATCH] Start getting input handling working --- applications/display-server/dbusinterface.cpp | 20 +++- applications/display-server/dbusinterface.h | 3 + .../display-server/display-server.pro | 8 +- applications/display-server/evdevdevice.cpp | 47 ++++++++ .../{keyboarddevice.h => evdevdevice.h} | 9 +- applications/display-server/evdevhandler.cpp | 108 ++++++++++++++++++ applications/display-server/evdevhandler.h | 29 +++++ .../display-server/keyboarddevice.cpp | 66 ----------- .../display-server/keyboardhandler.cpp | 76 ------------ applications/display-server/keyboardhandler.h | 29 ----- applications/display-server/surface.cpp | 14 ++- applications/display-server/surface.h | 3 + .../system-service/keyboarddevice.cpp | 22 ++-- applications/system-service/keyboarddevice.h | 6 +- .../system-service/keyboardhandler.cpp | 26 ++--- applications/system-service/keyboardhandler.h | 12 +- interfaces/blight.xml | 3 + shared/libblight/connection.cpp | 23 +++- shared/libblight/connection.h | 5 +- shared/libblight/libblight.cpp | 39 ++++++- shared/libblight/libblight.h | 1 + shared/libblight_client/main.cpp | 40 +++++-- shared/liboxide/devicesettings.cpp | 33 ++++-- shared/liboxide/devicesettings.h | 5 + 24 files changed, 387 insertions(+), 240 deletions(-) create mode 100644 applications/display-server/evdevdevice.cpp rename applications/display-server/{keyboarddevice.h => evdevdevice.h} (73%) create mode 100644 applications/display-server/evdevhandler.cpp create mode 100644 applications/display-server/evdevhandler.h delete mode 100644 applications/display-server/keyboarddevice.cpp delete mode 100644 applications/display-server/keyboardhandler.cpp delete mode 100644 applications/display-server/keyboardhandler.h diff --git a/applications/display-server/dbusinterface.cpp b/applications/display-server/dbusinterface.cpp index 54db1473c..e6d6aac79 100644 --- a/applications/display-server/dbusinterface.cpp +++ b/applications/display-server/dbusinterface.cpp @@ -1,4 +1,6 @@ #include "dbusinterface.h" +#include "evdevhandler.h" + #include #include #include @@ -11,7 +13,8 @@ DbusInterface* DbusInterface::singleton = nullptr; DbusInterface::DbusInterface(QObject* parent, QQmlApplicationEngine* engine) : QObject(parent), - engine(engine) + engine(engine), + m_focused(nullptr) { if(singleton != nullptr){ qFatal("DbusInterface singleton already exists"); @@ -142,7 +145,7 @@ QDBusUnixFileDescriptor DbusInterface::openInput(QDBusMessage message){ return QDBusUnixFileDescriptor(); } O_INFO("Open input for: " << connection->pid()); - return QDBusUnixFileDescriptor(connection.inputSocketDescriptor()); + return QDBusUnixFileDescriptor(connection->inputSocketDescriptor()); } QString DbusInterface::addSurface( @@ -215,6 +218,19 @@ QDBusUnixFileDescriptor DbusInterface::getSurface(QString identifier, QDBusMessa return QDBusUnixFileDescriptor(surface->fd()); } +void DbusInterface::setFocused(Connection* connection){ + m_focused = connection; + if(m_focused == nullptr){ + evdevHandler->setInputFd(-1); + O_DEBUG("No surface has focus"); + }else{ + evdevHandler->setInputFd(connection->inputSocketDescriptor()); + O_DEBUG(connection->id() << " has focus"); + } +} + +Connection* DbusInterface::focused(){ return m_focused; } + void DbusInterface::serviceOwnerChanged(const QString& name, const QString& oldOwner, const QString& newOwner){ Q_UNUSED(oldOwner); if(!newOwner.isEmpty()){ diff --git a/applications/display-server/dbusinterface.h b/applications/display-server/dbusinterface.h index f140684ab..7b9ccd80e 100644 --- a/applications/display-server/dbusinterface.h +++ b/applications/display-server/dbusinterface.h @@ -43,6 +43,8 @@ public slots: ); void repaint(QString identifier, QDBusMessage message); QDBusUnixFileDescriptor getSurface(QString identifier, QDBusMessage message); + void setFocused(Connection* connection); + Connection* focused(); private slots: void serviceOwnerChanged(const QString& name, const QString& oldOwner, const QString& newOwner); @@ -50,6 +52,7 @@ private slots: private: QQmlApplicationEngine* engine; QList connections; + Connection* m_focused; QTimer connectionTimer; Connection* getConnection(QDBusMessage message); diff --git a/applications/display-server/display-server.pro b/applications/display-server/display-server.pro index e218371fd..9796e5811 100644 --- a/applications/display-server/display-server.pro +++ b/applications/display-server/display-server.pro @@ -17,8 +17,8 @@ QMAKE_CFLAGS += -std=c99 SOURCES += \ connection.cpp \ dbusinterface.cpp \ - keyboarddevice.cpp \ - keyboardhandler.cpp \ + evdevdevice.cpp \ + evdevhandler.cpp \ main.cpp \ surface.cpp \ surfacewidget.cpp @@ -36,8 +36,8 @@ INSTALLS += target HEADERS += \ connection.h \ dbusinterface.h \ - keyboarddevice.h \ - keyboardhandler.h \ + evdevdevice.h \ + evdevhandler.h \ surface.h \ surfacewidget.h diff --git a/applications/display-server/evdevdevice.cpp b/applications/display-server/evdevdevice.cpp new file mode 100644 index 000000000..54adf7d3f --- /dev/null +++ b/applications/display-server/evdevdevice.cpp @@ -0,0 +1,47 @@ +#include "evdevdevice.h" +#include "evdevhandler.h" + +#include + +EvDevDevice::EvDevDevice(QThread* handler, event_device device) +: QObject(handler), + device(device), + sys("/sys/class/input/" + devName() + "/device/") +{ + _name = sys.strProperty("name").c_str(); + notifier = new QSocketNotifier(device.fd, QSocketNotifier::Read, this); + connect(notifier, &QSocketNotifier::activated, this, &EvDevDevice::readEvents); + notifier->setEnabled(true); +} + +EvDevDevice::~EvDevDevice(){ unlock(); } + +QString EvDevDevice::devName(){ return QFileInfo(device.device.c_str()).baseName(); } + +QString EvDevDevice::name(){ return _name; } + +QString EvDevDevice::path(){ return device.device.c_str(); } + +QString EvDevDevice::id(){ + return QString("%1:%2").arg( + sys.strProperty("id/vendor").c_str(), + sys.strProperty("id/product").c_str() + ); +} + +bool EvDevDevice::exists(){ return QFile::exists(path()); } + +void EvDevDevice::lock(){ exists() && device.lock(); } + +void EvDevDevice::unlock(){ exists() && device.locked && device.unlock(); } + + +void EvDevDevice::readEvents(){ + notifier->setEnabled(false); + auto handler = static_cast(parent()); + input_event event; + while(::read(device.fd, &event, sizeof(input_event)) > 0){ + handler->writeEvent(&event); + } + notifier->setEnabled(true); +} diff --git a/applications/display-server/keyboarddevice.h b/applications/display-server/evdevdevice.h similarity index 73% rename from applications/display-server/keyboarddevice.h rename to applications/display-server/evdevdevice.h index 165715365..0eb5c54d9 100644 --- a/applications/display-server/keyboarddevice.h +++ b/applications/display-server/evdevdevice.h @@ -7,17 +7,19 @@ using namespace Oxide; -class KeyboardDevice : public QObject{ +class EvDevDevice : public QObject{ Q_OBJECT public: - KeyboardDevice(QThread* handler, event_device device); - ~KeyboardDevice(); + EvDevDevice(QThread* handler, event_device device); + ~EvDevDevice(); QString devName(); QString name(); QString path(); QString id(); bool exists(); + void lock(); + void unlock(); public slots: void readEvents(); @@ -27,5 +29,4 @@ public slots: SysObject sys; QString _name; QSocketNotifier* notifier; - QMap pressed; }; diff --git a/applications/display-server/evdevhandler.cpp b/applications/display-server/evdevhandler.cpp new file mode 100644 index 000000000..862b36188 --- /dev/null +++ b/applications/display-server/evdevhandler.cpp @@ -0,0 +1,108 @@ +#include "evdevhandler.h" + +#include +#include +#include +#include +#include +#include +#include + +EvDevHandler* EvDevHandler::init(){ + static EvDevHandler* instance; + if(instance != nullptr){ + return instance; + } + instance = new EvDevHandler(); + instance->moveToThread(instance); + instance->start(); + return instance; +} + +EvDevHandler::EvDevHandler() +: QThread(), + m_fd(-1) +{ + setObjectName("EvDevHandler"); + reloadDevices(); + deviceSettings.onKeyboardAttachedChanged([this]{ reloadDevices(); }); +} + +EvDevHandler::~EvDevHandler(){} + +void EvDevHandler::writeEvent(int type, int code, int val){ + input_event ie; + ie.type = type; + ie.code = code; + ie.value = val; + // timestamp values below are ignored + ie.time.tv_sec = 0; + ie.time.tv_usec = 0; + writeEvent(&ie); +} + +void EvDevHandler::writeEvent(input_event* ie){ + O_DEBUG("writeEvent(" << ie->type << ie->code << ie->value << ")"); + if(m_fd < 0){ + return; + } + int res = -1; + while(res < 0){ + res = ::send(m_fd, ie, sizeof(ie), MSG_EOR); + if(res > -1){ + break; + } + if(errno == EAGAIN || errno == EINTR){ + timespec remaining; + timespec requested{ + .tv_sec = 0, + .tv_nsec = 5000 + }; + nanosleep(&requested, &remaining); + continue; + } + break; + } + if(res < 0){ + O_WARNING("Failed to write input event: " << std::strerror(errno)); + }else if(res != sizeof(ie)){ + O_WARNING("Failed to write input event: Size mismatch!"); + } +} + +void EvDevHandler::setInputFd(int fd){ m_fd = fd; } + + +bool EvDevHandler::hasDevice(event_device device){ + for(auto input : qAsConst(devices)){ + if(device.device.c_str() == input->path()){ + return true; + } + } + return false; +} + +void EvDevHandler::reloadDevices(){ + O_DEBUG("Reloading keyboards"); + for(auto& device : deviceSettings.inputDevices()){ + if(device.device == deviceSettings.getButtonsDevicePath()){ + continue; + } + if(!hasDevice(device) && device.fd != -1){ + auto input = new EvDevDevice(this, device); + O_DEBUG(input->name() << "added"); + devices.append(input); + input->readEvents(); + } + } + QMutableListIterator i(devices); + while(i.hasNext()){ + EvDevDevice* device = i.next(); + if(device->exists()){ + continue; + } + O_DEBUG(device->name() << "removed"); + i.remove(); + delete device; + } +} diff --git a/applications/display-server/evdevhandler.h b/applications/display-server/evdevhandler.h new file mode 100644 index 000000000..b642ec0b0 --- /dev/null +++ b/applications/display-server/evdevhandler.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include "evdevdevice.h" + +using namespace Oxide; + +#define evdevHandler EvDevHandler::init() + +class EvDevHandler : public QThread{ + Q_OBJECT + +public: + static EvDevHandler* init(); + EvDevHandler(); + ~EvDevHandler(); + void writeEvent(int type, int code, int val); + void writeEvent(input_event* ie); + void setInputFd(int fd); + +private: + QList devices; + bool hasDevice(event_device device); + void reloadDevices(); + int m_fd; +}; diff --git a/applications/display-server/keyboarddevice.cpp b/applications/display-server/keyboarddevice.cpp deleted file mode 100644 index 9398220ba..000000000 --- a/applications/display-server/keyboarddevice.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "keyboarddevice.h" -#include "keyboardhandler.h" - -#include - -KeyboardDevice::KeyboardDevice(QThread* handler, event_device device) -: QObject(handler), - device(device), - sys("/sys/class/input/" + devName() + "/device/") -{ - _name = sys.strProperty("name").c_str(); - device.lock(); - notifier = new QSocketNotifier(device.fd, QSocketNotifier::Read, this); - connect(notifier, &QSocketNotifier::activated, this, &KeyboardDevice::readEvents); - notifier->setEnabled(true); -} - -KeyboardDevice::~KeyboardDevice(){ - if(exists() && device.locked){ - device.unlock(); - } -} - -QString KeyboardDevice::devName(){ return QFileInfo(device.device.c_str()).baseName(); } - -QString KeyboardDevice::name(){ return _name; } - -QString KeyboardDevice::path(){ return device.device.c_str(); } - -QString KeyboardDevice::id(){ - return QString("%1:%2").arg( - sys.strProperty("id/vendor").c_str(), - sys.strProperty("id/product").c_str() - ); -} - -bool KeyboardDevice::exists(){ return QFile::exists(path()); } - - -void KeyboardDevice::readEvents(){ - notifier->setEnabled(false); - input_event event; - while(::read(device.fd, &event, sizeof(input_event)) > 0){ - switch(event.type){ - case EV_KEY: - pressed[event.code] = event.value; - break; - case EV_SYN: - switch(event.code){ - case SYN_DROPPED: - pressed.clear(); - break; - case SYN_REPORT: - auto handler = static_cast(parent()); - for(const auto& code : pressed.keys()){ - handler->writeEvent(EV_KEY, code, pressed[code]); - } - handler->writeEvent(EV_SYN, SYN_REPORT, 0); - pressed.clear(); - break; - } - break; - } - } - notifier->setEnabled(true); -} diff --git a/applications/display-server/keyboardhandler.cpp b/applications/display-server/keyboardhandler.cpp deleted file mode 100644 index b72dd60f2..000000000 --- a/applications/display-server/keyboardhandler.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "keyboardhandler.h" - -#include -#include -#include -#include -#include - -KeyboardHandler* KeyboardHandler::init(){ - static KeyboardHandler* instance; - if(instance != nullptr){ - return instance; - } - instance = new KeyboardHandler(); - instance->moveToThread(instance); - instance->start(); - return instance; -} - -KeyboardHandler::KeyboardHandler(){ - setObjectName("BlightVirtKeyboard"); - reloadDevices(); - deviceSettings.onKeyboardAttachedChanged([this]{ reloadDevices(); }); -} - -KeyboardHandler::~KeyboardHandler(){} - -void KeyboardHandler::writeEvent(int type, int code, int val){ - input_event ie; - ie.type = type; - ie.code = code; - ie.value = val; - // timestamp values below are ignored - ie.time.tv_sec = 0; - ie.time.tv_usec = 0; - // TODO call connection->inputEvent(ie); -} - -void KeyboardHandler::keyEvent(int code, int value){ - writeEvent(EV_KEY, code, value); - writeEvent(EV_SYN, SYN_REPORT, 0); -} - -bool KeyboardHandler::hasDevice(event_device device){ - for(auto keyboard : qAsConst(devices)){ - if(device.device.c_str() == keyboard->path()){ - return true; - } - } - return false; -} - -void KeyboardHandler::reloadDevices(){ - O_DEBUG("Reloading keyboards"); - for(auto& device : deviceSettings.keyboards()){ - if(device.device == deviceSettings.getButtonsDevicePath()){ - continue; - } - if(!hasDevice(device) && device.fd != -1){ - auto keyboard = new KeyboardDevice(this, device); - O_DEBUG(keyboard->name() << "added"); - devices.append(keyboard); - keyboard->readEvents(); - } - } - QMutableListIterator i(devices); - while(i.hasNext()){ - KeyboardDevice* device = i.next(); - if(device->exists()){ - continue; - } - O_DEBUG(device->name() << "removed"); - i.remove(); - delete device; - } -} diff --git a/applications/display-server/keyboardhandler.h b/applications/display-server/keyboardhandler.h deleted file mode 100644 index e619b3a2f..000000000 --- a/applications/display-server/keyboardhandler.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "keyboarddevice.h" - -using namespace Oxide; - -#define keyboardHandler KeyboardHandler::init() - -class KeyboardHandler : public QThread{ - Q_OBJECT - -public: - static KeyboardHandler* init(); - KeyboardHandler(); - ~KeyboardHandler(); - void writeEvent(int type, int code, int val); - -private slots: - void keyEvent(int code, int value); - -private: - QList devices; - bool hasDevice(event_device device); - void reloadDevices(); -}; diff --git a/applications/display-server/surface.cpp b/applications/display-server/surface.cpp index 249acf4a6..de745b251 100644 --- a/applications/display-server/surface.cpp +++ b/applications/display-server/surface.cpp @@ -25,7 +25,7 @@ Surface::Surface(QObject* parent, int fd, QRect geometry, int stride, QImage::Fo stride, format ); - auto interface = dynamic_cast(parent->parent()); + auto interface = dynamic_cast(connection->parent()); component = dynamic_cast(interface->loadComponent( "qrc:/Surface.qml", id(), @@ -35,6 +35,7 @@ Surface::Surface(QObject* parent, int fd, QRect geometry, int stride, QImage::Fo {"width", geometry.width()}, {"height", geometry.height()}, {"visible", true}, + {"focus", true} } )); if(component == nullptr){ @@ -48,7 +49,10 @@ Surface::Surface(QObject* parent, int fd, QRect geometry, int stride, QImage::Fo component = nullptr; return; } + widget->forceActiveFocus(); connect(this, &Surface::update, widget, &SurfaceWidget::update); + connect(widget, &SurfaceWidget::activeFocusChanged, this, &Surface::activeFocusChanged); + interface->setFocused(connection); } Surface::~Surface(){ @@ -87,4 +91,12 @@ void Surface::move(int x, int y){ component->setY(y); } +void Surface::activeFocusChanged(bool focus){ + if(focus){ + auto connection = dynamic_cast(parent()); + auto interface = dynamic_cast(connection->parent()); + interface->setFocused(connection); + } +} + #include "moc_surface.cpp" diff --git a/applications/display-server/surface.h b/applications/display-server/surface.h index 8f0840050..4a3773145 100644 --- a/applications/display-server/surface.h +++ b/applications/display-server/surface.h @@ -30,6 +30,9 @@ class Surface : public QObject { signals: void update(const QRect& geometry); +private slots: + void activeFocusChanged(bool focus); + private: QRect m_geometry; int m_stride; diff --git a/applications/system-service/keyboarddevice.cpp b/applications/system-service/keyboarddevice.cpp index f77fe671b..e2a640bc9 100644 --- a/applications/system-service/keyboarddevice.cpp +++ b/applications/system-service/keyboarddevice.cpp @@ -2,7 +2,7 @@ #include "buttonhandler.h" #include "keyboardhandler.h" -KeyboardDevice::KeyboardDevice(QThread* handler, event_device device) +EvDevDevice::EvDevDevice(QThread* handler, event_device device) : QObject(handler), device(device), sys("/sys/class/input/" + devName() + "/device/") @@ -10,38 +10,38 @@ KeyboardDevice::KeyboardDevice(QThread* handler, event_device device) _name = sys.strProperty("name").c_str(); device.lock(); notifier = new QSocketNotifier(device.fd, QSocketNotifier::Read, this); - connect(notifier, &QSocketNotifier::activated, this, &KeyboardDevice::readEvents); + connect(notifier, &QSocketNotifier::activated, this, &EvDevDevice::readEvents); notifier->setEnabled(true); } -KeyboardDevice::~KeyboardDevice(){ +EvDevDevice::~EvDevDevice(){ if(exists() && device.locked){ device.unlock(); } } -QString KeyboardDevice::devName(){ return QFileInfo(device.device.c_str()).baseName(); } +QString EvDevDevice::devName(){ return QFileInfo(device.device.c_str()).baseName(); } -QString KeyboardDevice::name(){ return _name; } +QString EvDevDevice::name(){ return _name; } -QString KeyboardDevice::path(){ return device.device.c_str(); } +QString EvDevDevice::path(){ return device.device.c_str(); } -QString KeyboardDevice::id(){ +QString EvDevDevice::id(){ return QString("%1:%2") .arg(sys.strProperty("id/vendor").c_str()) .arg(sys.strProperty("id/product").c_str()); } -bool KeyboardDevice::exists(){ return QFile::exists(path()); } +bool EvDevDevice::exists(){ return QFile::exists(path()); } -void KeyboardDevice::flood(){ +void EvDevDevice::flood(){ if(device.fd == -1 || !device.locked){ return; } ::write(device.fd, buttonHandler->event_flood(), EVENT_FLOOD_SIZE); } -void KeyboardDevice::readEvents(){ +void EvDevDevice::readEvents(){ notifier->setEnabled(false); input_event event; while(::read(device.fd, &event, sizeof(input_event)) > 0){ @@ -55,7 +55,7 @@ void KeyboardDevice::readEvents(){ pressed.clear(); break; case SYN_REPORT: - auto handler = static_cast(parent()); + auto handler = static_cast(parent()); for(auto code : pressed.keys()){ handler->writeEvent(EV_KEY, code, pressed[code]); } diff --git a/applications/system-service/keyboarddevice.h b/applications/system-service/keyboarddevice.h index 986df9c64..ca315eb34 100644 --- a/applications/system-service/keyboarddevice.h +++ b/applications/system-service/keyboarddevice.h @@ -5,12 +5,12 @@ using namespace Oxide; -class KeyboardDevice : public QObject{ +class EvDevDevice : public QObject{ Q_OBJECT public: - KeyboardDevice(QThread* handler, event_device device); - ~KeyboardDevice(); + EvDevDevice(QThread* handler, event_device device); + ~EvDevDevice(); QString devName(); QString name(); QString path(); diff --git a/applications/system-service/keyboardhandler.cpp b/applications/system-service/keyboardhandler.cpp index 5f25cc82a..fbd5edbdd 100644 --- a/applications/system-service/keyboardhandler.cpp +++ b/applications/system-service/keyboardhandler.cpp @@ -4,18 +4,18 @@ #include #include -KeyboardHandler* KeyboardHandler::init(){ - static KeyboardHandler* instance; +EvDevHandler* EvDevHandler::init(){ + static EvDevHandler* instance; if(instance != nullptr){ return instance; } - instance = new KeyboardHandler(); + instance = new EvDevHandler(); instance->moveToThread(instance); instance->start(); return instance; } -KeyboardHandler::KeyboardHandler(){ +EvDevHandler::EvDevHandler(){ setObjectName("OxideVirtKeyboard"); fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if(fd == -1){ @@ -611,14 +611,14 @@ KeyboardHandler::KeyboardHandler(){ deviceSettings.onKeyboardAttachedChanged([this]{ reloadDevices(); }); } -KeyboardHandler::~KeyboardHandler(){ +EvDevHandler::~EvDevHandler(){ if(fd != -1){ ioctl(fd, UI_DEV_DESTROY); close(fd); } } -void KeyboardHandler::flood(){ +void EvDevHandler::flood(){ qDebug() << "Flooding"; for(int i = 0; i < 512 * 8; i+=4){ writeEvent(EV_KEY, KEY_ROTATE_LOCK_TOGGLE, 1); @@ -628,7 +628,7 @@ void KeyboardHandler::flood(){ } } -void KeyboardHandler::writeEvent(int type, int code, int val){ +void EvDevHandler::writeEvent(int type, int code, int val){ input_event ie; ie.type = type; ie.code = code; @@ -639,12 +639,12 @@ void KeyboardHandler::writeEvent(int type, int code, int val){ ::write(fd, &ie, sizeof(input_event)); } -void KeyboardHandler::keyEvent(int code, int value){ +void EvDevHandler::keyEvent(int code, int value){ writeEvent(EV_KEY, code, value); writeEvent(EV_SYN, SYN_REPORT, 0); } -bool KeyboardHandler::hasDevice(event_device device){ +bool EvDevHandler::hasDevice(event_device device){ for(auto keyboard : devices){ if(device.device.c_str() == keyboard->path()){ return true; @@ -653,22 +653,22 @@ bool KeyboardHandler::hasDevice(event_device device){ return false; } -void KeyboardHandler::reloadDevices(){ +void EvDevHandler::reloadDevices(){ O_DEBUG("Reloading keyboards"); for(auto device : deviceSettings.keyboards()){ if(device.device == deviceSettings.getButtonsDevicePath()){ continue; } if(!hasDevice(device) && device.fd != -1){ - auto keyboard = new KeyboardDevice(this, device); + auto keyboard = new EvDevDevice(this, device); O_DEBUG(keyboard->name() << "added"); devices.append(keyboard); keyboard->readEvents(); } } - QMutableListIterator i(devices); + QMutableListIterator i(devices); while(i.hasNext()){ - KeyboardDevice* device = i.next(); + EvDevDevice* device = i.next(); if(device->exists()){ continue; } diff --git a/applications/system-service/keyboardhandler.h b/applications/system-service/keyboardhandler.h index e103100d8..199c0c9af 100644 --- a/applications/system-service/keyboardhandler.h +++ b/applications/system-service/keyboardhandler.h @@ -9,13 +9,13 @@ using namespace Oxide; #define keyboardHandler KeyboardHandler::init() -class KeyboardHandler : public QThread{ +class EvDevHandler : public QThread{ Q_OBJECT public: - static KeyboardHandler* init(); - KeyboardHandler(); - ~KeyboardHandler(); + static EvDevHandler* init(); + EvDevHandler(); + ~EvDevHandler(); void flood(); void writeEvent(int type, int code, int val); @@ -25,8 +25,8 @@ private slots: private: int fd; uinput_setup usetup; - - QList devices; + + QList devices; bool hasDevice(event_device device); void reloadDevices(); }; diff --git a/interfaces/blight.xml b/interfaces/blight.xml index 98de7d093..2a1b4559b 100644 --- a/interfaces/blight.xml +++ b/interfaces/blight.xml @@ -5,6 +5,9 @@ + + + diff --git a/shared/libblight/connection.cpp b/shared/libblight/connection.cpp index 983c5b221..5a453a271 100644 --- a/shared/libblight/connection.cpp +++ b/shared/libblight/connection.cpp @@ -55,6 +55,13 @@ namespace Blight{ { int flags = fcntl(fd, F_GETFD, NULL); fcntl(fd, F_SETFD, flags | O_NONBLOCK); + m_inputFd = Blight::open_input(); + if(m_inputFd < 0){ + std::cerr + << "Failed to open input stream:" + << std::strerror(errno) + << std::endl; + } } Connection::~Connection(){ @@ -71,6 +78,18 @@ namespace Blight{ mutex.unlock(); } + std::optional Connection::read_event(){ + if(m_inputFd < 0){ + return {}; + } + input_event ie; + auto res = ::recv(m_inputFd, &ie, sizeof(ie), 0); + if(res < 0){ + return {}; + } + return ie; + } + message_ptr_t Connection::read(){ return message_t::from_socket(m_fd); } maybe_ackid_ptr_t Connection::send(MessageType type, data_t data, size_t size){ @@ -353,10 +372,6 @@ namespace Blight{ return list_t::from_data(ack.value()->data.get()).identifiers(); } - int Connection::open_input(){ - - } - void Connection::run(Connection& connection){ std::cerr << "[BlightWorker] Starting" diff --git a/shared/libblight/connection.h b/shared/libblight/connection.h index 2685881d6..cc3bfbc10 100644 --- a/shared/libblight/connection.h +++ b/shared/libblight/connection.h @@ -2,6 +2,7 @@ #include "libblight_global.h" #include "types.h" +#include #include #include #include @@ -37,6 +38,7 @@ namespace Blight { ~Connection(); void onDisconnect(std::function callback); message_ptr_t read(); + std::optional read_event(); maybe_ackid_ptr_t send(MessageType type, data_t data, size_t size); void waitForMarker(unsigned int marker); maybe_ackid_ptr_t repaint( @@ -68,13 +70,14 @@ namespace Blight { std::vector buffers(); maybe_ackid_ptr_t remove(shared_buf_t buf); std::vector surfaces(); - int open_input(); std::mutex mutex; std::map acks; + private: std::map markers; int m_fd; + int m_inputFd; std::thread thread; std::atomic stop_requested; std::vector> disconnectCallbacks; diff --git a/shared/libblight/libblight.cpp b/shared/libblight/libblight.cpp index 3b2a1902c..767aafbaa 100644 --- a/shared/libblight/libblight.cpp +++ b/shared/libblight/libblight.cpp @@ -8,9 +8,9 @@ #include #include -static Blight::DBus* dbus = nullptr; - namespace Blight{ + static DBus* dbus = nullptr; + bool connect(bool use_system){ if(dbus != nullptr){ return true; @@ -23,6 +23,7 @@ namespace Blight{ return false; } } + bool exists(){ return connect() && dbus->has_service(BLIGHT_SERVICE); } int open(){ @@ -59,6 +60,40 @@ namespace Blight{ return dfd; } + int open_input(){ + if(!exists()){ + errno = EAGAIN; + return -EAGAIN; + } + auto reply = dbus->call_method(BLIGHT_SERVICE, "/", BLIGHT_INTERFACE, "openInput"); + if(reply->isError()){ + std::cerr + << "[Blight::open()::call_method(...)] Error: " + << reply->error_message() + << std::endl; + return reply->return_value; + } + auto fd = reply->read_value("h"); + if(!fd.has_value()){ + std::cerr + << "[Blight::open()::read_value(...)] " + << reply->error_message() + << std::endl; + return reply->return_value; + } + int dfd = fcntl(fd.value(), F_DUPFD_CLOEXEC, 3); + if(dfd < 0){ + std::cerr + << "[Blight::open()::dup(" + << std::to_string(fd.value()) + << ")] " + << std::strerror(errno) + << std::endl; + errno = -dfd; + } + return dfd; + } + std::optional createBuffer(int x, int y, int width, int height, int stride, Format format){ auto buf = new buf_t{ .fd = -1, diff --git a/shared/libblight/libblight.h b/shared/libblight/libblight.h index f67588067..3ca8cecb3 100644 --- a/shared/libblight/libblight.h +++ b/shared/libblight/libblight.h @@ -6,6 +6,7 @@ namespace Blight{ LIBBLIGHT_EXPORT bool connect(bool use_system = true); LIBBLIGHT_EXPORT bool exists(); LIBBLIGHT_EXPORT int open(); + LIBBLIGHT_EXPORT int open_input(); LIBBLIGHT_EXPORT std::optional createBuffer( int x, int y, diff --git a/shared/libblight_client/main.cpp b/shared/libblight_client/main.cpp index f0f23b675..7dd93f94f 100644 --- a/shared/libblight_client/main.cpp +++ b/shared/libblight_client/main.cpp @@ -39,6 +39,7 @@ static bool DO_HANDLE_FB = true; static bool FAKE_RM1 = false; static Blight::shared_buf_t blightBuffer = Blight::buf_t::new_ptr(); static Blight::Connection* blightConnection = nullptr; +static std::map inputDeviceMap; static ssize_t(*func_write)(int, const void*, size_t); static ssize_t(*func_writev)(int, const iovec*, int); static ssize_t(*func_writev64)(int, const iovec*, int); @@ -170,7 +171,7 @@ int fb_ioctl(unsigned long request, char* ptr){ case FBIOGET_FSCREENINFO:{ _DEBUG("%s", "ioctl /dev/fb0 FBIOGET_FSCREENINFO"); auto screeninfo = reinterpret_cast(ptr); - memcpy(screeninfo->id, "mxc_epdc_fb", 11); + memcpy(screeninfo->id, "mxc_epdc_fb\0", 12); screeninfo->smem_len = blightBuffer->size(); screeninfo->smem_start = (unsigned long)blightBuffer->data; screeninfo->line_length = blightBuffer->stride; @@ -260,7 +261,7 @@ int __open(const char* pathname){ ){ continue; } - _DEBUG("Reusing existing surface: %s", identifier); + _INFO("Reusing existing surface: %s", identifier.c_str()); blightBuffer = buffer; break; } @@ -290,10 +291,16 @@ int __open(const char* pathname){ _CRIT("Failed to create buffer: %s", std::strerror(errno)); std::exit(errno); }else{ - _DEBUG("Created buffer %s on fd %d", blightBuffer->uuid.c_str(), blightBuffer->fd); + _INFO("Created buffer %s on fd %d", blightBuffer->uuid.c_str(), blightBuffer->fd); } return res; } + }else if(strlen(pathname) >= 11 && (strncmp("/dev/input/", pathname, 11) == 0 )){ + _INFO("Opening event device: %s", pathname); + res = Blight::open_input(); + if(res > 0){ + inputDeviceMap[res] = pathname; + } } if(res == -1){ errno = EIO; @@ -461,13 +468,31 @@ extern "C" { } __attribute__((visibility("default"))) - int ioctl(int fd, unsigned long request, char* ptr){ + int ioctl(int fd, unsigned long request, ...){ + va_list args; + va_start(args, request); if(IS_INITIALIZED){ if(DO_HANDLE_FB && fd == blightBuffer->fd){ - return fb_ioctl(request, ptr); + char* ptr = va_arg(args, char*); + int res = fb_ioctl(request, ptr); + va_end(args); + return res; + } + if(inputDeviceMap.contains(fd)){ + auto path = inputDeviceMap[fd]; + auto fd = func_open(path.c_str(), O_RDONLY, 0); + int res = fd; + if(fd > 0){ + res = func_ioctl(fd, request, args); + func_close(fd); + } + va_end(args); + return res; } } - return func_ioctl(fd, request, ptr); + int res = func_ioctl(fd, request, args); + va_end(args); + return res; } __attribute__((visibility("default"))) @@ -632,7 +657,8 @@ extern "C" { return; } if( - path == "/opt/bin/yaft" + getenv("OXIDE_PRELOAD_FORCE_RM1") != nullptr + || path == "/opt/bin/yaft" // || path == "/opt/bin/something" ){ FAKE_RM1 = true; diff --git a/shared/liboxide/devicesettings.cpp b/shared/liboxide/devicesettings.cpp index 8ca926f51..1ff5df894 100644 --- a/shared/liboxide/devicesettings.cpp +++ b/shared/liboxide/devicesettings.cpp @@ -223,18 +223,12 @@ namespace Oxide { } }); } - QList DeviceSettings::keyboards(){ - QList keyboards; + + QList DeviceSettings::inputDevices(){ + QList devices; QDir dir("/dev/input"); for(auto path : dir.entryList(QDir::Files | QDir::NoSymLinks | QDir::System)){ QString fullPath(dir.path() + "/" + path); - if( - fullPath == QString::fromStdString(buttonsPath) - || fullPath == QString::fromStdString(wacomPath) - || fullPath == QString::fromStdString(touchPath) - ){ - continue; - } QFile device(fullPath); device.open(QIODevice::ReadOnly); int fd = device.handle(); @@ -242,6 +236,22 @@ namespace Oxide { if(ioctl(fd, EVIOCGVERSION, &version)){ continue; } + devices.append(event_device(fullPath.toStdString(), O_RDWR | O_NONBLOCK)); + } + return devices; + } + + QList DeviceSettings::keyboards(){ + QList keyboards; + for(auto device : inputDevices()){ + if( + device.device == buttonsPath + || device.device == wacomPath + || device.device == touchPath + ){ + continue; + } + int fd = device.fd; unsigned long bit[EV_MAX]; ioctl(fd, EVIOCGBIT(0, EV_MAX), bit); if(!test_bit(EV_KEY, bit)){ @@ -250,7 +260,8 @@ namespace Oxide { if(checkBitSet(fd, EV_KEY, BTN_STYLUS) && test_bit(EV_ABS, bit)){ continue; } - SysObject sys("/sys/class/input/" + path + "/device"); + auto name = QFileInfo(device.device.c_str()).baseName(); + SysObject sys("/sys/class/input/" + name + "/device"); auto vendor = sys.strProperty("id/vendor"); if(vendor == "0000"){ continue; @@ -259,7 +270,7 @@ namespace Oxide { if(product == "0000"){ continue; } - keyboards.append(event_device(fullPath.toStdString(), O_RDWR | O_NONBLOCK)); + keyboards.append(device); } return keyboards; } diff --git a/shared/liboxide/devicesettings.h b/shared/liboxide/devicesettings.h index 8193d7e2d..57e4a7f53 100644 --- a/shared/liboxide/devicesettings.h +++ b/shared/liboxide/devicesettings.h @@ -119,6 +119,11 @@ namespace Oxide{ * \param callback Callback to run */ void onKeyboardAttachedChanged(std::function callback); + /*! + * \brief Get the list of all evdev devices + * \return All input devices + */ + QList inputDevices(); /*! * \brief Get the list of all keyboard evdev devices * \return All keyboard devices