From 23291ec3822621fd48bb7ec9c799b1d1492b5c92 Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 7 Jan 2022 02:37:17 -0500 Subject: [PATCH 01/59] Add ipcgull submodule and require glib --- .gitmodules | 3 +++ CMakeLists.txt | 17 +++++++++++++---- README.md | 13 +++++++------ src/ipcgull | 1 + src/logid/CMakeLists.txt | 9 ++++++--- 5 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 .gitmodules create mode 160000 src/ipcgull diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9e71d79 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/ipcgull"] + path = src/ipcgull + url = git@github.com:PixlOne/ipcgull.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b147ab7..0c704ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,13 +8,13 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -Wall -Wextra") -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -find_package(Git) +find_package(Git REQUIRED) -# Set version number -if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) +# Set version number and update submodules +if(EXISTS ${CMAKE_SOURCE_DIR}/.git) execute_process(COMMAND ${GIT_EXECUTABLE} describe OUTPUT_VARIABLE LOGIOPS_VERSION RESULT_VARIABLE LOGIOPS_VERSION_RET @@ -25,10 +25,18 @@ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) OUTPUT_VARIABLE LOGIOPS_COMMIT_HASH) set(LOGIOPS_VERSION git-${LOGIOPS_COMMIT_HASH}) endif() + + execute_process(COMMAND ${GIT_EXECUTABLE} + submodule update --init --recursive) + string(REGEX REPLACE "\n$" "" LOGIOPS_VERSION ${LOGIOPS_VERSION}) elseif(EXISTS ${CMAKE_SOURCE_DIR}/version.txt) file(READ version.txt LOGIOPS_VERSION) string(REGEX REPLACE "\n$" "" LOGIOPS_VERSION ${LOGIOPS_VERSION}) + + IF(NOT EXISTS src/ipcgull) + message(FATAL_ERROR "Missing ipcgull submodule") + endif() endif() if(NOT LOGIOPS_VERSION) @@ -38,4 +46,5 @@ message("LogiOps Version Number: ${LOGIOPS_VERSION}") add_definitions( -DLOGIOPS_VERSION="${LOGIOPS_VERSION}") +add_subdirectory(src/ipcgull) add_subdirectory(src/logid) diff --git a/README.md b/README.md index b03dc28..9f3caff 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,18 @@ Default location for the configuration file is /etc/logid.cfg, but another can b ## Dependencies -This project requires a C++14 compiler, `cmake`, `libevdev`, `libudev`, and `libconfig`. For popular distributions, I've included commands below. +This project requires a C++17 compiler, `cmake`, `libevdev`, `libudev`, `glib`, and `libconfig`. +For popular distributions, I've included commands below. -**Arch Linux:** `sudo pacman -S cmake libevdev libconfig pkgconf` +**Arch Linux:** `sudo pacman -S cmake libevdev libconfig pkgconf glib2` -**Debian/Ubuntu:** `sudo apt install cmake libevdev-dev libudev-dev libconfig++-dev` +**Debian/Ubuntu:** `sudo apt install cmake libevdev-dev libudev-dev libconfig++-dev libglib2.0` -**Fedora:** `sudo dnf install cmake libevdev-devel systemd-devel libconfig-devel gcc-c++` +**Fedora:** `sudo dnf install cmake libevdev-devel systemd-devel libconfig-devel gcc-c++ glib2` -**Gentoo Linux:** `sudo emerge dev-libs/libconfig dev-libs/libevdev dev-util/cmake virtual/libudev` +**Gentoo Linux:** `sudo emerge dev-libs/libconfig dev-libs/libevdev dev-libs/glib dev-util/cmake virtual/libudev` -**Solus:** `sudo eopkg install libevdev-devel libconfig-devel libgudev-devel` +**Solus:** `sudo eopkg install libevdev-devel libconfig-devel libgudev-devel glib2` ## Building diff --git a/src/ipcgull b/src/ipcgull new file mode 160000 index 0000000..89c6103 --- /dev/null +++ b/src/ipcgull @@ -0,0 +1 @@ +Subproject commit 89c6103af33705320494043da86c4709cc938b32 diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 00ee796..45a9fd0 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) project(logid) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake") @@ -82,10 +82,13 @@ find_path(EVDEV_INCLUDE_DIR libevdev/libevdev.h find_library(EVDEV_LIBRARY NAMES evdev libevdev) -include_directories(${EVDEV_INCLUDE_DIR} ${LIBUDEV_INCLUDE_DIRECTORIES}) +set(IPCGULL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../ipcgull/src/include) +message(${IPCGULL_INCLUDE_DIRS}) + +include_directories(${EVDEV_INCLUDE_DIR} ${LIBUDEV_INCLUDE_DIRECTORIES} ${IPCGULL_INCLUDE_DIRS}) target_link_libraries(logid ${CMAKE_THREAD_LIBS_INIT} ${EVDEV_LIBRARY} config++ - ${LIBUDEV_LIBRARIES}) + ${LIBUDEV_LIBRARIES} ipcgull) install(TARGETS logid DESTINATION bin) From 65fc2526078febfa1e58f2c29b4692fcee0d18ba Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 7 Jan 2022 19:43:41 -0500 Subject: [PATCH 02/59] Eliminate global variables global_loglevel is kept for the time being and will be replaced alongside the current logger. --- src/logid/Configuration.h | 1 - src/logid/Device.cpp | 56 +++++++++++++++++++---- src/logid/Device.h | 16 +++++-- src/logid/DeviceManager.cpp | 53 ++++++++++++++++++--- src/logid/DeviceManager.h | 20 ++++++-- src/logid/InputDevice.h | 2 - src/logid/Receiver.cpp | 22 +++++++-- src/logid/Receiver.h | 4 +- src/logid/actions/ChangeDPI.cpp | 3 +- src/logid/actions/ChangeHostAction.cpp | 3 +- src/logid/actions/CycleDPI.cpp | 3 +- src/logid/actions/KeypressAction.cpp | 13 ++++-- src/logid/actions/ToggleHiresScroll.cpp | 3 +- src/logid/actions/ToggleSmartShift.cpp | 3 +- src/logid/actions/gesture/AxisGesture.cpp | 15 +++--- src/logid/backend/dj/Receiver.cpp | 7 ++- src/logid/backend/dj/Receiver.h | 4 +- src/logid/backend/dj/ReceiverMonitor.cpp | 16 +++++-- src/logid/backend/dj/ReceiverMonitor.h | 5 +- src/logid/backend/hidpp/Device.cpp | 8 ++-- src/logid/backend/hidpp/Device.h | 4 +- src/logid/backend/hidpp10/Device.cpp | 6 ++- src/logid/backend/hidpp10/Device.h | 4 +- src/logid/backend/hidpp20/Device.cpp | 9 ++-- src/logid/backend/hidpp20/Device.h | 4 +- src/logid/backend/raw/DeviceMonitor.cpp | 20 ++++++-- src/logid/backend/raw/DeviceMonitor.h | 12 +++-- src/logid/backend/raw/RawDevice.cpp | 23 ++++++---- src/logid/backend/raw/RawDevice.h | 9 +++- src/logid/features/DeviceStatus.cpp | 2 +- src/logid/logid.cpp | 24 +++------- src/logid/logid.h | 32 ------------- src/logid/util/log.h | 2 + src/logid/util/task.cpp | 7 +-- src/logid/util/task.h | 5 +- src/logid/util/workqueue.h | 1 - 36 files changed, 277 insertions(+), 144 deletions(-) delete mode 100644 src/logid/logid.h diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index 03eb62d..168c416 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -58,7 +58,6 @@ namespace logid libconfig::Config _config; }; - extern std::shared_ptr global_config; } #endif //LOGID_CONFIGURATION_H diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 6f34d6b..5788b95 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -20,6 +20,7 @@ #include "util/log.h" #include "features/DPI.h" #include "Device.h" +#include "DeviceManager.h" #include "Receiver.h" #include "features/SmartShift.h" #include "features/RemapButton.h" @@ -31,24 +32,37 @@ using namespace logid; using namespace logid::backend; -Device::Device(std::string path, backend::hidpp::DeviceIndex index) : - _hidpp20 (path, index), _path (std::move(path)), _index (index), - _config (global_config, this), _receiver (nullptr) +Device::Device(std::string path, backend::hidpp::DeviceIndex index, + const std::shared_ptr& manager) : + _hidpp20 (path, index, + manager->config()->ioTimeout(), manager->workQueue()), + _path (std::move(path)), _index (index), + _config (manager->config(), this), + _receiver (nullptr), + _manager (manager) { _init(); } Device::Device(const std::shared_ptr& raw_device, - hidpp::DeviceIndex index) : _hidpp20(raw_device, index), _path - (raw_device->hidrawPath()), _index (index), - _config (global_config, this), _receiver (nullptr) + hidpp::DeviceIndex index, + const std::shared_ptr& manager) : + _hidpp20(raw_device, index), + _path (raw_device->hidrawPath()), _index (index), + _config (manager->config(), this), + _receiver (nullptr), + _manager (manager) { _init(); } -Device::Device(Receiver* receiver, hidpp::DeviceIndex index) : _hidpp20 - (receiver->rawReceiver(), index), _path (receiver->path()), _index (index), - _config (global_config, this), _receiver (receiver) +Device::Device(Receiver* receiver, hidpp::DeviceIndex index, + const std::shared_ptr& manager) : + _hidpp20 (receiver->rawReceiver(), index), + _path (receiver->path()), _index (index), + _config (manager->config(), this), + _receiver (receiver), + _manager (manager) { _init(); } @@ -111,6 +125,30 @@ void Device::reset() "available.", _path.c_str(), _index); } +std::shared_ptr Device::workQueue() const { + if(auto manager = _manager.lock()) { + return manager->workQueue(); + } else { + logPrintf(ERROR, "Device manager lost"); + logPrintf(ERROR, + "Fatal error occurred, file a bug report," + " the program will now exit."); + std::terminate(); + } +} + +std::shared_ptr Device::virtualInput() const { + if(auto manager = _manager.lock()) { + return manager->virtualInput(); + } else { + logPrintf(ERROR, "Device manager lost"); + logPrintf(ERROR, + "Fatal error occurred, file a bug report," + " the program will now exit."); + std::terminate(); + } +} + DeviceConfig& Device::config() { return _config; diff --git a/src/logid/Device.h b/src/logid/Device.h index f1ddd1f..fdb8c33 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -27,8 +27,10 @@ namespace logid { + class DeviceManager; class Device; class Receiver; + class InputDevice; class DeviceConfig { @@ -49,10 +51,13 @@ namespace logid class Device { public: - Device(std::string path, backend::hidpp::DeviceIndex index); + Device(std::string path, backend::hidpp::DeviceIndex index, + const std::shared_ptr& manager); Device(const std::shared_ptr& raw_device, - backend::hidpp::DeviceIndex index); - Device(Receiver* receiver, backend::hidpp::DeviceIndex index); + backend::hidpp::DeviceIndex index, + const std::shared_ptr& manager); + Device(Receiver* receiver, backend::hidpp::DeviceIndex index, + const std::shared_ptr& manager); std::string name(); uint16_t pid(); @@ -65,6 +70,10 @@ namespace logid void reset(); + [[nodiscard]] std::shared_ptr workQueue() const; + + [[nodiscard]] std::shared_ptr virtualInput() const; + template std::shared_ptr getFeature(std::string name) { auto it = _features.find(name); @@ -100,6 +109,7 @@ namespace logid DeviceConfig _config; Receiver* _receiver; + const std::weak_ptr _manager; void _makeResetMechanism(); std::unique_ptr> _reset_mechanism; diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 924c499..37402d0 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -18,16 +18,55 @@ #include #include +#include #include "DeviceManager.h" #include "Receiver.h" #include "util/log.h" +#include "util/workqueue.h" #include "backend/hidpp10/Error.h" #include "backend/Error.h" using namespace logid; using namespace logid::backend; +namespace logid { + class _DeviceManager : public logid::DeviceManager + { + public: + template + explicit _DeviceManager(Args... args) : + DeviceManager(std::forward(args)...) { } + }; +} + +DeviceManager::DeviceManager(std::shared_ptr config, + std::shared_ptr virtual_input) : + backend::raw::DeviceMonitor(config->workerCount()), + _config (std::move(config)), + _virtual_input (std::move(virtual_input)) +{ +} + +std::shared_ptr DeviceManager::make( + const std::shared_ptr& config, + const std::shared_ptr& virtual_input) +{ + auto ret = std::make_shared<_DeviceManager>(config, virtual_input); + ret->_self = ret; + return ret; +} + +std::shared_ptr DeviceManager::config() const +{ + return _config; +} + +std::shared_ptr DeviceManager::virtualInput() const +{ + return _virtual_input; +} + void DeviceManager::addDevice(std::string path) { bool defaultExists = true; @@ -35,8 +74,8 @@ void DeviceManager::addDevice(std::string path) // Check if device is ignored before continuing { - raw::RawDevice raw_dev(path); - if(global_config->isIgnored(raw_dev.productId())) { + raw::RawDevice raw_dev(path, config()->ioTimeout(), workQueue()); + if(config()->isIgnored(raw_dev.productId())) { logPrintf(DEBUG, "%s: Device 0x%04x ignored.", path.c_str(), raw_dev.productId()); return; @@ -44,7 +83,8 @@ void DeviceManager::addDevice(std::string path) } try { - hidpp::Device device(path, hidpp::DefaultDevice); + hidpp::Device device(path, hidpp::DefaultDevice, + config()->ioTimeout(), workQueue()); isReceiver = device.version() == std::make_tuple(1, 0); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) @@ -62,19 +102,20 @@ void DeviceManager::addDevice(std::string path) if(isReceiver) { logPrintf(INFO, "Detected receiver at %s", path.c_str()); - auto receiver = std::make_shared(path); + auto receiver = std::make_shared(path, _self.lock()); receiver->run(); _receivers.emplace(path, receiver); } else { /* TODO: Can non-receivers only contain 1 device? * If the device exists, it is guaranteed to be an HID++ 2.0 device */ if(defaultExists) { - auto device = std::make_shared(path, hidpp::DefaultDevice); + auto device = std::make_shared(path, hidpp::DefaultDevice, + _self.lock()); _devices.emplace(path, device); } else { try { auto device = std::make_shared(path, - hidpp::CordedDevice); + hidpp::CordedDevice, _self.lock()); _devices.emplace(path, device); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index 6305963..55c53f5 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -30,21 +30,31 @@ namespace logid { + class workqueue; + class InputDevice; class DeviceManager : public backend::raw::DeviceMonitor { public: - DeviceManager() = default; + static std::shared_ptr make( + const std::shared_ptr& config, + const std::shared_ptr& virtual_input); + [[nodiscard]] std::shared_ptr config() const; + [[nodiscard]] std::shared_ptr virtualInput() const; protected: - void addDevice(std::string path) override; - void removeDevice(std::string path) override; + void addDevice(std::string path) final; + void removeDevice(std::string path) final; private: - + friend class _DeviceManager; + DeviceManager(std::shared_ptr config, + std::shared_ptr virtual_input); + std::weak_ptr _self; + std::shared_ptr _config; + std::shared_ptr _virtual_input; std::map> _devices; std::map> _receivers; }; - extern std::unique_ptr device_manager; } #endif //LOGID_DEVICEMANAGER_H \ No newline at end of file diff --git a/src/logid/InputDevice.h b/src/logid/InputDevice.h index c3c803d..17e5045 100644 --- a/src/logid/InputDevice.h +++ b/src/logid/InputDevice.h @@ -65,8 +65,6 @@ namespace logid libevdev* device; libevdev_uinput* ui_device{}; }; - - extern std::unique_ptr virtual_input; } #endif //LOGID_INPUTDEVICE_H diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index 49c053d..98a6459 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -17,6 +17,7 @@ */ #include "Receiver.h" +#include "DeviceManager.h" #include "util/log.h" #include "backend/hidpp10/Error.h" #include "backend/hidpp20/Error.h" @@ -25,17 +26,30 @@ using namespace logid; using namespace logid::backend; -Receiver::Receiver(const std::string& path) : - dj::ReceiverMonitor(path), _path (path) +Receiver::Receiver(const std::string& path, + const std::shared_ptr& manager) : + dj::ReceiverMonitor(path, + manager->config()->ioTimeout(), + manager->workQueue()), + _path (path), _manager (manager) { } void Receiver::addDevice(hidpp::DeviceConnectionEvent event) { std::unique_lock lock(_devices_change); + + auto manager = _manager.lock(); + if(!manager) { + logPrintf(ERROR, "Orphan Receiver, missing DeviceManager"); + logPrintf(ERROR, + "Fatal error, file a bug report. Program will now exit."); + std::terminate(); + } + try { // Check if device is ignored before continuing - if(global_config->isIgnored(event.pid)) { + if(manager->config()->isIgnored(event.pid)) { logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.", _path.c_str(), event.index, event.pid); return; @@ -64,7 +78,7 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) } std::shared_ptr device = std::make_shared(this, - event.index); + event.index, manager); _devices.emplace(event.index, device); diff --git a/src/logid/Receiver.h b/src/logid/Receiver.h index e055008..509113f 100644 --- a/src/logid/Receiver.h +++ b/src/logid/Receiver.h @@ -28,7 +28,8 @@ namespace logid class Receiver : public backend::dj::ReceiverMonitor { public: - explicit Receiver(const std::string& path); + explicit Receiver(const std::string& path, + const std::shared_ptr& manager); const std::string& path() const; std::shared_ptr rawReceiver(); protected: @@ -38,6 +39,7 @@ namespace logid std::mutex _devices_change; std::map> _devices; std::string _path; + std::weak_ptr _manager; }; } diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index faab6b9..3929fbc 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -39,7 +39,8 @@ void ChangeDPI::press() { _pressed = true; if(_dpi) { - task::spawn([this]{ + task::spawn(_device->workQueue(), + [this]{ try { uint16_t last_dpi = _dpi->getDPI(_config.sensor()); _dpi->setDPI(last_dpi + _config.interval(), _config.sensor()); diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index 411b8ac..84c3375 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -44,7 +44,8 @@ void ChangeHostAction::press() void ChangeHostAction::release() { if(_change_host) { - task::spawn([this] { + task::spawn(_device->workQueue(), + [this] { auto host_info = _change_host->getHostInfo(); auto next_host = _config.nextHost(host_info); if(next_host != host_info.currentHost) diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index 19b729c..a5b33c7 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -40,7 +40,8 @@ void CycleDPI::press() { _pressed = true; if(_dpi && !_config.empty()) { - task::spawn([this](){ + task::spawn(_device->workQueue(), + [this](){ uint16_t dpi = _config.nextDPI(); try { _dpi->setDPI(dpi, _config.sensor()); diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index a71546b..caa004c 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -16,6 +16,7 @@ * */ #include "KeypressAction.h" +#include "../Device.h" #include "../util/log.h" #include "../InputDevice.h" #include "../backend/hidpp20/features/ReprogControls.h" @@ -32,14 +33,14 @@ void KeypressAction::press() { _pressed = true; for(auto& key : _config.keys()) - virtual_input->pressKey(key); + _device->virtualInput()->pressKey(key); } void KeypressAction::release() { _pressed = false; for(auto& key : _config.keys()) - virtual_input->releaseKey(key); + _device->virtualInput()->releaseKey(key); } uint8_t KeypressAction::reprogFlags() const @@ -64,11 +65,13 @@ KeypressAction::Config::Config(Device* device, libconfig::Setting& config) : auto& key = keys[i]; if(key.isNumber()) { _keys.push_back(key); - virtual_input->registerKey(key); + _device->virtualInput()->registerKey(key); } else if(key.getType() == libconfig::Setting::TypeString) { try { - _keys.push_back(virtual_input->toKeyCode(key)); - virtual_input->registerKey(virtual_input->toKeyCode(key)); + _keys.push_back( + _device->virtualInput()->toKeyCode(key)); + _device->virtualInput()->registerKey( + _device->virtualInput()->toKeyCode(key)); } catch(InputDevice::InvalidEventCode& e) { logPrintf(WARN, "Line %d: Invalid keycode %s, skipping." , key.getSourceLine(), key.c_str()); diff --git a/src/logid/actions/ToggleHiresScroll.cpp b/src/logid/actions/ToggleHiresScroll.cpp index 0c57d54..591e09b 100644 --- a/src/logid/actions/ToggleHiresScroll.cpp +++ b/src/logid/actions/ToggleHiresScroll.cpp @@ -38,7 +38,8 @@ void ToggleHiresScroll::press() _pressed = true; if(_hires_scroll) { - task::spawn([hires=this->_hires_scroll](){ + task::spawn(_device->workQueue(), + [hires=this->_hires_scroll](){ auto mode = hires->getMode(); mode ^= backend::hidpp20::HiresScroll::HiRes; hires->setMode(mode); diff --git a/src/logid/actions/ToggleSmartShift.cpp b/src/logid/actions/ToggleSmartShift.cpp index 5e4fd6e..58c5e36 100644 --- a/src/logid/actions/ToggleSmartShift.cpp +++ b/src/logid/actions/ToggleSmartShift.cpp @@ -37,7 +37,8 @@ void ToggleSmartShift::press() { _pressed = true; if(_smartshift) { - task::spawn([ss=this->_smartshift](){ + task::spawn(_device->workQueue(), + [ss=this->_smartshift](){ auto status = ss->getStatus(); status.setActive = true; status.active = !status.active; diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 8ec26f5..2da114d 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -17,6 +17,7 @@ */ #include #include "AxisGesture.h" +#include "../../Device.h" #include "../../InputDevice.h" #include "../../util/log.h" @@ -69,19 +70,19 @@ void AxisGesture::move(int16_t axis) if(low_res_axis != -1) { int lowres_movement = 0, hires_movement = move_floor; - virtual_input->moveAxis(_config.axis(), hires_movement); + _device->virtualInput()->moveAxis(_config.axis(), hires_movement); hires_remainder += hires_movement; if(abs(hires_remainder) >= 60) { lowres_movement = hires_remainder/120; if(lowres_movement == 0) lowres_movement = hires_remainder > 0 ? 1 : -1; hires_remainder -= lowres_movement*120; - virtual_input->moveAxis(low_res_axis, lowres_movement); + _device->virtualInput()->moveAxis(low_res_axis, lowres_movement); } _hires_remainder = hires_remainder; } else { - virtual_input->moveAxis(_config.axis(), move_floor); + _device->virtualInput()->moveAxis(_config.axis(), move_floor); } } _axis = new_axis; @@ -104,11 +105,11 @@ AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) : auto& axis = setting.lookup("axis"); if(axis.isNumber()) { _axis = axis; - virtual_input->registerAxis(_axis); + _device->virtualInput()->registerAxis(_axis); } else if(axis.getType() == libconfig::Setting::TypeString) { try { - _axis = virtual_input->toAxisCode(axis); - virtual_input->registerAxis(_axis); + _axis = _device->virtualInput()->toAxisCode(axis); + _device->virtualInput()->registerAxis(_axis); } catch(InputDevice::InvalidEventCode& e) { logPrintf(WARN, "Line %d: Invalid axis %s, skipping." , axis.getSourceLine(), axis.c_str()); @@ -143,7 +144,7 @@ AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) : int low_res_axis = InputDevice::getLowResAxis(_axis); if(low_res_axis != -1) { _multiplier *= 120; - virtual_input->registerAxis(low_res_axis); + _device->virtualInput()->registerAxis(low_res_axis); } } diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index 40cbbbd..2f3e4d7 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -44,8 +44,11 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept return _reason; } -Receiver::Receiver(std::string path) : - _raw_device (std::make_shared(std::move(path))), +Receiver::Receiver(std::string path, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq) : + _raw_device (std::make_shared( + std::move(path), io_timeout, wq)), _hidpp10_device (_raw_device, hidpp::DefaultDevice) { if(!supportsDjReports(_raw_device->reportDescriptor())) diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index 767689a..f0e4a21 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -52,7 +52,9 @@ namespace dj class Receiver final { public: - explicit Receiver(std::string path); + Receiver(std::string path, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); enum DjEvents : uint8_t { diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index 80a9283..f847a75 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -25,8 +25,12 @@ using namespace logid::backend::dj; -ReceiverMonitor::ReceiverMonitor(std::string path) : _receiver ( - std::make_shared(std::move(path))) +ReceiverMonitor::ReceiverMonitor( + std::string path, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq) : + _workqueue (wq), + _receiver (std::make_shared(std::move(path), io_timeout, wq)) { assert(_receiver->hidppEventHandlers().find("RECVMON") == _receiver->hidppEventHandlers().end()); @@ -62,14 +66,15 @@ void ReceiverMonitor::run() /* Running in a new thread prevents deadlocks since the * receiver may be enumerating. */ - task::spawn({[this, report]() { + task::spawn(_workqueue, + [this, report]() { if (report.subId() == Receiver::DeviceConnection) this->addDevice(this->_receiver->deviceConnectionEvent (report)); else if (report.subId() == Receiver::DeviceDisconnection) this->removeDevice(this->_receiver-> deviceDisconnectionEvent(report)); - }}, {[report, path=this->_receiver->rawDevice()->hidrawPath()] + }, {[report, path=this->_receiver->rawDevice()->hidrawPath()] (std::exception& e) { if(report.subId() == Receiver::DeviceConnection) logPrintf(ERROR, "Failed to add device %d to receiver " @@ -117,7 +122,8 @@ void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) event.index = index; event.fromTimeoutCheck = true; - task::spawn({[this, event, nickname]() { + task::spawn(_workqueue, + {[this, event, nickname]() { _receiver->rawDevice()->removeEventHandler(nickname); this->addDevice(event); }}, {[path=_receiver->rawDevice()->hidrawPath(), event] diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 88d7686..6c88627 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -32,7 +32,9 @@ namespace dj class ReceiverMonitor { public: - explicit ReceiverMonitor(std::string path); + ReceiverMonitor(std::string path, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); virtual ~ReceiverMonitor(); void enumerate(); @@ -53,6 +55,7 @@ namespace dj std::shared_ptr receiver() const; private: + std::shared_ptr _workqueue; std::shared_ptr _receiver; }; diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index cc9db25..0b853c1 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -49,9 +49,11 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept return _reason; } -Device::Device(const std::string& path, DeviceIndex index): - _raw_device (std::make_shared(path)), _receiver (nullptr), - _path (path), _index (index) +Device::Device(const std::string& path, DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq): + _raw_device (std::make_shared(path, io_timeout, wq)), + _receiver (nullptr), _path (path), _index (index) { _init(); } diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 612318b..666ad45 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -61,7 +61,9 @@ namespace hidpp Reason _reason; }; - explicit Device(const std::string& path, DeviceIndex index); + Device(const std::string& path, DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); Device(std::shared_ptr raw_device, DeviceIndex index); Device(std::shared_ptr receiver, diff --git a/src/logid/backend/hidpp10/Device.cpp b/src/logid/backend/hidpp10/Device.cpp index c56e407..ab5f990 100644 --- a/src/logid/backend/hidpp10/Device.cpp +++ b/src/logid/backend/hidpp10/Device.cpp @@ -24,8 +24,10 @@ using namespace logid::backend; using namespace logid::backend::hidpp10; -Device::Device(const std::string &path, hidpp::DeviceIndex index) : - hidpp::Device(path, index) +Device::Device(const std::string &path, hidpp::DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq) : + hidpp::Device(path, index, io_timeout, wq) { assert(version() == std::make_tuple(1, 0)); } diff --git a/src/logid/backend/hidpp10/Device.h b/src/logid/backend/hidpp10/Device.h index a86d0e5..b6d92b5 100644 --- a/src/logid/backend/hidpp10/Device.h +++ b/src/logid/backend/hidpp10/Device.h @@ -28,7 +28,9 @@ namespace hidpp10 class Device : public hidpp::Device { public: - Device(const std::string& path, hidpp::DeviceIndex index); + Device(const std::string& path, hidpp::DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); Device(std::shared_ptr raw_dev, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index d32bf41..278f119 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -23,13 +23,16 @@ using namespace logid::backend::hidpp20; -Device::Device(std::string path, hidpp::DeviceIndex index) - : hidpp::Device(path, index) +Device::Device(std::string path, hidpp::DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq) : + hidpp::Device(path, index, io_timeout, wq) { assert(std::get<0>(version()) >= 2); } -Device::Device(std::shared_ptr raw_device, hidpp::DeviceIndex index) +Device::Device(std::shared_ptr raw_device, + hidpp::DeviceIndex index) : hidpp::Device(raw_device, index) { assert(std::get<0>(version()) >= 2); diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index 2628016..f593758 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -28,7 +28,9 @@ namespace hidpp20 { class Device : public hidpp::Device { public: - Device(std::string path, hidpp::DeviceIndex index); + Device(std::string path, hidpp::DeviceIndex index, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); Device(std::shared_ptr raw_device, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, hidpp::DeviceIndex index); diff --git a/src/logid/backend/raw/DeviceMonitor.cpp b/src/logid/backend/raw/DeviceMonitor.cpp index f98ed48..8520c23 100644 --- a/src/logid/backend/raw/DeviceMonitor.cpp +++ b/src/logid/backend/raw/DeviceMonitor.cpp @@ -18,6 +18,7 @@ #include "DeviceMonitor.h" #include "../../util/task.h" +#include "../../util/workqueue.h" #include "../../util/log.h" #include "RawDevice.h" #include "../hidpp/Device.h" @@ -31,9 +32,11 @@ extern "C" #include } +using namespace logid; using namespace logid::backend::raw; -DeviceMonitor::DeviceMonitor() +DeviceMonitor::DeviceMonitor(int worker_count) : + _workqueue (std::make_shared(worker_count)) { if(-1 == pipe(_pipe)) throw std::system_error(errno, std::system_category(), @@ -100,7 +103,8 @@ void DeviceMonitor::run() std::string devnode = udev_device_get_devnode(device); if (action == "add") - task::spawn([this, name=devnode]() { + task::spawn(_workqueue, + [this, name=devnode]() { // Wait for device to initialise std::this_thread::sleep_for(std::chrono::milliseconds(100)); auto supported_reports = backend::hidpp::getSupportedReports( @@ -115,7 +119,8 @@ void DeviceMonitor::run() name.c_str(), e.what()); }); else if (action == "remove") - task::spawn([this, name=devnode]() { + task::spawn(_workqueue, + [this, name=devnode]() { this->removeDevice(name); }, [name=devnode](std::exception& e){ logPrintf(WARN, "Error removing device %s: %s", @@ -167,7 +172,8 @@ void DeviceMonitor::enumerate() std::string devnode = udev_device_get_devnode(device); udev_device_unref(device); - task::spawn([this, name=devnode]() { + task::spawn(_workqueue, + [this, name=devnode]() { auto supported_reports = backend::hidpp::getSupportedReports( RawDevice::getReportDescriptor(name)); if(supported_reports) @@ -182,4 +188,8 @@ void DeviceMonitor::enumerate() } udev_enumerate_unref(udev_enum); -} \ No newline at end of file +} + +std::shared_ptr DeviceMonitor::workQueue() const { + return _workqueue; +} diff --git a/src/logid/backend/raw/DeviceMonitor.h b/src/logid/backend/raw/DeviceMonitor.h index d795019..c54cb64 100644 --- a/src/logid/backend/raw/DeviceMonitor.h +++ b/src/logid/backend/raw/DeviceMonitor.h @@ -22,13 +22,12 @@ #include #include #include +#include -extern "C" -{ -#include -} +struct udev; namespace logid { + class workqueue; namespace backend { namespace raw { @@ -38,8 +37,10 @@ namespace raw void enumerate(); void run(); void stop(); + + std::shared_ptr workQueue() const; protected: - DeviceMonitor(); + explicit DeviceMonitor(int worker_count); virtual ~DeviceMonitor(); virtual void addDevice(std::string device) = 0; virtual void removeDevice(std::string device) = 0; @@ -48,6 +49,7 @@ namespace raw int _pipe[2]; std::atomic _run_monitor; std::mutex _running; + std::shared_ptr _workqueue; }; }}} diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 0493862..95e6995 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -64,8 +64,13 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length) } } -RawDevice::RawDevice(std::string path) : _path (std::move(path)), - _continue_listen (false), _continue_respond (false) +RawDevice::RawDevice(std::string path, + const milliseconds& io_timeout, + const std::shared_ptr& wq) : + _path (std::move(path)), + _continue_listen (false), _continue_respond (false), + _io_timeout (io_timeout), + _workqueue (wq) { int ret; @@ -189,7 +194,7 @@ std::vector RawDevice::sendReport(const std::vector& report) _io_queue.push(task); interruptRead(false); // Alert listener to prioritise cv.wait(lock, [&top_of_queue]{ return top_of_queue; }); - auto status = f.wait_for(global_config->ioTimeout()); + auto status = f.wait_for(_io_timeout); if(status == std::future_status::timeout) { _continue_respond = false; interruptRead(); @@ -210,9 +215,9 @@ std::vector RawDevice::sendReport(const std::vector& report) _exception = std::make_exception_ptr(e); } }); - global_workqueue->queue(t); + _workqueue->queue(t); t->waitStart(); - auto status = t->waitFor(global_config->ioTimeout()); + auto status = t->waitFor(_io_timeout); if(_exception) std::rethrow_exception(_exception); if(status == std::future_status::timeout) { @@ -257,7 +262,7 @@ std::vector RawDevice::_respondToReport while(_continue_respond) { std::vector response; auto current_point = std::chrono::steady_clock::now(); - auto timeout = global_config->ioTimeout() - std::chrono::duration_cast + auto timeout = _io_timeout - std::chrono::duration_cast (current_point - start_point); if(timeout.count() <= 0) throw TimeoutError(); @@ -337,7 +342,7 @@ int RawDevice::_sendReport(const std::vector& report) int RawDevice::_readReport(std::vector &report, std::size_t maxDataLength) { - return _readReport(report, maxDataLength, global_config->ioTimeout()); + return _readReport(report, maxDataLength, _io_timeout); } int RawDevice::_readReport(std::vector &report, @@ -348,10 +353,10 @@ int RawDevice::_readReport(std::vector &report, report.resize(maxDataLength); timeval timeout_tv{}; - timeout_tv.tv_sec = duration_cast(global_config->ioTimeout()) + timeout_tv.tv_sec = duration_cast(_io_timeout) .count(); timeout_tv.tv_usec = duration_cast( - global_config->ioTimeout()).count() % + _io_timeout).count() % duration_cast(seconds(1)).count(); auto timeout_ms = duration_cast(timeout).count(); diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 9ec935a..7935a0c 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -31,6 +31,8 @@ #include "../../util/mutex_queue.h" namespace logid { + class workqueue; + namespace backend { namespace raw { @@ -39,7 +41,9 @@ namespace raw public: static bool supportedReport(uint8_t id, uint8_t length); - explicit RawDevice(std::string path); + explicit RawDevice(std::string path, + const std::chrono::milliseconds& io_timeout, + const std::shared_ptr& wq); ~RawDevice(); std::string hidrawPath() const; @@ -80,6 +84,9 @@ namespace raw std::atomic _continue_respond; std::condition_variable _listen_condition; + const std::chrono::milliseconds _io_timeout; + const std::shared_ptr _workqueue; + std::map> _event_handlers; std::mutex _event_handler_lock; diff --git a/src/logid/features/DeviceStatus.cpp b/src/logid/features/DeviceStatus.cpp index 7ff8a01..b41a7a2 100644 --- a/src/logid/features/DeviceStatus.cpp +++ b/src/logid/features/DeviceStatus.cpp @@ -62,7 +62,7 @@ void DeviceStatus::listen() auto event = hidpp20::WirelessDeviceStatus::statusBroadcastEvent( report); if(event.reconfNeeded) - task::spawn([dev](){ dev->wakeup(); }); + task::spawn(dev->workQueue(), [dev](){ dev->wakeup(); }); }; _device->hidpp20().addEventHandler(EVENTHANDLER_NAME, handler); diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index ddb77ec..0352b1f 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -23,7 +23,6 @@ #include "util/log.h" #include "DeviceManager.h" -#include "logid.h" #include "InputDevice.h" #include "util/workqueue.h" @@ -43,13 +42,6 @@ struct CmdlineOptions }; LogLevel logid::global_loglevel = INFO; -std::shared_ptr logid::global_config; -std::unique_ptr logid::device_manager; -std::unique_ptr logid::virtual_input; -std::shared_ptr logid::global_workqueue; - -bool logid::kill_logid = false; -std::mutex logid::device_manager_reload; enum class Option { @@ -162,16 +154,16 @@ int main(int argc, char** argv) { CmdlineOptions options{}; readCliOptions(argc, argv, options); + std::shared_ptr config; + std::shared_ptr virtual_input; // Read config try { - global_config = std::make_shared(options.config_file); + config = std::make_shared(options.config_file); } catch (std::exception &e) { - global_config = std::make_shared(); + config = std::make_shared(); } - global_workqueue = std::make_shared( - global_config->workerCount()); //Create a virtual input device try { @@ -182,13 +174,9 @@ int main(int argc, char** argv) } // Scan devices, create listeners, handlers, etc. - device_manager = std::make_unique(); + auto device_manager = DeviceManager::make(config, virtual_input); - while(!kill_logid) { - device_manager_reload.lock(); - device_manager_reload.unlock(); - device_manager->run(); - } + device_manager->run(); return EXIT_SUCCESS; } diff --git a/src/logid/logid.h b/src/logid/logid.h deleted file mode 100644 index 850721f..0000000 --- a/src/logid/logid.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 . - * - */ - -#ifndef LOGID_LOGID_H -#define LOGID_LOGID_H - -#include - -namespace logid -{ - // void reload(); - - extern bool kill_logid; - extern std::mutex device_manager_reload; -} - -#endif //LOGID_LOGID_H \ No newline at end of file diff --git a/src/logid/util/log.h b/src/logid/util/log.h index fad0b66..920ee71 100644 --- a/src/logid/util/log.h +++ b/src/logid/util/log.h @@ -22,6 +22,8 @@ namespace logid { + /// TODO: Replace with a safer object-oriented logger + enum LogLevel { RAWREPORT, diff --git a/src/logid/util/task.cpp b/src/logid/util/task.cpp index 29a4987..7a680d7 100644 --- a/src/logid/util/task.cpp +++ b/src/logid/util/task.cpp @@ -72,9 +72,10 @@ std::future_status task::waitFor(std::chrono::milliseconds ms) return _future.wait_for(ms); } -void task::spawn(const std::function& function, - const std::function& exception_handler) +void task::spawn(std::shared_ptr wq, + const std::function& function, + const std::function& exception_handler) { auto t = std::make_shared(function, exception_handler); - global_workqueue->queue(t); + wq->queue(t); } \ No newline at end of file diff --git a/src/logid/util/task.h b/src/logid/util/task.h index c988cc9..728504d 100644 --- a/src/logid/util/task.h +++ b/src/logid/util/task.h @@ -25,6 +25,8 @@ namespace logid { + class workqueue; + class task { public: @@ -50,7 +52,8 @@ namespace logid /* This function spawns a new task into the least used worker queue * and forgets about it. */ - static void spawn(const std::function& function, + static void spawn(std::shared_ptr wq, + const std::function& function, const std::function& exception_handler={[](std::exception& e) {ExceptionHandler::Default(e);}}); diff --git a/src/logid/util/workqueue.h b/src/logid/util/workqueue.h index 301b60b..b8191fd 100644 --- a/src/logid/util/workqueue.h +++ b/src/logid/util/workqueue.h @@ -52,7 +52,6 @@ namespace logid std::size_t _worker_count; }; - extern std::shared_ptr global_workqueue; } #endif //LOGID_WORKQUEUE_H From daa8c37c7d3c5e417e851e046379208aa7b87f62 Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 7 Jan 2022 23:40:29 -0500 Subject: [PATCH 03/59] Change default I/O timeout to 400ms --- src/logid/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index 168c416..8e63248 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -25,7 +25,7 @@ #include #include -#define LOGID_DEFAULT_IO_TIMEOUT std::chrono::seconds(2) +#define LOGID_DEFAULT_IO_TIMEOUT std::chrono::milliseconds(400) #define LOGID_DEFAULT_WORKER_COUNT 4 namespace logid From 918ea63755a66d69373d7da431b61203fa878b41 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 8 Jan 2022 00:05:32 -0500 Subject: [PATCH 04/59] Add Device and Receiver signals to DeviceManager --- src/ipcgull | 2 +- src/logid/Device.cpp | 89 ++++++++++++++++-- src/logid/Device.h | 59 ++++++++++-- src/logid/DeviceManager.cpp | 175 ++++++++++++++++++++++++++++++++++-- src/logid/DeviceManager.h | 51 ++++++++++- src/logid/InputDevice.cpp | 7 +- src/logid/Receiver.cpp | 67 ++++++++++++-- src/logid/Receiver.h | 40 ++++++++- src/logid/logid.cpp | 18 +++- 9 files changed, 467 insertions(+), 41 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index 89c6103..0d53465 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 89c6103af33705320494043da86c4709cc938b32 +Subproject commit 0d53465fe70ab07e07f9f9d853413a6cc82704c6 diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 5788b95..5bfd7f4 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -32,37 +32,106 @@ using namespace logid; using namespace logid::backend; +DeviceNickname::DeviceNickname(const std::shared_ptr& manager) : + _nickname (manager->newDeviceNickname()), _manager (manager) +{ +} + +DeviceNickname::operator std::string() const { + return std::to_string(_nickname); +} + +DeviceNickname::~DeviceNickname() +{ + if(auto manager = _manager.lock()) { + std::lock_guard lock(manager->_nick_lock); + manager->_device_nicknames.erase(_nickname); + } +} + +namespace logid { + class _Device : public Device { + public: + template + _Device(Args... args) : Device(std::forward(args)...) { } + }; +} + +std::shared_ptr Device::make( + std::string path, backend::hidpp::DeviceIndex index, + std::shared_ptr manager) +{ + auto ret = std::make_shared<_Device>(std::move(path), + index, + std::move(manager)); + ret->_self = ret; + ret->_ipc_node->manage(ret); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + return ret; +} + +std::shared_ptr Device::make( + std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager) +{ + auto ret = std::make_shared<_Device>(std::move(raw_device), + index, + std::move(manager)); + ret->_self = ret; + ret->_ipc_node->manage(ret); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + return ret; +} + +std::shared_ptr Device::make( + Receiver* receiver, backend::hidpp::DeviceIndex index, + std::shared_ptr manager) +{ + auto ret = std::make_shared<_Device>(receiver, index, std::move(manager)); + ret->_self = ret; + ret->_ipc_node->manage(ret); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + return ret; +} + Device::Device(std::string path, backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager) : + std::shared_ptr manager) : _hidpp20 (path, index, manager->config()->ioTimeout(), manager->workQueue()), _path (std::move(path)), _index (index), _config (manager->config(), this), _receiver (nullptr), - _manager (manager) + _manager (manager), + _nickname (manager), + _ipc_node(manager->devicesNode()->make_child(_nickname)) { _init(); } -Device::Device(const std::shared_ptr& raw_device, +Device::Device(std::shared_ptr raw_device, hidpp::DeviceIndex index, - const std::shared_ptr& manager) : + std::shared_ptr manager) : _hidpp20(raw_device, index), _path (raw_device->hidrawPath()), _index (index), _config (manager->config(), this), _receiver (nullptr), - _manager (manager) + _manager (manager), + _nickname (manager), + _ipc_node (manager->devicesNode()->make_child(_nickname)) { _init(); } Device::Device(Receiver* receiver, hidpp::DeviceIndex index, - const std::shared_ptr& manager) : + std::shared_ptr manager) : _hidpp20 (receiver->rawReceiver(), index), _path (receiver->path()), _index (index), _config (manager->config(), this), _receiver (receiver), - _manager (manager) + _manager (manager), + _nickname (manager), + _ipc_node (manager->devicesNode()->make_child(_nickname)) { _init(); } @@ -173,6 +242,12 @@ void Device::_makeResetMechanism() } } +Device::DeviceIPC::DeviceIPC(Device* device) : + ipcgull::interface("pizza.pixl.LogiOps.Device", {}, {}, {}) +{ + +} + DeviceConfig::DeviceConfig(const std::shared_ptr& config, Device* device) : _device (device), _config (config) { diff --git a/src/logid/Device.h b/src/logid/Device.h index fdb8c33..dcb1f53 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -19,6 +19,8 @@ #ifndef LOGID_DEVICE_H #define LOGID_DEVICE_H +#include +#include #include "backend/hidpp/defs.h" #include "backend/hidpp20/Device.h" #include "features/DeviceFeature.h" @@ -32,6 +34,19 @@ namespace logid class Receiver; class InputDevice; + class DeviceNickname { + public: + explicit DeviceNickname(const std::shared_ptr& manager); + DeviceNickname() = delete; + DeviceNickname(const DeviceNickname&) = delete; + ~DeviceNickname(); + + operator std::string() const; + private: + const int _nickname; + const std::weak_ptr _manager; + }; + class DeviceConfig { public: @@ -48,23 +63,28 @@ namespace logid * Currently, the logid::Device class has a hardcoded requirement * for an HID++ 2.0 device. */ - class Device + class Device : public ipcgull::object { public: - Device(std::string path, backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager); - Device(const std::shared_ptr& raw_device, - backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager); - Device(Receiver* receiver, backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager); - std::string name(); uint16_t pid(); DeviceConfig& config(); backend::hidpp20::Device& hidpp20(); + static std::shared_ptr make( + std::string path, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + static std::shared_ptr make( + std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + static std::shared_ptr make( + Receiver* receiver, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + void wakeup(); void sleep(); @@ -89,6 +109,15 @@ namespace logid } private: + friend class _Device; + Device(std::string path, backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + Device(std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + Device(Receiver* receiver, backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + void _init(); /* Adds a feature without calling an error if unsupported */ @@ -113,6 +142,18 @@ namespace logid void _makeResetMechanism(); std::unique_ptr> _reset_mechanism; + + const DeviceNickname _nickname; + std::shared_ptr _ipc_node; + + class DeviceIPC : public ipcgull::interface { + public: + DeviceIPC(Device* device); + }; + + std::shared_ptr _ipc_interface; + + std::weak_ptr _self; }; } diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 37402d0..2cc806f 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -41,18 +41,28 @@ namespace logid { } DeviceManager::DeviceManager(std::shared_ptr config, - std::shared_ptr virtual_input) : + std::shared_ptr virtual_input, + std::shared_ptr server) : backend::raw::DeviceMonitor(config->workerCount()), - _config (std::move(config)), - _virtual_input (std::move(virtual_input)) + _server (std::move(server)), _config (std::move(config)), + _virtual_input (std::move(virtual_input)), + _root_node (ipcgull::node::make_root("")), + _device_node (ipcgull::node::make_root("devices")), + _receiver_node (ipcgull::node::make_root("receivers")) { + _ipc_devices = _root_node->make_interface(); + _ipc_receivers = _root_node->make_interface(); + _device_node->add_server(_server); + _receiver_node->add_server(_server); + _root_node->add_server(_server); } std::shared_ptr DeviceManager::make( const std::shared_ptr& config, - const std::shared_ptr& virtual_input) + const std::shared_ptr& virtual_input, + const std::shared_ptr& server) { - auto ret = std::make_shared<_DeviceManager>(config, virtual_input); + auto ret = std::make_shared<_DeviceManager>(config, virtual_input, server); ret->_self = ret; return ret; } @@ -67,6 +77,16 @@ std::shared_ptr DeviceManager::virtualInput() const return _virtual_input; } +std::shared_ptr DeviceManager::devicesNode() const +{ + return _device_node; +} + +std::shared_ptr DeviceManager::receiversNode() const +{ + return _receiver_node; +} + void DeviceManager::addDevice(std::string path) { bool defaultExists = true; @@ -102,21 +122,24 @@ void DeviceManager::addDevice(std::string path) if(isReceiver) { logPrintf(INFO, "Detected receiver at %s", path.c_str()); - auto receiver = std::make_shared(path, _self.lock()); + auto receiver = Receiver::make(path, _self.lock()); receiver->run(); _receivers.emplace(path, receiver); + _ipc_receivers->receiverAdded(receiver); } else { /* TODO: Can non-receivers only contain 1 device? * If the device exists, it is guaranteed to be an HID++ 2.0 device */ if(defaultExists) { - auto device = std::make_shared(path, hidpp::DefaultDevice, - _self.lock()); + auto device = Device::make(path, hidpp::DefaultDevice, + _self.lock()); _devices.emplace(path, device); + _ipc_devices->deviceAdded(device); } else { try { - auto device = std::make_shared(path, + auto device = Device::make(path, hidpp::CordedDevice, _self.lock()); _devices.emplace(path, device); + _ipc_devices->deviceAdded(device); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) throw; @@ -134,18 +157,152 @@ void DeviceManager::addDevice(std::string path) } } +void DeviceManager::addExternalDevice(const std::shared_ptr &d) +{ + _ipc_devices->deviceAdded(d); +} + +void DeviceManager::removeExternalDevice(const std::shared_ptr &d) +{ + _ipc_devices->deviceRemoved(d); +} + void DeviceManager::removeDevice(std::string path) { auto receiver = _receivers.find(path); if(receiver != _receivers.end()) { + _ipc_receivers->receiverRemoved(receiver->second); _receivers.erase(receiver); logPrintf(INFO, "Receiver on %s disconnected", path.c_str()); } else { auto device = _devices.find(path); if(device != _devices.end()) { + _ipc_devices->deviceRemoved(device->second); _devices.erase(device); logPrintf(INFO, "Device on %s disconnected", path.c_str()); } } } + +DeviceManager::DevicesIPC::DevicesIPC() : ipcgull::interface( + "pizza.pixl.LogiOps.Devices", + {}, + {}, + { + {"deviceAdded", + ipcgull::make_signal>( + {"device"})}, + {"deviceRemoved", + ipcgull::make_signal>( + {"device"})} + } + ) +{ +} + +void DeviceManager::DevicesIPC::deviceAdded( + const std::shared_ptr& d) { + emit_signal("deviceAdded", d); +} + +void DeviceManager::DevicesIPC::deviceRemoved( + const std::shared_ptr& d) { + emit_signal("deviceRemoved", d); +} + +DeviceManager::ReceiversIPC::ReceiversIPC() : ipcgull::interface( + "pizza.pixl.LogiOps.Receivers", + {}, + {}, + { + {"receiverAdded", + ipcgull::make_signal>( + {"device"})}, + {"receiverRemoved", + ipcgull::make_signal>( + {"device"})} + }) +{ +} + +void DeviceManager::ReceiversIPC::receiverAdded( + const std::shared_ptr& r) { + emit_signal("receiverAdded", r); +} + +void DeviceManager::ReceiversIPC::receiverRemoved( + const std::shared_ptr& r) { + emit_signal("receiverRemoved", r); +} + +int DeviceManager::newDeviceNickname() +{ + std::lock_guard lock(_nick_lock); + + auto begin = _device_nicknames.begin(); + if(begin != _device_nicknames.end()) { + if(*begin != 0) { + _device_nicknames.insert(0); + return 0; + } + } + + const auto i = std::adjacent_find(_device_nicknames.begin(), + _device_nicknames.end(), + [](int l, int r) { return l + 1 < r; }); + + + if(i == _device_nicknames.end()) { + auto end = _device_nicknames.rbegin(); + if(end != _device_nicknames.rend()) { + auto ret = *end + 1; + assert(ret > 0); + _device_nicknames.insert(ret); + return ret; + } else { + _device_nicknames.insert(0); + return 0; + } + } + + auto ret = *i + 1; + assert(ret > 0); + _device_nicknames.insert(ret); + return ret; +} + +int DeviceManager::newReceiverNickname() +{ + std::lock_guard lock(_nick_lock); + + auto begin = _receiver_nicknames.begin(); + if(begin != _receiver_nicknames.end()) { + if(*begin != 0) { + _receiver_nicknames.insert(0); + return 0; + } + } + + const auto i = std::adjacent_find(_receiver_nicknames.begin(), + _receiver_nicknames.end(), + [](int l, int r) { return l + 1 < r; }); + + if(i == _receiver_nicknames.end()) { + auto end = _receiver_nicknames.rbegin(); + if(end != _receiver_nicknames.rend()) { + auto ret = *end + 1; + assert(ret > 0); + _receiver_nicknames.insert(ret); + return ret; + } else { + _receiver_nicknames.insert(0); + return 0; + } + } + + auto ret = *i + 1; + assert(ret > 0); + _receiver_nicknames.insert(ret); + return ret; +} diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index 55c53f5..56e180e 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "backend/raw/DeviceMonitor.h" #include "backend/hidpp/Device.h" @@ -38,23 +40,66 @@ namespace logid public: static std::shared_ptr make( const std::shared_ptr& config, - const std::shared_ptr& virtual_input); + const std::shared_ptr& virtual_input, + const std::shared_ptr& server); [[nodiscard]] std::shared_ptr config() const; [[nodiscard]] std::shared_ptr virtualInput() const; + [[nodiscard]] std::shared_ptr devicesNode() const; + [[nodiscard]] std::shared_ptr + receiversNode() const; + + void addExternalDevice(const std::shared_ptr& d); + void removeExternalDevice(const std::shared_ptr& d); protected: void addDevice(std::string path) final; void removeDevice(std::string path) final; private: + class DevicesIPC : public ipcgull::interface { + public: + DevicesIPC(); + void deviceAdded(const std::shared_ptr& d); + void deviceRemoved(const std::shared_ptr& d); + }; + + class ReceiversIPC : public ipcgull::interface { + public: + ReceiversIPC(); + void receiverAdded(const std::shared_ptr& r); + void receiverRemoved(const std::shared_ptr& r); + }; + friend class _DeviceManager; DeviceManager(std::shared_ptr config, - std::shared_ptr virtual_input); + std::shared_ptr virtual_input, + std::shared_ptr server); + std::weak_ptr _self; + std::shared_ptr _server; std::shared_ptr _config; std::shared_ptr _virtual_input; + + std::shared_ptr _root_node; + + std::shared_ptr _device_node; + std::shared_ptr _receiver_node; + + std::shared_ptr _ipc_devices; + std::shared_ptr _ipc_receivers; + std::map> _devices; std::map> _receivers; + + friend class DeviceNickname; + friend class ReceiverNickname; + + [[nodiscard]] int newDeviceNickname(); + [[nodiscard]] int newReceiverNickname(); + + std::mutex _nick_lock; + std::set _device_nicknames; + std::set _receiver_nicknames; }; } -#endif //LOGID_DEVICEMANAGER_H \ No newline at end of file +#endif //LOGID_DEVICEMANAGER_H diff --git a/src/logid/InputDevice.cpp b/src/logid/InputDevice.cpp index 8bc93dc..131514c 100644 --- a/src/logid/InputDevice.cpp +++ b/src/logid/InputDevice.cpp @@ -56,6 +56,9 @@ InputDevice::InputDevice(const char* name) } } + for (unsigned int i = 0; i < REL_CNT; i++) + registered_axis[i] = false; + libevdev_enable_event_type(device, EV_REL); int err = libevdev_uinput_create_from_device(device, @@ -76,7 +79,7 @@ InputDevice::~InputDevice() void InputDevice::registerKey(uint code) { // TODO: Maybe print error message, if wrong code is passed? - if(registered_keys[code] || code > KEY_CNT) { + if(code >= KEY_CNT || registered_keys[code]) { return; } @@ -88,7 +91,7 @@ void InputDevice::registerKey(uint code) void InputDevice::registerAxis(uint axis) { // TODO: Maybe print error message, if wrong code is passed? - if(registered_axis[axis] || axis > REL_CNT) { + if(axis >= REL_CNT || registered_axis[axis]) { return; } diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index 98a6459..cfd2f8f 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -26,15 +26,61 @@ using namespace logid; using namespace logid::backend; +ReceiverNickname::ReceiverNickname( + const std::shared_ptr& manager) : + _nickname (manager->newReceiverNickname()), _manager (manager) +{ +} + +ReceiverNickname::operator std::string() const { + return std::to_string(_nickname); +} + +ReceiverNickname::~ReceiverNickname() +{ + if(auto manager = _manager.lock()) { + std::lock_guard lock(manager->_nick_lock); + manager->_receiver_nicknames.erase(_nickname); + } +} + +namespace logid { + class _Receiver : public Receiver { + public: + template + _Receiver(Args... args) : Receiver(std::forward(args)...) { } + }; +} + +std::shared_ptr Receiver::make( + const std::string &path, + const std::shared_ptr &manager) { + auto ret = std::make_shared<_Receiver>(path, manager); + ret->_self = ret; + ret->_ipc_node->manage(ret); + return ret; +} + + Receiver::Receiver(const std::string& path, const std::shared_ptr& manager) : dj::ReceiverMonitor(path, manager->config()->ioTimeout(), manager->workQueue()), - _path (path), _manager (manager) + _path (path), _manager (manager), _nickname (manager), + _ipc_node (manager->receiversNode()->make_child(_nickname)), + _ipc_interface (_ipc_node->make_interface(this)) { } +Receiver::~Receiver() +{ + if(auto manager = _manager.lock()) { + for(auto& d : _devices) + manager->removeExternalDevice(d.second); + } +} + void Receiver::addDevice(hidpp::DeviceConnectionEvent event) { std::unique_lock lock(_devices_change); @@ -77,10 +123,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) return; } - std::shared_ptr device = std::make_shared(this, - event.index, manager); - + auto device = Device::make(this, event.index, manager); _devices.emplace(event.index, device); + manager->addExternalDevice(device); } catch(hidpp10::Error &e) { logPrintf(ERROR, @@ -100,7 +145,12 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) void Receiver::removeDevice(hidpp::DeviceIndex index) { std::unique_lock lock(_devices_change); - _devices.erase(index); + auto device = _devices.find(index); + if(device != _devices.end()) { + if(auto manager = _manager.lock()) + manager->removeExternalDevice(device->second); + _devices.erase(device); + } } const std::string& Receiver::path() const @@ -111,4 +161,9 @@ const std::string& Receiver::path() const std::shared_ptr Receiver::rawReceiver() { return receiver(); -} \ No newline at end of file +} + +Receiver::ReceiverIPC::ReceiverIPC(Receiver *receiver) : + ipcgull::interface("pizza.pixl.LogiOps.Receiver", {}, {}, {}) +{ +} diff --git a/src/logid/Receiver.h b/src/logid/Receiver.h index 509113f..61c65c9 100644 --- a/src/logid/Receiver.h +++ b/src/logid/Receiver.h @@ -25,21 +25,55 @@ namespace logid { - class Receiver : public backend::dj::ReceiverMonitor + class ReceiverNickname { + public: + explicit ReceiverNickname(const std::shared_ptr& manager); + ReceiverNickname() = delete; + ReceiverNickname(const ReceiverNickname&) = delete; + ~ReceiverNickname(); + + operator std::string() const; + private: + const int _nickname; + const std::weak_ptr _manager; + }; + + class Receiver : public backend::dj::ReceiverMonitor, + public ipcgull::object { public: - explicit Receiver(const std::string& path, - const std::shared_ptr& manager); + ~Receiver(); + + static std::shared_ptr make( + const std::string& path, + const std::shared_ptr& manager); const std::string& path() const; std::shared_ptr rawReceiver(); protected: void addDevice(backend::hidpp::DeviceConnectionEvent event) override; void removeDevice(backend::hidpp::DeviceIndex index) override; private: + friend class _Receiver; + + Receiver(const std::string& path, + const std::shared_ptr& manager); + std::mutex _devices_change; std::map> _devices; std::string _path; std::weak_ptr _manager; + + const ReceiverNickname _nickname; + std::shared_ptr _ipc_node; + + class ReceiverIPC : public ipcgull::interface { + public: + ReceiverIPC(Receiver* receiver); + }; + + std::shared_ptr _ipc_interface; + + std::weak_ptr _self; }; } diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index 0352b1f..340fece 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "util/log.h" #include "DeviceManager.h" @@ -157,6 +158,19 @@ int main(int argc, char** argv) std::shared_ptr config; std::shared_ptr virtual_input; + auto server = ipcgull::make_server("pizza.pixl.LogiOps", + "/pizza/pixl/logiops", + ipcgull::IPCGULL_USER); + + std::thread( [server]() { + try { + server->start(); + } catch(ipcgull::connection_failed& e) { + logPrintf(ERROR, "Lost IPC connection, terminating."); + std::terminate(); + } + } ).detach(); + // Read config try { config = std::make_shared(options.config_file); @@ -174,9 +188,11 @@ int main(int argc, char** argv) } // Scan devices, create listeners, handlers, etc. - auto device_manager = DeviceManager::make(config, virtual_input); + auto device_manager = DeviceManager::make(config, virtual_input, server); device_manager->run(); + server->stop_sync(); + return EXIT_SUCCESS; } From 436729b07bb1e24e3bf834e8ac31540a3951876d Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 8 Jan 2022 16:29:17 -0500 Subject: [PATCH 05/59] Properly handle full workqueue --- src/logid/util/worker_thread.cpp | 3 ++- src/logid/util/worker_thread.h | 4 ++-- src/logid/util/workqueue.cpp | 39 +++++++++++++++++--------------- src/logid/util/workqueue.h | 12 +++++++--- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/logid/util/worker_thread.cpp b/src/logid/util/worker_thread.cpp index 116e991..81dda91 100644 --- a/src/logid/util/worker_thread.cpp +++ b/src/logid/util/worker_thread.cpp @@ -43,7 +43,7 @@ worker_thread::~worker_thread() } } -void worker_thread::queue(std::shared_ptr t) +void worker_thread::queue(const std::shared_ptr& t) { _queue.push(t); _queue_cv.notify_all(); @@ -74,6 +74,7 @@ void worker_thread::_run() _queue.front()->run(); _queue.pop(); } + _parent->notifyFree(); } } diff --git a/src/logid/util/worker_thread.h b/src/logid/util/worker_thread.h index 0c252e1..0dd53ca 100644 --- a/src/logid/util/worker_thread.h +++ b/src/logid/util/worker_thread.h @@ -32,7 +32,7 @@ namespace logid worker_thread(workqueue* parent, std::size_t worker_number); ~worker_thread(); - void queue(std::shared_ptr t); + void queue(const std::shared_ptr& t); bool busy(); private: @@ -40,7 +40,7 @@ namespace logid void _exception_handler(std::exception& e); workqueue* _parent; - std::size_t _worker_number; + const std::size_t _worker_number; std::mutex _run_lock; std::atomic _continue_run; diff --git a/src/logid/util/workqueue.cpp b/src/logid/util/workqueue.cpp index 2bf409d..44fb347 100644 --- a/src/logid/util/workqueue.cpp +++ b/src/logid/util/workqueue.cpp @@ -17,6 +17,7 @@ */ #include #include "workqueue.h" +#include "worker_thread.h" #include "log.h" using namespace logid; @@ -47,7 +48,7 @@ workqueue::~workqueue() } } -void workqueue::queue(std::shared_ptr t) +void workqueue::queue(const std::shared_ptr& t) { assert(t != nullptr); _queue.push(t); @@ -70,6 +71,11 @@ std::size_t workqueue::threadCount() const return _workers.size(); } +void workqueue::notifyFree() +{ + _busy_cv.notify_all(); +} + void workqueue::_run() { using namespace std::chrono_literals; @@ -77,6 +83,7 @@ void workqueue::_run() std::unique_lock lock(_run_lock); _continue_run = true; while(_continue_run) { + bool queued = false; _queue_cv.wait(lock, [this]{ return !(_queue.empty()); }); while(!_queue.empty()) { if(_workers.empty()) { @@ -88,33 +95,29 @@ void workqueue::_run() continue; } - auto worker = _workers.begin(); - for(; worker != _workers.end(); worker++) { - if(!(*worker)->busy()) + for(auto& worker : _workers) { + if(!worker->busy()) { + worker->queue(_queue.front()); + queued = true; break; + } } - if(worker != _workers.end()) - (*worker)->queue(_queue.front()); - else { - _busy_cv.wait_for(lock, 500ms, [this, &worker]{ - for(worker = _workers.begin(); worker != _workers.end(); - worker++) { - if (!(*worker)->busy()) { - return true; + if(!queued) { + if(_busy_cv.wait_for(lock, 500ms) == std::cv_status::no_timeout) { + for(auto& worker : _workers) { + if(!worker->busy()) { + worker->queue(_queue.front()); + break; } } - return false; - }); - - if(worker != _workers.end()) - (*worker)->queue(_queue.front()); - else{ + } else{ // Workers busy, launch in new thread logPrintf(DEBUG, "All workers were busy for 500ms, " "running task in new thread."); thread::spawn([t = _queue.front()]() { t->run(); }); } } + _queue.pop(); } } diff --git a/src/logid/util/workqueue.h b/src/logid/util/workqueue.h index b8191fd..39cb891 100644 --- a/src/logid/util/workqueue.h +++ b/src/logid/util/workqueue.h @@ -18,24 +18,30 @@ #ifndef LOGID_WORKQUEUE_H #define LOGID_WORKQUEUE_H -#include "worker_thread.h" +#include "mutex_queue.h" +#include "task.h" #include "thread.h" namespace logid { + class worker_thread; + class workqueue { public: explicit workqueue(std::size_t thread_count); ~workqueue(); - void queue(std::shared_ptr t); + void queue(const std::shared_ptr& t); void busyUpdate(); void stop(); - std::size_t threadCount() const; + [[nodiscard]] std::size_t threadCount() const; + + friend class worker_thread; + void notifyFree(); private: void _run(); From 9f4979ba597795c80f376f9bbc6e85fafaa237df Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 8 Jan 2022 21:04:13 -0500 Subject: [PATCH 06/59] Updated ipcgull version --- src/ipcgull | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipcgull b/src/ipcgull index 0d53465..73d837a 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 0d53465fe70ab07e07f9f9d853413a6cc82704c6 +Subproject commit 73d837add44f7524603557ee1819610dcc4a3037 From f23326c66038b06ba43c342f7fce6d2f8ca4be73 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 8 Jan 2022 22:32:49 -0500 Subject: [PATCH 07/59] Complete DeviceManager interface --- src/ipcgull | 2 +- src/logid/DeviceManager.cpp | 75 ++++++++++++++++++++++++++++--------- src/logid/DeviceManager.h | 12 +++++- src/logid/Receiver.cpp | 8 ++++ src/logid/Receiver.h | 7 +++- src/logid/logid.cpp | 2 +- 6 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index 73d837a..5f95b11 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 73d837add44f7524603557ee1819610dcc4a3037 +Subproject commit 5f95b1111ea2f3a6f8e2f0d60ccae12aebaa1a90 diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 2cc806f..a1b7978 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "DeviceManager.h" #include "Receiver.h" @@ -50,8 +51,8 @@ DeviceManager::DeviceManager(std::shared_ptr config, _device_node (ipcgull::node::make_root("devices")), _receiver_node (ipcgull::node::make_root("receivers")) { - _ipc_devices = _root_node->make_interface(); - _ipc_receivers = _root_node->make_interface(); + _ipc_devices = _root_node->make_interface(this); + _ipc_receivers = _root_node->make_interface(this); _device_node->add_server(_server); _receiver_node->add_server(_server); _root_node->add_server(_server); @@ -124,6 +125,7 @@ void DeviceManager::addDevice(std::string path) logPrintf(INFO, "Detected receiver at %s", path.c_str()); auto receiver = Receiver::make(path, _self.lock()); receiver->run(); + std::lock_guard lock(_map_lock); _receivers.emplace(path, receiver); _ipc_receivers->receiverAdded(receiver); } else { @@ -132,12 +134,14 @@ void DeviceManager::addDevice(std::string path) if(defaultExists) { auto device = Device::make(path, hidpp::DefaultDevice, _self.lock()); + std::lock_guard lock(_map_lock); _devices.emplace(path, device); _ipc_devices->deviceAdded(device); } else { try { auto device = Device::make(path, hidpp::CordedDevice, _self.lock()); + std::lock_guard lock(_map_lock); _devices.emplace(path, device); _ipc_devices->deviceAdded(device); } catch(hidpp10::Error &e) { @@ -167,8 +171,14 @@ void DeviceManager::removeExternalDevice(const std::shared_ptr &d) _ipc_devices->deviceRemoved(d); } +std::mutex& DeviceManager::mutex() const +{ + return _map_lock; +} + void DeviceManager::removeDevice(std::string path) { + std::lock_guard lock(_map_lock); auto receiver = _receivers.find(path); if(receiver != _receivers.end()) { @@ -185,55 +195,84 @@ void DeviceManager::removeDevice(std::string path) } } -DeviceManager::DevicesIPC::DevicesIPC() : ipcgull::interface( +DeviceManager::DevicesIPC::DevicesIPC(DeviceManager* manager) : +ipcgull::interface( "pizza.pixl.LogiOps.Devices", - {}, + { + {"Enumerate",{manager, &DeviceManager::listDevices,{"devices"}}} + }, {}, { - {"deviceAdded", + {"DeviceAdded", ipcgull::make_signal>( {"device"})}, - {"deviceRemoved", + {"DeviceRemoved", ipcgull::make_signal>( {"device"})} - } - ) + }) { } +std::vector> DeviceManager::listDevices() const +{ + std::lock_guard lock(_map_lock); + std::vector> devices; + for(auto& x : _devices) + devices.emplace_back(x.second); + for(auto& x : _receivers) { + for(auto& d : x.second->devices()) + devices.emplace_back(d.second); + } + + return devices; +} + +std::vector> DeviceManager::listReceivers() const +{ + std::lock_guard lock(_map_lock); + std::vector> receivers; + for(auto& x : _receivers) + receivers.emplace_back(x.second); + return receivers; +} + void DeviceManager::DevicesIPC::deviceAdded( const std::shared_ptr& d) { - emit_signal("deviceAdded", d); + emit_signal("DeviceAdded", d); } void DeviceManager::DevicesIPC::deviceRemoved( const std::shared_ptr& d) { - emit_signal("deviceRemoved", d); + emit_signal("DeviceRemoved", d); } -DeviceManager::ReceiversIPC::ReceiversIPC() : ipcgull::interface( +DeviceManager::ReceiversIPC::ReceiversIPC(DeviceManager* manager) : +ipcgull::interface( "pizza.pixl.LogiOps.Receivers", - {}, + { + {"Enumerate",{manager, &DeviceManager::listReceivers, + {"receivers"}}} + }, {}, { - {"receiverAdded", + {"ReceiverAdded", ipcgull::make_signal>( - {"device"})}, - {"receiverRemoved", + {"receiver"})}, + {"ReceiverRemoved", ipcgull::make_signal>( - {"device"})} + {"receiver"})} }) { } void DeviceManager::ReceiversIPC::receiverAdded( const std::shared_ptr& r) { - emit_signal("receiverAdded", r); + emit_signal("ReceiverAdded", r); } void DeviceManager::ReceiversIPC::receiverRemoved( const std::shared_ptr& r) { - emit_signal("receiverRemoved", r); + emit_signal("ReceiverRemoved", r); } int DeviceManager::newDeviceNickname() diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index 56e180e..8f67934 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -50,23 +50,29 @@ namespace logid void addExternalDevice(const std::shared_ptr& d); void removeExternalDevice(const std::shared_ptr& d); + + std::mutex& mutex() const; protected: void addDevice(std::string path) final; void removeDevice(std::string path) final; private: class DevicesIPC : public ipcgull::interface { public: - DevicesIPC(); + explicit DevicesIPC(DeviceManager* manager); void deviceAdded(const std::shared_ptr& d); void deviceRemoved(const std::shared_ptr& d); }; + [[nodiscard]] + std::vector> listDevices() const; class ReceiversIPC : public ipcgull::interface { public: - ReceiversIPC(); + explicit ReceiversIPC(DeviceManager* manager); void receiverAdded(const std::shared_ptr& r); void receiverRemoved(const std::shared_ptr& r); }; + [[nodiscard]] + std::vector> listReceivers() const; friend class _DeviceManager; DeviceManager(std::shared_ptr config, @@ -89,6 +95,8 @@ namespace logid std::map> _devices; std::map> _receivers; + mutable std::mutex _map_lock; + friend class DeviceNickname; friend class ReceiverNickname; diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index cfd2f8f..e4e487e 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -73,6 +73,10 @@ Receiver::Receiver(const std::string& path, { } +const Receiver::DeviceList& Receiver::devices() const { + return _devices; +} + Receiver::~Receiver() { if(auto manager = _manager.lock()) { @@ -124,6 +128,7 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) } auto device = Device::make(this, event.index, manager); + std::lock_guard manager_lock(manager->mutex()); _devices.emplace(event.index, device); manager->addExternalDevice(device); @@ -145,6 +150,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) void Receiver::removeDevice(hidpp::DeviceIndex index) { std::unique_lock lock(_devices_change); + std::unique_lock manager_lock; + if(auto manager = _manager.lock()) + manager_lock = std::unique_lock(manager->mutex()); auto device = _devices.find(index); if(device != _devices.end()) { if(auto manager = _manager.lock()) diff --git a/src/logid/Receiver.h b/src/logid/Receiver.h index 61c65c9..8022261 100644 --- a/src/logid/Receiver.h +++ b/src/logid/Receiver.h @@ -42,6 +42,9 @@ namespace logid public ipcgull::object { public: + typedef std::map> + DeviceList; + ~Receiver(); static std::shared_ptr make( @@ -49,6 +52,8 @@ namespace logid const std::shared_ptr& manager); const std::string& path() const; std::shared_ptr rawReceiver(); + + [[nodiscard]] const DeviceList& devices() const; protected: void addDevice(backend::hidpp::DeviceConnectionEvent event) override; void removeDevice(backend::hidpp::DeviceIndex index) override; @@ -59,7 +64,7 @@ namespace logid const std::shared_ptr& manager); std::mutex _devices_change; - std::map> _devices; + DeviceList _devices; std::string _path; std::weak_ptr _manager; diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index 340fece..b3ffcd6 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -159,7 +159,7 @@ int main(int argc, char** argv) std::shared_ptr virtual_input; auto server = ipcgull::make_server("pizza.pixl.LogiOps", - "/pizza/pixl/logiops", + "/pizza/pixl/LogiOps", ipcgull::IPCGULL_USER); std::thread( [server]() { From f93a8b694dc27bb104e8a2af53c155b1a2091c58 Mon Sep 17 00:00:00 2001 From: pixl Date: Sun, 23 Aug 2020 19:57:27 -0400 Subject: [PATCH 08/59] Implement profile support (cherry picked from commit 1aa6cd0224ebe4dc9ca72171728f7b500c624b65) --- src/logid/Device.cpp | 108 +++++++++++++++++++++++++++++++++++++++++-- src/logid/Device.h | 35 ++++++++------ 2 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 5bfd7f4..7e9befc 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -218,7 +218,7 @@ std::shared_ptr Device::virtualInput() const { } } -DeviceConfig& Device::config() +Device::Config& Device::config() { return _config; } @@ -248,7 +248,7 @@ Device::DeviceIPC::DeviceIPC(Device* device) : } -DeviceConfig::DeviceConfig(const std::shared_ptr& config, Device* +Device::Config::Config(const std::shared_ptr& config, Device* device) : _device (device), _config (config) { try { @@ -256,10 +256,110 @@ DeviceConfig::DeviceConfig(const std::shared_ptr& config, Device* } catch(Configuration::DeviceNotFound& e) { logPrintf(INFO, "Device %s not configured, using default config.", device->name().c_str()); + return; + } + + try { + auto& profiles = _config->getSetting(_root_setting + "/profiles"); + int profile_index = 0; + if(!profiles.isList()) { + logPrintf(WARN, "Line %d: profiles must be a list, defaulting to" + "old-style config", profiles.getSourceLine()); + } + + try { + auto& default_profile = _config->getSetting(_root_setting + + "/default_profile"); + if(default_profile.getType() == libconfig::Setting::TypeString) { + _profile_name = (const char*)default_profile; + } else if(default_profile.isNumber()) { + profile_index = default_profile; + } else { + logPrintf(WARN, "Line %d: default_profile must be a string or" + " integer, defaulting to first profile", + default_profile.getSourceLine()); + } + } catch(libconfig::SettingNotFoundException& e) { + logPrintf(INFO, "Line %d: default_profile missing, defaulting to " + "first profile", profiles.getSourceLine()); + } + + if(profiles.getLength() <= profile_index) { + if(profiles.getLength() == 0) { + logPrintf(WARN, "Line %d: No profiles defined", + profiles.getSourceLine()); + } else { + logPrintf(WARN, "Line %d: default_profile does not exist, " + "defaulting to first", + profiles.getSourceLine()); + profile_index = 0; + } + } + + for(int i = 0; i < profiles.getLength(); i++) { + const auto& profile = profiles[i]; + std::string name; + if(!profile.isGroup()) { + logPrintf(WARN, "Line %d: Profile must be a group, " + "skipping", profile.getSourceLine()); + continue; + } + + try { + const auto& name_setting = profile.lookup("name"); + if(name_setting.getType() != + libconfig::Setting::TypeString) { + logPrintf(WARN, "Line %d: Profile names must be " + "strings, using name \"%d\"", + name_setting.getSourceLine(), i); + name = std::to_string(i); + } else { + name = (const char *) name_setting; + } + + if(_profiles.find(name) != _profiles.end()) { + logPrintf(WARN, "Line %d: Profile with the same name " + "already exists, skipping.", + name_setting.getSourceLine()); + continue; + } + } catch(libconfig::SettingNotFoundException& e) { + logPrintf(INFO, "Line %d: Profile is unnamed, using name " + "\"%d\"", profile.getSourceLine(), i); + } + + if(i == profile_index && _profile_name.empty()) + _profile_root = profile.getPath(); + _profiles[name] = profile.getPath(); + } + + if(_profiles.empty()) { + _profile_name = "0"; + } + + if(_profile_root.empty()) + _profile_root = _profiles[_profile_name]; + } catch(libconfig::SettingNotFoundException& e) { + // No profiles, default to root + _profile_root = _root_setting; } } -libconfig::Setting& DeviceConfig::getSetting(const std::string& path) +libconfig::Setting& Device::Config::getSetting(const std::string& path) { - return _config->getSetting(_root_setting + '/' + path); + if(_profile_root.empty()) + throw libconfig::SettingNotFoundException((_root_setting + '/' + + path).c_str()); + return _config->getSetting(_profile_root + '/' + path); +} + +const std::map & Device::Config::getProfiles() const +{ + return _profiles; +} + +void Device::Config::setProfile(const std::string &name) +{ + _profile_name = name; + _profile_root = _profiles[name]; } diff --git a/src/logid/Device.h b/src/logid/Device.h index dcb1f53..4488157 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -47,29 +47,19 @@ namespace logid const std::weak_ptr _manager; }; - class DeviceConfig - { - public: - DeviceConfig(const std::shared_ptr& config, Device* - device); - libconfig::Setting& getSetting(const std::string& path); - private: - Device* _device; - std::string _root_setting; - std::shared_ptr _config; - }; - /* TODO: Implement HID++ 1.0 support * Currently, the logid::Device class has a hardcoded requirement * for an HID++ 2.0 device. */ class Device : public ipcgull::object { + private: + class Config; public: std::string name(); uint16_t pid(); - DeviceConfig& config(); + Config& config(); backend::hidpp20::Device& hidpp20(); static std::shared_ptr make( @@ -130,12 +120,29 @@ namespace logid } } + class Config + { + public: + Config(const std::shared_ptr& config, Device* + device); + libconfig::Setting& getSetting(const std::string& path); + const std::map& getProfiles() const; + void setProfile(const std::string& name); + private: + Device* _device; + std::string _root_setting; + std::string _profile_root; + std::string _profile_name; + std::map _profiles; + std::shared_ptr _config; + }; + backend::hidpp20::Device _hidpp20; std::string _path; backend::hidpp::DeviceIndex _index; std::map> _features; - DeviceConfig _config; + Config _config; Receiver* _receiver; const std::weak_ptr _manager; From 3c723dc3cf3fb1c4e8a2e09eb716965f44bdc32b Mon Sep 17 00:00:00 2001 From: pixl Date: Sun, 9 Jan 2022 21:49:09 -0500 Subject: [PATCH 09/59] Expand Device and RemapButton interface --- src/ipcgull | 2 +- src/logid/Device.cpp | 51 ++++++++++++++++++++++++++---- src/logid/Device.h | 9 ++++-- src/logid/features/RemapButton.cpp | 29 +++++++++++++++-- src/logid/features/RemapButton.h | 12 +++++++ 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index 5f95b11..ac4cd8f 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 5f95b1111ea2f3a6f8e2f0d60ccae12aebaa1a90 +Subproject commit ac4cd8f52eb6d632e885c2b1ed3eb4b310897800 diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 7e9befc..d93f3c8 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -104,7 +104,8 @@ Device::Device(std::string path, backend::hidpp::DeviceIndex index, _receiver (nullptr), _manager (manager), _nickname (manager), - _ipc_node(manager->devicesNode()->make_child(_nickname)) + _ipc_node(manager->devicesNode()->make_child(_nickname)), + _awake (ipcgull::property_readable, true) { _init(); } @@ -118,7 +119,8 @@ Device::Device(std::shared_ptr raw_device, _receiver (nullptr), _manager (manager), _nickname (manager), - _ipc_node (manager->devicesNode()->make_child(_nickname)) + _ipc_node (manager->devicesNode()->make_child(_nickname)), + _awake (ipcgull::property_readable, true) { _init(); } @@ -131,7 +133,8 @@ Device::Device(Receiver* receiver, hidpp::DeviceIndex index, _receiver (receiver), _manager (manager), _nickname (manager), - _ipc_node (manager->devicesNode()->make_child(_nickname)) + _ipc_node (manager->devicesNode()->make_child(_nickname)), + _awake (ipcgull::property_readable, true) { _init(); } @@ -171,11 +174,17 @@ uint16_t Device::pid() void Device::sleep() { - logPrintf(INFO, "%s:%d fell asleep.", _path.c_str(), _index); + std::lock_guard lock(_state_lock); + if(_awake) { + logPrintf(INFO, "%s:%d fell asleep.", _path.c_str(), _index); + _awake = false; + _ipc_interface->notifyStatus(); + } } void Device::wakeup() { + std::lock_guard lock(_state_lock); logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index); std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -183,6 +192,11 @@ void Device::wakeup() for(auto& feature: _features) feature.second->configure(); + + if(!_awake) { + _awake = true; + _ipc_interface->notifyStatus(); + } } void Device::reset() @@ -194,7 +208,8 @@ void Device::reset() "available.", _path.c_str(), _index); } -std::shared_ptr Device::workQueue() const { +std::shared_ptr Device::workQueue() const +{ if(auto manager = _manager.lock()) { return manager->workQueue(); } else { @@ -206,7 +221,8 @@ std::shared_ptr Device::workQueue() const { } } -std::shared_ptr Device::virtualInput() const { +std::shared_ptr Device::virtualInput() const +{ if(auto manager = _manager.lock()) { return manager->virtualInput(); } else { @@ -218,6 +234,11 @@ std::shared_ptr Device::virtualInput() const { } } +std::shared_ptr Device::ipcNode() const +{ + return _ipc_node; +} + Device::Config& Device::config() { return _config; @@ -243,9 +264,25 @@ void Device::_makeResetMechanism() } Device::DeviceIPC::DeviceIPC(Device* device) : - ipcgull::interface("pizza.pixl.LogiOps.Device", {}, {}, {}) + ipcgull::interface( + "pizza.pixl.LogiOps.Device", + {}, + { + {"Name", ipcgull::property( + ipcgull::property_readable, device->name())}, + {"ProductID", ipcgull::property( + ipcgull::property_readable, device->pid())}, + {"Active", device->_awake} + }, { + {"StatusChanged", + ipcgull::signal::make_signal({"active"})} + }), _device (*device) { +} +void Device::DeviceIPC::notifyStatus() const +{ + emit_signal("StatusChanged", (bool)(_device._awake)); } Device::Config::Config(const std::shared_ptr& config, Device* diff --git a/src/logid/Device.h b/src/logid/Device.h index 4488157..21b1e15 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -81,8 +81,8 @@ namespace logid void reset(); [[nodiscard]] std::shared_ptr workQueue() const; - [[nodiscard]] std::shared_ptr virtualInput() const; + [[nodiscard]] std::shared_ptr ipcNode() const; template std::shared_ptr getFeature(std::string name) { @@ -154,11 +154,16 @@ namespace logid std::shared_ptr _ipc_node; class DeviceIPC : public ipcgull::interface { + private: + Device& _device; public: DeviceIPC(Device* device); + void notifyStatus() const; }; - std::shared_ptr _ipc_interface; + ipcgull::property _awake; + std::mutex _state_lock; + std::shared_ptr _ipc_interface; std::weak_ptr _self; }; diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index a72fb4f..e019c46 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -29,7 +29,8 @@ using namespace logid::actions; #define EVENTHANDLER_NAME "REMAP_BUTTON" -RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev) +RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), + _ipc_node (dev->ipcNode()->make_child("buttons")) { try { _reprog_controls = hidpp20::ReprogControls::autoVersion( @@ -58,6 +59,14 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev) FLAG(MouseButton), ADDITIONAL_FLAG(RawXY)); #undef FLAG } + + for(const auto& control : _reprog_controls->getControls()) { + auto i = std::to_string(_button_ipcs.size()); + auto node = _ipc_node->make_child(i); + auto iface = node->make_interface(this, + control.second); + _button_ipcs.emplace_back(node, iface); + } } RemapButton::~RemapButton() @@ -206,4 +215,20 @@ void RemapButton::Config::_parseButton(libconfig::Setting &setting) const std::map>& RemapButton::Config::buttons() { return _buttons; -} \ No newline at end of file +} + + +RemapButton::ButtonIPC::ButtonIPC( + RemapButton *parent, + backend::hidpp20::ReprogControls::ControlInfo info) : + ipcgull::interface("pizza.pixl.LogiOps.Device.Button", {}, { + {"ControlID", ipcgull::property( + ipcgull::property_readable, info.controlID)}, + {"Remappable", ipcgull::property( + ipcgull::property_readable, info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, + {"GestureSupport", ipcgull::property( + ipcgull::property_readable, (info.additionalFlags & hidpp20::ReprogControls::RawXY) + )} + }, {}) +{ +} diff --git a/src/logid/features/RemapButton.h b/src/logid/features/RemapButton.h index f4aa4b6..1aa1425 100644 --- a/src/logid/features/RemapButton.h +++ b/src/logid/features/RemapButton.h @@ -44,11 +44,23 @@ namespace features std::map> _buttons; }; private: + class ButtonIPC : public ipcgull::interface + { + public: + ButtonIPC(RemapButton* parent, + backend::hidpp20::ReprogControls::ControlInfo info); + }; + void _buttonEvent(const std::set& new_state); Config _config; std::shared_ptr _reprog_controls; std::set _pressed_buttons; std::mutex _button_lock; + + std::shared_ptr _ipc_node; + typedef std::pair, + std::shared_ptr> ButtonIPCPair; + std::vector _button_ipcs; }; }} From 62095a3e37ccc292a3570a22957602a11f4979f9 Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 18:01:14 -0500 Subject: [PATCH 10/59] Require C++20 --- src/logid/CMakeLists.txt | 3 ++- src/logid/util/mutex_queue.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 45a9fd0..3fe8150 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.10) project(logid) -set(CMAKE_CXX_STANDARD 17) +# C++20 is only needed for string literal template parameters +set(CMAKE_CXX_STANDARD 20) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake") diff --git a/src/logid/util/mutex_queue.h b/src/logid/util/mutex_queue.h index 9efc927..95e6f8c 100644 --- a/src/logid/util/mutex_queue.h +++ b/src/logid/util/mutex_queue.h @@ -26,7 +26,7 @@ template class mutex_queue { public: - mutex_queue() = default; + mutex_queue() = default; bool empty() { std::lock_guard lock(_mutex); From fbc3a1a4722b5dd5af73b38049ebef9bacae8ffb Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 18:02:40 -0500 Subject: [PATCH 11/59] Added refined config struct templates --- src/logid/config/group.h | 206 ++++++++++++++++++++ src/logid/config/map.h | 46 +++++ src/logid/config/types.h | 398 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 650 insertions(+) create mode 100644 src/logid/config/group.h create mode 100644 src/logid/config/map.h create mode 100644 src/logid/config/types.h diff --git a/src/logid/config/group.h b/src/logid/config/group.h new file mode 100644 index 0000000..9179b16 --- /dev/null +++ b/src/logid/config/group.h @@ -0,0 +1,206 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 . + * + */ +#ifndef LOGID_CONFIG_GROUP_H +#define LOGID_CONFIG_GROUP_H + +#include +#include +#include +#include +#include "../util/log.h" + +namespace logid::config { + template + void set(libconfig::Setting& parent, + const std::string& name, + const T& t); + + template + void set(libconfig::Setting& parent, const T& t); + + template + T get(const libconfig::Setting& parent, const std::string& name); + + template + void append(libconfig::Setting& list, const T& t); + + namespace { + template + struct group_io { }; + + template + struct group_io { + static void get( + [[maybe_unused]] const libconfig::Setting& s, + [[maybe_unused]] T* t, + [[maybe_unused]] const std::vector& names, + [[maybe_unused]] const std::size_t index) { } + static void set( + [[maybe_unused]] libconfig::Setting& s, + [[maybe_unused]] const T* t, + [[maybe_unused]] const std::vector& names, + [[maybe_unused]] const std::size_t index) { } + }; + + template + struct group_io { + static void get( + const libconfig::Setting& s, T* t, + const std::vector& names, + const std::size_t index, A T::* arg, M T::*... rest) { + auto& x = t->*(arg); + A old {x}; + try { + x = config::get(s, names[index]); + group_io::get(s, t, names, index+1, rest...); + } catch(libconfig::SettingTypeException& e) { + x = old; + throw; + } catch(libconfig::SettingException& e) { + x = old; + throw libconfig::SettingTypeException(s); + } + } + + static void set( + libconfig::Setting& s, const T* t, + const std::vector& names, + const std::size_t index, A T::* arg, M T::*... rest) { + config::set(s, names[index], t->*(arg)); + group_io::set(s, t, names, index+1, rest...); + } + }; + } + + template + struct signed_group; + + struct group { + private: + const std::vector _names; + const std::function&)> _getter; + const std::function&)> _setter; + + template + friend struct signed_group; + protected: + template + group(const std::array& names, + M T::*... args) : + _names (names.begin(), names.end()), + _getter ([args...](const libconfig::Setting& s, group* g, + const std::vector& names) { + T* t = dynamic_cast(g); + group_io::get(s, t, names, 0, args...); + }), + _setter ([args...](libconfig::Setting& s, const group* g, + const std::vector& names) { + const T* t = dynamic_cast(g);; + group_io::set(s, t, names, 0, args...); + }) { + static_assert(std::is_base_of::value); + } + + group() : _getter ([](const libconfig::Setting&, group*, + const std::vector&) { }), + _setter ([](libconfig::Setting&, const group*, + const std::vector&) { }) { } + + public: + group(const group& o) = default; + group(group&& o) noexcept = default; + group& operator=(const group&) { + return *this; + } + group& operator=(group&&) noexcept { + return *this; + } + + virtual ~group() = default; + + virtual void save(libconfig::Setting& setting) const { + _setter(setting, this, _names); + } + + virtual void load(const libconfig::Setting& setting) { + _getter(setting, this, _names); + } + }; + + namespace { + template + struct normalize_signature { + static const T& make(const T& ret) { return ret; } + }; + + template <> + struct normalize_signature { + static std::string make(const std::string& data) { + std::string ret = data; + std::transform(ret.begin(), ret.end(), + ret.begin(), ::tolower); + return ret; + } + }; + } + + template + struct signed_group : public group { + private: + const std::string _sig_field; + const Sign _signature; + protected: + signed_group(std::string sign_name, const Sign& sign_data) : + group(), _sig_field (std::move(sign_name)), + _signature (normalize_signature::make(sign_data)) { } + + template + signed_group( + std::string sign_name, const Sign& sign_data, + const std::array& names, + M T::*... args) : group(names, args...), + _sig_field (std::move(sign_name)), + _signature (normalize_signature::make(sign_data)) { } + public: + signed_group(const signed_group& o) = default; + signed_group(signed_group&& o) noexcept = default; + signed_group& operator=(const signed_group&) { + return *this; + } + signed_group& operator=(signed_group&&) noexcept { + return *this; + } + + void save(libconfig::Setting& setting) const override { + set(setting, _signature, _sig_field); + _setter(setting, this, _names); + } + + void load(const libconfig::Setting& setting) override { + if(normalize_signature::make(get(setting, _sig_field)) + != _signature) + throw libconfig::SettingTypeException(setting); + _getter(setting, this, _names); + } + }; + +} + +#endif //LOGID_CONFIG_GROUP_H diff --git a/src/logid/config/map.h b/src/logid/config/map.h new file mode 100644 index 0000000..8543bc3 --- /dev/null +++ b/src/logid/config/map.h @@ -0,0 +1,46 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 . + * + */ +#ifndef LOGID_CONFIG_MAP_H +#define LOGID_CONFIG_MAP_H + +#include "group.h" +#include +#include +#include + +namespace logid::config { + template + struct string_literal { + constexpr string_literal(const char (&str)[N]) { + std::copy_n(str, N, value); + } + + char value[N]; + }; + + // Warning: map must be a variant of groups or a group + template + class map : public std::map { + public: + template + map(Args... args) : + std::map(std::forward(args)...) { } + }; +} + +#endif //LOGID_CONFIG_MAP_H diff --git a/src/logid/config/types.h b/src/logid/config/types.h new file mode 100644 index 0000000..a8a8393 --- /dev/null +++ b/src/logid/config/types.h @@ -0,0 +1,398 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 . + * + */ +#ifndef LOGID_CONFIG_PRIMITIVE_H +#define LOGID_CONFIG_PRIMITIVE_H + +#include +#include +#include +#include +#include "group.h" +#include "map.h" +#include "../util/log.h" + +/// TODO: A single element failing should not cause the container to be invalid. + +namespace logid::config { + namespace { + template + struct config_io { + static_assert(std::is_base_of::value); + + static T get(const libconfig::Setting& parent, + const std::string& name) { + T t {}; + t.load(parent.lookup(name)); + return t; + } + + static T get(const libconfig::Setting& setting) { + T t {}; + t.load(setting); + return t; + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + if(!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeGroup); + } else if(parent.lookup(name).getType() + != libconfig::Setting::TypeGroup) { + + } + t.save(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, const T& t) { + t.save(setting); + } + + static void append(libconfig::Setting& list, const T& t) { + auto& x = list.add(libconfig::Setting::TypeGroup); + set(x, t); + } + }; + + template + struct primitive_io { + static T get(const libconfig::Setting& parent, + const std::string& name) { + return parent.lookup(name); + } + + static T get(const libconfig::Setting& setting) { + return setting; + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + if(!parent.exists(name)) + parent.add(name, TypeEnum); + set(parent.lookup(name), t); + } + + static void set(libconfig::Setting& setting, const T& t) { + setting = t; + } + + static void append(libconfig::Setting& list, const T& t) { + auto& x = list.add(TypeEnum); + set(x, t); + } + }; + + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + + template + struct config_io> { + private: + template + static std::variant try_each( + const libconfig::Setting& setting) { + try { + return config_io::get(setting); + } catch(libconfig::SettingTypeException& e) { + throw; + } + } + + template + static std::variant try_each( + const libconfig::Setting& setting) { + try { + return config_io::get(setting); + } catch(libconfig::SettingException& e) { + return try_each(setting); + } + } + public: + static std::variant get(const libconfig::Setting& setting) { + return try_each(setting); + } + + static std::variant get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::variant& t) { + std::visit([&setting](auto&& arg){ + config::set(setting, arg); + }, t); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::variant& t) { + std::visit([&parent, &name](auto&& arg){ + config::set(parent, name, arg); + }, t); + } + + static void append(libconfig::Setting& list, + const std::variant& t) { + std::visit([&list](auto&& arg){ + config::append(list, arg); + }, t); + } + }; + + template + struct config_io> { + static std::vector get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::vector t(size); + for(int i = 0; i < size; ++i) + t[i] = config_io::get(setting[i]); + return t; + } + + static std::vector get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::vector& t) { + const auto orig_size = setting.getLength(); + for(int i = 0; i < orig_size; ++i) + config_io::set(setting[i], t[i]); + for(int i = orig_size; i < t.size(); ++i) + config_io::append(setting, t[i]); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::vector& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeArray); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeArray); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::vector& t) { + auto& s = list.add(libconfig::Setting::TypeArray); + set(s, t); + } + }; + + template + struct config_io> { + static map get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + map t; + for(int i = 0; i < size; ++i) { + auto& s = setting[i]; + t.emplace(config_io::get(s.lookup(KeyName.value)), + config_io::get(s)); + } + return t; + } + + static map get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const map& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + auto& s = setting.add(libconfig::Setting::TypeGroup); + config_io::set(s, x.second); + config_io::set(s, KeyName.value, x.first); + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const map& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const map& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io>> { + static std::vector> get( + const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::vector> t(size); + for(int i = 0; i < size; ++i) + t[i] = config_io>::get(setting[i]); + return t; + } + + static std::vector> get( + const libconfig::Setting& parent, const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::vector>& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(int i = 0; i < t.size(); ++i) + config_io>::append(setting, t[i]); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::vector>& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isList()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::variant>& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io> { + static std::optional get(const libconfig::Setting& parent, + const std::string& name) { + try { + return config_io::get(parent.lookup(name)); + } catch(libconfig::SettingException& e) { + return {}; + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::optional& t) { + if (t.has_value()) + config_io::set(parent, name, t.value()); + } + }; + + // Optionals may not appear as part of a list or array + template + struct config_io, Rest...>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + + template + struct config_io>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + + template + struct config_io>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + } + + template + void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + config_io::set(parent, name, t); + } + + template + void set(libconfig::Setting& setting, const T& t) { + config_io::set(setting, t); + } + + + template + void append(libconfig::Setting& list, const T& t) { + config_io::set(list, t); + } + + template + T get(const libconfig::Setting& setting) { + return config_io::get(setting); + } + + template + T get(const libconfig::Setting& parent, const std::string& name) { + return config_io::get(parent, name); + } +} + +#endif //LOGID_CONFIG_PRIMITIVE_H From c421affe2596afaac2c0e2959f1ff7507eeb8638 Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 20:33:26 -0500 Subject: [PATCH 12/59] Add config schema --- src/logid/config/schema.h | 181 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/logid/config/schema.h diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h new file mode 100644 index 0000000..cbf45a7 --- /dev/null +++ b/src/logid/config/schema.h @@ -0,0 +1,181 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 . + * + */ +#ifndef LOGID_CONFIG_SCHEMA_H +#define LOGID_CONFIG_SCHEMA_H + +#include "types.h" + +namespace logid::config { + struct NoAction : public signed_group { + NoAction() : signed_group("type", "None") { } + }; + + struct KeypressAction : public signed_group { + std::variant> keys; + KeypressAction() : signed_group( + "type", "Keypress", + {"keys"}, &KeypressAction::keys) { } + }; + + struct ToggleSmartShift : public signed_group { + ToggleSmartShift() : + signed_group("type", "ToggleSmartShift") { } + }; + + struct ToggleHiresScroll : public signed_group { + ToggleHiresScroll() : + signed_group("type", "ToggleHiresScroll") { } + }; + + struct CycleDPI : public signed_group { + std::vector dpis; + std::optional sensor; + CycleDPI() : signed_group( + "type", "CycleDPI", + {"dpis", "sensor"}, + &CycleDPI::dpis, + &CycleDPI::sensor) { } + }; + + struct ChangeDPI : public signed_group { + int inc; + std::optional sensor; + ChangeDPI() : signed_group( + "type", "ChangeDPI", + {"inc", "sensor"}, + &ChangeDPI::inc, + &ChangeDPI::sensor) { } + }; + + struct ChangeHost : public signed_group { + std::variant host; + ChangeHost() : signed_group( + "type", "ChangeHost", + {"host"}, &ChangeHost::host) { } + }; + + struct Gesture; + + struct GestureAction : public signed_group { + std::optional> _gestures; + + GestureAction() : signed_group( + "type", "Gestures") { } + }; + + typedef std::variant< + NoAction, + KeypressAction, + ToggleSmartShift, + ToggleHiresScroll, + CycleDPI, + ChangeDPI, + ChangeHost + > BasicAction; + + typedef std::variant< + NoAction, + KeypressAction, + ToggleSmartShift, + ToggleHiresScroll, + CycleDPI, + ChangeDPI, + ChangeHost, + GestureAction + > Action; + + struct Gesture : public group { + std::optional threshold; + std::optional mode; + std::optional axis; + std::optional axis_multiplier; + Action action; + + Gesture() : group( + {"threshold", "mode", "axis", "axis_multiplier"}, + &Gesture::threshold, + &Gesture::mode, + &Gesture::axis, + &Gesture::axis_multiplier + ) { } + }; + + struct Button : public group { + std::optional action; + Button() : group({"action"}, + &Button::action) { } + }; + + struct Smartshift : public group { + std::optional on; + std::optional threshold; + Smartshift() : group({"on", "threshold"}, + &Smartshift::on, &Smartshift::threshold) { } + }; + + + struct Hiresscroll : public group { + std::optional hires; + std::optional invert; + std::optional target; + Hiresscroll() : group({"hires", "invert", "target"}, + &Hiresscroll::hires, + &Hiresscroll::invert, + &Hiresscroll::target) { } + }; + + using DPI = std::variant>; + + + struct Profile : public group { + std::optional dpi; + std::optional smartshift; + std::optional> hiresscroll; + std::optional> buttons; + + Profile() : group({"dpi", "smartshift", "hiresscroll", "buttons"}, + &Profile::dpi, + &Profile::smartshift, + &Profile::hiresscroll, + &Profile::buttons) { } + }; + + struct Device : public group { + std::string default_profile; + map profiles; + + Device() : group({"default_profile", "profiles"}, + &Device::default_profile, + &Device::profiles) { } + }; + + struct Config : public group { + std::optional, "name">> devices; + std::optional> ignore; + std::optional io_timeout; + std::optional workers; + Config() : group({"devices", "ignore", "io_timeout", "workers"}, + &Config::devices, + &Config::ignore, + &Config::io_timeout, + &Config::workers) { } + }; +} + +#endif //LOGID_CONFIG_SCHEMA_H From 9b94fad0a6b840bb58a7470fe4f813e334389b29 Mon Sep 17 00:00:00 2001 From: pixl Date: Thu, 20 Jan 2022 01:29:18 -0500 Subject: [PATCH 13/59] Use new config interface --- src/ipcgull | 2 +- src/logid/Configuration.cpp | 167 +++---------- src/logid/Configuration.h | 33 +-- src/logid/Device.cpp | 152 +++--------- src/logid/Device.h | 28 +-- src/logid/DeviceManager.cpp | 15 +- src/logid/Receiver.cpp | 6 +- src/logid/actions/Action.cpp | 79 +++--- src/logid/actions/Action.h | 14 +- src/logid/actions/ChangeDPI.cpp | 52 +--- src/logid/actions/ChangeDPI.h | 15 +- src/logid/actions/ChangeHostAction.cpp | 85 ++----- src/logid/actions/ChangeHostAction.h | 14 +- src/logid/actions/CycleDPI.cpp | 82 +------ src/logid/actions/CycleDPI.h | 19 +- src/logid/actions/GestureAction.cpp | 197 ++++----------- src/logid/actions/GestureAction.h | 16 +- src/logid/actions/KeypressAction.cpp | 88 +++---- src/logid/actions/KeypressAction.h | 14 +- src/logid/actions/NullAction.h | 2 + src/logid/actions/ToggleHiresScroll.h | 3 + src/logid/actions/ToggleSmartShift.h | 3 + src/logid/actions/gesture/AxisGesture.cpp | 119 +++------ src/logid/actions/gesture/AxisGesture.h | 19 +- src/logid/actions/gesture/Gesture.cpp | 102 ++------ src/logid/actions/gesture/Gesture.h | 15 +- src/logid/actions/gesture/IntervalGesture.cpp | 64 ++--- src/logid/actions/gesture/IntervalGesture.h | 14 +- src/logid/actions/gesture/NullGesture.cpp | 11 +- src/logid/actions/gesture/NullGesture.h | 5 +- src/logid/actions/gesture/ReleaseGesture.cpp | 18 +- src/logid/actions/gesture/ReleaseGesture.h | 5 +- .../actions/gesture/ThresholdGesture.cpp | 24 +- src/logid/actions/gesture/ThresholdGesture.h | 5 +- src/logid/backend/dj/Receiver.cpp | 2 +- src/logid/backend/dj/Receiver.h | 2 +- src/logid/backend/dj/ReceiverMonitor.cpp | 2 +- src/logid/backend/dj/ReceiverMonitor.h | 2 +- src/logid/backend/hidpp/Device.cpp | 2 +- src/logid/backend/hidpp/Device.h | 2 +- src/logid/backend/hidpp10/Device.cpp | 2 +- src/logid/backend/hidpp10/Device.h | 2 +- src/logid/backend/hidpp20/Device.cpp | 3 +- src/logid/backend/hidpp20/Device.h | 3 +- src/logid/backend/raw/RawDevice.cpp | 5 +- src/logid/backend/raw/RawDevice.h | 2 +- src/logid/config/group.h | 8 +- src/logid/config/schema.h | 201 +++++++++++---- src/logid/config/types.h | 210 +++++++++------- src/logid/features/DPI.cpp | 68 ++---- src/logid/features/DPI.h | 13 +- src/logid/features/DeviceFeature.h | 9 - src/logid/features/DeviceStatus.cpp | 2 +- src/logid/features/HiresScroll.cpp | 228 ++++++------------ src/logid/features/HiresScroll.h | 29 +-- src/logid/features/RemapButton.cpp | 104 +++----- src/logid/features/RemapButton.h | 14 +- src/logid/features/SmartShift.cpp | 45 ++-- src/logid/features/SmartShift.h | 11 +- src/logid/features/ThumbWheel.cpp | 225 ++++++----------- src/logid/features/ThumbWheel.h | 38 +-- 61 files changed, 952 insertions(+), 1769 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index ac4cd8f..2255923 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit ac4cd8f52eb6d632e885c2b1ed3eb4b310897800 +Subproject commit 22559236d8c6e30aac640f79b8d4983467ba5cc8 diff --git a/src/logid/Configuration.cpp b/src/logid/Configuration.cpp index a5fad09..b87df91 100644 --- a/src/logid/Configuration.cpp +++ b/src/logid/Configuration.cpp @@ -25,154 +25,41 @@ using namespace logid; using namespace libconfig; -using namespace std::chrono; +using namespace logid::config; -Configuration::Configuration(const std::string& config_file) +Configuration::Configuration(const std::string& config_file) : + _config_file (config_file) { try { - _config.readFile(config_file.c_str()); + _config.readFile(_config_file); } catch(const FileIOException &e) { - logPrintf(ERROR, "I/O Error while reading %s: %s", config_file.c_str(), - e.what()); - throw e; + logPrintf(ERROR, "I/O Error while reading %s: %s", _config_file.c_str(), + e.what()); + throw; } catch(const ParseException &e) { logPrintf(ERROR, "Parse error in %s, line %d: %s", e.getFile(), - e.getLine(), e.getError()); - throw e; + e.getLine(), e.getError()); + throw; } - const Setting &root = _config.getRoot(); + Config::operator=(get(_config.getRoot())); + if(!devices.has_value()) + devices = decltype(config::Config::devices)(); +} + +void Configuration::save() +{ + config::set(_config.getRoot(), *this); try { - auto& worker_count = root["workers"]; - if(worker_count.getType() == Setting::TypeInt) { - _worker_threads = worker_count; - if(_worker_threads < 0) - logPrintf(WARN, "Line %d: workers cannot be negative.", - worker_count.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: workers must be an integer.", - worker_count.getSourceLine()); - } - } catch(const SettingNotFoundException& e) { - // Ignore + _config.writeFile(_config_file); + } catch(const FileIOException &e) { + logPrintf(ERROR, "I/O Error while writing %s: %s", + _config_file.c_str(), e.what()); + throw; + } catch(const std::exception& e) { + logPrintf(ERROR, "Error while writing %s: %s", + _config_file.c_str(), e.what()); + throw; } - - try { - auto& timeout = root["io_timeout"]; - if(timeout.isNumber()) { - if(timeout.getType() == Setting::TypeFloat) - _io_timeout = duration_cast( - duration(timeout)); - else - _io_timeout = milliseconds((int)timeout); - } else - logPrintf(WARN, "Line %d: io_timeout must be a number.", - timeout.getSourceLine()); - } catch(const SettingNotFoundException& e) { - // Ignore - } - - try { - auto& devices = root["devices"]; - - for(int i = 0; i < devices.getLength(); i++) { - const Setting& device = devices[i]; - std::string name; - try { - if(!device.lookupValue("name", name)) { - logPrintf(WARN, "Line %d: 'name' must be a string, skipping" - " device.", device["name"].getSourceLine()); - continue; - } - } catch(SettingNotFoundException &e) { - logPrintf(WARN, "Line %d: Missing name field, skipping device." - , device.getSourceLine()); - continue; - } - _device_paths.insert({name, device.getPath()}); - } - } - catch(const SettingNotFoundException &e) { - logPrintf(WARN, "No devices listed in config file."); - } - - try { - auto& ignore = root.lookup("ignore"); - if(ignore.getType() == libconfig::Setting::TypeInt) { - _ignore_list.insert((int)ignore); - } else if(ignore.isList() || ignore.isArray()) { - int ignore_count = ignore.getLength(); - for(int i = 0; i < ignore_count; i++) { - if(ignore[i].getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: ignore must refer to device PIDs", - ignore[i].getSourceLine()); - if(ignore.isArray()) - break; - } else - _ignore_list.insert((int)ignore[i]); - } - } - } catch(const SettingNotFoundException& e) { - // May be called blacklist - try { - auto& ignore = root.lookup("blacklist"); - if(ignore.getType() == libconfig::Setting::TypeInt) { - _ignore_list.insert((int)ignore); - } else if(ignore.isList() || ignore.isArray()) { - int ignore_count = ignore.getLength(); - for(int i = 0; i < ignore_count; i++) { - if(ignore[i].getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: blacklist must refer to " - "device PIDs", - ignore[i].getSourceLine()); - if(ignore.isArray()) - break; - } else - _ignore_list.insert((int)ignore[i]); - } - } - } catch(const SettingNotFoundException& e) { - // Ignore - } - } -} - -libconfig::Setting& Configuration::getSetting(const std::string& path) -{ - return _config.lookup(path); -} - -std::string Configuration::getDevice(const std::string& name) -{ - auto it = _device_paths.find(name); - if(it == _device_paths.end()) - throw DeviceNotFound(name); - else - return it->second; -} - -bool Configuration::isIgnored(uint16_t pid) const -{ - return _ignore_list.find(pid) != _ignore_list.end(); -} - -Configuration::DeviceNotFound::DeviceNotFound(std::string name) : - _name (std::move(name)) -{ -} - -const char * Configuration::DeviceNotFound::what() const noexcept -{ - return _name.c_str(); -} - -int Configuration::workerCount() const -{ - return _worker_threads; -} - -std::chrono::milliseconds Configuration::ioTimeout() const -{ - return _io_timeout; -} +} \ No newline at end of file diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index 8e63248..213d654 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -25,36 +25,27 @@ #include #include -#define LOGID_DEFAULT_IO_TIMEOUT std::chrono::milliseconds(400) -#define LOGID_DEFAULT_WORKER_COUNT 4 +#include "config/schema.h" namespace logid { - class Configuration + namespace defaults { + static constexpr double io_timeout = 500; + static constexpr int gesture_threshold = 50; + static constexpr int worker_count = 4; + } + + class Configuration : public config::Config { public: explicit Configuration(const std::string& config_file); Configuration() = default; - libconfig::Setting& getSetting(const std::string& path); - std::string getDevice(const std::string& name); - bool isIgnored(uint16_t pid) const; - class DeviceNotFound : public std::exception - { - public: - explicit DeviceNotFound(std::string name); - const char* what() const noexcept override; - private: - std::string _name; - }; - - std::chrono::milliseconds ioTimeout() const; - int workerCount() const; + // Reloading is not safe, references will be invalidated + //void reload(); + void save(); private: - std::map _device_paths; - std::set _ignore_list; - std::chrono::milliseconds _io_timeout = LOGID_DEFAULT_IO_TIMEOUT; - int _worker_threads = LOGID_DEFAULT_WORKER_COUNT; + std::string _config_file; libconfig::Config _config; }; diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index d93f3c8..2163e24 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -98,9 +98,10 @@ std::shared_ptr Device::make( Device::Device(std::string path, backend::hidpp::DeviceIndex index, std::shared_ptr manager) : _hidpp20 (path, index, - manager->config()->ioTimeout(), manager->workQueue()), + manager->config()->io_timeout.value_or(defaults::io_timeout), + manager->workQueue()), _path (std::move(path)), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (nullptr), _manager (manager), _nickname (manager), @@ -115,7 +116,7 @@ Device::Device(std::shared_ptr raw_device, std::shared_ptr manager) : _hidpp20(raw_device, index), _path (raw_device->hidrawPath()), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (nullptr), _manager (manager), _nickname (manager), @@ -129,7 +130,7 @@ Device::Device(Receiver* receiver, hidpp::DeviceIndex index, std::shared_ptr manager) : _hidpp20 (receiver->rawReceiver(), index), _path (receiver->path()), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (receiver), _manager (manager), _nickname (manager), @@ -144,6 +145,10 @@ void Device::_init() logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(), hidpp20().devicePath().c_str(), _index); + _profile = _config.profiles.find(_config.default_profile); + if(_profile == _config.profiles.end()) + _profile = _config.profiles.insert({_config.default_profile, {}}).first; + _addFeature("dpi"); _addFeature("smartshift"); _addFeature("hiresscroll"); @@ -239,9 +244,18 @@ std::shared_ptr Device::ipcNode() const return _ipc_node; } -Device::Config& Device::config() +/*config::Device& Device::config() { return _config; +}*/ + +config::Profile& Device::activeProfile() +{ + return _profile->second; +} +const config::Profile& Device::activeProfile() const +{ + return _profile->second; } hidpp20::Device& Device::hidpp20() @@ -285,118 +299,28 @@ void Device::DeviceIPC::notifyStatus() const emit_signal("StatusChanged", (bool)(_device._awake)); } -Device::Config::Config(const std::shared_ptr& config, Device* - device) : _device (device), _config (config) +config::Device& Device::_getConfig( + const std::shared_ptr& manager, + const std::string& name) { - try { - _root_setting = config->getDevice(device->name()); - } catch(Configuration::DeviceNotFound& e) { - logPrintf(INFO, "Device %s not configured, using default config.", - device->name().c_str()); - return; + static std::mutex config_mutex; + std::lock_guard lock(config_mutex); + auto& devices = manager->config()->devices; + if(!devices.has_value()) + devices = decltype(config::Config::devices)(); + auto& device = devices.value()[name]; + if(std::holds_alternative(device)) { + config::Device d; + d.profiles["default"] = std::get(device); + d.default_profile = "default"; + device = std::move(d); } - try { - auto& profiles = _config->getSetting(_root_setting + "/profiles"); - int profile_index = 0; - if(!profiles.isList()) { - logPrintf(WARN, "Line %d: profiles must be a list, defaulting to" - "old-style config", profiles.getSourceLine()); - } - - try { - auto& default_profile = _config->getSetting(_root_setting + - "/default_profile"); - if(default_profile.getType() == libconfig::Setting::TypeString) { - _profile_name = (const char*)default_profile; - } else if(default_profile.isNumber()) { - profile_index = default_profile; - } else { - logPrintf(WARN, "Line %d: default_profile must be a string or" - " integer, defaulting to first profile", - default_profile.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(INFO, "Line %d: default_profile missing, defaulting to " - "first profile", profiles.getSourceLine()); - } - - if(profiles.getLength() <= profile_index) { - if(profiles.getLength() == 0) { - logPrintf(WARN, "Line %d: No profiles defined", - profiles.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: default_profile does not exist, " - "defaulting to first", - profiles.getSourceLine()); - profile_index = 0; - } - } - - for(int i = 0; i < profiles.getLength(); i++) { - const auto& profile = profiles[i]; - std::string name; - if(!profile.isGroup()) { - logPrintf(WARN, "Line %d: Profile must be a group, " - "skipping", profile.getSourceLine()); - continue; - } - - try { - const auto& name_setting = profile.lookup("name"); - if(name_setting.getType() != - libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Profile names must be " - "strings, using name \"%d\"", - name_setting.getSourceLine(), i); - name = std::to_string(i); - } else { - name = (const char *) name_setting; - } - - if(_profiles.find(name) != _profiles.end()) { - logPrintf(WARN, "Line %d: Profile with the same name " - "already exists, skipping.", - name_setting.getSourceLine()); - continue; - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(INFO, "Line %d: Profile is unnamed, using name " - "\"%d\"", profile.getSourceLine(), i); - } - - if(i == profile_index && _profile_name.empty()) - _profile_root = profile.getPath(); - _profiles[name] = profile.getPath(); - } - - if(_profiles.empty()) { - _profile_name = "0"; - } - - if(_profile_root.empty()) - _profile_root = _profiles[_profile_name]; - } catch(libconfig::SettingNotFoundException& e) { - // No profiles, default to root - _profile_root = _root_setting; + auto& conf = std::get(device); + if(conf.profiles.empty()) { + conf.profiles["default"] = std::get(device); + conf.default_profile = "default"; } -} -libconfig::Setting& Device::Config::getSetting(const std::string& path) -{ - if(_profile_root.empty()) - throw libconfig::SettingNotFoundException((_root_setting + '/' + - path).c_str()); - return _config->getSetting(_profile_root + '/' + path); -} - -const std::map & Device::Config::getProfiles() const -{ - return _profiles; -} - -void Device::Config::setProfile(const std::string &name) -{ - _profile_name = name; - _profile_root = _profiles[name]; + return conf; } diff --git a/src/logid/Device.h b/src/logid/Device.h index 21b1e15..0c143d9 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -59,7 +59,9 @@ namespace logid std::string name(); uint16_t pid(); - Config& config(); + //config::Device& config(); + config::Profile& activeProfile(); + const config::Profile& activeProfile() const; backend::hidpp20::Device& hidpp20(); static std::shared_ptr make( @@ -108,6 +110,10 @@ namespace logid Device(Receiver* receiver, backend::hidpp::DeviceIndex index, std::shared_ptr manager); + static config::Device& _getConfig( + const std::shared_ptr& manager, + const std::string& name); + void _init(); /* Adds a feature without calling an error if unsupported */ @@ -120,29 +126,13 @@ namespace logid } } - class Config - { - public: - Config(const std::shared_ptr& config, Device* - device); - libconfig::Setting& getSetting(const std::string& path); - const std::map& getProfiles() const; - void setProfile(const std::string& name); - private: - Device* _device; - std::string _root_setting; - std::string _profile_root; - std::string _profile_name; - std::map _profiles; - std::shared_ptr _config; - }; - backend::hidpp20::Device _hidpp20; std::string _path; backend::hidpp::DeviceIndex _index; std::map> _features; - Config _config; + config::Device& _config; + std::map::iterator _profile; Receiver* _receiver; const std::weak_ptr _manager; diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index a1b7978..854df9d 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -44,7 +44,7 @@ namespace logid { DeviceManager::DeviceManager(std::shared_ptr config, std::shared_ptr virtual_input, std::shared_ptr server) : - backend::raw::DeviceMonitor(config->workerCount()), + backend::raw::DeviceMonitor(config->workers.value_or(defaults::worker_count)), _server (std::move(server)), _config (std::move(config)), _virtual_input (std::move(virtual_input)), _root_node (ipcgull::node::make_root("")), @@ -95,8 +95,11 @@ void DeviceManager::addDevice(std::string path) // Check if device is ignored before continuing { - raw::RawDevice raw_dev(path, config()->ioTimeout(), workQueue()); - if(config()->isIgnored(raw_dev.productId())) { + raw::RawDevice raw_dev( + path,config()->io_timeout.value_or(defaults::io_timeout), + workQueue()); + if(config()->ignore.has_value() && + config()->ignore.value().contains(raw_dev.productId())) { logPrintf(DEBUG, "%s: Device 0x%04x ignored.", path.c_str(), raw_dev.productId()); return; @@ -104,8 +107,10 @@ void DeviceManager::addDevice(std::string path) } try { - hidpp::Device device(path, hidpp::DefaultDevice, - config()->ioTimeout(), workQueue()); + hidpp::Device device( + path, hidpp::DefaultDevice, + config()->io_timeout.value_or(defaults::io_timeout), + workQueue()); isReceiver = device.version() == std::make_tuple(1, 0); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index e4e487e..cc1edaf 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -65,7 +65,8 @@ std::shared_ptr Receiver::make( Receiver::Receiver(const std::string& path, const std::shared_ptr& manager) : dj::ReceiverMonitor(path, - manager->config()->ioTimeout(), + manager->config()->io_timeout.value_or( + defaults::io_timeout), manager->workQueue()), _path (path), _manager (manager), _nickname (manager), _ipc_node (manager->receiversNode()->make_child(_nickname)), @@ -99,7 +100,8 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) try { // Check if device is ignored before continuing - if(manager->config()->isIgnored(event.pid)) { + if(manager->config()->ignore.value_or( + std::set()).contains(event.pid)) { logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.", _path.c_str(), event.index, event.pid); return; diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index ecac552..b93a28e 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -18,7 +18,6 @@ #include #include "Action.h" -#include "../util/log.h" #include "KeypressAction.h" #include "ToggleSmartShift.h" #include "ToggleHiresScroll.h" @@ -31,49 +30,39 @@ using namespace logid; using namespace logid::actions; -std::shared_ptr Action::makeAction(Device *device, libconfig::Setting - &setting) +template +struct action_type { + typedef typename T::action type; +}; + +template +struct action_type : action_type { }; + +template +struct action_type : action_type { }; + +template +std::shared_ptr _makeAction(Device* device, + T action) { + return std::make_shared::type>(device, action); +} + +std::shared_ptr Action::makeAction(Device *device, + config::BasicAction& action) { - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: Action is not a group, ignoring.", - setting.getSourceLine()); - throw InvalidAction(); - } + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeAction(device, x); + }, action); + return ret; +} - try { - auto& action_type = setting.lookup("type"); - - if(action_type.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Action type must be a string", - action_type.getSourceLine()); - throw InvalidAction(); - } - - std::string type = action_type; - std::transform(type.begin(), type.end(), type.begin(), ::tolower); - - if(type == "keypress") - return std::make_shared(device, setting); - else if(type == "togglesmartshift") - return std::make_shared(device); - else if(type == "togglehiresscroll") - return std::make_shared(device); - else if(type == "gestures") - return std::make_shared(device, setting); - else if(type == "cycledpi") - return std::make_shared(device, setting); - else if(type == "changedpi") - return std::make_shared(device, setting); - else if(type == "none") - return std::make_shared(device); - else if(type == "changehost") - return std::make_shared(device, setting); - else - throw InvalidAction(type); - - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: Action type is missing, ignoring.", - setting.getSourceLine()); - throw InvalidAction(); - } -} \ No newline at end of file +std::shared_ptr Action::makeAction(Device *device, + config::Action& action) +{ + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeAction(device, x); + }, action); + return ret; +} diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index 46024ee..34393d8 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -21,6 +21,7 @@ #include #include #include +#include "../config/schema.h" namespace logid { class Device; @@ -46,7 +47,10 @@ namespace actions { { public: static std::shared_ptr makeAction(Device* device, - libconfig::Setting& setting); + config::BasicAction& action); + + static std::shared_ptr makeAction(Device* device, + config::Action& action); virtual void press() = 0; virtual void release() = 0; @@ -65,14 +69,6 @@ namespace actions { virtual ~Action() = default; - class Config - { - protected: - explicit Config(Device* device) : _device (device) - { - } - Device* _device; - }; protected: explicit Action(Device* device) : _device (device), _pressed (false) { diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index 3929fbc..7eee2c9 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -24,8 +24,8 @@ using namespace logid::actions; -ChangeDPI::ChangeDPI(Device *device, libconfig::Setting &setting) : - Action(device), _config(device, setting) +ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) : + Action(device), _config (config) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -42,15 +42,16 @@ void ChangeDPI::press() task::spawn(_device->workQueue(), [this]{ try { - uint16_t last_dpi = _dpi->getDPI(_config.sensor()); - _dpi->setDPI(last_dpi + _config.interval(), _config.sensor()); + uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0)); + _dpi->setDPI(last_dpi + _config.inc, + _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) logPrintf(WARN, "%s:%d: Could not get/set DPI for sensor " "%d", _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex(), - _config.sensor()); + _config.sensor.value_or(0)); else throw e; } @@ -67,44 +68,3 @@ uint8_t ChangeDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeDPI::Config::Config(Device *device, libconfig::Setting &config) : - Action::Config(device), _interval (0), _sensor (0) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto& inc = config.lookup("inc"); - if(inc.getType() != libconfig::Setting::TypeInt) - logPrintf(WARN, "Line %d: inc must be an integer", - inc.getSourceLine()); - _interval = (int)inc; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: inc is a required field, skipping.", - config.getSourceLine()); - } - - try { - auto& sensor = config.lookup("sensor"); - if(sensor.getType() != libconfig::Setting::TypeInt) - logPrintf(WARN, "Line %d: sensor must be an integer", - sensor.getSourceLine()); - _sensor = (int)sensor; - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } -} - -uint16_t ChangeDPI::Config::interval() const -{ - return _interval; -} - -uint8_t ChangeDPI::Config::sensor() const -{ - return _sensor; -} \ No newline at end of file diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h index 4d9e04f..f5d33e8 100644 --- a/src/logid/actions/ChangeDPI.h +++ b/src/logid/actions/ChangeDPI.h @@ -27,26 +27,15 @@ namespace logid { class ChangeDPI : public Action { public: - explicit ChangeDPI(Device* device, libconfig::Setting& setting); + explicit ChangeDPI(Device* device, config::ChangeDPI& setting); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint16_t interval() const; - uint8_t sensor() const; - private: - uint16_t _interval; - uint8_t _sensor; - }; - protected: - Config _config; + config::ChangeDPI& _config; std::shared_ptr _dpi; }; }} diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index 84c3375..0b87507 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -24,9 +24,14 @@ using namespace logid::actions; using namespace logid::backend; -ChangeHostAction::ChangeHostAction(Device *device, libconfig::Setting& -config) : Action(device), _config (device, config) +ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config) + : Action(device), _config (config) { + if(std::holds_alternative(_config.host)) { + auto& host = std::get(_config.host); + std::transform(host.begin(), host.end(), + host.begin(), ::tolower); + } try { _change_host = std::make_shared(&device->hidpp20()); } catch (hidpp20::UnsupportedFeature& e) { @@ -47,9 +52,21 @@ void ChangeHostAction::release() task::spawn(_device->workQueue(), [this] { auto host_info = _change_host->getHostInfo(); - auto next_host = _config.nextHost(host_info); + int next_host; + if(std::holds_alternative(_config.host)) { + const auto& host = std::get(_config.host); + if(host == "next") + next_host = host_info.currentHost + 1; + else if(host == "prev" || host == "previous") + next_host = host_info.currentHost - 1; + else + next_host = host_info.currentHost; + } else { + next_host = std::get(_config.host)-1; + } + next_host %= host_info.hostCount; if(next_host != host_info.currentHost) - _change_host->setHost(next_host); + _change_host->setHost(next_host-1); }); } } @@ -58,63 +75,3 @@ uint8_t ChangeHostAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeHostAction::Config::Config(Device *device, libconfig::Setting& config) - : Action::Config(device) -{ - try { - auto& host = config.lookup("host"); - if(host.getType() == libconfig::Setting::TypeInt) { - _offset = false; - _host = host; - _host--; // hosts are one-indexed in config - - if(_host < 0) { - logPrintf(WARN, "Line %d: host must be positive.", - host.getSourceLine()); - _offset = true; - _host = 0; - } - - } else if(host.getType() == libconfig::Setting::TypeString) { - _offset = true; - std::string hostmode = host; - std::transform(hostmode.begin(), hostmode.end(), - hostmode.begin(), ::tolower); - - if(hostmode == "next") - _host = 1; - else if(hostmode == "prev" || hostmode == "previous") - _host = -1; - else { - logPrintf(WARN, "Line %d: host must equal an integer, 'next'," - "or 'prev'.", host.getSourceLine()); - _host = 0; - } - } else { - logPrintf(WARN, "Line %d: host must equal an integer, 'next'," - "or 'prev'.", host.getSourceLine()); - _offset = true; - _host = 0; - } - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: host is a required field, skipping.", - config.getSourceLine()); - _offset = true; - _host = 0; - } -} - -uint8_t ChangeHostAction::Config::nextHost(hidpp20::ChangeHost::HostInfo info) -{ - if(_offset) { - return (info.currentHost + _host) % info.hostCount; - } else { - if(_host >= info.hostCount || _host < 0) { - logPrintf(WARN, "No such host %d, defaulting to current.", - _host+1); - return info.currentHost; - } else - return _host; - } -} \ No newline at end of file diff --git a/src/logid/actions/ChangeHostAction.h b/src/logid/actions/ChangeHostAction.h index 4466a62..6c293d9 100644 --- a/src/logid/actions/ChangeHostAction.h +++ b/src/logid/actions/ChangeHostAction.h @@ -28,26 +28,16 @@ namespace actions class ChangeHostAction : public Action { public: - ChangeHostAction(Device* device, libconfig::Setting& config); + ChangeHostAction(Device* device, config::ChangeHost& config); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint8_t nextHost(backend::hidpp20::ChangeHost::HostInfo info); - private: - bool _offset; - int _host; - }; - protected: std::shared_ptr _change_host; - Config _config; + config::ChangeHost& _config; }; }} diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index a5b33c7..499e29d 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -25,8 +25,8 @@ using namespace logid::actions; using namespace libconfig; -CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) : - Action (device), _config (device, setting) +CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) : + Action (device), _config (config), _current_dpi (_config.dpis.begin()) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -39,18 +39,21 @@ CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) : void CycleDPI::press() { _pressed = true; - if(_dpi && !_config.empty()) { + if(_dpi && !_config.dpis.empty()) { task::spawn(_device->workQueue(), [this](){ - uint16_t dpi = _config.nextDPI(); + std::lock_guard lock(_dpi_lock); + ++_current_dpi; + if(_current_dpi == _config.dpis.end()) + _current_dpi = _config.dpis.begin(); try { - _dpi->setDPI(dpi, _config.sensor()); + _dpi->setDPI(*_current_dpi, _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) logPrintf(WARN, "%s:%d: Could not set DPI to %d for " "sensor %d", _device->hidpp20().devicePath().c_str(), - _device->hidpp20().deviceIndex(), dpi, - _config.sensor()); + _device->hidpp20().deviceIndex(), *_current_dpi, + _config.sensor.value_or(0)); else throw e; } @@ -67,68 +70,3 @@ uint8_t CycleDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -CycleDPI::Config::Config(Device *device, libconfig::Setting &config) : - Action::Config(device), _current_index (0), _sensor (0) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto& sensor = config.lookup("sensor"); - if(sensor.getType() != Setting::TypeInt) - logPrintf(WARN, "Line %d: sensor must be an integer", - sensor.getSourceLine()); - _sensor = (int)sensor; - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } - - try { - auto& dpis = config.lookup("dpis"); - if(!dpis.isList() && !dpis.isArray()) { - logPrintf(WARN, "Line %d: dpis must be a list or array, skipping.", - dpis.getSourceLine()); - return; - } - - int dpi_count = dpis.getLength(); - for(int i = 0; i < dpi_count; i++) { - if(dpis[i].getType() != Setting::TypeInt) { - logPrintf(WARN, "Line %d: dpis must be integers, skipping.", - dpis[i].getSourceLine()); - if(dpis.isList()) - continue; - else - break; - } - - _dpis.push_back((int)(dpis[i])); - } - - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: dpis is a required field, skipping.", - config.getSourceLine()); - } -} - -uint16_t CycleDPI::Config::nextDPI() -{ - uint16_t dpi = _dpis[_current_index++]; - if(_current_index >= _dpis.size()) - _current_index = 0; - return dpi; -} - -bool CycleDPI::Config::empty() const -{ - return _dpis.empty(); -} - -uint8_t CycleDPI::Config::sensor() const -{ - return _sensor; -} \ No newline at end of file diff --git a/src/logid/actions/CycleDPI.h b/src/logid/actions/CycleDPI.h index b6a5017..6f9d482 100644 --- a/src/logid/actions/CycleDPI.h +++ b/src/logid/actions/CycleDPI.h @@ -27,29 +27,18 @@ namespace actions { class CycleDPI : public Action { public: - explicit CycleDPI(Device* device, libconfig::Setting& setting); + explicit CycleDPI(Device* device, config::CycleDPI& setting); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint16_t nextDPI(); - bool empty() const; - uint8_t sensor() const; - private: - std::size_t _current_index; - std::vector _dpis; - uint8_t _sensor; - }; - protected: - Config _config; + std::mutex _dpi_lock; + config::CycleDPI& _config; std::shared_ptr _dpi; + std::list::const_iterator _current_dpi; }; }} diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index f364a32..e85fc46 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -54,16 +54,28 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y) return x <= -y ? Up : Right; } -GestureAction::GestureAction(Device* dev, libconfig::Setting& config) : - Action (dev), _config (dev, config) +GestureAction::GestureAction(Device* dev, config::GestureAction& config) : + Action (dev), _config (config) { + if(_config.gestures.has_value()) { + auto& gestures = _config.gestures.value(); + for(auto& x : gestures) { + try { + auto direction = toDirection(x.first); + _gestures.emplace(direction, + Gesture::makeGesture(dev, x.second)); + } catch(std::invalid_argument& e) { + logPrintf(WARN, "%s is not a direction", x.first.c_str()); + } + } + } } void GestureAction::press() { _pressed = true; _x = 0, _y = 0; - for(auto& gesture : _config.gestures()) + for(auto& gesture : _gestures) gesture.second->press(); } @@ -73,13 +85,13 @@ void GestureAction::release() bool threshold_met = false; auto d = toDirection(_x, _y); - auto primary_gesture = _config.gestures().find(d); - if(primary_gesture != _config.gestures().end()) { + auto primary_gesture = _gestures.find(d); + if(primary_gesture != _gestures.end()) { threshold_met = primary_gesture->second->metThreshold(); primary_gesture->second->release(true); } - for(auto& gesture : _config.gestures()) { + for(auto& gesture : _gestures) { if(gesture.first == d) continue; if(!threshold_met) { @@ -96,10 +108,13 @@ void GestureAction::release() } if(!threshold_met) { - if(_config.noneAction()) { - _config.noneAction()->press(); - _config.noneAction()->release(); - } + try { + auto none = _gestures.at(None); + if(none) { + none->press(); + none->release(); + } + } catch(std::out_of_range& e) { } } } @@ -109,60 +124,60 @@ void GestureAction::move(int16_t x, int16_t y) if(abs(x) > 0) { if(_x < 0 && new_x >= 0) { // Left -> Origin/Right - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(_x); if(new_x) { // Ignore to origin - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(new_x); } } else if(_x > 0 && new_x <= 0) { // Right -> Origin/Left - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(-_x); if(new_x) { // Ignore to origin - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(-new_x); } } else if(new_x < 0) { // Origin/Left to Left - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(-x); } else if(new_x > 0) { // Origin/Right to Right - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(x); } } if(abs(y) > 0) { if(_y > 0 && new_y <= 0) { // Up -> Origin/Down - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(_y); if(new_y) { // Ignore to origin - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(new_y); } } else if(_y < 0 && new_y >= 0) { // Down -> Origin/Up - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(-_y); if(new_y) { // Ignore to origin - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(-new_y); } } else if(new_y < 0) { // Origin/Up to Up - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(-y); } else if(new_y > 0) {// Origin/Down to Down - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(y); } } @@ -175,117 +190,3 @@ uint8_t GestureAction::reprogFlags() const return (hidpp20::ReprogControls::TemporaryDiverted | hidpp20::ReprogControls::RawXYDiverted); } - -GestureAction::Config::Config(Device* device, libconfig::Setting &root) : - Action::Config(device) -{ - try { - auto& gestures = root.lookup("gestures"); - - if(!gestures.isList()) { - logPrintf(WARN, "Line %d: gestures must be a list, ignoring.", - gestures.getSourceLine()); - return; - } - - int gesture_count = gestures.getLength(); - - for(int i = 0; i < gesture_count; i++) { - if(!gestures[i].isGroup()) { - logPrintf(WARN, "Line %d: gesture must be a group, skipping.", - gestures[i].getSourceLine()); - continue; - } - - Direction d; - try { - auto& direction = gestures[i].lookup("direction"); - if(direction.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: direction must be a string, " - "skipping.", direction.getSourceLine()); - continue; - } - - try { - d = toDirection(direction); - } catch(std::invalid_argument& e) { - logPrintf(WARN, "Line %d: Invalid direction %s", - direction.getSourceLine(), (const char*)direction); - continue; - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: direction is a required field, " - "skipping.", gestures[i].getSourceLine()); - continue; - } - - if(_gestures.find(d) != _gestures.end() || (d == None && _none_action)) { - logPrintf(WARN, "Line %d: Gesture is already defined for " - "this direction, duplicate ignored.", - gestures[i].getSourceLine()); - continue; - } - - if(d == None) { - try { - auto& mode = gestures[i].lookup("mode"); - if(mode.getType() == libconfig::Setting::TypeString) { - std::string mode_str = mode; - std::transform(mode_str.begin(), mode_str.end(), - mode_str.begin(), ::tolower); - if(mode_str == "nopress") // No action - continue; - else if(mode_str != "onrelease") - logPrintf(WARN, "Line %d: Only NoPress and " - "OnRelease are supported for the " - "None direction, defaulting to " - "OnRelease.", mode.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: mode must be a string, " - "defaulting to OnRelease", - mode.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // Default to OnRelease - } - - try { - _none_action = Action::makeAction(_device, - gestures[i].lookup("action")); - } catch (InvalidAction& e) { - logPrintf(WARN, "Line %d: %s is not a valid action, " - "skipping.", gestures[i].lookup("action") - .getSourceLine(), e.what()); - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: action is a required field, " - "skipping.", gestures[i].getSourceLine(), - e.what()); - } - continue; - } - - try { - _gestures.emplace(d, Gesture::makeGesture(_device, - gestures[i])); - } catch(InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid gesture: %s", - gestures[i].getSourceLine(), e.what()); - } - } - - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: gestures is a required field, ignoring.", - root.getSourceLine()); - } -} - -std::map>& - GestureAction::Config::gestures() -{ - return _gestures; -} - -std::shared_ptr GestureAction::Config::noneAction() -{ - return _none_action; -} \ No newline at end of file diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index 3928f75..1dff30b 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -39,7 +39,7 @@ namespace actions { static Direction toDirection(std::string direction); static Direction toDirection(int16_t x, int16_t y); - GestureAction(Device* dev, libconfig::Setting& config); + GestureAction(Device* dev, config::GestureAction& config); virtual void press(); virtual void release(); @@ -47,20 +47,10 @@ namespace actions { virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& root); - std::map>& gestures(); - std::shared_ptr noneAction(); - protected: - std::map> _gestures; - std::shared_ptr _none_action; - }; - protected: int16_t _x, _y; - Config _config; + std::map> _gestures; + config::GestureAction& _config; }; }} diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index caa004c..c55317f 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -24,22 +24,57 @@ using namespace logid::actions; using namespace logid::backend; -KeypressAction::KeypressAction(Device *device, libconfig::Setting& config) : - Action(device), _config (device, config) +KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : + Action(device), _config (config) { + if(std::holds_alternative(_config.keys)) { + const auto& key = std::get(_config.keys); + try { + auto code = _device->virtualInput()->toKeyCode(key); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid keycode %s, skipping.", key.c_str()); + } + } else if(std::holds_alternative(_config.keys)) { + const auto& key = std::get(_config.keys); + _device->virtualInput()->registerKey(key); + _keys.emplace_back(key); + } else if(std::holds_alternative>>(_config.keys)) { + const auto& keys = std::get>>( + _config.keys); + for(const auto& key : keys) { + if(std::holds_alternative(_config.keys)) { + const auto& key_str = std::get(key); + try { + auto code = _device->virtualInput()->toKeyCode(key_str); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid keycode %s, skipping.", + key_str.c_str()); + } + } else if(std::holds_alternative(_config.keys)) { + auto& code = std::get(_config.keys); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } + } + } } void KeypressAction::press() { _pressed = true; - for(auto& key : _config.keys()) + for(auto& key : _keys) _device->virtualInput()->pressKey(key); } void KeypressAction::release() { _pressed = false; - for(auto& key : _config.keys()) + for(auto& key : _keys) _device->virtualInput()->releaseKey(key); } @@ -47,48 +82,3 @@ uint8_t KeypressAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -KeypressAction::Config::Config(Device* device, libconfig::Setting& config) : - Action::Config(device) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto &keys = config.lookup("keys"); - if(keys.isArray() || keys.isList()) { - int key_count = keys.getLength(); - for(int i = 0; i < key_count; i++) { - auto& key = keys[i]; - if(key.isNumber()) { - _keys.push_back(key); - _device->virtualInput()->registerKey(key); - } else if(key.getType() == libconfig::Setting::TypeString) { - try { - _keys.push_back( - _device->virtualInput()->toKeyCode(key)); - _device->virtualInput()->registerKey( - _device->virtualInput()->toKeyCode(key)); - } catch(InputDevice::InvalidEventCode& e) { - logPrintf(WARN, "Line %d: Invalid keycode %s, skipping." - , key.getSourceLine(), key.c_str()); - } - } else { - logPrintf(WARN, "Line %d: keycode must be string or int", - key.getSourceLine(), key.c_str()); - } - } - } - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: keys is a required field, skipping.", - config.getSourceLine()); - } -} - -std::vector& KeypressAction::Config::keys() -{ - return _keys; -} \ No newline at end of file diff --git a/src/logid/actions/KeypressAction.h b/src/logid/actions/KeypressAction.h index 4385faf..5ac09d6 100644 --- a/src/logid/actions/KeypressAction.h +++ b/src/logid/actions/KeypressAction.h @@ -27,23 +27,15 @@ namespace actions { class KeypressAction : public Action { public: - KeypressAction(Device* dev, libconfig::Setting& config); + KeypressAction(Device* dev, config::KeypressAction& config); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - - class Config : public Action::Config - { - public: - explicit Config(Device* device, libconfig::Setting& root); - std::vector& keys(); - protected: - std::vector _keys; - }; protected: - Config _config; + config::KeypressAction& _config; + std::list _keys; }; }} diff --git a/src/logid/actions/NullAction.h b/src/logid/actions/NullAction.h index 2d2d0ef..24f169b 100644 --- a/src/logid/actions/NullAction.h +++ b/src/logid/actions/NullAction.h @@ -27,6 +27,8 @@ namespace actions { public: explicit NullAction(Device* device); + NullAction(Device* device, [[maybe_unused]] config::NoAction& config) : + NullAction(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/ToggleHiresScroll.h b/src/logid/actions/ToggleHiresScroll.h index bd60f71..52c41c6 100644 --- a/src/logid/actions/ToggleHiresScroll.h +++ b/src/logid/actions/ToggleHiresScroll.h @@ -28,6 +28,9 @@ namespace actions { public: explicit ToggleHiresScroll(Device* dev); + ToggleHiresScroll(Device* device, + [[maybe_unused]] config::ToggleHiresScroll& action) : + ToggleHiresScroll(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/ToggleSmartShift.h b/src/logid/actions/ToggleSmartShift.h index 7884f48..90c0025 100644 --- a/src/logid/actions/ToggleSmartShift.h +++ b/src/logid/actions/ToggleSmartShift.h @@ -28,6 +28,9 @@ namespace actions { { public: explicit ToggleSmartShift(Device* dev); + ToggleSmartShift(Device* device, + [[maybe_unused]] config::ToggleSmartShift& action) : + ToggleSmartShift(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 2da114d..19d8b00 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -23,14 +23,28 @@ using namespace logid::actions; -AxisGesture::AxisGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +AxisGesture::AxisGesture(Device *device, config::AxisGesture& config) : + Gesture (device), _multiplier (1), _config (config) { + if(std::holds_alternative(_config.axis)) { + _input_axis = std::get(_config.axis); + } else { + const auto& axis = std::get(_config.axis); + try { + _axis = _device->virtualInput()->toAxisCode(axis); + _device->virtualInput()->registerAxis(_axis); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid axis %s."); + throw InvalidGesture(); + } + } + _device->virtualInput()->registerAxis(_input_axis); } void AxisGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; _axis_remainder = 0; _hires_remainder = 0; } @@ -43,19 +57,23 @@ void AxisGesture::release(bool primary) void AxisGesture::move(int16_t axis) { + const auto threshold = _config.threshold.value_or( + defaults::gesture_threshold); int16_t new_axis = _axis+axis; - int low_res_axis = InputDevice::getLowResAxis(_config.axis()); + int low_res_axis = InputDevice::getLowResAxis(axis); int hires_remainder = _hires_remainder; - if(new_axis > _config.threshold()) { + if(new_axis > threshold) { double move = axis; - if(_axis < _config.threshold()) - move = new_axis - _config.threshold(); - bool negative_multiplier = _config.multiplier() < 0; + if(_axis < threshold) + move = new_axis - threshold; + bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0; if(negative_multiplier) - move *= -_config.multiplier(); + move *= -_config.axis_multiplier.value_or(1); else - move *= _config.multiplier(); + move *= _config.axis_multiplier.value_or(1); + // Handle hi-res multiplier + move *= _multiplier; double move_floor = floor(move); _axis_remainder = move - move_floor; @@ -70,7 +88,7 @@ void AxisGesture::move(int16_t axis) if(low_res_axis != -1) { int lowres_movement = 0, hires_movement = move_floor; - _device->virtualInput()->moveAxis(_config.axis(), hires_movement); + _device->virtualInput()->moveAxis(_input_axis, hires_movement); hires_remainder += hires_movement; if(abs(hires_remainder) >= 60) { lowres_movement = hires_remainder/120; @@ -82,7 +100,7 @@ void AxisGesture::move(int16_t axis) _hires_remainder = hires_remainder; } else { - _device->virtualInput()->moveAxis(_config.axis(), move_floor); + _device->virtualInput()->moveAxis(_input_axis, move_floor); } } _axis = new_axis; @@ -90,72 +108,7 @@ void AxisGesture::move(int16_t axis) bool AxisGesture::metThreshold() const { - return _axis >= _config.threshold(); -} - -void AxisGesture::setHiresMultiplier(double multiplier) -{ - _config.setHiresMultiplier(multiplier); -} - -AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) : - Gesture::Config(device, setting, false) -{ - try { - auto& axis = setting.lookup("axis"); - if(axis.isNumber()) { - _axis = axis; - _device->virtualInput()->registerAxis(_axis); - } else if(axis.getType() == libconfig::Setting::TypeString) { - try { - _axis = _device->virtualInput()->toAxisCode(axis); - _device->virtualInput()->registerAxis(_axis); - } catch(InputDevice::InvalidEventCode& e) { - logPrintf(WARN, "Line %d: Invalid axis %s, skipping." - , axis.getSourceLine(), axis.c_str()); - } - } else { - logPrintf(WARN, "Line %d: axis must be string or int, skipping.", - axis.getSourceLine(), axis.c_str()); - throw InvalidGesture(); - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: axis is a required field, skippimg.", - setting.getSourceLine()); - throw InvalidGesture(); - } - - try { - auto& multiplier = setting.lookup("axis_multiplier"); - if(multiplier.isNumber()) { - if(multiplier.getType() == libconfig::Setting::TypeFloat) - _multiplier = multiplier; - else - _multiplier = (int)multiplier; - } else { - logPrintf(WARN, "Line %d: axis_multiplier must be a number, " - "setting to default (1).", - multiplier.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } - - int low_res_axis = InputDevice::getLowResAxis(_axis); - if(low_res_axis != -1) { - _multiplier *= 120; - _device->virtualInput()->registerAxis(low_res_axis); - } -} - -unsigned int AxisGesture::Config::axis() const -{ - return _axis; -} - -double AxisGesture::Config::multiplier() const -{ - return _multiplier; + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } bool AxisGesture::wheelCompatibility() const @@ -163,15 +116,9 @@ bool AxisGesture::wheelCompatibility() const return true; } -void AxisGesture::Config::setHiresMultiplier(double multiplier) +void AxisGesture::setHiresMultiplier(double multiplier) { - if(_hires_multiplier == multiplier || multiplier == 0) - return; - if(InputDevice::getLowResAxis(_axis) != -1) { - _multiplier *= _hires_multiplier; - _multiplier /= multiplier; + _multiplier = multiplier; } - - _hires_multiplier = multiplier; } diff --git a/src/logid/actions/gesture/AxisGesture.h b/src/logid/actions/gesture/AxisGesture.h index 5352f9f..eaf42e6 100644 --- a/src/logid/actions/gesture/AxisGesture.h +++ b/src/logid/actions/gesture/AxisGesture.h @@ -26,7 +26,7 @@ namespace logid { class AxisGesture : public Gesture { public: - AxisGesture(Device* device, libconfig::Setting& root); + AxisGesture(Device* device, config::AxisGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -37,24 +37,13 @@ namespace logid { void setHiresMultiplier(double multiplier); - class Config : public Gesture::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - unsigned int axis() const; - double multiplier() const; - void setHiresMultiplier(double multiplier); - private: - unsigned int _axis; - double _multiplier = 1; - double _hires_multiplier = 1; - }; - protected: int16_t _axis; double _axis_remainder; int _hires_remainder; - Config _config; + uint _input_axis; + double _multiplier; + config::AxisGesture& _config; }; }} diff --git a/src/logid/actions/gesture/Gesture.cpp b/src/logid/actions/gesture/Gesture.cpp index eb3bcfe..55982ef 100644 --- a/src/logid/actions/gesture/Gesture.cpp +++ b/src/logid/actions/gesture/Gesture.cpp @@ -18,104 +18,42 @@ #include #include "Gesture.h" -#include "../../util/log.h" #include "ReleaseGesture.h" #include "ThresholdGesture.h" -#include "../../backend/hidpp20/features/ReprogControls.h" #include "IntervalGesture.h" #include "AxisGesture.h" #include "NullGesture.h" +using namespace logid; using namespace logid::actions; Gesture::Gesture(Device *device) : _device (device) { } -Gesture::Config::Config(Device* device, libconfig::Setting& root, - bool action_required) : _device (device) -{ - if(action_required) { - try { - _action = Action::makeAction(_device, - root.lookup("action")); - } catch (libconfig::SettingNotFoundException &e) { - throw InvalidGesture("action is missing"); - } +template +struct gesture_type { + typedef typename T::gesture type; +}; - if(_action->reprogFlags() & backend::hidpp20::ReprogControls::RawXYDiverted) - throw InvalidGesture("gesture cannot require RawXY"); - } +template +struct gesture_type : gesture_type { }; - _threshold = LOGID_GESTURE_DEFAULT_THRESHOLD; - try { - auto& threshold = root.lookup("threshold"); - if(threshold.getType() == libconfig::Setting::TypeInt) { - _threshold = (int)threshold; - if(_threshold <= 0) { - _threshold = LOGID_GESTURE_DEFAULT_THRESHOLD; - logPrintf(WARN, "Line %d: threshold must be positive, setting " - "to default (%d)", threshold.getSourceLine(), - _threshold); - } - } else - logPrintf(WARN, "Line %d: threshold must be an integer, setting " - "to default (%d).", threshold.getSourceLine()); - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } +template +struct gesture_type : gesture_type { }; + +template +std::shared_ptr _makeGesture(Device* device, + T gesture) { + return std::make_shared::type>(device, gesture); } std::shared_ptr Gesture::makeGesture(Device *device, - libconfig::Setting &setting) + config::Gesture& gesture) { - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: Gesture is not a group, ignoring.", - setting.getSourceLine()); - throw InvalidGesture(); - } - - try { - auto& gesture_mode = setting.lookup("mode"); - - if(gesture_mode.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Gesture mode must be a string," - "defaulting to OnRelease.", - gesture_mode.getSourceLine()); - return std::make_shared(device, setting); - } - - std::string type = gesture_mode; - std::transform(type.begin(), type.end(), type.begin(), ::tolower); - - if(type == "onrelease") - return std::make_shared(device, setting); - else if(type == "onthreshold") - return std::make_shared(device, setting); - else if(type == "oninterval" || type == "onfewpixels") - return std::make_shared(device, setting); - else if(type == "axis") - return std::make_shared(device, setting); - else if(type == "nopress") - return std::make_shared(device, setting); - else { - logPrintf(WARN, "Line %d: Unknown gesture mode %s, defaulting to " - "OnRelease.", gesture_mode.getSourceLine(), - (const char*)gesture_mode); - return std::make_shared(device, setting); - } - - } catch(libconfig::SettingNotFoundException& e) { - return std::make_shared(device, setting); - } + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeGesture(device, x); + }, gesture); + return ret; } - -int16_t Gesture::Config::threshold() const -{ - return _threshold; -} - -std::shared_ptr Gesture::Config::action() -{ - return _action; -} \ No newline at end of file diff --git a/src/logid/actions/gesture/Gesture.h b/src/logid/actions/gesture/Gesture.h index dcb84ea..58c39d5 100644 --- a/src/logid/actions/gesture/Gesture.h +++ b/src/logid/actions/gesture/Gesture.h @@ -51,21 +51,8 @@ namespace actions virtual ~Gesture() = default; - class Config - { - public: - Config(Device* device, libconfig::Setting& root, - bool action_required=true); - virtual int16_t threshold() const; - virtual std::shared_ptr action(); - protected: - Device* _device; - std::shared_ptr _action; - int16_t _threshold; - }; - static std::shared_ptr makeGesture(Device* device, - libconfig::Setting& setting); + config::Gesture& gesture); protected: explicit Gesture(Device* device); diff --git a/src/logid/actions/gesture/IntervalGesture.cpp b/src/logid/actions/gesture/IntervalGesture.cpp index a3d8438..6f9988a 100644 --- a/src/logid/actions/gesture/IntervalGesture.cpp +++ b/src/logid/actions/gesture/IntervalGesture.cpp @@ -17,17 +17,26 @@ */ #include "IntervalGesture.h" #include "../../util/log.h" +#include "../../Configuration.h" using namespace logid::actions; -IntervalGesture::IntervalGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config) : + Gesture (device), _config (config) { + if(config.action) { + try { + _action = Action::makeAction(device, config.action.value()); + } catch(InvalidAction& e) { + logPrintf(WARN, "Mapping gesture to invalid action"); + } + } } void IntervalGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; _interval_pass_count = 0; } @@ -39,15 +48,19 @@ void IntervalGesture::release(bool primary) void IntervalGesture::move(int16_t axis) { + const auto threshold = + _config.threshold.value_or(defaults::gesture_threshold); _axis += axis; - if(_axis < _config.threshold()) + if(_axis < threshold) return; - int16_t new_interval_count = (_axis - _config.threshold())/ - _config.interval(); + int16_t new_interval_count = (_axis - threshold)/ + _config.interval; if(new_interval_count > _interval_pass_count) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } } _interval_pass_count = new_interval_count; } @@ -59,38 +72,5 @@ bool IntervalGesture::wheelCompatibility() const bool IntervalGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold);; } - -IntervalGesture::Config::Config(Device *device, libconfig::Setting &setting) : - Gesture::Config(device, setting) -{ - try { - auto& interval = setting.lookup("interval"); - if(interval.getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: interval must be an integer, skipping.", - interval.getSourceLine()); - throw InvalidGesture(); - } - _interval = (int)interval; - } catch(libconfig::SettingNotFoundException& e) { - try { - // pixels is an alias for interval - auto& interval = setting.lookup("pixels"); - if(interval.getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: pixels must be an integer, skipping.", - interval.getSourceLine()); - throw InvalidGesture(); - } - _interval = (int)interval; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: interval is a required field, skipping.", - setting.getSourceLine()); - } - } -} - -int16_t IntervalGesture::Config::interval() const -{ - return _interval; -} \ No newline at end of file diff --git a/src/logid/actions/gesture/IntervalGesture.h b/src/logid/actions/gesture/IntervalGesture.h index 268822d..cb68cd2 100644 --- a/src/logid/actions/gesture/IntervalGesture.h +++ b/src/logid/actions/gesture/IntervalGesture.h @@ -26,7 +26,7 @@ namespace actions class IntervalGesture : public Gesture { public: - IntervalGesture(Device* device, libconfig::Setting& root); + IntervalGesture(Device* device, config::IntervalGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -35,19 +35,11 @@ namespace actions virtual bool wheelCompatibility() const; virtual bool metThreshold() const; - class Config : public Gesture::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - int16_t interval() const; - private: - int16_t _interval; - }; - protected: int16_t _axis; int16_t _interval_pass_count; - Config _config; + std::shared_ptr _action; + config::IntervalGesture& _config; }; }} diff --git a/src/logid/actions/gesture/NullGesture.cpp b/src/logid/actions/gesture/NullGesture.cpp index dbb7e57..515746f 100644 --- a/src/logid/actions/gesture/NullGesture.cpp +++ b/src/logid/actions/gesture/NullGesture.cpp @@ -16,17 +16,20 @@ * */ #include "NullGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -NullGesture::NullGesture(Device *device, libconfig::Setting& setting) : - Gesture (device), _config (device, setting, false) +NullGesture::NullGesture(Device *device, + config::NoGesture& config) : + Gesture (device), _config (config) { } void NullGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? _config.threshold.value_or( + defaults::gesture_threshold) : 0; } void NullGesture::release(bool primary) @@ -47,5 +50,5 @@ bool NullGesture::wheelCompatibility() const bool NullGesture::metThreshold() const { - return _axis > _config.threshold(); + return _axis > _config.threshold.value_or(defaults::gesture_threshold); } \ No newline at end of file diff --git a/src/logid/actions/gesture/NullGesture.h b/src/logid/actions/gesture/NullGesture.h index 6b0f980..89b0158 100644 --- a/src/logid/actions/gesture/NullGesture.h +++ b/src/logid/actions/gesture/NullGesture.h @@ -26,7 +26,8 @@ namespace actions class NullGesture : public Gesture { public: - NullGesture(Device* device, libconfig::Setting& setting); + NullGesture(Device* device, + config::NoGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -36,7 +37,7 @@ namespace actions virtual bool metThreshold() const; protected: int16_t _axis; - Gesture::Config _config; + config::NoGesture& _config; }; }} diff --git a/src/logid/actions/gesture/ReleaseGesture.cpp b/src/logid/actions/gesture/ReleaseGesture.cpp index 613412b..e09989b 100644 --- a/src/logid/actions/gesture/ReleaseGesture.cpp +++ b/src/logid/actions/gesture/ReleaseGesture.cpp @@ -16,24 +16,30 @@ * */ #include "ReleaseGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -ReleaseGesture::ReleaseGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config) : + Gesture (device), _config (config) { + if(_config.action.has_value()) + _action = Action::makeAction(device, _config.action.value()); } void ReleaseGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? _config.threshold.value_or( + defaults::gesture_threshold) : 0; } void ReleaseGesture::release(bool primary) { if(metThreshold() && primary) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } } } @@ -49,5 +55,5 @@ bool ReleaseGesture::wheelCompatibility() const bool ReleaseGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } \ No newline at end of file diff --git a/src/logid/actions/gesture/ReleaseGesture.h b/src/logid/actions/gesture/ReleaseGesture.h index 59cc528..24166a7 100644 --- a/src/logid/actions/gesture/ReleaseGesture.h +++ b/src/logid/actions/gesture/ReleaseGesture.h @@ -26,7 +26,7 @@ namespace actions class ReleaseGesture : public Gesture { public: - ReleaseGesture(Device* device, libconfig::Setting& root); + ReleaseGesture(Device* device, config::ReleaseGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -37,7 +37,8 @@ namespace actions protected: int16_t _axis; - Gesture::Config _config; + std::shared_ptr _action; + config::ReleaseGesture& _config; }; }} diff --git a/src/logid/actions/gesture/ThresholdGesture.cpp b/src/logid/actions/gesture/ThresholdGesture.cpp index 5e1ebd9..ccae5a9 100644 --- a/src/logid/actions/gesture/ThresholdGesture.cpp +++ b/src/logid/actions/gesture/ThresholdGesture.cpp @@ -16,17 +16,27 @@ * */ #include "ThresholdGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -ThresholdGesture::ThresholdGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +ThresholdGesture::ThresholdGesture(Device *device, + config::ThresholdGesture& config) : + Gesture (device), _config (config) { + if(config.action) { + try { + _action = Action::makeAction(device, config.action.value()); + } catch(InvalidAction& e) { + logPrintf(WARN, "Mapping gesture to invalid action"); + } + } } void ThresholdGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; this->_executed = false; } @@ -42,15 +52,17 @@ void ThresholdGesture::move(int16_t axis) _axis += axis; if(!this->_executed && metThreshold()) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } this->_executed = true; } } bool ThresholdGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } bool ThresholdGesture::wheelCompatibility() const diff --git a/src/logid/actions/gesture/ThresholdGesture.h b/src/logid/actions/gesture/ThresholdGesture.h index 0a38b96..501117d 100644 --- a/src/logid/actions/gesture/ThresholdGesture.h +++ b/src/logid/actions/gesture/ThresholdGesture.h @@ -26,7 +26,7 @@ namespace actions class ThresholdGesture : public Gesture { public: - ThresholdGesture(Device* device, libconfig::Setting& root); + ThresholdGesture(Device* device, config::ThresholdGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -38,7 +38,8 @@ namespace actions protected: int16_t _axis; - Gesture::Config _config; + std::shared_ptr _action; + config::ThresholdGesture& _config; private: bool _executed = false; diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index 2f3e4d7..f0909e5 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -45,7 +45,7 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept } Receiver::Receiver(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _raw_device (std::make_shared( std::move(path), io_timeout, wq)), diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index f0e4a21..270a4eb 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -53,7 +53,7 @@ namespace dj { public: Receiver(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); enum DjEvents : uint8_t diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index f847a75..ae51314 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -27,7 +27,7 @@ using namespace logid::backend::dj; ReceiverMonitor::ReceiverMonitor( std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _workqueue (wq), _receiver (std::make_shared(std::move(path), io_timeout, wq)) diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 6c88627..1349bf8 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -33,7 +33,7 @@ namespace dj { public: ReceiverMonitor(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); virtual ~ReceiverMonitor(); diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 0b853c1..a4d727c 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -50,7 +50,7 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept } Device::Device(const std::string& path, DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq): _raw_device (std::make_shared(path, io_timeout, wq)), _receiver (nullptr), _path (path), _index (index) diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 666ad45..1dea588 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -62,7 +62,7 @@ namespace hidpp }; Device(const std::string& path, DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_device, DeviceIndex index); diff --git a/src/logid/backend/hidpp10/Device.cpp b/src/logid/backend/hidpp10/Device.cpp index ab5f990..8f6e54e 100644 --- a/src/logid/backend/hidpp10/Device.cpp +++ b/src/logid/backend/hidpp10/Device.cpp @@ -25,7 +25,7 @@ using namespace logid::backend; using namespace logid::backend::hidpp10; Device::Device(const std::string &path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : hidpp::Device(path, index, io_timeout, wq) { diff --git a/src/logid/backend/hidpp10/Device.h b/src/logid/backend/hidpp10/Device.h index b6d92b5..b61e054 100644 --- a/src/logid/backend/hidpp10/Device.h +++ b/src/logid/backend/hidpp10/Device.h @@ -29,7 +29,7 @@ namespace hidpp10 { public: Device(const std::string& path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_dev, hidpp::DeviceIndex index); diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index 278f119..ed93b70 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -24,8 +24,7 @@ using namespace logid::backend::hidpp20; Device::Device(std::string path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, - const std::shared_ptr& wq) : + double io_timeout, const std::shared_ptr& wq) : hidpp::Device(path, index, io_timeout, wq) { assert(std::get<0>(version()) >= 2); diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index f593758..482abe8 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -29,8 +29,7 @@ namespace hidpp20 { { public: Device(std::string path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, - const std::shared_ptr& wq); + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_device, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, hidpp::DeviceIndex index); diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 95e6995..dd2103e 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -65,11 +65,12 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length) } RawDevice::RawDevice(std::string path, - const milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _path (std::move(path)), _continue_listen (false), _continue_respond (false), - _io_timeout (io_timeout), + _io_timeout (duration_cast( + duration(io_timeout))), _workqueue (wq) { int ret; diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 7935a0c..2619e90 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -42,7 +42,7 @@ namespace raw static bool supportedReport(uint8_t id, uint8_t length); explicit RawDevice(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); ~RawDevice(); std::string hidrawPath() const; diff --git a/src/logid/config/group.h b/src/logid/config/group.h index 9179b16..9c419ed 100644 --- a/src/logid/config/group.h +++ b/src/logid/config/group.h @@ -135,11 +135,11 @@ namespace logid::config { virtual ~group() = default; - virtual void save(libconfig::Setting& setting) const { + virtual void _save(libconfig::Setting& setting) const { _setter(setting, this, _names); } - virtual void load(const libconfig::Setting& setting) { + virtual void _load(const libconfig::Setting& setting) { _getter(setting, this, _names); } }; @@ -188,12 +188,12 @@ namespace logid::config { return *this; } - void save(libconfig::Setting& setting) const override { + void _save(libconfig::Setting& setting) const override { set(setting, _signature, _sig_field); _setter(setting, this, _names); } - void load(const libconfig::Setting& setting) override { + void _load(const libconfig::Setting& setting) override { if(normalize_signature::make(get(setting, _sig_field)) != _signature) throw libconfig::SettingTypeException(setting); diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h index cbf45a7..ecffbf3 100644 --- a/src/logid/config/schema.h +++ b/src/logid/config/schema.h @@ -20,30 +20,54 @@ #include "types.h" +namespace logid::actions { + class ChangeDPI; + class ChangeHostAction; + class CycleDPI; + class GestureAction; + class KeypressAction; + class NullAction; + class ToggleHiresScroll; + class ToggleSmartShift; + + class AxisGesture; + class IntervalGesture; + class NullGesture; + class ReleaseGesture; + class ThresholdGesture; +} + namespace logid::config { + struct NoAction : public signed_group { + typedef actions::NullAction action; NoAction() : signed_group("type", "None") { } }; struct KeypressAction : public signed_group { - std::variant> keys; + typedef actions::KeypressAction action; + std::variant>> keys; KeypressAction() : signed_group( "type", "Keypress", {"keys"}, &KeypressAction::keys) { } }; struct ToggleSmartShift : public signed_group { + typedef actions::ToggleSmartShift action; ToggleSmartShift() : signed_group("type", "ToggleSmartShift") { } }; struct ToggleHiresScroll : public signed_group { + typedef actions::ToggleHiresScroll action; ToggleHiresScroll() : signed_group("type", "ToggleHiresScroll") { } }; struct CycleDPI : public signed_group { - std::vector dpis; + typedef actions::CycleDPI action; + std::list dpis; std::optional sensor; CycleDPI() : signed_group( "type", "CycleDPI", @@ -53,6 +77,7 @@ namespace logid::config { }; struct ChangeDPI : public signed_group { + typedef actions::ChangeDPI action; int inc; std::optional sensor; ChangeDPI() : signed_group( @@ -63,21 +88,13 @@ namespace logid::config { }; struct ChangeHost : public signed_group { + typedef actions::ChangeHostAction action; std::variant host; ChangeHost() : signed_group( "type", "ChangeHost", {"host"}, &ChangeHost::host) { } }; - struct Gesture; - - struct GestureAction : public signed_group { - std::optional> _gestures; - - GestureAction() : signed_group( - "type", "Gestures") { } - }; - typedef std::variant< NoAction, KeypressAction, @@ -88,6 +105,89 @@ namespace logid::config { ChangeHost > BasicAction; + struct AxisGesture : public signed_group { + typedef actions::AxisGesture gesture; + std::optional threshold; + std::variant axis; + std::optional axis_multiplier; + + AxisGesture() : signed_group("mode", "Axis", + {"threshold", "axis", "axis_multiplier"}, + &AxisGesture::threshold, + &AxisGesture::axis, + &AxisGesture::axis_multiplier) { } + }; + + struct IntervalGesture : public signed_group { + typedef actions::IntervalGesture gesture; + std::optional threshold; + std::optional action; + int interval; + protected: + IntervalGesture(const std::string& name) : signed_group( + "mode", name, + {"threshold", "action", "interval"}, + &IntervalGesture::threshold, + &IntervalGesture::action, + &IntervalGesture::interval) { } + public: + IntervalGesture() : IntervalGesture("OnInterval") { } + }; + + struct FewPixelsGesture : public IntervalGesture { + FewPixelsGesture() : IntervalGesture("OnFewPixels") { } + }; + + struct ReleaseGesture : public signed_group { + typedef actions::ReleaseGesture gesture; + std::optional threshold; + std::optional action; + + ReleaseGesture() : signed_group("mode", "OnRelease", + {"threshold", "action"}, + &ReleaseGesture::threshold, + &ReleaseGesture::action) { } + }; + + struct ThresholdGesture : public signed_group { + typedef actions::ThresholdGesture gesture; + std::optional threshold; + std::optional action; + + ThresholdGesture() : signed_group("mode", "OnThreshold", + {"threshold", "action"}, + &ThresholdGesture::threshold, + &ThresholdGesture::action) { } + }; + + struct NoGesture : public signed_group { + typedef actions::NullGesture gesture; + std::optional threshold; + NoGesture() : signed_group("mode", "NoPress", + {"threshold"}, + &NoGesture::threshold) { } + }; + + typedef std::variant< + NoGesture, + AxisGesture, + IntervalGesture, + FewPixelsGesture, + ReleaseGesture, + ThresholdGesture + > Gesture; + + + struct GestureAction : public signed_group { + typedef actions::GestureAction action; + std::optional> gestures; + + GestureAction() : signed_group( + "type", "Gestures", + {"gestures"}, + &GestureAction::gestures) { } + }; + typedef std::variant< NoAction, KeypressAction, @@ -99,60 +199,67 @@ namespace logid::config { GestureAction > Action; - struct Gesture : public group { - std::optional threshold; - std::optional mode; - std::optional axis; - std::optional axis_multiplier; - Action action; - - Gesture() : group( - {"threshold", "mode", "axis", "axis_multiplier"}, - &Gesture::threshold, - &Gesture::mode, - &Gesture::axis, - &Gesture::axis_multiplier - ) { } - }; - struct Button : public group { - std::optional action; + std::optional action; Button() : group({"action"}, &Button::action) { } }; - struct Smartshift : public group { + struct SmartShift : public group { std::optional on; std::optional threshold; - Smartshift() : group({"on", "threshold"}, - &Smartshift::on, &Smartshift::threshold) { } + SmartShift() : group({"on", "threshold"}, + &SmartShift::on, &SmartShift::threshold) { } }; - struct Hiresscroll : public group { + struct HiresScroll : public group { std::optional hires; std::optional invert; std::optional target; - Hiresscroll() : group({"hires", "invert", "target"}, - &Hiresscroll::hires, - &Hiresscroll::invert, - &Hiresscroll::target) { } + std::optional up; + std::optional down; + HiresScroll() : group({"hires", "invert", "target", "up", "down"}, + &HiresScroll::hires, + &HiresScroll::invert, + &HiresScroll::target, + &HiresScroll::up, + &HiresScroll::down) { } }; - using DPI = std::variant>; + typedef std::variant> DPI; + struct ThumbWheel : public group { + std::optional divert; + std::optional invert; + std::optional left; + std::optional right; + std::optional proxy; + std::optional touch; + std::optional tap; + + ThumbWheel() : group({"divert", "invert", "left", "right", + "proxy", "touch", "tap" }, + &ThumbWheel::divert, &ThumbWheel::invert, + &ThumbWheel::left, &ThumbWheel::right, + &ThumbWheel::proxy, &ThumbWheel::touch, + &ThumbWheel::tap) { } + }; + + typedef map RemapButton; struct Profile : public group { std::optional dpi; - std::optional smartshift; - std::optional> hiresscroll; - std::optional> buttons; + std::optional smartshift; + std::optional> hiresscroll; + std::optional thumbwheel; + std::optional buttons; - Profile() : group({"dpi", "smartshift", "hiresscroll", "buttons"}, - &Profile::dpi, - &Profile::smartshift, - &Profile::hiresscroll, - &Profile::buttons) { } + Profile() : group({"dpi", "smartshift", "hiresscroll", + "buttons", "thumbwheel"}, + &Profile::dpi, &Profile::smartshift, + &Profile::hiresscroll, &Profile::buttons, + &Profile::thumbwheel) { } }; struct Device : public group { @@ -166,8 +273,8 @@ namespace logid::config { struct Config : public group { std::optional, "name">> devices; - std::optional> ignore; + std::variant, "name">> devices; + std::optional> ignore; std::optional io_timeout; std::optional workers; Config() : group({"devices", "ignore", "io_timeout", "workers"}, diff --git a/src/logid/config/types.h b/src/logid/config/types.h index a8a8393..ad729ae 100644 --- a/src/logid/config/types.h +++ b/src/logid/config/types.h @@ -22,12 +22,16 @@ #include #include #include +#include +#include #include "group.h" #include "map.h" #include "../util/log.h" /// TODO: A single element failing should not cause the container to be invalid. +// Containers are chosen specifically so that no iterator is invalidated. + namespace logid::config { namespace { template @@ -37,13 +41,13 @@ namespace logid::config { static T get(const libconfig::Setting& parent, const std::string& name) { T t {}; - t.load(parent.lookup(name)); + t._load(parent.lookup(name)); return t; } static T get(const libconfig::Setting& setting) { T t {}; - t.load(setting); + t._load(setting); return t; } @@ -54,13 +58,14 @@ namespace logid::config { parent.add(name, libconfig::Setting::TypeGroup); } else if(parent.lookup(name).getType() != libconfig::Setting::TypeGroup) { - + parent.remove(name); + parent.add(name, libconfig::Setting::TypeGroup); } - t.save(parent.lookup(name)); + t._save(parent.lookup(name)); } static void set(libconfig::Setting& setting, const T& t) { - t.save(setting); + t._save(setting); } static void append(libconfig::Setting& list, const T& t) { @@ -83,8 +88,12 @@ namespace logid::config { static void set(libconfig::Setting& parent, const std::string& name, const T& t) { - if(!parent.exists(name)) + if(!parent.exists(name)) { parent.add(name, TypeEnum); + } else if(parent.lookup(name).getType() != TypeEnum) { + parent.remove(name); + parent.add(name, TypeEnum); + } set(parent.lookup(name), t); } @@ -98,38 +107,68 @@ namespace logid::config { } }; + template + struct reinterpret_io { + static T get(const libconfig::Setting& parent, + const std::string& name) { + return static_cast(primitive_io::get(parent, name)); + } + + static T get(const libconfig::Setting& setting) { + return static_cast(primitive_io::get(setting)); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + primitive_io::set(parent, name, + static_cast(t)); + } + + static void set(libconfig::Setting& setting, const T& t) { + primitive_io::set(setting, + static_cast(t)); + } + + static void append(libconfig::Setting& list, const T& t) { + primitive_io::append(list, + static_cast(t)); + } + }; + template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io : + public reinterpret_io { }; template <> struct config_io : public primitive_io - struct config_io> { - static std::vector get(const libconfig::Setting& setting) { + struct config_io> { + static std::list get(const libconfig::Setting& setting) { const auto size = setting.getLength(); - std::vector t(size); - for(int i = 0; i < size; ++i) - t[i] = config_io::get(setting[i]); + std::list t {}; + for(int i = 0; i < size; ++i) { + try { + t.emplace_back(config_io::get(setting[i])); + } catch(libconfig::SettingException& e) { } + } return t; } - static std::vector get(const libconfig::Setting& parent, + static std::list get(const libconfig::Setting& parent, const std::string& name) { return get(parent.lookup(name)); } static void set(libconfig::Setting& setting, - const std::vector& t) { - const auto orig_size = setting.getLength(); - for(int i = 0; i < orig_size; ++i) - config_io::set(setting[i], t[i]); - for(int i = orig_size; i < t.size(); ++i) - config_io::append(setting, t[i]); + const std::list& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + config_io::append(setting, x); + } } static void set(libconfig::Setting& parent, const std::string& name, - const std::vector& t) { + const std::list& t) { if (!parent.exists(name)) { - parent.add(name, libconfig::Setting::TypeArray); - } else if(!parent.lookup(name).isArray()) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isList()) { parent.remove(name); - parent.add(name, libconfig::Setting::TypeArray); + parent.add(name, libconfig::Setting::TypeList); } set(parent.lookup(name), t); } static void append(libconfig::Setting& list, - const std::vector& t) { - auto& s = list.add(libconfig::Setting::TypeArray); + const std::list& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io> { + static std::set get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::set t; + for(int i = 0; i < size; ++i) { + try { + t.emplace(config_io::get(setting[i])); + } catch(libconfig::SettingException& e) { } + } + return t; + } + + static std::set get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::set& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + auto& s = setting.add(libconfig::Setting::TypeGroup); + config_io::set(s, x); + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::set& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::set& t) { + auto& s = list.add(libconfig::Setting::TypeList); set(s, t); } }; @@ -246,8 +335,10 @@ namespace logid::config { map t; for(int i = 0; i < size; ++i) { auto& s = setting[i]; - t.emplace(config_io::get(s.lookup(KeyName.value)), - config_io::get(s)); + try { + t.emplace(config_io::get(s.lookup(KeyName.value)), + config_io::get(s)); + } catch(libconfig::SettingException& e) { } } return t; } @@ -287,49 +378,6 @@ namespace logid::config { } }; - template - struct config_io>> { - static std::vector> get( - const libconfig::Setting& setting) { - const auto size = setting.getLength(); - std::vector> t(size); - for(int i = 0; i < size; ++i) - t[i] = config_io>::get(setting[i]); - return t; - } - - static std::vector> get( - const libconfig::Setting& parent, const std::string& name) { - return get(parent.lookup(name)); - } - - static void set(libconfig::Setting& setting, - const std::vector>& t) { - while(setting.getLength() != 0) - setting.remove((int)0); - for(int i = 0; i < t.size(); ++i) - config_io>::append(setting, t[i]); - } - - static void set(libconfig::Setting& parent, - const std::string& name, - const std::vector>& t) { - if (!parent.exists(name)) { - parent.add(name, libconfig::Setting::TypeList); - } else if(!parent.lookup(name).isList()) { - parent.remove(name); - parent.add(name, libconfig::Setting::TypeList); - } - set(parent.lookup(name), t); - } - - static void append(libconfig::Setting& list, - const std::variant>& t) { - auto& s = list.add(libconfig::Setting::TypeList); - set(s, t); - } - }; - template struct config_io> { static std::optional get(const libconfig::Setting& parent, @@ -356,7 +404,7 @@ namespace logid::config { }; template - struct config_io>> { + struct config_io>> { static_assert(!sizeof(std::optional), "Invalid type"); }; diff --git a/src/logid/features/DPI.cpp b/src/logid/features/DPI.cpp index 82093a1..1fd856c 100644 --- a/src/logid/features/DPI.cpp +++ b/src/logid/features/DPI.cpp @@ -19,12 +19,11 @@ #include #include "DPI.h" #include "../Device.h" -#include "../util/log.h" using namespace logid::features; using namespace logid::backend; -uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list, +uint16_t getClosestDPI(const hidpp20::AdjustableDPI::SensorDPIList& dpi_list, uint16_t dpi) { if(dpi_list.isRange) { @@ -58,7 +57,8 @@ uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list, } } -DPI::DPI(Device* device) : DeviceFeature(device), _config (device) +DPI::DPI(Device* device) : DeviceFeature(device), + _config (device->activeProfile().dpi) { try { _adjustable_dpi = std::make_shared @@ -70,20 +70,23 @@ DPI::DPI(Device* device) : DeviceFeature(device), _config (device) void DPI::configure() { - const uint8_t sensors = _adjustable_dpi->getSensorCount(); - for(uint8_t i = 0; i < _config.getSensorCount(); i++) { - hidpp20::AdjustableDPI::SensorDPIList dpi_list; - if(_dpi_lists.size() <= i) { - dpi_list = _adjustable_dpi->getSensorDPIList(i); - _dpi_lists.push_back(dpi_list); + if(_config.has_value()) { + const auto& config = _config.value(); + if(std::holds_alternative(config)) { + const auto& dpi = std::get(config); + _adjustable_dpi->setSensorDPI( + 0, + getClosestDPI(_adjustable_dpi->getSensorDPIList(0), + dpi) ); } else { - dpi_list = _dpi_lists[i]; - } - if(i < sensors) { - auto dpi = _config.getDPI(i); - if(dpi) { - _adjustable_dpi->setSensorDPI(i, getClosestDPI(dpi_list, - dpi)); + const auto& dpis = std::get>(config); + int i = 0; + for(const auto& dpi : dpis) { + _adjustable_dpi->setSensorDPI( + i, + getClosestDPI(_adjustable_dpi->getSensorDPIList(i), + dpi) ); + ++i; } } } @@ -111,36 +114,3 @@ void DPI::setDPI(uint16_t dpi, uint8_t sensor) dpi_list = _dpi_lists[sensor]; _adjustable_dpi->setSensorDPI(sensor, getClosestDPI(dpi_list, dpi)); } - -/* Some devices have multiple sensors, but an older config format - * only supports a single DPI. The dpi setting can be an array or - * an integer. - */ -DPI::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("dpi"); - if(config_root.isNumber()) { - int dpi = config_root; - _dpis.push_back(dpi); - } else if(config_root.isArray()) { - for(int i = 0; i < config_root.getLength(); i++) - _dpis.push_back((int)config_root[i]); - } else { - logPrintf(WARN, "Line %d: dpi is improperly formatted", - config_root.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // DPI not configured, use default - } -} - -uint8_t DPI::Config::getSensorCount() -{ - return _dpis.size(); -} - -uint16_t DPI::Config::getDPI(uint8_t sensor) -{ - return _dpis[sensor]; -} diff --git a/src/logid/features/DPI.h b/src/logid/features/DPI.h index f2f6c33..de804b8 100644 --- a/src/logid/features/DPI.h +++ b/src/logid/features/DPI.h @@ -20,6 +20,7 @@ #include "../backend/hidpp20/features/AdjustableDPI.h" #include "DeviceFeature.h" +#include "../config/schema.h" namespace logid { namespace features @@ -33,18 +34,8 @@ namespace features uint16_t getDPI(uint8_t sensor=0); void setDPI(uint16_t dpi, uint8_t sensor=0); - - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - uint16_t getDPI(uint8_t sensor); - uint8_t getSensorCount(); - protected: - std::vector _dpis; - }; private: - Config _config; + std::optional& _config; std::shared_ptr _adjustable_dpi; std::vector _dpi_lists; }; diff --git a/src/logid/features/DeviceFeature.h b/src/logid/features/DeviceFeature.h index b5d60ee..7b7ed4a 100644 --- a/src/logid/features/DeviceFeature.h +++ b/src/logid/features/DeviceFeature.h @@ -44,15 +44,6 @@ namespace features virtual void configure() = 0; virtual void listen() = 0; virtual ~DeviceFeature() = default; - class Config - { - public: - explicit Config(Device* dev) : _device (dev) - { - } - protected: - Device* _device; - }; protected: Device* _device; diff --git a/src/logid/features/DeviceStatus.cpp b/src/logid/features/DeviceStatus.cpp index b41a7a2..e7c2bc7 100644 --- a/src/logid/features/DeviceStatus.cpp +++ b/src/logid/features/DeviceStatus.cpp @@ -34,7 +34,7 @@ DeviceStatus::DeviceStatus(logid::Device *dev) : DeviceFeature(dev) throw UnsupportedFeature(); try { - _wireless_device_status =std::make_shared< + _wireless_device_status = std::make_shared< hidpp20::WirelessDeviceStatus>(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { throw UnsupportedFeature(); diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index 720f994..b52b950 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -18,7 +18,6 @@ #include "HiresScroll.h" #include "../Device.h" #include "../InputDevice.h" -#include "../actions/gesture/Gesture.h" #include "../actions/gesture/AxisGesture.h" using namespace logid::features; @@ -26,38 +25,45 @@ using namespace logid::backend; #define MOVE_EVENTHANDLER_NAME "HIRES_SCROLL" -HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), _config(dev) +HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), + _config (dev->activeProfile().hiresscroll), _mode (0), _mask (0) { + if(_config.has_value()) { + if(std::holds_alternative(_config.value())) { + config::HiresScroll conf {}; + conf.hires = std::get(_config.value()); + conf.invert = false; + conf.target = false; + _mask |= hidpp20::HiresScroll::Mode::HiRes; + _config.value() = conf; + } + auto& conf = std::get(_config.value()); + if(conf.hires.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::HiRes; + if(conf.hires.value()) + _mode |= hidpp20::HiresScroll::Mode::HiRes; + } + if(conf.invert.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::Inverted; + if(conf.invert.value()) + _mode |= hidpp20::HiresScroll::Mode::Inverted; + } + if(conf.target.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::Target; + if(conf.target.value()) + _mode |= hidpp20::HiresScroll::Mode::Target; + } + + _makeAction(_up_action, conf.up); + _makeAction(_down_action, conf.down); + } + try { _hires_scroll = std::make_shared(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { throw UnsupportedFeature(); } - if(_config.upAction()) { - try { - auto up_axis = std::dynamic_pointer_cast( - _config.upAction()); - if(up_axis) - up_axis->setHiresMultiplier( - _hires_scroll->getCapabilities().multiplier); - } catch(std::bad_cast& e) { } - - _config.upAction()->press(true); - } - - if(_config.downAction()) { - try { - auto down_axis = std::dynamic_pointer_cast( - _config.downAction()); - if(down_axis) - down_axis->setHiresMultiplier( - _hires_scroll->getCapabilities().multiplier); - } catch(std::bad_cast& e) { } - - _config.downAction()->press(true); - } - _last_scroll = std::chrono::system_clock::now(); } @@ -69,8 +75,8 @@ HiresScroll::~HiresScroll() void HiresScroll::configure() { auto mode = _hires_scroll->getMode(); - mode &= ~_config.getMask(); - mode |= (_config.getMode() & _config.getMask()); + mode &= ~_mask; + mode |= (_mode & _mask); _hires_scroll->setMode(mode); } @@ -103,18 +109,37 @@ void HiresScroll::setMode(uint8_t mode) _hires_scroll->setMode(mode); } +void HiresScroll::_makeAction(std::shared_ptr &gesture, + std::optional &config) +{ + if(config.has_value()) { + gesture = actions::Gesture::makeGesture(_device, config.value()); + try { + auto axis = std::dynamic_pointer_cast( + gesture); + if(axis) + axis->setHiresMultiplier( + _hires_scroll->getCapabilities().multiplier); + } catch(std::bad_cast& e) { } + if(gesture) + gesture->press(true); + } else { + gesture.reset(); + } +} + void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) { auto now = std::chrono::system_clock::now(); if(std::chrono::duration_cast( now - _last_scroll).count() >= 1) { - if(_config.upAction()) { - _config.upAction()->release(); - _config.upAction()->press(true); + if(_up_action) { + _up_action->release(); + _up_action->press(true); } - if(_config.downAction()) { - _config.downAction()->release(); - _config.downAction()->press(true); + if(_down_action) { + _down_action->release(); + _down_action->press(true); } _last_direction = 0; @@ -122,140 +147,25 @@ void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) if(event.deltaV > 0) { if(_last_direction == -1) { - if(_config.downAction()){ - _config.downAction()->release(); - _config.downAction()->press(true); + if(_down_action){ + _down_action->release(); + _down_action->press(true); } } - if(_config.upAction()) - _config.upAction()->move(event.deltaV); + if(_up_action) + _up_action->move(event.deltaV); _last_direction = 1; } else if(event.deltaV < 0) { if(_last_direction == 1) { - if(_config.upAction()){ - _config.upAction()->release(); - _config.upAction()->press(true); + if(_up_action){ + _up_action->release(); + _up_action->press(true); } } - if(_config.downAction()) - _config.downAction()->move(-event.deltaV); + if(_down_action) + _down_action->move(-event.deltaV); _last_direction = -1; } _last_scroll = now; } - -HiresScroll::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("hiresscroll"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: hiresscroll must be a group", - config_root.getSourceLine()); - return; - } - _mode = 0; - _mask = 0; - try { - auto& hires = config_root.lookup("hires"); - if(hires.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::HiRes; - if(hires) - _mode |= hidpp20::HiresScroll::Mode::HiRes; - } else { - logPrintf(WARN, "Line %d: hires must be a boolean", - hires.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& invert = config_root.lookup("invert"); - if(invert.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::Inverted; - if(invert) - _mode |= hidpp20::HiresScroll::Mode::Inverted; - } else { - logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.", - invert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& target = config_root.lookup("target"); - if(target.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::Target; - if(target) - _mode |= hidpp20::HiresScroll::Mode::Target; - } else { - logPrintf(WARN, "Line %d: target must be a boolean, ignoring.", - target.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - if(_mode & hidpp20::HiresScroll::Mode::Target) { - try { - auto& up = config_root.lookup("up"); - try { - auto g = actions::Gesture::makeGesture(dev, up); - if(g->wheelCompatibility()) { - _up_action = g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - up.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - up.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException&) { - logPrintf(WARN, "Line %d: target is true but no up action was" - " set", config_root.getSourceLine()); - } - - try { - auto& down = config_root.lookup("down"); - try { - auto g = actions::Gesture::makeGesture(dev, down); - if(g->wheelCompatibility()) { - _down_action = g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - down.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - down.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException&) { - logPrintf(WARN, "Line %d: target is true but no down action was" - " set", config_root.getSourceLine()); - } - } - } catch(libconfig::SettingNotFoundException& e) { - // HiresScroll not configured, use default - } -} - -uint8_t HiresScroll::Config::getMode() const -{ - return _mode; -} - -uint8_t HiresScroll::Config::getMask() const -{ - return _mask; -} - -const std::shared_ptr& - HiresScroll::Config::upAction() const -{ - return _up_action; -} - -const std::shared_ptr& - HiresScroll::Config::downAction() const -{ - return _down_action; -} \ No newline at end of file diff --git a/src/logid/features/HiresScroll.h b/src/logid/features/HiresScroll.h index 7cc2f67..1f74825 100644 --- a/src/logid/features/HiresScroll.h +++ b/src/logid/features/HiresScroll.h @@ -35,29 +35,22 @@ namespace features uint8_t getMode(); void setMode(uint8_t mode); - - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - uint8_t getMode() const; - uint8_t getMask() const; - - const std::shared_ptr& upAction() const; - const std::shared_ptr& downAction() const; - protected: - uint8_t _mode; - uint8_t _mask; - - std::shared_ptr _up_action; - std::shared_ptr _down_action; - }; private: + void _makeAction(std::shared_ptr& gesture, + std::optional& config); + void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event); std::shared_ptr _hires_scroll; std::chrono::time_point _last_scroll; int16_t _last_direction = 0; - Config _config; + + std::optional>& _config; + + uint8_t _mode; + uint8_t _mask; + + std::shared_ptr _up_action; + std::shared_ptr _down_action; }; }} diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index e019c46..ea86014 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -29,9 +29,26 @@ using namespace logid::actions; #define EVENTHANDLER_NAME "REMAP_BUTTON" -RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), +RemapButton::RemapButton(Device *dev): DeviceFeature(dev), + _config (dev->activeProfile().buttons), _ipc_node (dev->ipcNode()->make_child("buttons")) { + if(_config.has_value()) { + for(auto& button : _config.value()) { + if(button.second.action.has_value()) { + try { + _buttons.emplace( + button.first, + Action::makeAction( + dev,button.second.action.value())); + } catch(std::exception& e) { + logPrintf(WARN, "Error creating button action: %s", + e.what()); + } + } + } + } + try { _reprog_controls = hidpp20::ReprogControls::autoVersion( &dev->hidpp20()); @@ -42,10 +59,10 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), _reprog_controls->initCidMap(); if(global_loglevel <= DEBUG) { - #define FLAG(x) control.second.flags & hidpp20::ReprogControls::x ? \ - "YES" : "" - #define ADDITIONAL_FLAG(x) control.second.additionalFlags & \ - hidpp20::ReprogControls::x ? "YES" : "" + #define FLAG(x) (control.second.flags & hidpp20::ReprogControls::x ? \ + "YES" : "") + #define ADDITIONAL_FLAG(x) (control.second.additionalFlags & \ + hidpp20::ReprogControls::x ? "YES" : "") // Print CIDs, originally by zv0n logPrintf(DEBUG, "%s:%d remappable buttons:", @@ -57,6 +74,7 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), logPrintf(DEBUG, "0x%02x | %-7s | %-7s | %-10s | %s", control.first, FLAG(TemporaryDivertable), FLAG(FKey), FLAG(MouseButton), ADDITIONAL_FLAG(RawXY)); + #undef ADDITIONAL_FLAG #undef FLAG } @@ -77,7 +95,7 @@ RemapButton::~RemapButton() void RemapButton::configure() { ///TODO: DJ reporting trickery if cannot be remapped - for(const auto& i : _config.buttons()) { + for(const auto& i : _buttons) { hidpp20::ReprogControls::ControlInfo info{}; try { info = _reprog_controls->getControlIdInfo(i.first); @@ -123,7 +141,7 @@ void RemapButton::listen() report)); else { // RawXY auto divertedXY = _reprog_controls->divertedRawXYEvent(report); - for(const auto& button : this->_config.buttons()) + for(const auto& button : this->_buttons) if(button.second->pressed()) button.second->move(divertedXY.x, divertedXY.y); } @@ -144,80 +162,22 @@ void RemapButton::_buttonEvent(const std::set& new_state) if(old_i != _pressed_buttons.end()) { _pressed_buttons.erase(old_i); } else { - auto action = _config.buttons().find(i); - if(action != _config.buttons().end()) + auto action = _buttons.find(i); + if(action != _buttons.end()) action->second->press(); } } // Release all removed buttons for(auto& i : _pressed_buttons) { - auto action = _config.buttons().find(i); - if(action != _config.buttons().end()) + auto action = _buttons.find(i); + if(action != _buttons.end()) action->second->release(); } _pressed_buttons = new_state; } -RemapButton::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("buttons"); - if(!config_root.isList()) { - logPrintf(WARN, "Line %d: buttons must be a list.", - config_root.getSourceLine()); - return; - } - int button_count = config_root.getLength(); - for(int i = 0; i < button_count; i++) - _parseButton(config_root[i]); - } catch(libconfig::SettingNotFoundException& e) { - // buttons not configured, use default - } -} - -void RemapButton::Config::_parseButton(libconfig::Setting &setting) -{ - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: button must be an object, ignoring.", - setting.getSourceLine()); - return; - } - - uint16_t cid; - try { - auto& cid_setting = setting.lookup("cid"); - if(!cid_setting.isNumber()) { - logPrintf(WARN, "Line %d: cid must be a number, ignoring.", - cid_setting.getSourceLine()); - return; - } - cid = (int)cid_setting; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: cid is required, ignoring.", - setting.getSourceLine()); - return; - } - - try { - _buttons.emplace(cid, Action::makeAction(_device, - setting.lookup("action"))); - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: action is required, ignoring.", - setting.getSourceLine()); - } catch(InvalidAction& e) { - logPrintf(WARN, "Line %d: %s is not a valid action, ignoring.", - setting["action"].getSourceLine(), e.what()); - } -} - -const std::map>& RemapButton::Config::buttons() -{ - return _buttons; -} - - RemapButton::ButtonIPC::ButtonIPC( RemapButton *parent, backend::hidpp20::ReprogControls::ControlInfo info) : @@ -225,9 +185,11 @@ RemapButton::ButtonIPC::ButtonIPC( {"ControlID", ipcgull::property( ipcgull::property_readable, info.controlID)}, {"Remappable", ipcgull::property( - ipcgull::property_readable, info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, + ipcgull::property_readable, + info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, {"GestureSupport", ipcgull::property( - ipcgull::property_readable, (info.additionalFlags & hidpp20::ReprogControls::RawXY) + ipcgull::property_readable, + (info.additionalFlags & hidpp20::ReprogControls::RawXY) )} }, {}) { diff --git a/src/logid/features/RemapButton.h b/src/logid/features/RemapButton.h index 1aa1425..e78fe26 100644 --- a/src/logid/features/RemapButton.h +++ b/src/logid/features/RemapButton.h @@ -33,16 +33,6 @@ namespace features virtual void configure(); virtual void listen(); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - const std::map>& - buttons(); - protected: - void _parseButton(libconfig::Setting& setting); - std::map> _buttons; - }; private: class ButtonIPC : public ipcgull::interface { @@ -52,11 +42,13 @@ namespace features }; void _buttonEvent(const std::set& new_state); - Config _config; std::shared_ptr _reprog_controls; std::set _pressed_buttons; std::mutex _button_lock; + std::optional& _config; + std::map> _buttons; + std::shared_ptr _ipc_node; typedef std::pair, std::shared_ptr> ButtonIPCPair; diff --git a/src/logid/features/SmartShift.cpp b/src/logid/features/SmartShift.cpp index 5f219e7..91f319d 100644 --- a/src/logid/features/SmartShift.cpp +++ b/src/logid/features/SmartShift.cpp @@ -22,8 +22,8 @@ using namespace logid::features; using namespace logid::backend; -SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config - (device) +SmartShift::SmartShift(Device* device) : DeviceFeature(device), + _config (device->activeProfile().smartshift) { try { _smartshift = std::make_shared(&device->hidpp20()); @@ -34,7 +34,18 @@ SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config void SmartShift::configure() { - _smartshift->setStatus(_config.getSettings()); + if(_config.has_value()) { + const auto& conf = _config.value(); + hidpp20::SmartShift::SmartshiftStatus settings {}; + settings.setActive = conf.on.has_value(); + if(settings.setActive) + settings.active = conf.on.value(); + settings.setAutoDisengage = conf.threshold.has_value(); + if(settings.setAutoDisengage) + settings.autoDisengage = conf.threshold.value(); + + _smartshift->setStatus(settings); + } } void SmartShift::listen() @@ -51,31 +62,3 @@ void SmartShift::setStatus(backend::hidpp20::SmartShift::SmartshiftStatus { _smartshift->setStatus(status); } - -SmartShift::Config::Config(Device *dev) : DeviceFeature::Config(dev), _status() -{ - try { - auto& config_root = dev->config().getSetting("smartshift"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: smartshift must be an object", - config_root.getSourceLine()); - return; - } - _status.setActive = config_root.lookupValue("on", _status.active); - int tmp; - _status.setAutoDisengage = config_root.lookupValue("threshold", tmp); - if(_status.setAutoDisengage) - _status.autoDisengage = tmp; - _status.setDefaultAutoDisengage = config_root.lookupValue - ("default_threshold", tmp); - if(_status.setDefaultAutoDisengage) - _status.defaultAutoDisengage = tmp; - } catch(libconfig::SettingNotFoundException& e) { - // SmartShift not configured, use default - } -} - -hidpp20::SmartShift::SmartshiftStatus SmartShift::Config::getSettings() -{ - return _status; -} \ No newline at end of file diff --git a/src/logid/features/SmartShift.h b/src/logid/features/SmartShift.h index ed7ac35..6ef3330 100644 --- a/src/logid/features/SmartShift.h +++ b/src/logid/features/SmartShift.h @@ -20,6 +20,7 @@ #include "../backend/hidpp20/features/SmartShift.h" #include "DeviceFeature.h" +#include "../config/schema.h" namespace logid { namespace features @@ -34,16 +35,8 @@ namespace features backend::hidpp20::SmartShift::SmartshiftStatus getStatus(); void setStatus(backend::hidpp20::SmartShift::SmartshiftStatus status); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - backend::hidpp20::SmartShift::SmartshiftStatus getSettings(); - protected: - backend::hidpp20::SmartShift::SmartshiftStatus _status; - }; private: - Config _config; + std::optional& _config; std::shared_ptr _smartshift; }; }} diff --git a/src/logid/features/ThumbWheel.cpp b/src/logid/features/ThumbWheel.cpp index 14b5dcc..458de92 100644 --- a/src/logid/features/ThumbWheel.cpp +++ b/src/logid/features/ThumbWheel.cpp @@ -29,9 +29,46 @@ using namespace logid; #define SCROLL_EVENTHANDLER_NAME "THUMB_WHEEL" -ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), - _config(dev) +std::shared_ptr _genAction( + Device* dev, std::optional& conf) { + if(conf.has_value()) { + try { + return actions::Action::makeAction(dev, conf.value()); + } catch(actions::InvalidAction& e) { + logPrintf(WARN, "Mapping thumb wheel to invalid action"); + } + } + + return nullptr; +} + +std::shared_ptr _genGesture( + Device* dev, std::optional& conf) +{ + if(conf.has_value()) { + try { + return actions::Gesture::makeGesture(dev, conf.value()); + } catch (actions::InvalidAction &e) { + logPrintf(WARN, "Mapping thumb wheel to invalid gesture"); + } + } + + return nullptr; +} + +ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), + _config (dev->activeProfile().thumbwheel) +{ + if(_config.has_value()) { + auto& conf = _config.value(); + _left_action = _genGesture(dev, conf.left); + _right_action = _genGesture(dev, conf.right); + _touch_action = _genAction(dev, conf.touch); + _tap_action = _genAction(dev, conf.tap); + _proxy_action = _genAction(dev, conf.proxy); + } + try { _thumb_wheel = std::make_shared(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { @@ -47,33 +84,41 @@ ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), logPrintf(DEBUG, "Thumb wheel resolution: native (%d), diverted (%d)", _wheel_info.nativeRes, _wheel_info.divertedRes); - if(_config.leftAction()) { + if(_left_action) { try { auto left_axis = std::dynamic_pointer_cast( - _config.leftAction()); + _left_action); // TODO: How do hires multipliers work on 0x2150 thumbwheels? if(left_axis) left_axis->setHiresMultiplier(_wheel_info.divertedRes); } catch(std::bad_cast& e) { } - _config.leftAction()->press(true); + _left_action->press(true); } - if(_config.rightAction()) { + if(_right_action) { try { auto right_axis = std::dynamic_pointer_cast( - _config.rightAction()); + _right_action); if(right_axis) right_axis->setHiresMultiplier(_wheel_info.divertedRes); } catch(std::bad_cast& e) { } - _config.rightAction()->press(true); + _right_action->press(true); } } +ThumbWheel::~ThumbWheel() { + _device->hidpp20().removeEventHandler(SCROLL_EVENTHANDLER_NAME); +} + void ThumbWheel::configure() { - _thumb_wheel->setStatus(_config.divert(), _config.invert()); + if(_config.has_value()) { + const auto& config = _config.value(); + _thumb_wheel->setStatus(config.divert.value_or(false), + config.invert.value_or(false)); + } } void ThumbWheel::listen() @@ -98,7 +143,7 @@ void ThumbWheel::listen() void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) { if(event.flags & hidpp20::ThumbWheel::SingleTap) { - auto action = _config.tapAction(); + auto action = _tap_action; if(action) { action->press(); action->release(); @@ -107,23 +152,21 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) if((bool)(event.flags & hidpp20::ThumbWheel::Proxy) != _last_proxy) { _last_proxy = !_last_proxy; - auto action = _config.proxyAction(); - if(action) { + if(_proxy_action) { if(_last_proxy) - action->press(); + _proxy_action->press(); else - action->release(); + _proxy_action->release(); } } if((bool)(event.flags & hidpp20::ThumbWheel::Touch) != _last_touch) { _last_touch = !_last_touch; - auto action = _config.touchAction(); - if(action) { + if(_touch_action) { if(_last_touch) - action->press(); + _touch_action->press(); else - action->release(); + _touch_action->release(); } } @@ -132,10 +175,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) event.rotation *= _wheel_info.defaultDirection; if(event.rotationStatus == hidpp20::ThumbWheel::Start) { - if(_config.rightAction()) - _config.rightAction()->press(true); - if(_config.leftAction()) - _config.leftAction()->press(true); + if(_right_action) + _right_action->press(true); + if(_left_action) + _left_action->press(true); _last_direction = 0; } @@ -144,9 +187,9 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) std::shared_ptr scroll_action; if(direction > 0) - scroll_action = _config.rightAction(); + scroll_action = _right_action; else - scroll_action = _config.leftAction(); + scroll_action = _left_action; if(scroll_action) { scroll_action->press(true); @@ -157,136 +200,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) } if(event.rotationStatus == hidpp20::ThumbWheel::Stop) { - if(_config.rightAction()) - _config.rightAction()->release(); - if(_config.leftAction()) - _config.leftAction()->release(); + if(_right_action) + _right_action->release(); + if(_left_action) + _left_action->release(); } } } - -ThumbWheel::Config::Config(Device* dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("thumbwheel"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: thumbwheel must be a group", - config_root.getSourceLine()); - return; - } - - try { - auto& divert = config_root.lookup("divert"); - if(divert.getType() == libconfig::Setting::TypeBoolean) { - _divert = divert; - } else { - logPrintf(WARN, "Line %d: divert must be a boolean", - divert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& invert = config_root.lookup("invert"); - if(invert.getType() == libconfig::Setting::TypeBoolean) { - _invert = invert; - } else { - logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.", - invert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - if(_divert) { - _left_action = _genGesture(dev, config_root, "left"); - if(!_left_action) - logPrintf(WARN, "Line %d: divert is true but no left action " - "was set", config_root.getSourceLine()); - - _right_action = _genGesture(dev, config_root, "right"); - if(!_right_action) - logPrintf(WARN, "Line %d: divert is true but no right action " - "was set", config_root.getSourceLine()); - } - - _proxy_action = _genAction(dev, config_root, "proxy"); - _tap_action = _genAction(dev, config_root, "tap"); - _touch_action = _genAction(dev, config_root, "touch"); - } catch(libconfig::SettingNotFoundException& e) { - // ThumbWheel not configured, use default - } -} - -std::shared_ptr ThumbWheel::Config::_genAction(Device* dev, - libconfig::Setting& config_root, const std::string& name) -{ - try { - auto& a_group = config_root.lookup(name); - try { - return actions::Action::makeAction(dev, a_group); - } catch(actions::InvalidAction& e) { - logPrintf(WARN, "Line %d: Invalid action", - a_group.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - - } - return nullptr; -} - -std::shared_ptr ThumbWheel::Config::_genGesture(Device* dev, - libconfig::Setting& config_root, const std::string& name) -{ - try { - auto& g_group = config_root.lookup(name); - try { - auto g = actions::Gesture::makeGesture(dev, g_group); - if(g->wheelCompatibility()) { - return g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - g_group.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - g_group.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - - } - return nullptr; -} - -bool ThumbWheel::Config::divert() const -{ - return _divert; -} - -bool ThumbWheel::Config::invert() const -{ - return _invert; -} - -const std::shared_ptr& ThumbWheel::Config::leftAction() const -{ - return _left_action; -} - -const std::shared_ptr& ThumbWheel::Config::rightAction() const -{ - return _right_action; -} - -const std::shared_ptr& ThumbWheel::Config::proxyAction() const -{ - return _proxy_action; -} - -const std::shared_ptr& ThumbWheel::Config::tapAction() const -{ - return _tap_action; -} - -const std::shared_ptr& ThumbWheel::Config::touchAction() const -{ - return _touch_action; -} diff --git a/src/logid/features/ThumbWheel.h b/src/logid/features/ThumbWheel.h index fae93ea..f76fd33 100644 --- a/src/logid/features/ThumbWheel.h +++ b/src/logid/features/ThumbWheel.h @@ -21,6 +21,7 @@ #include "../backend/hidpp20/features/ThumbWheel.h" #include "DeviceFeature.h" #include "../actions/gesture/Gesture.h" +#include "../config/schema.h" namespace logid { namespace features @@ -29,45 +30,26 @@ namespace features { public: explicit ThumbWheel(Device* dev); + ~ThumbWheel(); virtual void configure(); virtual void listen(); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - bool divert() const; - bool invert() const; - - const std::shared_ptr& leftAction() const; - const std::shared_ptr& rightAction() const; - const std::shared_ptr& proxyAction() const; - const std::shared_ptr& tapAction() const; - const std::shared_ptr& touchAction() const; - protected: - bool _divert = false; - bool _invert = false; - - static std::shared_ptr _genGesture(Device* dev, - libconfig::Setting& setting, const std::string& name); - static std::shared_ptr _genAction(Device* dev, - libconfig::Setting& setting, const std::string& name); - - std::shared_ptr _left_action; - std::shared_ptr _right_action; - std::shared_ptr _proxy_action; - std::shared_ptr _tap_action; - std::shared_ptr _touch_action; - }; private: void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event); std::shared_ptr _thumb_wheel; backend::hidpp20::ThumbWheel::ThumbwheelInfo _wheel_info; + + std::shared_ptr _left_action; + std::shared_ptr _right_action; + std::shared_ptr _proxy_action; + std::shared_ptr _tap_action; + std::shared_ptr _touch_action; + int8_t _last_direction = 0; bool _last_proxy = false; bool _last_touch = false; - Config _config; + std::optional& _config; }; }} From 1dd6dbfe02459055a794f5865736bc3570181cb2 Mon Sep 17 00:00:00 2001 From: pixl Date: Thu, 20 Jan 2022 22:02:29 -0500 Subject: [PATCH 14/59] Move Buttons into their own class --- src/logid/actions/KeypressAction.cpp | 6 +- src/logid/actions/gesture/AxisGesture.cpp | 4 +- src/logid/features/RemapButton.cpp | 147 +++++++++++++--------- src/logid/features/RemapButton.h | 51 ++++++-- 4 files changed, 133 insertions(+), 75 deletions(-) diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index c55317f..0dc0b1d 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -45,7 +45,7 @@ KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : const auto& keys = std::get>>( _config.keys); for(const auto& key : keys) { - if(std::holds_alternative(_config.keys)) { + if(std::holds_alternative(key)) { const auto& key_str = std::get(key); try { auto code = _device->virtualInput()->toKeyCode(key_str); @@ -55,8 +55,8 @@ KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : logPrintf(WARN, "Invalid keycode %s, skipping.", key_str.c_str()); } - } else if(std::holds_alternative(_config.keys)) { - auto& code = std::get(_config.keys); + } else if(std::holds_alternative(key)) { + auto& code = std::get(key); _device->virtualInput()->registerKey(code); _keys.emplace_back(code); } diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 19d8b00..248fa0c 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -31,8 +31,8 @@ AxisGesture::AxisGesture(Device *device, config::AxisGesture& config) : } else { const auto& axis = std::get(_config.axis); try { - _axis = _device->virtualInput()->toAxisCode(axis); - _device->virtualInput()->registerAxis(_axis); + _input_axis = _device->virtualInput()->toAxisCode(axis); + _device->virtualInput()->registerAxis(_input_axis); } catch(InputDevice::InvalidEventCode& e) { logPrintf(WARN, "Invalid axis %s."); throw InvalidGesture(); diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index ea86014..647e127 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -33,22 +33,6 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev->activeProfile().buttons), _ipc_node (dev->ipcNode()->make_child("buttons")) { - if(_config.has_value()) { - for(auto& button : _config.value()) { - if(button.second.action.has_value()) { - try { - _buttons.emplace( - button.first, - Action::makeAction( - dev,button.second.action.value())); - } catch(std::exception& e) { - logPrintf(WARN, "Error creating button action: %s", - e.what()); - } - } - } - } - try { _reprog_controls = hidpp20::ReprogControls::autoVersion( &dev->hidpp20()); @@ -58,6 +42,39 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _reprog_controls->initCidMap(); + if(!_config.has_value()) + _config = config::RemapButton(); + + for(const auto& control : _reprog_controls->getControls()) { + const auto i = _buttons.size(); + Button::ConfigFunction func = [this, info=control.second]( + std::shared_ptr action) { + hidpp20::ReprogControls::ControlInfo report{}; + report.controlID = info.controlID; + report.flags = HIDPP20_REPROG_REBIND; + + if(action) { + if(( action->reprogFlags() & + hidpp20::ReprogControls::RawXYDiverted ) && + ( !_reprog_controls->supportsRawXY() || + !(info.additionalFlags & hidpp20::ReprogControls::RawXY) )) + logPrintf(WARN, + "%s: Cannot divert raw XY movements for CID " + "0x%02x", _device->name().c_str(), + info.controlID); + + report.flags |= action->reprogFlags(); + } + _reprog_controls->setControlReporting(info.controlID, report); + }; + _buttons.emplace(std::piecewise_construct, + std::forward_as_tuple(control.second.controlID), + std::forward_as_tuple(control.second, i, + _device, func, + _ipc_node, + _config.value()[control.first])); + } + if(global_loglevel <= DEBUG) { #define FLAG(x) (control.second.flags & hidpp20::ReprogControls::x ? \ "YES" : "") @@ -77,14 +94,6 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), #undef ADDITIONAL_FLAG #undef FLAG } - - for(const auto& control : _reprog_controls->getControls()) { - auto i = std::to_string(_button_ipcs.size()); - auto node = _ipc_node->make_child(i); - auto iface = node->make_interface(this, - control.second); - _button_ipcs.emplace_back(node, iface); - } } RemapButton::~RemapButton() @@ -94,32 +103,8 @@ RemapButton::~RemapButton() void RemapButton::configure() { - ///TODO: DJ reporting trickery if cannot be remapped - for(const auto& i : _buttons) { - hidpp20::ReprogControls::ControlInfo info{}; - try { - info = _reprog_controls->getControlIdInfo(i.first); - } catch(hidpp20::Error& e) { - if(e.code() == hidpp20::Error::InvalidArgument) { - logPrintf(WARN, "%s: CID 0x%02x does not exist.", - _device->name().c_str(), i.first); - continue; - } - throw e; - } - - if((i.second->reprogFlags() & hidpp20::ReprogControls::RawXYDiverted) && - (!_reprog_controls->supportsRawXY() || !(info.additionalFlags & - hidpp20::ReprogControls::RawXY))) - logPrintf(WARN, "%s: Cannot divert raw XY movements for CID " - "0x%02x", _device->name().c_str(), i.first); - - hidpp20::ReprogControls::ControlInfo report{}; - report.controlID = i.first; - report.flags = HIDPP20_REPROG_REBIND; - report.flags |= i.second->reprogFlags(); - _reprog_controls->setControlReporting(i.first, report); - } + for(const auto& button : _buttons) + button.second.configure(); } void RemapButton::listen() @@ -142,8 +127,8 @@ void RemapButton::listen() else { // RawXY auto divertedXY = _reprog_controls->divertedRawXYEvent(report); for(const auto& button : this->_buttons) - if(button.second->pressed()) - button.second->move(divertedXY.x, divertedXY.y); + if(button.second.pressed()) + button.second.move(divertedXY.x, divertedXY.y); } }; @@ -164,7 +149,7 @@ void RemapButton::_buttonEvent(const std::set& new_state) } else { auto action = _buttons.find(i); if(action != _buttons.end()) - action->second->press(); + action->second.press(); } } @@ -172,22 +157,66 @@ void RemapButton::_buttonEvent(const std::set& new_state) for(auto& i : _pressed_buttons) { auto action = _buttons.find(i); if(action != _buttons.end()) - action->second->release(); + action->second.release(); } _pressed_buttons = new_state; } -RemapButton::ButtonIPC::ButtonIPC( - RemapButton *parent, - backend::hidpp20::ReprogControls::ControlInfo info) : +Button::Button(Info info, int index, + Device *device, ConfigFunction conf_func, + std::shared_ptr root, + config::Button &config) : + _node (root->make_child(std::to_string(index))), + _interface (_node->make_interface(this, info)), + _device (device), _conf_func (std::move(conf_func)), + _config (config), + _info (info) +{ + if(_config.action.has_value()) { + try { + _action = Action::makeAction(_device, _config.action.value()); + } catch(std::exception& e) { + logPrintf(WARN, "Error creating button action: %s", + e.what()); + } + } +} + +void Button::press() const { + if(_action) + _action->press(); +} + +void Button::release() const { + if(_action) + _action->release(); +} + +void Button::move(int16_t x, int16_t y) const { + if(_action) + _action->move(x, y); +} + +bool Button::pressed() const { + if(_action) + return _action->pressed(); + return false; +} + +void Button::configure() const { + _conf_func(_action); +} + +Button::IPC::IPC(Button* parent, + const Info& info) : ipcgull::interface("pizza.pixl.LogiOps.Device.Button", {}, { {"ControlID", ipcgull::property( ipcgull::property_readable, info.controlID)}, - {"Remappable", ipcgull::property( + {"Remappable", ipcgull::property( ipcgull::property_readable, info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, - {"GestureSupport", ipcgull::property( + {"GestureSupport", ipcgull::property( ipcgull::property_readable, (info.additionalFlags & hidpp20::ReprogControls::RawXY) )} diff --git a/src/logid/features/RemapButton.h b/src/logid/features/RemapButton.h index e78fe26..e2d2611 100644 --- a/src/logid/features/RemapButton.h +++ b/src/logid/features/RemapButton.h @@ -25,6 +25,45 @@ namespace logid { namespace features { + class RemapButton; + + class Button + { + public: + typedef backend::hidpp20::ReprogControls::ControlInfo Info; + typedef std::function)> + ConfigFunction; + + Button(Info info, int index, + Device* device, ConfigFunction conf_func, + std::shared_ptr root, + config::Button& config); + void press() const; + void release() const; + void move(int16_t x, int16_t y) const; + + void configure() const; + + bool pressed() const; + private: + class IPC : public ipcgull::interface + { + public: + IPC(Button* parent, + const Info& info); + }; + + std::shared_ptr _node; + std::shared_ptr _interface; + Device* _device; + const ConfigFunction _conf_func; + + config::Button& _config; + + std::shared_ptr _action; + const Info _info; + }; + class RemapButton : public DeviceFeature { public: @@ -34,25 +73,15 @@ namespace features virtual void listen(); private: - class ButtonIPC : public ipcgull::interface - { - public: - ButtonIPC(RemapButton* parent, - backend::hidpp20::ReprogControls::ControlInfo info); - }; - void _buttonEvent(const std::set& new_state); std::shared_ptr _reprog_controls; std::set _pressed_buttons; std::mutex _button_lock; std::optional& _config; - std::map> _buttons; + std::map _buttons; std::shared_ptr _ipc_node; - typedef std::pair, - std::shared_ptr> ButtonIPCPair; - std::vector _button_ipcs; }; }} From dbe24f9350212c1ea68dc2de60f431117214fb0e Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 21 Jan 2022 23:24:47 -0500 Subject: [PATCH 15/59] Phase out workqueue --- src/logid/CMakeLists.txt | 5 +- src/logid/Device.cpp | 16 +-- src/logid/Device.h | 1 - src/logid/DeviceManager.cpp | 9 +- src/logid/DeviceManager.h | 1 - src/logid/Receiver.cpp | 3 +- src/logid/actions/ChangeDPI.cpp | 2 +- src/logid/actions/ChangeHostAction.cpp | 2 +- src/logid/actions/CycleDPI.cpp | 2 +- src/logid/actions/ToggleHiresScroll.cpp | 2 +- src/logid/actions/ToggleSmartShift.cpp | 2 +- src/logid/backend/dj/Receiver.cpp | 7 +- src/logid/backend/dj/Receiver.h | 4 +- src/logid/backend/dj/ReceiverMonitor.cpp | 68 ++++++------ src/logid/backend/dj/ReceiverMonitor.h | 4 +- src/logid/backend/hidpp/Device.cpp | 6 +- src/logid/backend/hidpp/Device.h | 3 +- src/logid/backend/hidpp10/Device.cpp | 5 +- src/logid/backend/hidpp10/Device.h | 3 +- src/logid/backend/hidpp20/Device.cpp | 5 +- src/logid/backend/hidpp20/Device.h | 2 +- src/logid/backend/raw/DeviceMonitor.cpp | 72 ++++++------ src/logid/backend/raw/DeviceMonitor.h | 11 +- src/logid/backend/raw/RawDevice.cpp | 41 ++----- src/logid/backend/raw/RawDevice.h | 12 +- src/logid/config/schema.h | 6 +- src/logid/features/DeviceStatus.cpp | 2 +- src/logid/logid.cpp | 1 - src/logid/util/task.cpp | 67 ++---------- src/logid/util/task.h | 46 +------- src/logid/util/worker_thread.cpp | 89 --------------- src/logid/util/worker_thread.h | 56 ---------- src/logid/util/workqueue.cpp | 134 ----------------------- src/logid/util/workqueue.h | 63 ----------- 34 files changed, 128 insertions(+), 624 deletions(-) delete mode 100644 src/logid/util/worker_thread.cpp delete mode 100644 src/logid/util/worker_thread.h delete mode 100644 src/logid/util/workqueue.cpp delete mode 100644 src/logid/util/workqueue.h diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 3fe8150..63bac6b 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -64,11 +64,8 @@ add_executable(logid backend/hidpp20/features/WirelessDeviceStatus.cpp backend/hidpp20/features/ThumbWheel.cpp backend/dj/Report.cpp - util/mutex_queue.h - util/workqueue.cpp - util/worker_thread.cpp - util/task.cpp util/thread.cpp + util/task.cpp util/ExceptionHandler.cpp) set_target_properties(logid PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 2163e24..bbc176e 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -98,8 +98,7 @@ std::shared_ptr Device::make( Device::Device(std::string path, backend::hidpp::DeviceIndex index, std::shared_ptr manager) : _hidpp20 (path, index, - manager->config()->io_timeout.value_or(defaults::io_timeout), - manager->workQueue()), + manager->config()->io_timeout.value_or(defaults::io_timeout)), _path (std::move(path)), _index (index), _config (_getConfig(manager, _hidpp20.name())), _receiver (nullptr), @@ -213,19 +212,6 @@ void Device::reset() "available.", _path.c_str(), _index); } -std::shared_ptr Device::workQueue() const -{ - if(auto manager = _manager.lock()) { - return manager->workQueue(); - } else { - logPrintf(ERROR, "Device manager lost"); - logPrintf(ERROR, - "Fatal error occurred, file a bug report," - " the program will now exit."); - std::terminate(); - } -} - std::shared_ptr Device::virtualInput() const { if(auto manager = _manager.lock()) { diff --git a/src/logid/Device.h b/src/logid/Device.h index 0c143d9..503ab44 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -82,7 +82,6 @@ namespace logid void reset(); - [[nodiscard]] std::shared_ptr workQueue() const; [[nodiscard]] std::shared_ptr virtualInput() const; [[nodiscard]] std::shared_ptr ipcNode() const; diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 854df9d..7ae827d 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -24,7 +24,6 @@ #include "DeviceManager.h" #include "Receiver.h" #include "util/log.h" -#include "util/workqueue.h" #include "backend/hidpp10/Error.h" #include "backend/Error.h" @@ -44,7 +43,7 @@ namespace logid { DeviceManager::DeviceManager(std::shared_ptr config, std::shared_ptr virtual_input, std::shared_ptr server) : - backend::raw::DeviceMonitor(config->workers.value_or(defaults::worker_count)), + backend::raw::DeviceMonitor(), _server (std::move(server)), _config (std::move(config)), _virtual_input (std::move(virtual_input)), _root_node (ipcgull::node::make_root("")), @@ -96,8 +95,7 @@ void DeviceManager::addDevice(std::string path) // Check if device is ignored before continuing { raw::RawDevice raw_dev( - path,config()->io_timeout.value_or(defaults::io_timeout), - workQueue()); + path,config()->io_timeout.value_or(defaults::io_timeout)); if(config()->ignore.has_value() && config()->ignore.value().contains(raw_dev.productId())) { logPrintf(DEBUG, "%s: Device 0x%04x ignored.", @@ -109,8 +107,7 @@ void DeviceManager::addDevice(std::string path) try { hidpp::Device device( path, hidpp::DefaultDevice, - config()->io_timeout.value_or(defaults::io_timeout), - workQueue()); + config()->io_timeout.value_or(defaults::io_timeout)); isReceiver = device.version() == std::make_tuple(1, 0); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index 8f67934..aecc991 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -32,7 +32,6 @@ namespace logid { - class workqueue; class InputDevice; class DeviceManager : public backend::raw::DeviceMonitor diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index cc1edaf..7ea7f5c 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -66,8 +66,7 @@ Receiver::Receiver(const std::string& path, const std::shared_ptr& manager) : dj::ReceiverMonitor(path, manager->config()->io_timeout.value_or( - defaults::io_timeout), - manager->workQueue()), + defaults::io_timeout)), _path (path), _manager (manager), _nickname (manager), _ipc_node (manager->receiversNode()->make_child(_nickname)), _ipc_interface (_ipc_node->make_interface(this)) diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index 7eee2c9..c1f7f62 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -39,7 +39,7 @@ void ChangeDPI::press() { _pressed = true; if(_dpi) { - task::spawn(_device->workQueue(), + spawn_task( [this]{ try { uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0)); diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index 0b87507..ad0a8b3 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -49,7 +49,7 @@ void ChangeHostAction::press() void ChangeHostAction::release() { if(_change_host) { - task::spawn(_device->workQueue(), + spawn_task( [this] { auto host_info = _change_host->getHostInfo(); int next_host; diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index 499e29d..60c0f04 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -40,7 +40,7 @@ void CycleDPI::press() { _pressed = true; if(_dpi && !_config.dpis.empty()) { - task::spawn(_device->workQueue(), + spawn_task( [this](){ std::lock_guard lock(_dpi_lock); ++_current_dpi; diff --git a/src/logid/actions/ToggleHiresScroll.cpp b/src/logid/actions/ToggleHiresScroll.cpp index 591e09b..35e5f8d 100644 --- a/src/logid/actions/ToggleHiresScroll.cpp +++ b/src/logid/actions/ToggleHiresScroll.cpp @@ -38,7 +38,7 @@ void ToggleHiresScroll::press() _pressed = true; if(_hires_scroll) { - task::spawn(_device->workQueue(), + spawn_task( [hires=this->_hires_scroll](){ auto mode = hires->getMode(); mode ^= backend::hidpp20::HiresScroll::HiRes; diff --git a/src/logid/actions/ToggleSmartShift.cpp b/src/logid/actions/ToggleSmartShift.cpp index 58c5e36..fe5efe1 100644 --- a/src/logid/actions/ToggleSmartShift.cpp +++ b/src/logid/actions/ToggleSmartShift.cpp @@ -37,7 +37,7 @@ void ToggleSmartShift::press() { _pressed = true; if(_smartshift) { - task::spawn(_device->workQueue(), + spawn_task( [ss=this->_smartshift](){ auto status = ss->getStatus(); status.setActive = true; diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index f0909e5..a97ece1 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -20,7 +20,6 @@ #include "Report.h" #include "Receiver.h" #include "Error.h" -#include "../../util/thread.h" using namespace logid::backend::dj; using namespace logid::backend; @@ -44,11 +43,9 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept return _reason; } -Receiver::Receiver(std::string path, - double io_timeout, - const std::shared_ptr& wq) : +Receiver::Receiver(std::string path, double io_timeout) : _raw_device (std::make_shared( - std::move(path), io_timeout, wq)), + std::move(path), io_timeout)), _hidpp10_device (_raw_device, hidpp::DefaultDevice) { if(!supportsDjReports(_raw_device->reportDescriptor())) diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index 270a4eb..7152918 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -52,9 +52,7 @@ namespace dj class Receiver final { public: - Receiver(std::string path, - double io_timeout, - const std::shared_ptr& wq); + Receiver(std::string path, double io_timeout); enum DjEvents : uint8_t { diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index ae51314..55e527d 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -25,12 +25,8 @@ using namespace logid::backend::dj; -ReceiverMonitor::ReceiverMonitor( - std::string path, - double io_timeout, - const std::shared_ptr& wq) : - _workqueue (wq), - _receiver (std::make_shared(std::move(path), io_timeout, wq)) +ReceiverMonitor::ReceiverMonitor(std::string path, double io_timeout) : + _receiver (std::make_shared(std::move(path), io_timeout)) { assert(_receiver->hidppEventHandlers().find("RECVMON") == _receiver->hidppEventHandlers().end()); @@ -66,25 +62,29 @@ void ReceiverMonitor::run() /* Running in a new thread prevents deadlocks since the * receiver may be enumerating. */ - task::spawn(_workqueue, - [this, report]() { - if (report.subId() == Receiver::DeviceConnection) - this->addDevice(this->_receiver->deviceConnectionEvent - (report)); - else if (report.subId() == Receiver::DeviceDisconnection) - this->removeDevice(this->_receiver-> - deviceDisconnectionEvent(report)); - }, {[report, path=this->_receiver->rawDevice()->hidrawPath()] - (std::exception& e) { - if(report.subId() == Receiver::DeviceConnection) - logPrintf(ERROR, "Failed to add device %d to receiver " - "on %s: %s", report.deviceIndex(), - path.c_str(), e.what()); - else if(report.subId() == Receiver::DeviceDisconnection) - logPrintf(ERROR, "Failed to remove device %d from " - "receiver on %s: %s", report.deviceIndex() - ,path.c_str(), e.what()); - }}); + std::async([this, report, + path=this->_receiver->rawDevice()->hidrawPath()]() { + if (report.subId() == Receiver::DeviceConnection) { + try { + this->addDevice(this->_receiver->deviceConnectionEvent + (report)); + } catch(std::exception& e) { + logPrintf(ERROR, "Failed to add device %d to receiver " + "on %s: %s", report.deviceIndex(), + path.c_str(), e.what()); + } + } + else if (report.subId() == Receiver::DeviceDisconnection) { + try { + this->removeDevice(this->_receiver-> + deviceDisconnectionEvent(report)); + } catch(std::exception& e) { + logPrintf(ERROR, "Failed to remove device %d from " + "receiver on %s: %s", report.deviceIndex(), + path.c_str(), e.what()); + } + } + }); }; _receiver->addHidppEventHandler("RECVMON", event_handler); @@ -122,16 +122,18 @@ void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) event.index = index; event.fromTimeoutCheck = true; - task::spawn(_workqueue, - {[this, event, nickname]() { + spawn_task( + [this, event, nickname]() { + try { _receiver->rawDevice()->removeEventHandler(nickname); this->addDevice(event); - }}, {[path=_receiver->rawDevice()->hidrawPath(), event] - (std::exception& e) { - logPrintf(ERROR, "Failed to add device %d to receiver " - "on %s: %s", event.index, - path.c_str(), e.what()); - }}); + } catch(std::exception& e) { + logPrintf(ERROR, "Failed to add device %d to receiver " + "on %s: %s", event.index, + _receiver->rawDevice()->hidrawPath().c_str(), + e.what()); + } + }); }; _receiver->rawDevice()->addEventHandler(nickname, handler); diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 1349bf8..33517b4 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -33,8 +33,7 @@ namespace dj { public: ReceiverMonitor(std::string path, - double io_timeout, - const std::shared_ptr& wq); + double io_timeout); virtual ~ReceiverMonitor(); void enumerate(); @@ -55,7 +54,6 @@ namespace dj std::shared_ptr receiver() const; private: - std::shared_ptr _workqueue; std::shared_ptr _receiver; }; diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index a4d727c..7bc521d 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -18,7 +18,6 @@ #include #include -#include "../../util/thread.h" #include "Device.h" #include "Report.h" #include "../hidpp20/features/Root.h" @@ -50,9 +49,8 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept } Device::Device(const std::string& path, DeviceIndex index, - double io_timeout, - const std::shared_ptr& wq): - _raw_device (std::make_shared(path, io_timeout, wq)), + double io_timeout): + _raw_device (std::make_shared(path, io_timeout)), _receiver (nullptr), _path (path), _index (index) { _init(); diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 1dea588..9c36b85 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -62,8 +62,7 @@ namespace hidpp }; Device(const std::string& path, DeviceIndex index, - double io_timeout, - const std::shared_ptr& wq); + double io_timeout); Device(std::shared_ptr raw_device, DeviceIndex index); Device(std::shared_ptr receiver, diff --git a/src/logid/backend/hidpp10/Device.cpp b/src/logid/backend/hidpp10/Device.cpp index 8f6e54e..65cf538 100644 --- a/src/logid/backend/hidpp10/Device.cpp +++ b/src/logid/backend/hidpp10/Device.cpp @@ -25,9 +25,8 @@ using namespace logid::backend; using namespace logid::backend::hidpp10; Device::Device(const std::string &path, hidpp::DeviceIndex index, - double io_timeout, - const std::shared_ptr& wq) : - hidpp::Device(path, index, io_timeout, wq) + double io_timeout) : + hidpp::Device(path, index, io_timeout) { assert(version() == std::make_tuple(1, 0)); } diff --git a/src/logid/backend/hidpp10/Device.h b/src/logid/backend/hidpp10/Device.h index b61e054..be98dd0 100644 --- a/src/logid/backend/hidpp10/Device.h +++ b/src/logid/backend/hidpp10/Device.h @@ -29,8 +29,7 @@ namespace hidpp10 { public: Device(const std::string& path, hidpp::DeviceIndex index, - double io_timeout, - const std::shared_ptr& wq); + double io_timeout); Device(std::shared_ptr raw_dev, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index ed93b70..a3ac6a3 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -23,9 +23,8 @@ using namespace logid::backend::hidpp20; -Device::Device(std::string path, hidpp::DeviceIndex index, - double io_timeout, const std::shared_ptr& wq) : - hidpp::Device(path, index, io_timeout, wq) +Device::Device(std::string path, hidpp::DeviceIndex index, double io_timeout) : + hidpp::Device(path, index, io_timeout) { assert(std::get<0>(version()) >= 2); } diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index 482abe8..64f80c3 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -29,7 +29,7 @@ namespace hidpp20 { { public: Device(std::string path, hidpp::DeviceIndex index, - double io_timeout, const std::shared_ptr& wq); + double io_timeout); Device(std::shared_ptr raw_device, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, hidpp::DeviceIndex index); diff --git a/src/logid/backend/raw/DeviceMonitor.cpp b/src/logid/backend/raw/DeviceMonitor.cpp index 8520c23..1553e61 100644 --- a/src/logid/backend/raw/DeviceMonitor.cpp +++ b/src/logid/backend/raw/DeviceMonitor.cpp @@ -18,7 +18,6 @@ #include "DeviceMonitor.h" #include "../../util/task.h" -#include "../../util/workqueue.h" #include "../../util/log.h" #include "RawDevice.h" #include "../hidpp/Device.h" @@ -35,8 +34,7 @@ extern "C" using namespace logid; using namespace logid::backend::raw; -DeviceMonitor::DeviceMonitor(int worker_count) : - _workqueue (std::make_shared(worker_count)) +DeviceMonitor::DeviceMonitor() { if(-1 == pipe(_pipe)) throw std::system_error(errno, std::system_category(), @@ -103,28 +101,32 @@ void DeviceMonitor::run() std::string devnode = udev_device_get_devnode(device); if (action == "add") - task::spawn(_workqueue, + spawn_task( [this, name=devnode]() { - // Wait for device to initialise - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - auto supported_reports = backend::hidpp::getSupportedReports( - RawDevice::getReportDescriptor(name)); - if(supported_reports) - this->addDevice(name); - else - logPrintf(DEBUG, "Unsupported device %s ignored", - name.c_str()); - }, [name=devnode](std::exception& e){ - logPrintf(WARN, "Error adding device %s: %s", - name.c_str(), e.what()); + try { + // Wait for device to initialise + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + auto supported_reports = backend::hidpp::getSupportedReports( + RawDevice::getReportDescriptor(name)); + if(supported_reports) + this->addDevice(name); + else + logPrintf(DEBUG, "Unsupported device %s ignored", + name.c_str()); + } catch(std::exception& e) { + logPrintf(WARN, "Error adding device %s: %s", + name.c_str(), e.what()); + } }); else if (action == "remove") - task::spawn(_workqueue, + spawn_task( [this, name=devnode]() { - this->removeDevice(name); - }, [name=devnode](std::exception& e){ - logPrintf(WARN, "Error removing device %s: %s", - name.c_str(), e.what()); + try { + this->removeDevice(name); + } catch(std::exception& e) { + logPrintf(WARN, "Error removing device %s: %s", + name.c_str(), e.what()); + } }); udev_device_unref (device); @@ -172,24 +174,22 @@ void DeviceMonitor::enumerate() std::string devnode = udev_device_get_devnode(device); udev_device_unref(device); - task::spawn(_workqueue, + spawn_task( [this, name=devnode]() { - auto supported_reports = backend::hidpp::getSupportedReports( - RawDevice::getReportDescriptor(name)); - if(supported_reports) - this->addDevice(name); - else - logPrintf(DEBUG, "Unsupported device %s ignored", - name.c_str()); - }, [name=devnode](std::exception& e){ - logPrintf(WARN, "Error adding device %s: %s", - name.c_str(), e.what()); + try { + auto supported_reports = backend::hidpp::getSupportedReports( + RawDevice::getReportDescriptor(name)); + if(supported_reports) + this->addDevice(name); + else + logPrintf(DEBUG, "Unsupported device %s ignored", + name.c_str()); + } catch(std::exception& e) { + logPrintf(WARN, "Error adding device %s: %s", + name.c_str(), e.what()); + } }); } udev_enumerate_unref(udev_enum); } - -std::shared_ptr DeviceMonitor::workQueue() const { - return _workqueue; -} diff --git a/src/logid/backend/raw/DeviceMonitor.h b/src/logid/backend/raw/DeviceMonitor.h index c54cb64..9b7fc8e 100644 --- a/src/logid/backend/raw/DeviceMonitor.h +++ b/src/logid/backend/raw/DeviceMonitor.h @@ -26,10 +26,7 @@ struct udev; -namespace logid { - class workqueue; -namespace backend { -namespace raw +namespace logid::backend::raw { class DeviceMonitor { @@ -38,9 +35,8 @@ namespace raw void run(); void stop(); - std::shared_ptr workQueue() const; protected: - explicit DeviceMonitor(int worker_count); + DeviceMonitor(); virtual ~DeviceMonitor(); virtual void addDevice(std::string device) = 0; virtual void removeDevice(std::string device) = 0; @@ -49,8 +45,7 @@ namespace raw int _pipe[2]; std::atomic _run_monitor; std::mutex _running; - std::shared_ptr _workqueue; }; -}}} +} #endif //LOGID_BACKEND_RAW_DEVICEMONITOR_H \ No newline at end of file diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index dd2103e..0c86eb6 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -22,10 +22,7 @@ #include "../dj/defs.h" #include "../../util/log.h" #include "../hidpp/Report.h" -#include "../../Configuration.h" #include "../../util/thread.h" -#include "../../util/task.h" -#include "../../util/workqueue.h" #include #include @@ -64,14 +61,11 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length) } } -RawDevice::RawDevice(std::string path, - double io_timeout, - const std::shared_ptr& wq) : +RawDevice::RawDevice(std::string path, double io_timeout) : _path (std::move(path)), _continue_listen (false), _continue_respond (false), _io_timeout (duration_cast( - duration(io_timeout))), - _workqueue (wq) + duration(io_timeout))) { int ret; @@ -204,32 +198,19 @@ std::vector RawDevice::sendReport(const std::vector& report) return f.get(); } else { - std::vector response; std::exception_ptr _exception; - std::shared_ptr t = std::make_shared( - [this, report, &response]() { - response = _respondToReport(report); - }, [&_exception](std::exception& e) { - try { - throw e; - } catch(std::exception& e) { - _exception = std::make_exception_ptr(e); - } - }); - _workqueue->queue(t); - t->waitStart(); - auto status = t->waitFor(_io_timeout); - if(_exception) - std::rethrow_exception(_exception); + auto response = std::async(std::launch::deferred, + [this, report]()->std::vector { + return _respondToReport(report); + }); + auto status = response.wait_for(_io_timeout); if(status == std::future_status::timeout) { - _continue_respond = false; interruptRead(); - t->wait(); - if(_exception) - std::rethrow_exception(_exception); + if(response.valid()) + response.wait(); throw TimeoutError(); - } else - return response; + } + return response.get(); } } diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 2619e90..0a41caa 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -30,11 +30,7 @@ #include "defs.h" #include "../../util/mutex_queue.h" -namespace logid { - class workqueue; - -namespace backend { -namespace raw +namespace logid::backend::raw { class RawDevice { @@ -42,8 +38,7 @@ namespace raw static bool supportedReport(uint8_t id, uint8_t length); explicit RawDevice(std::string path, - double io_timeout, - const std::shared_ptr& wq); + double io_timeout); ~RawDevice(); std::string hidrawPath() const; @@ -85,7 +80,6 @@ namespace raw std::condition_variable _listen_condition; const std::chrono::milliseconds _io_timeout; - const std::shared_ptr _workqueue; std::map> _event_handlers; @@ -104,6 +98,6 @@ namespace raw mutex_queue()>>> _io_queue; }; -}}} +} #endif //LOGID_BACKEND_RAWDEVICE_H \ No newline at end of file diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h index ecffbf3..3fe3f52 100644 --- a/src/logid/config/schema.h +++ b/src/logid/config/schema.h @@ -276,12 +276,10 @@ namespace logid::config { std::variant, "name">> devices; std::optional> ignore; std::optional io_timeout; - std::optional workers; - Config() : group({"devices", "ignore", "io_timeout", "workers"}, + Config() : group({"devices", "ignore", "io_timeout"}, &Config::devices, &Config::ignore, - &Config::io_timeout, - &Config::workers) { } + &Config::io_timeout) { } }; } diff --git a/src/logid/features/DeviceStatus.cpp b/src/logid/features/DeviceStatus.cpp index e7c2bc7..0757cd8 100644 --- a/src/logid/features/DeviceStatus.cpp +++ b/src/logid/features/DeviceStatus.cpp @@ -62,7 +62,7 @@ void DeviceStatus::listen() auto event = hidpp20::WirelessDeviceStatus::statusBroadcastEvent( report); if(event.reconfNeeded) - task::spawn(dev->workQueue(), [dev](){ dev->wakeup(); }); + spawn_task( [dev](){ dev->wakeup(); }); }; _device->hidpp20().addEventHandler(EVENTHANDLER_NAME, handler); diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index b3ffcd6..223546f 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -25,7 +25,6 @@ #include "util/log.h" #include "DeviceManager.h" #include "InputDevice.h" -#include "util/workqueue.h" #define LOGID_VIRTUAL_INPUT_NAME "LogiOps Virtual Input" #define DEFAULT_CONFIG_FILE "/etc/logid.cfg" diff --git a/src/logid/util/task.cpp b/src/logid/util/task.cpp index 7a680d7..32f4a05 100644 --- a/src/logid/util/task.cpp +++ b/src/logid/util/task.cpp @@ -16,66 +16,17 @@ * */ #include "task.h" -#include "workqueue.h" using namespace logid; -task::task(const std::function& function, - const std::function& exception_handler) : - _function (std::make_shared>(function)), - _exception_handler (std::make_shared> - (exception_handler)), _status (Waiting), - _task_pkg ([this](){ - try { - (*_function)(); - } catch(std::exception& e) { - (*_exception_handler)(e); - } - }), _future (_task_pkg.get_future()) +void logid::spawn_task(const std::function& function) { -} - -void task::run() -{ - _status = Running; - _status_cv.notify_all(); - _task_pkg(); - _status = Completed; - _status_cv.notify_all(); -} - -task::Status task::getStatus() -{ - return _status; -} - -void task::wait() -{ - if(_future.valid()) - _future.wait(); - else { - std::mutex wait_start; - std::unique_lock lock(wait_start); - _status_cv.wait(lock, [this](){ return _status == Completed; }); - } -} - -void task::waitStart() -{ - std::mutex wait_start; - std::unique_lock lock(wait_start); - _status_cv.wait(lock, [this](){ return _status != Waiting; }); -} - -std::future_status task::waitFor(std::chrono::milliseconds ms) -{ - return _future.wait_for(ms); -} - -void task::spawn(std::shared_ptr wq, - const std::function& function, - const std::function& exception_handler) -{ - auto t = std::make_shared(function, exception_handler); - wq->queue(t); + auto future = std::make_shared>(); + *future = std::async(std::launch::async,[function, future]() { + try { + function(); + } catch(std::exception& e) { + ExceptionHandler::Default(e); + } + }); } \ No newline at end of file diff --git a/src/logid/util/task.h b/src/logid/util/task.h index 728504d..e258465 100644 --- a/src/logid/util/task.h +++ b/src/logid/util/task.h @@ -25,48 +25,10 @@ namespace logid { - class workqueue; - - class task - { - public: - enum Status - { - Waiting, - Running, - Completed - }; - - explicit task(const std::function& function, - const std::function& - exception_handler={[](std::exception& e) - {ExceptionHandler::Default(e);}}); - - Status getStatus(); - - void run(); // Runs synchronously - void wait(); - void waitStart(); - std::future_status waitFor(std::chrono::milliseconds ms); - - /* This function spawns a new task into the least used worker queue - * and forgets about it. - */ - static void spawn(std::shared_ptr wq, - const std::function& function, - const std::function& - exception_handler={[](std::exception& e) - {ExceptionHandler::Default(e);}}); - - private: - std::shared_ptr> _function; - std::shared_ptr> - _exception_handler; - std::atomic _status; - std::condition_variable _status_cv; - std::packaged_task _task_pkg; - std::future _future; - }; + /* This function spawns a new task into the least used worker queue + * and forgets about it. + */ + void spawn_task(const std::function& function); } #endif //LOGID_TASK_H diff --git a/src/logid/util/worker_thread.cpp b/src/logid/util/worker_thread.cpp deleted file mode 100644 index 81dda91..0000000 --- a/src/logid/util/worker_thread.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 -#include "worker_thread.h" -#include "log.h" -#include "workqueue.h" - -using namespace logid; - -worker_thread::worker_thread(workqueue* parent, std::size_t worker_number) : -_parent (parent), _worker_number (worker_number), _continue_run (false), -_thread (std::make_unique ([this](){ - _run(); }, [this](std::exception& e){ _exception_handler(e); })) -{ - _thread->run(); -} - -worker_thread::~worker_thread() -{ - _continue_run = false; - _queue_cv.notify_all(); - // Block until task is complete - std::unique_lock lock(_busy); - - while(!_queue.empty()) { - _parent->queue(_queue.front()); - _queue.pop(); - } -} - -void worker_thread::queue(const std::shared_ptr& t) -{ - _queue.push(t); - _queue_cv.notify_all(); -} - -bool worker_thread::busy() -{ - bool not_busy = _busy.try_lock(); - - if(not_busy) - _busy.unlock(); - - return !not_busy; -} - -void worker_thread::_run() -{ - std::unique_lock lock(_run_lock); - _continue_run = true; - while(_continue_run) { - _parent->busyUpdate(); - _queue_cv.wait(lock, [this]{ return !_queue.empty() || - !_continue_run; }); - if(!_continue_run) - return; - std::unique_lock busy_lock(_busy); - while(!_queue.empty()) { - _queue.front()->run(); - _queue.pop(); - } - _parent->notifyFree(); - } -} - -void worker_thread::_exception_handler(std::exception &e) -{ - logPrintf(WARN, "Exception caught on worker thread %d, restarting: %s", - _worker_number, e.what()); - // This action destroys the logid::thread, std::thread should detach safely. - _thread = std::make_unique([this](){ _run(); }, - [this](std::exception& e) { _exception_handler(e); }); - _thread->run(); -} \ No newline at end of file diff --git a/src/logid/util/worker_thread.h b/src/logid/util/worker_thread.h deleted file mode 100644 index 0dd53ca..0000000 --- a/src/logid/util/worker_thread.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 . - * - */ -#ifndef LOGID_WORKER_THREAD_H -#define LOGID_WORKER_THREAD_H - -#include "mutex_queue.h" -#include "task.h" -#include "thread.h" - -namespace logid -{ - class workqueue; - - class worker_thread - { - public: - worker_thread(workqueue* parent, std::size_t worker_number); - ~worker_thread(); - - void queue(const std::shared_ptr& t); - - bool busy(); - private: - void _run(); - void _exception_handler(std::exception& e); - - workqueue* _parent; - const std::size_t _worker_number; - - std::mutex _run_lock; - std::atomic _continue_run; - std::condition_variable _queue_cv; - - std::unique_ptr _thread; - std::mutex _busy; - - mutex_queue> _queue; - }; -} - -#endif //LOGID_WORKER_THREAD_H diff --git a/src/logid/util/workqueue.cpp b/src/logid/util/workqueue.cpp deleted file mode 100644 index 44fb347..0000000 --- a/src/logid/util/workqueue.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 -#include "workqueue.h" -#include "worker_thread.h" -#include "log.h" - -using namespace logid; - -workqueue::workqueue(std::size_t thread_count) : _manager_thread ( - std::make_unique( - [this](){ _run(); } - , [this](std::exception& e){ _exception_handler(e); } - )), _continue_run (false), _worker_count (thread_count) -{ - _workers.reserve(_worker_count); - for(std::size_t i = 0; i < _worker_count; i++) - _workers.push_back(std::make_unique(this, i)); - _manager_thread->run(); -} - -workqueue::~workqueue() -{ - stop(); - - while(_workers.empty()) - _workers.pop_back(); - - // Queue should have been empty before, but just confirm here. - while(!_queue.empty()) { - thread::spawn([t=_queue.front()](){ t->run(); }); - _queue.pop(); - } -} - -void workqueue::queue(const std::shared_ptr& t) -{ - assert(t != nullptr); - _queue.push(t); - _queue_cv.notify_all(); -} - -void workqueue::busyUpdate() -{ - _busy_cv.notify_all(); -} - -void workqueue::stop() -{ - _continue_run = false; - std::unique_lock lock(_run_lock); -} - -std::size_t workqueue::threadCount() const -{ - return _workers.size(); -} - -void workqueue::notifyFree() -{ - _busy_cv.notify_all(); -} - -void workqueue::_run() -{ - using namespace std::chrono_literals; - - std::unique_lock lock(_run_lock); - _continue_run = true; - while(_continue_run) { - bool queued = false; - _queue_cv.wait(lock, [this]{ return !(_queue.empty()); }); - while(!_queue.empty()) { - if(_workers.empty()) { - if(_worker_count) - logPrintf(DEBUG, "No workers were found, running task in" - " a new thread."); - thread::spawn([t=_queue.front()](){ t->run(); }); - _queue.pop(); - continue; - } - - for(auto& worker : _workers) { - if(!worker->busy()) { - worker->queue(_queue.front()); - queued = true; - break; - } - } - if(!queued) { - if(_busy_cv.wait_for(lock, 500ms) == std::cv_status::no_timeout) { - for(auto& worker : _workers) { - if(!worker->busy()) { - worker->queue(_queue.front()); - break; - } - } - } else{ - // Workers busy, launch in new thread - logPrintf(DEBUG, "All workers were busy for 500ms, " - "running task in new thread."); - thread::spawn([t = _queue.front()]() { t->run(); }); - } - } - - _queue.pop(); - } - } -} - -void workqueue::_exception_handler(std::exception &e) -{ - logPrintf(WARN, "Exception caught on workqueue manager thread, " - "restarting: %s" , e.what()); - // This action destroys the logid::thread, std::thread should detach safely. - _manager_thread = std::make_unique([this](){ _run(); }, - [this](std::exception& e) { _exception_handler(e); }); - _manager_thread->run(); -} \ No newline at end of file diff --git a/src/logid/util/workqueue.h b/src/logid/util/workqueue.h deleted file mode 100644 index 39cb891..0000000 --- a/src/logid/util/workqueue.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 . - * - */ -#ifndef LOGID_WORKQUEUE_H -#define LOGID_WORKQUEUE_H - -#include "mutex_queue.h" -#include "task.h" -#include "thread.h" - -namespace logid -{ - class worker_thread; - - class workqueue - { - public: - explicit workqueue(std::size_t thread_count); - ~workqueue(); - - void queue(const std::shared_ptr& t); - - void busyUpdate(); - - void stop(); - - [[nodiscard]] std::size_t threadCount() const; - - friend class worker_thread; - void notifyFree(); - private: - void _run(); - - void _exception_handler(std::exception& e); - std::unique_ptr _manager_thread; - - mutex_queue> _queue; - std::condition_variable _queue_cv; - std::condition_variable _busy_cv; - std::mutex _run_lock; - std::atomic _continue_run; - - std::vector> _workers; - std::size_t _worker_count; - }; - -} - -#endif //LOGID_WORKQUEUE_H From 7862c85d719229a68d891ac421db06d4dff6d904 Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 28 Jan 2022 15:48:00 -0500 Subject: [PATCH 16/59] Use epoll for I/O multiplexing --- src/logid/CMakeLists.txt | 1 + src/logid/Device.cpp | 26 +- src/logid/DeviceManager.cpp | 7 +- src/logid/Receiver.cpp | 7 +- src/logid/backend/Error.cpp | 5 + src/logid/backend/Error.h | 7 + src/logid/backend/dj/Receiver.cpp | 92 ++--- src/logid/backend/dj/Receiver.h | 11 +- src/logid/backend/dj/ReceiverMonitor.cpp | 78 ++-- src/logid/backend/dj/ReceiverMonitor.h | 9 +- src/logid/backend/dj/Report.cpp | 4 +- src/logid/backend/dj/Report.h | 10 +- src/logid/backend/hidpp/Device.cpp | 226 +++++------ src/logid/backend/hidpp/Device.h | 36 +- src/logid/backend/hidpp/Report.cpp | 8 +- src/logid/backend/hidpp/Report.h | 12 +- src/logid/backend/hidpp/defs.h | 2 +- src/logid/backend/hidpp10/Device.cpp | 92 ++++- src/logid/backend/hidpp10/Device.h | 21 +- src/logid/backend/hidpp20/Device.cpp | 128 ++++++- src/logid/backend/hidpp20/Device.h | 31 +- src/logid/backend/raw/DeviceMonitor.cpp | 208 +++++----- src/logid/backend/raw/DeviceMonitor.h | 26 +- src/logid/backend/raw/IOMonitor.cpp | 200 ++++++++++ src/logid/backend/raw/IOMonitor.h | 69 ++++ src/logid/backend/raw/RawDevice.cpp | 459 +++++------------------ src/logid/backend/raw/RawDevice.h | 85 ++--- src/logid/backend/raw/defs.h | 10 +- src/logid/logid.cpp | 29 +- 29 files changed, 1056 insertions(+), 843 deletions(-) create mode 100644 src/logid/backend/raw/IOMonitor.cpp create mode 100644 src/logid/backend/raw/IOMonitor.h diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 63bac6b..aca7539 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(logid backend/Error.cpp backend/raw/DeviceMonitor.cpp backend/raw/RawDevice.cpp + backend/raw/IOMonitor.cpp backend/dj/Receiver.cpp backend/dj/ReceiverMonitor.cpp backend/dj/Error.cpp diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index bbc176e..dc06158 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -17,6 +17,7 @@ */ #include +#include #include "util/log.h" #include "features/DPI.h" #include "Device.h" @@ -97,7 +98,7 @@ std::shared_ptr Device::make( Device::Device(std::string path, backend::hidpp::DeviceIndex index, std::shared_ptr manager) : - _hidpp20 (path, index, + _hidpp20 (path, index, manager, manager->config()->io_timeout.value_or(defaults::io_timeout)), _path (std::move(path)), _index (index), _config (_getConfig(manager, _hidpp20.name())), @@ -113,21 +114,24 @@ Device::Device(std::string path, backend::hidpp::DeviceIndex index, Device::Device(std::shared_ptr raw_device, hidpp::DeviceIndex index, std::shared_ptr manager) : - _hidpp20(raw_device, index), - _path (raw_device->hidrawPath()), _index (index), - _config (_getConfig(manager, _hidpp20.name())), - _receiver (nullptr), - _manager (manager), - _nickname (manager), - _ipc_node (manager->devicesNode()->make_child(_nickname)), - _awake (ipcgull::property_readable, true) + _hidpp20(std::move(raw_device), index, + manager->config()->io_timeout.value_or(defaults::io_timeout)), + _path (raw_device->rawPath()), _index (index), + _config (_getConfig(manager, _hidpp20.name())), + _receiver (nullptr), + _manager (manager), + _nickname (manager), + _ipc_node (manager->devicesNode()->make_child(_nickname)), + _awake (ipcgull::property_readable, true) { _init(); } Device::Device(Receiver* receiver, hidpp::DeviceIndex index, std::shared_ptr manager) : - _hidpp20 (receiver->rawReceiver(), index), + _hidpp20 (receiver->rawReceiver(), index, + manager->config()->io_timeout.value_or( + defaults::io_timeout)), _path (receiver->path()), _index (index), _config (_getConfig(manager, _hidpp20.name())), _receiver (receiver), @@ -162,8 +166,6 @@ void Device::_init() feature.second->configure(); feature.second->listen(); } - - _hidpp20.listen(); } std::string Device::name() diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 7ae827d..0b03527 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -55,6 +55,7 @@ DeviceManager::DeviceManager(std::shared_ptr config, _device_node->add_server(_server); _receiver_node->add_server(_server); _root_node->add_server(_server); + ready(); } std::shared_ptr DeviceManager::make( @@ -94,8 +95,7 @@ void DeviceManager::addDevice(std::string path) // Check if device is ignored before continuing { - raw::RawDevice raw_dev( - path,config()->io_timeout.value_or(defaults::io_timeout)); + raw::RawDevice raw_dev(path, _self.lock()); if(config()->ignore.has_value() && config()->ignore.value().contains(raw_dev.productId())) { logPrintf(DEBUG, "%s: Device 0x%04x ignored.", @@ -106,7 +106,7 @@ void DeviceManager::addDevice(std::string path) try { hidpp::Device device( - path, hidpp::DefaultDevice, + path, hidpp::DefaultDevice, _self.lock(), config()->io_timeout.value_or(defaults::io_timeout)); isReceiver = device.version() == std::make_tuple(1, 0); } catch(hidpp10::Error &e) { @@ -126,7 +126,6 @@ void DeviceManager::addDevice(std::string path) if(isReceiver) { logPrintf(INFO, "Detected receiver at %s", path.c_str()); auto receiver = Receiver::make(path, _self.lock()); - receiver->run(); std::lock_guard lock(_map_lock); _receivers.emplace(path, receiver); _ipc_receivers->receiverAdded(receiver); diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index 7ea7f5c..ce4004c 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -64,13 +64,14 @@ std::shared_ptr Receiver::make( Receiver::Receiver(const std::string& path, const std::shared_ptr& manager) : - dj::ReceiverMonitor(path, + dj::ReceiverMonitor(path, manager, manager->config()->io_timeout.value_or( defaults::io_timeout)), _path (path), _manager (manager), _nickname (manager), _ipc_node (manager->receiversNode()->make_child(_nickname)), _ipc_interface (_ipc_node->make_interface(this)) { + ready(); } const Receiver::DeviceList& Receiver::devices() const { @@ -118,7 +119,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) if(!event.linkEstablished) return; - hidpp::Device hidpp_device(receiver(), event); + hidpp::Device hidpp_device( + receiver(), event, + manager->config()->io_timeout.value_or(defaults::io_timeout)); auto version = hidpp_device.version(); diff --git a/src/logid/backend/Error.cpp b/src/logid/backend/Error.cpp index f15fc0e..bb4d811 100644 --- a/src/logid/backend/Error.cpp +++ b/src/logid/backend/Error.cpp @@ -22,3 +22,8 @@ const char *logid::backend::TimeoutError::what() const noexcept { return "Device timed out"; } + +const char *logid::backend::InvalidDevice::what() const noexcept +{ + return "Device has become invalidated"; +} diff --git a/src/logid/backend/Error.h b/src/logid/backend/Error.h index d281a3b..9c41214 100644 --- a/src/logid/backend/Error.h +++ b/src/logid/backend/Error.h @@ -29,6 +29,13 @@ public: TimeoutError() = default; const char* what() const noexcept override; }; + +class InvalidDevice : public std::exception +{ +public: + InvalidDevice() = default; + const char* what() const noexcept override; +}; }} #endif //LOGID_BACKEND_ERROR_H \ No newline at end of file diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index a97ece1..fc19374 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -43,13 +43,44 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept return _reason; } -Receiver::Receiver(std::string path, double io_timeout) : - _raw_device (std::make_shared( - std::move(path), io_timeout)), - _hidpp10_device (_raw_device, hidpp::DefaultDevice) +Receiver::Receiver(std::string path, + const std::shared_ptr& monitor, + double timeout) : + _raw_device (std::make_shared(std::move(path), monitor)), + _hidpp10_device (_raw_device, hidpp::DefaultDevice, timeout) { if(!supportsDjReports(_raw_device->reportDescriptor())) throw InvalidReceiver(InvalidReceiver::NoDJReports); + + // Pass all HID++ events on DefaultDevice to handleHidppEvent + _raw_hidpp_handler = _raw_device->addEventHandler({ + [](const std::vector& report)->bool { + return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short || + report[hidpp::Offset::Type] == hidpp::Report::Type::Long); + }, + [this](const std::vector& report)->void { + hidpp::Report _report(report); + this->_handleHidppEvent(_report); + } + }); + + // Pass all DJ events with device index to handleDjEvent + _raw_dj_handler = _raw_device->addEventHandler({ + [](const std::vector& report)->bool { + return (report[Offset::Type] == Report::Type::Short || + report[Offset::Type] == Report::Type::Long); + }, + [this](const std::vector& report)->void { + Report _report(report); + this->_handleDjEvent(_report); + } + }); +} + +Receiver::~Receiver() +{ + _raw_device->removeEventHandler(_raw_dj_handler); + _raw_device->removeEventHandler(_raw_hidpp_handler); } void Receiver::enumerateDj() @@ -312,7 +343,7 @@ void Receiver::_sendDjRequest(hidpp::DeviceIndex index, uint8_t function, std::copy(params.begin(), params.end(), request.paramBegin()); - _raw_device->sendReportNoResponse(request.rawData()); + _raw_device->sendReport(request.rawData()); } Receiver::ConnectionStatusEvent Receiver::connectionStatusEvent(Report& report) @@ -324,57 +355,6 @@ Receiver::ConnectionStatusEvent Receiver::connectionStatusEvent(Report& report) return event; } -void Receiver::listen() -{ - if(!_raw_device->isListening()) - _raw_device->listenAsync(); - - if(_raw_device->eventHandlers().find("RECV_HIDPP") == - _raw_device->eventHandlers().end()) { - // Pass all HID++ events on DefaultDevice to handleHidppEvent - std::shared_ptr hidpp_handler = - std::make_shared(); - hidpp_handler->condition = [](std::vector& report)->bool - { - return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short || - report[hidpp::Offset::Type] == hidpp::Report::Type::Long); - }; - hidpp_handler->callback = [this](std::vector& report) - ->void { - hidpp::Report _report(report); - this->_handleHidppEvent(_report); - }; - _raw_device->addEventHandler("RECV_HIDPP", hidpp_handler); - } - - if(_raw_device->eventHandlers().find("RECV_DJ") == - _raw_device->eventHandlers().end()) { - // Pass all DJ events with device index to handleDjEvent - std::shared_ptr dj_handler = - std::make_shared(); - dj_handler->condition = [](std::vector& report)->bool - { - return (report[Offset::Type] == Report::Type::Short || - report[Offset::Type] == Report::Type::Long); - }; - dj_handler->callback = [this](std::vector& report)->void - { - Report _report(report); - this->_handleDjEvent(_report); - }; - _raw_device->addEventHandler("RECV_DJ", dj_handler); - } -} - -void Receiver::stopListening() -{ - _raw_device->removeEventHandler("RECV_HIDPP"); - _raw_device->removeEventHandler("RECV_DJ"); - - if(_raw_device->eventHandlers().empty()) - _raw_device->stopListener(); -} - std::shared_ptr Receiver::rawDevice() const { return _raw_device; diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index 7152918..37c0262 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -52,7 +52,10 @@ namespace dj class Receiver final { public: - Receiver(std::string path, double io_timeout); + Receiver(std::string path, + const std::shared_ptr& monitor, + double timeout); + ~Receiver(); enum DjEvents : uint8_t { @@ -161,9 +164,6 @@ namespace dj static hidpp::DeviceConnectionEvent deviceConnectionEvent( const hidpp::Report& report); - void listen(); - void stopListening(); - void addDjEventHandler(const std::string& nickname, const std::shared_ptr& handler); void removeDjEventHandler(const std::string& nickname); @@ -184,6 +184,9 @@ namespace dj void _handleDjEvent(dj::Report& report); void _handleHidppEvent(hidpp::Report& report); + raw::RawDevice::EvHandlerId _raw_hidpp_handler; + raw::RawDevice::EvHandlerId _raw_dj_handler; + std::map> _dj_event_handlers; std::map> diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index 55e527d..96feea6 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -25,8 +25,11 @@ using namespace logid::backend::dj; -ReceiverMonitor::ReceiverMonitor(std::string path, double io_timeout) : - _receiver (std::make_shared(std::move(path), io_timeout)) +ReceiverMonitor::ReceiverMonitor(std::string path, + std::shared_ptr monitor, + double timeout): + _receiver (std::make_shared( + std::move(path), std::move(monitor), timeout)) { assert(_receiver->hidppEventHandlers().find("RECVMON") == _receiver->hidppEventHandlers().end()); @@ -42,13 +45,11 @@ ReceiverMonitor::ReceiverMonitor(std::string path, double io_timeout) : ReceiverMonitor::~ReceiverMonitor() { - this->stop(); + _receiver->removeHidppEventHandler("RECVMON"); } -void ReceiverMonitor::run() +void ReceiverMonitor::ready() { - _receiver->listen(); - if(_receiver->hidppEventHandlers().find("RECVMON") == _receiver->hidppEventHandlers().end()) { std::shared_ptr event_handler = @@ -62,8 +63,8 @@ void ReceiverMonitor::run() /* Running in a new thread prevents deadlocks since the * receiver may be enumerating. */ - std::async([this, report, - path=this->_receiver->rawDevice()->hidrawPath()]() { + spawn_task([this, report, + path= this->_receiver->rawDevice()->rawPath()]() { if (report.subId() == Receiver::DeviceConnection) { try { this->addDevice(this->_receiver->deviceConnectionEvent @@ -93,13 +94,6 @@ void ReceiverMonitor::run() enumerate(); } -void ReceiverMonitor::stop() -{ - _receiver->removeHidppEventHandler("RECVMON"); - - _receiver->stopListening(); -} - void ReceiverMonitor::enumerate() { _receiver->enumerateHidpp(); @@ -107,36 +101,34 @@ void ReceiverMonitor::enumerate() void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) { - std::string nickname = "WAIT_DEV_" + std::to_string(index); - auto handler = std::make_shared(); - handler->condition = [index](std::vector& report)->bool { - return report[Offset::DeviceIndex] == index; - }; + auto handler_id = std::make_shared(); - handler->callback = [this, index, nickname](std::vector& report) { - (void)report; // Suppress unused warning + *handler_id = _receiver->rawDevice()->addEventHandler({ + [index](const std::vector& report)->bool { + return report[Offset::DeviceIndex] == index; + }, + [this, index, handler_id]( + [[maybe_unused]] const std::vector& report) { + hidpp::DeviceConnectionEvent event{}; + event.withPayload = false; + event.linkEstablished = true; + event.index = index; + event.fromTimeoutCheck = true; - hidpp::DeviceConnectionEvent event{}; - event.withPayload = false; - event.linkEstablished = true; - event.index = index; - event.fromTimeoutCheck = true; - - spawn_task( - [this, event, nickname]() { - try { - _receiver->rawDevice()->removeEventHandler(nickname); - this->addDevice(event); - } catch(std::exception& e) { - logPrintf(ERROR, "Failed to add device %d to receiver " - "on %s: %s", event.index, - _receiver->rawDevice()->hidrawPath().c_str(), - e.what()); - } - }); - }; - - _receiver->rawDevice()->addEventHandler(nickname, handler); + spawn_task([this, event, handler_id]() { + assert(handler_id); + try { + _receiver->rawDevice()->removeEventHandler(*handler_id); + addDevice(event); + } catch(std::exception& e) { + logPrintf(ERROR, "Failed to add device %d to receiver " + "on %s: %s", event.index, + _receiver->rawDevice()->rawPath().c_str(), + e.what()); + } + }); + } + }); } std::shared_ptr ReceiverMonitor::receiver() const diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 33517b4..343d590 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -33,14 +33,13 @@ namespace dj { public: ReceiverMonitor(std::string path, - double io_timeout); + std::shared_ptr monitor, + double timeout); virtual ~ReceiverMonitor(); void enumerate(); - void run(); - void stop(); - protected: + void ready(); virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0; virtual void removeDevice(hidpp::DeviceIndex index) = 0; @@ -52,7 +51,7 @@ namespace dj void _unpair(); - std::shared_ptr receiver() const; + [[nodiscard]] std::shared_ptr receiver() const; private: std::shared_ptr _receiver; }; diff --git a/src/logid/backend/dj/Report.cpp b/src/logid/backend/dj/Report.cpp index dff4040..f2abac6 100644 --- a/src/logid/backend/dj/Report.cpp +++ b/src/logid/backend/dj/Report.cpp @@ -66,7 +66,7 @@ static const std::array DJReportDesc2 = { 0xC0 // End Collection }; -bool dj::supportsDjReports(std::vector&& rdesc) +bool dj::supportsDjReports(const std::vector& rdesc) { auto it = std::search(rdesc.begin(), rdesc.end(), DJReportDesc.begin(), DJReportDesc.end()); @@ -76,7 +76,7 @@ bool dj::supportsDjReports(std::vector&& rdesc) return it != rdesc.end(); } -Report::Report(std::vector& data) : _data (data) +Report::Report(const std::vector& data) : _data (data) { switch(data[Offset::Type]) { case ReportType::Short: diff --git a/src/logid/backend/dj/Report.h b/src/logid/backend/dj/Report.h index 76439a5..0a89d1d 100644 --- a/src/logid/backend/dj/Report.h +++ b/src/logid/backend/dj/Report.h @@ -24,9 +24,7 @@ #include "defs.h" #include "../hidpp/defs.h" -namespace logid { -namespace backend { -namespace dj +namespace logid::backend::dj { namespace Offset { @@ -36,13 +34,13 @@ namespace dj static constexpr uint8_t Parameters = 3; } - bool supportsDjReports(std::vector&& rdesc); + bool supportsDjReports(const std::vector& rdesc); class Report { public: typedef ReportType::ReportType Type; - explicit Report(std::vector& data); + explicit Report(const std::vector& data); Report(Type type, hidpp::DeviceIndex index, uint8_t feature); Type type() const; @@ -53,6 +51,6 @@ namespace dj private: std::vector _data; }; -}}} +} #endif //LOGID_BACKEND_DJ_REPORT_H diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 7bc521d..1a18a1d 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -24,11 +24,14 @@ #include "../hidpp20/features/DeviceName.h" #include "../hidpp20/Error.h" #include "../hidpp10/Error.h" +#include "../Error.h" #include "../dj/Receiver.h" using namespace logid::backend; using namespace logid::backend::hidpp; +using namespace std::chrono; + const char* Device::InvalidDevice::what() const noexcept { switch(_reason) { @@ -49,24 +52,31 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept } Device::Device(const std::string& path, DeviceIndex index, - double io_timeout): - _raw_device (std::make_shared(path, io_timeout)), + std::shared_ptr monitor, double timeout): + io_timeout (duration_cast( + duration(timeout))), + _raw_device (std::make_shared(path, std::move(monitor))), _receiver (nullptr), _path (path), _index (index) { _init(); } -Device::Device(std::shared_ptr raw_device, DeviceIndex index) : - _raw_device (std::move(raw_device)), _receiver (nullptr), - _path (_raw_device->hidrawPath()), _index (index) +Device::Device(std::shared_ptr raw_device, DeviceIndex index, + double timeout) : + io_timeout (duration_cast( + duration(timeout))), + _raw_device (std::move(raw_device)), _receiver (nullptr), + _path (_raw_device->rawPath()), _index (index) { _init(); } Device::Device(std::shared_ptr receiver, - hidpp::DeviceConnectionEvent event) : - _raw_device (receiver->rawDevice()), _receiver (receiver), - _path (receiver->rawDevice()->hidrawPath()), _index (event.index) + hidpp::DeviceConnectionEvent event, double timeout) : + io_timeout (duration_cast( + duration(timeout))), + _raw_device (receiver->rawDevice()), _receiver (receiver), + _path (receiver->rawDevice()->rawPath()), _index (event.index) { // Device will throw an error soon, just do it now if(!event.linkEstablished) @@ -80,8 +90,11 @@ Device::Device(std::shared_ptr receiver, } Device::Device(std::shared_ptr receiver, - DeviceIndex index) : _raw_device (receiver->rawDevice()), - _receiver (receiver), _path (receiver->rawDevice()->hidrawPath()), + DeviceIndex index, double timeout) : + io_timeout (duration_cast( + duration(timeout))), + _raw_device (receiver->rawDevice()), + _receiver (receiver), _path (receiver->rawDevice()->rawPath()), _index (index) { _pid = receiver->getPairingInfo(_index).pid; @@ -105,53 +118,66 @@ std::tuple Device::version() const void Device::_init() { - _listening = false; - _supported_reports = getSupportedReports(_raw_device->reportDescriptor()); - if(!_supported_reports) + supported_reports = getSupportedReports(_raw_device->reportDescriptor()); + if(!supported_reports) throw InvalidDevice(InvalidDevice::NoHIDPPReport); + _raw_handler = _raw_device->addEventHandler({ + [index=this->_index](const std::vector& report)->bool { + return (report[Offset::Type] == Report::Type::Short || + report[Offset::Type] == Report::Type::Long) && + (report[Offset::DeviceIndex] == index); + }, [this](const std::vector& report)->void { + Report _report(report); + this->handleEvent(_report); + } }); + try { - hidpp20::EssentialRoot root(this); - _version = root.getVersion(); - } catch(hidpp10::Error &e) { - // Valid HID++ 1.0 devices should send an InvalidSubID error - if(e.code() != hidpp10::Error::InvalidSubID) - throw; + try { + hidpp20::EssentialRoot root(this); + _version = root.getVersion(); + } catch(hidpp10::Error &e) { + // Valid HID++ 1.0 devices should send an InvalidSubID error + if(e.code() != hidpp10::Error::InvalidSubID) + throw; - // HID++ 2.0 is not supported, assume HID++ 1.0 - _version = std::make_tuple(1, 0); - } + // HID++ 2.0 is not supported, assume HID++ 1.0 + _version = std::make_tuple(1, 0); + } - if(!_receiver) { - _pid = _raw_device->productId(); - if(std::get<0>(_version) >= 2) { - try { - hidpp20::EssentialDeviceName deviceName(this); - _name = deviceName.getName(); - } catch(hidpp20::UnsupportedFeature &e) { + if(!_receiver) { + _pid = _raw_device->productId(); + if(std::get<0>(_version) >= 2) { + try { + hidpp20::EssentialDeviceName deviceName(this); + _name = deviceName.getName(); + } catch(hidpp20::UnsupportedFeature &e) { + _name = _raw_device->name(); + } + } else { _name = _raw_device->name(); } } else { - _name = _raw_device->name(); - } - } else { - if(std::get<0>(_version) >= 2) { - try { - hidpp20::EssentialDeviceName deviceName(this); - _name = deviceName.getName(); - } catch(hidpp20::UnsupportedFeature &e) { + if(std::get<0>(_version) >= 2) { + try { + hidpp20::EssentialDeviceName deviceName(this); + _name = deviceName.getName(); + } catch(hidpp20::UnsupportedFeature &e) { + _name = _receiver->getDeviceName(_index); + } + } else { _name = _receiver->getDeviceName(_index); } - } else { - _name = _receiver->getDeviceName(_index); } + } catch(std::exception& e) { + _raw_device->removeEventHandler(_raw_handler); + throw; } } Device::~Device() { - if(_listening) - _raw_device->removeEventHandler("DEV_" + std::to_string(_index)); + _raw_device->removeEventHandler(_raw_handler); } void Device::addEventHandler(const std::string& nickname, @@ -175,53 +201,76 @@ const std::map>& void Device::handleEvent(Report& report) { + if(responseReport(report)) + return; + for(auto& handler : _event_handlers) if(handler.second->condition(report)) handler.second->callback(report); } -Report Device::sendReport(Report& report) +Report Device::sendReport(const Report &report) { - switch(report.type()) + std::lock_guard lock(_send_lock); { - case Report::Type::Short: - if(!(_supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) - report.setType(Report::Type::Long); - break; - case Report::Type::Long: - /* Report can be truncated, but that isn't a good idea. */ - assert(_supported_reports & HIDPP_REPORT_LONG_SUPPORTED); + std::lock_guard sl(_slot_lock); + _report_slot = {}; } + sendReportNoResponse(report); + std::unique_lock wait(_resp_wait_lock); + bool valid = _resp_cv.wait_for( + wait, io_timeout, [this](){ + std::lock_guard sl(_slot_lock); + return _report_slot.has_value(); + }); - auto raw_response = _raw_device->sendReport(report.rawReport()); + if(!valid) + throw TimeoutError(); - Report response(raw_response); - - Report::Hidpp10Error hidpp10_error{}; - if(response.isError10(&hidpp10_error)) - throw hidpp10::Error(hidpp10_error.error_code); - - Report::Hidpp20Error hidpp20_error{}; - if(response.isError20(&hidpp20_error)) - throw hidpp20::Error(hidpp20_error.error_code); - - return response; + { + Report::Hidpp10Error error{}; + if(report.isError10(&error)) + throw hidpp10::Error(error.error_code); + } + { + Report::Hidpp20Error error{}; + if(report.isError20(&error)) + throw hidpp20::Error(error.error_code); + } + return _report_slot.value(); } -void Device::sendReportNoResponse(Report &report) +bool Device::responseReport(const Report &report) +{ + if(_send_lock.try_lock()) { + _send_lock.unlock(); + return false; + } + + std::lock_guard lock(_slot_lock); + _report_slot = report; + _resp_cv.notify_all(); + return true; +} + +void Device::sendReportNoResponse(Report report) +{ + reportFixup(report); + _raw_device->sendReport(report.rawReport()); +} + +void Device::reportFixup(Report& report) { switch(report.type()) { - case Report::Type::Short: - if(!(_supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) - report.setType(Report::Type::Long); - break; - case Report::Type::Long: - /* Report can be truncated, but that isn't a good idea. */ - assert(_supported_reports & HIDPP_REPORT_LONG_SUPPORTED); + case Report::Type::Short: + if(!(supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) + report.setType(Report::Type::Long); + break; + case Report::Type::Long: + /* Report can be truncated, but that isn't a good idea. */ + assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED); } - - _raw_device->sendReportNoResponse(report.rawReport()); } std::string Device::name() const @@ -233,36 +282,3 @@ uint16_t Device::pid() const { return _pid; } - -void Device::listen() -{ - if(!_raw_device->isListening()) - _raw_device->listenAsync(); - - // Pass all HID++ events with device index to this device. - auto handler = std::make_shared(); - handler->condition = [index=this->_index](std::vector& report) - ->bool { - return (report[Offset::Type] == Report::Type::Short || - report[Offset::Type] == Report::Type::Long) && - (report[Offset::DeviceIndex] == index); - }; - handler->callback = [this](std::vector& report)->void { - Report _report(report); - this->handleEvent(_report); - }; - - _raw_device->addEventHandler("DEV_" + std::to_string(_index), handler); - _listening = true; -} - -void Device::stopListening() -{ - if(_listening) - _raw_device->removeEventHandler("DEV_" + std::to_string(_index)); - - _listening = false; - - if(!_raw_device->eventHandlers().empty()) - _raw_device->stopListener(); -} \ No newline at end of file diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 9c36b85..534b7a7 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -19,6 +19,7 @@ #ifndef LOGID_BACKEND_HIDPP_DEVICE_H #define LOGID_BACKEND_HIDPP_DEVICE_H +#include #include #include #include @@ -62,14 +63,14 @@ namespace hidpp }; Device(const std::string& path, DeviceIndex index, - double io_timeout); - Device(std::shared_ptr raw_device, - DeviceIndex index); + std::shared_ptr monitor, double timeout); + Device(std::shared_ptr raw_device, DeviceIndex index, + double timeout); Device(std::shared_ptr receiver, - hidpp::DeviceConnectionEvent event); + hidpp::DeviceConnectionEvent event, double timeout); Device(std::shared_ptr receiver, - DeviceIndex index); - ~Device(); + DeviceIndex index, double timeout); + virtual ~Device(); std::string devicePath() const; DeviceIndex deviceIndex() const; @@ -78,33 +79,42 @@ namespace hidpp std::string name() const; uint16_t pid() const; - void listen(); // Runs asynchronously - void stopListening(); - void addEventHandler(const std::string& nickname, const std::shared_ptr& handler); void removeEventHandler(const std::string& nickname); const std::map>& eventHandlers(); - Report sendReport(Report& report); - void sendReportNoResponse(Report& report); + virtual Report sendReport(const Report& report); + void sendReportNoResponse(Report report); void handleEvent(Report& report); + protected: + // Returns whether the report is a response + virtual bool responseReport(const Report& report); + + void reportFixup(Report& report); + + const std::chrono::milliseconds io_timeout; + uint8_t supported_reports; private: void _init(); std::shared_ptr _raw_device; + raw::RawDevice::EvHandlerId _raw_handler; std::shared_ptr _receiver; std::string _path; DeviceIndex _index; - uint8_t _supported_reports; std::tuple _version; uint16_t _pid; std::string _name; - std::atomic _listening; + std::mutex _send_lock; + std::mutex _resp_wait_lock; + std::condition_variable _resp_cv; + std::mutex _slot_lock; + std::optional _report_slot; std::map> _event_handlers; }; diff --git a/src/logid/backend/hidpp/Report.cpp b/src/logid/backend/hidpp/Report.cpp index c5683a7..209847f 100644 --- a/src/logid/backend/hidpp/Report.cpp +++ b/src/logid/backend/hidpp/Report.cpp @@ -84,7 +84,7 @@ static const std::array LongReportDesc2 = { 0xC0 // End Collection }; -uint8_t hidpp::getSupportedReports(std::vector&& rdesc) +uint8_t hidpp::getSupportedReports(const std::vector& rdesc) { uint8_t ret = 0; @@ -248,7 +248,7 @@ uint8_t Report::swId() const void Report::setSwId(uint8_t sub_id) { - _data[Offset::Function] &= 0x0f; + _data[Offset::Function] &= 0xf0; _data[Offset::Function] |= sub_id & 0x0f; } @@ -290,7 +290,7 @@ void Report::setParams(const std::vector& _params) _data[Offset::Parameters + i] = _params[i]; } -bool Report::isError10(Report::Hidpp10Error *error) +bool Report::isError10(Report::Hidpp10Error *error) const { assert(error != nullptr); @@ -305,7 +305,7 @@ bool Report::isError10(Report::Hidpp10Error *error) return true; } -bool Report::isError20(Report::Hidpp20Error* error) +bool Report::isError20(Report::Hidpp20Error* error) const { assert(error != nullptr); diff --git a/src/logid/backend/hidpp/Report.h b/src/logid/backend/hidpp/Report.h index e406a6d..41b4839 100644 --- a/src/logid/backend/hidpp/Report.h +++ b/src/logid/backend/hidpp/Report.h @@ -32,7 +32,7 @@ namespace logid { namespace backend { namespace hidpp { - uint8_t getSupportedReports(std::vector&& rdesc); + uint8_t getSupportedReports(const std::vector& rdesc); namespace Offset { @@ -78,8 +78,8 @@ namespace hidpp Report::Type type() const; void setType(Report::Type type); - logid::backend::hidpp::DeviceIndex deviceIndex() const; - void setDeviceIndex(hidpp::DeviceIndex index); + DeviceIndex deviceIndex() const; + void setDeviceIndex(DeviceIndex index); uint8_t feature() const; void setFeature(uint8_t feature); @@ -106,15 +106,15 @@ namespace hidpp { uint8_t sub_id, address, error_code; }; - bool isError10(Hidpp10Error* error); + bool isError10(Hidpp10Error* error) const; struct Hidpp20Error { uint8_t feature_index, function, software_id, error_code; }; - bool isError20(Hidpp20Error* error); + bool isError20(Hidpp20Error* error) const; - std::vector rawReport () const { return _data; } + std::vector rawReport() const { return _data; } static constexpr std::size_t HeaderLength = 4; private: diff --git a/src/logid/backend/hidpp/defs.h b/src/logid/backend/hidpp/defs.h index 3a85470..96a8bf6 100644 --- a/src/logid/backend/hidpp/defs.h +++ b/src/logid/backend/hidpp/defs.h @@ -19,7 +19,7 @@ #ifndef LOGID_BACKEND_HIDPP_DEFS_H #define LOGID_BACKEND_HIDPP_DEFS_H -#define LOGID_HIDPP_SOFTWARE_ID 0 +#define LOGID_HIDPP_SOFTWARE_ID 1 #include diff --git a/src/logid/backend/hidpp10/Device.cpp b/src/logid/backend/hidpp10/Device.cpp index 65cf538..2596669 100644 --- a/src/logid/backend/hidpp10/Device.cpp +++ b/src/logid/backend/hidpp10/Device.cpp @@ -20,29 +20,107 @@ #include #include "Device.h" #include "defs.h" +#include "../Error.h" using namespace logid::backend; using namespace logid::backend::hidpp10; -Device::Device(const std::string &path, hidpp::DeviceIndex index, - double io_timeout) : - hidpp::Device(path, index, io_timeout) +Device::Device(const std::string &path, + hidpp::DeviceIndex index, + std::shared_ptr monitor, double timeout) : + hidpp::Device(path, index, std::move(monitor), timeout) { assert(version() == std::make_tuple(1, 0)); } Device::Device(std::shared_ptr raw_dev, - hidpp::DeviceIndex index) : hidpp::Device(std::move(raw_dev), index) + hidpp::DeviceIndex index, + double timeout) : hidpp::Device(std::move(raw_dev), index, timeout) { assert(version() == std::make_tuple(1, 0)); } -Device::Device(std::shared_ptr receiver, hidpp::DeviceIndex index) - : hidpp::Device(receiver, index) +Device::Device(std::shared_ptr receiver, + hidpp::DeviceIndex index, + double timeout) + : hidpp::Device(std::move(receiver), index, timeout) { assert(version() == std::make_tuple(1, 0)); } +hidpp::Report Device::sendReport(const hidpp::Report& report) +{ + decltype(_responses)::iterator response_slot; + while(true) { + { + std::lock_guard lock(_response_lock); + response_slot = _responses.find(report.subId()); + if(response_slot == _responses.end()) { + response_slot = _responses.emplace( + report.subId(), std::optional()).first; + break; + } + } + std::unique_lock lock(_response_wait_lock); + _response_cv.wait(lock, [this, sub_id=report.subId()](){ + std::lock_guard lock(_response_lock); + return _responses.find(sub_id) != _responses.end(); + }); + } + + sendReportNoResponse(report); + std::unique_lock wait(_response_wait_lock); + bool valid = _response_cv.wait_for(wait, io_timeout, + [this, &response_slot]() { + std::lock_guard lock(_response_lock); + return response_slot->second.has_value(); + }); + + if(!valid) { + std::lock_guard lock(_response_lock); + _responses.erase(response_slot); + throw TimeoutError(); + } + + std::lock_guard lock(_response_lock); + assert(response_slot->second.has_value()); + auto response = response_slot->second.value(); + _responses.erase(response_slot); + if(std::holds_alternative(response)) + return std::get(response); + else // if(std::holds_alternative(response)) + throw Error(std::get(response)); +} + +bool Device::responseReport(const hidpp::Report& report) +{ + std::lock_guard lock(_response_lock); + uint8_t sub_id; + + bool is_error = false; + hidpp::Report::Hidpp10Error hidpp10_error {}; + if(report.isError10(&hidpp10_error)) { + sub_id = hidpp10_error.sub_id; + is_error = true; + } else { + sub_id = report.subId(); + } + + auto response_slot = _responses.find(sub_id); + if(response_slot == _responses.end()) + return false; + + if(is_error) { + response_slot->second = static_cast( + hidpp10_error.error_code); + } else { + response_slot->second = report; + } + + _response_cv.notify_all(); + return true; +} + std::vector Device::getRegister(uint8_t address, const std::vector& params, hidpp::Report::Type type) { @@ -76,7 +154,7 @@ std::vector Device::accessRegister(uint8_t sub_id, uint8_t address, std::copy(params.begin(), params.end(), request.paramBegin()); auto response = sendReport(request); - return std::vector(response.paramBegin(), response.paramEnd()); + return {response.paramBegin(), response.paramEnd()}; } diff --git a/src/logid/backend/hidpp10/Device.h b/src/logid/backend/hidpp10/Device.h index be98dd0..659abbb 100644 --- a/src/logid/backend/hidpp10/Device.h +++ b/src/logid/backend/hidpp10/Device.h @@ -19,7 +19,11 @@ #ifndef LOGID_BACKEND_HIDPP10_DEVICE_H #define LOGID_BACKEND_HIDPP10_DEVICE_H +#include +#include + #include "../hidpp/Device.h" +#include "Error.h" namespace logid { namespace backend { @@ -29,18 +33,29 @@ namespace hidpp10 { public: Device(const std::string& path, hidpp::DeviceIndex index, - double io_timeout); + std::shared_ptr monitor, double timeout); Device(std::shared_ptr raw_dev, - hidpp::DeviceIndex index); + hidpp::DeviceIndex index, double timeout); Device(std::shared_ptr receiver, - hidpp::DeviceIndex index); + hidpp::DeviceIndex index, double timeout); + + hidpp::Report sendReport(const hidpp::Report& report) final; std::vector getRegister(uint8_t address, const std::vector& params, hidpp::Report::Type type); std::vector setRegister(uint8_t address, const std::vector& params, hidpp::Report::Type type); + protected: + bool responseReport(const hidpp::Report& report) final; private: + std::mutex _response_lock; + std::mutex _response_wait_lock; + std::condition_variable _response_cv; + + typedef std::variant Response; + std::map> _responses; + std::vector accessRegister(uint8_t sub_id, uint8_t address, const std::vector& params); }; diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index a3ac6a3..78cce96 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -20,26 +20,44 @@ #include "Device.h" #include "../hidpp/defs.h" +#include "../Error.h" +#include "../dj/Receiver.h" +using namespace logid::backend; using namespace logid::backend::hidpp20; -Device::Device(std::string path, hidpp::DeviceIndex index, double io_timeout) : - hidpp::Device(path, index, io_timeout) +Device::Device(const std::string& path, hidpp::DeviceIndex index, + std::shared_ptr monitor, double timeout) : + hidpp::Device(path, index, + std::move(monitor), timeout) { - assert(std::get<0>(version()) >= 2); + // TODO: Fix version check + if(std::get<0>(version()) < 2) + throw std::runtime_error("Invalid HID++ version"); } Device::Device(std::shared_ptr raw_device, - hidpp::DeviceIndex index) - : hidpp::Device(raw_device, index) + hidpp::DeviceIndex index, double timeout) : + hidpp::Device(std::move(raw_device), index, timeout) { - assert(std::get<0>(version()) >= 2); + if(std::get<0>(version()) < 2) + throw std::runtime_error("Invalid HID++ version"); } -Device::Device(std::shared_ptr receiver, hidpp::DeviceIndex index) - : hidpp::Device(receiver, index) +Device::Device(std::shared_ptr receiver, + hidpp::DeviceConnectionEvent event, double timeout) : + hidpp::Device(std::move(receiver), event, timeout) { - assert(std::get<0>(version()) >= 2); + if(std::get<0>(version()) < 2) + throw std::runtime_error("Invalid HID++ version"); +} + +Device::Device(std::shared_ptr receiver, + hidpp::DeviceIndex index, double timeout) + : hidpp::Device(std::move(receiver), index, timeout) +{ + if(std::get<0>(version()) < 2) + throw std::runtime_error("Invalid HID++ version"); } std::vector Device::callFunction(uint8_t feature_index, @@ -81,4 +99,94 @@ void Device::callFunctionNoResponse(uint8_t feature_index, uint8_t function, std::copy(params.begin(), params.end(), request.paramBegin()); this->sendReportNoResponse(request); -} \ No newline at end of file +} + +hidpp::Report Device::sendReport(const hidpp::Report& report) +{ + decltype(_responses)::iterator response_slot; + + while(true) { + { + std::lock_guard lock(_response_lock); + if(_responses.empty()) { + response_slot = _responses.emplace( + 2, std::optional()).first; + break; + } else if(_responses.size() < response_slots) { + uint8_t i = 0; + for(auto& x : _responses) { + if(x.first != i + 1) { + ++i; + break; + } + i = x.first; + } + assert(_responses.count(i) == 0); + + response_slot = _responses.emplace( + i, std::optional()).first; + break; + } + } + + std::unique_lock lock(_response_wait_lock); + _response_cv.wait(lock, [this, sub_id=report.subId()](){ + std::lock_guard lock(_response_lock); + return _responses.size() < response_slots; + }); + } + + { + std::lock_guard lock(_response_lock); + hidpp::Report mod_report {report}; + mod_report.setSwId(response_slot->first); + sendReportNoResponse(std::move(mod_report)); + } + + std::unique_lock wait(_response_wait_lock); + bool valid = _response_cv.wait_for(wait, io_timeout, + [this, &response_slot]() { + std::lock_guard lock(_response_lock); + return response_slot->second.has_value(); + }); + + if(!valid) { + std::lock_guard lock(_response_lock); + _responses.erase(response_slot); + throw TimeoutError(); + } + + std::lock_guard lock(_response_lock); + assert(response_slot->second.has_value()); + auto response = response_slot->second.value(); + _responses.erase(response_slot); + if(std::holds_alternative(response)) + return std::get(response); + else // if(std::holds_alternative(response)) + throw Error(std::get(response)); +} + +bool Device::responseReport(const hidpp::Report& report) +{ + std::lock_guard lock(_response_lock); + uint8_t sw_id = report.swId(); + + bool is_error = false; + hidpp::Report::Hidpp20Error hidpp20_error {}; + if(report.isError20(&hidpp20_error)) + is_error = true; + + auto response_slot = _responses.find(sw_id); + if(response_slot == _responses.end()) + return false; + + if(is_error) { + response_slot->second = static_cast( + hidpp20_error.error_code); + } else { + response_slot->second = report; + } + + _response_cv.notify_all(); + return true; +} diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index 64f80c3..0813cd5 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -19,8 +19,12 @@ #ifndef LOGID_BACKEND_HIDPP20_DEVICE_H #define LOGID_BACKEND_HIDPP20_DEVICE_H -#include "../hidpp/Device.h" #include +#include +#include + +#include "../hidpp/Device.h" +#include "Error.h" namespace logid { namespace backend { @@ -28,11 +32,14 @@ namespace hidpp20 { class Device : public hidpp::Device { public: - Device(std::string path, hidpp::DeviceIndex index, - double io_timeout); - Device(std::shared_ptr raw_device, hidpp::DeviceIndex index); - Device(std::shared_ptr receiver, hidpp::DeviceIndex - index); + Device(const std::string& path, hidpp::DeviceIndex index, + std::shared_ptr monitor, double timeout); + Device(std::shared_ptr raw_device, + hidpp::DeviceIndex index, double timeout); + Device(std::shared_ptr receiver, + hidpp::DeviceConnectionEvent event, double timeout); + Device(std::shared_ptr receiver, + hidpp::DeviceIndex index, double timeout); std::vector callFunction(uint8_t feature_index, uint8_t function, @@ -41,6 +48,18 @@ namespace hidpp20 { void callFunctionNoResponse(uint8_t feature_index, uint8_t function, std::vector& params); + + hidpp::Report sendReport(const hidpp::Report& report) final; + protected: + bool responseReport(const hidpp::Report& report) final; + private: + std::mutex _response_lock; + std::mutex _response_wait_lock; + std::condition_variable _response_cv; + + static constexpr int response_slots = 14; + typedef std::variant Response; + std::map> _responses; }; }}} diff --git a/src/logid/backend/raw/DeviceMonitor.cpp b/src/logid/backend/raw/DeviceMonitor.cpp index 1553e61..2a1756f 100644 --- a/src/logid/backend/raw/DeviceMonitor.cpp +++ b/src/logid/backend/raw/DeviceMonitor.cpp @@ -22,7 +22,6 @@ #include "RawDevice.h" #include "../hidpp/Device.h" -#include #include extern "C" @@ -34,117 +33,85 @@ extern "C" using namespace logid; using namespace logid::backend::raw; -DeviceMonitor::DeviceMonitor() +DeviceMonitor::DeviceMonitor() : _io_monitor (std::make_shared()), + _ready (false) { - if(-1 == pipe(_pipe)) - throw std::system_error(errno, std::system_category(), - "pipe creation failed"); - + int ret; _udev_context = udev_new(); if(!_udev_context) throw std::runtime_error("udev_new failed"); + + _udev_monitor = udev_monitor_new_from_netlink(_udev_context, + "udev"); + if(!_udev_monitor) { + if(_udev_context) + udev_unref(_udev_context); + throw std::runtime_error("udev_monitor_new_from_netlink failed"); + } + + ret = udev_monitor_filter_add_match_subsystem_devtype( + _udev_monitor, "hidraw", nullptr); + if(0 != ret) { + if(_udev_monitor) + udev_monitor_unref(_udev_monitor); + if(_udev_context) + udev_unref(_udev_context); + throw std::system_error( + -ret, std::system_category(), + "udev_monitor_filter_add_match_subsystem_devtype"); + } + + ret = udev_monitor_enable_receiving(_udev_monitor); + if(0 != ret) { + if(_udev_monitor) + udev_monitor_unref(_udev_monitor); + if(_udev_context) + udev_unref(_udev_context); + throw std::system_error(-ret, std::system_category(), + "udev_monitor_enable_receiving"); + } + + _fd = udev_monitor_get_fd(_udev_monitor); } DeviceMonitor::~DeviceMonitor() { - this->stop(); + if(_ready) + _io_monitor->remove(_fd); - udev_unref(_udev_context); - - for(int i : _pipe) - close(i); + if(_udev_monitor) + udev_monitor_unref(_udev_monitor); + if(_udev_context) + udev_unref(_udev_context); } -void DeviceMonitor::run() +void DeviceMonitor::ready() { - int ret; - std::lock_guard lock(_running); + if(_ready) + return; + _ready = true; - struct udev_monitor* monitor = udev_monitor_new_from_netlink(_udev_context, - "udev"); - if(!monitor) - throw std::runtime_error("udev_monitor_new_from_netlink failed"); + _io_monitor->add(_fd, { + [this]() { + struct udev_device *device = udev_monitor_receive_device( + _udev_monitor); + std::string action = udev_device_get_action(device); + std::string devnode = udev_device_get_devnode(device); - ret = udev_monitor_filter_add_match_subsystem_devtype(monitor, "hidraw", - nullptr); - if (0 != ret) - throw std::system_error (-ret, std::system_category(), - "udev_monitor_filter_add_match_subsystem_devtype"); + if (action == "add") + spawn_task([this, devnode]() { _addHandler(devnode); } ); + else if (action == "remove") + spawn_task([this, devnode]() { _removeHandler(devnode); } ); - ret = udev_monitor_enable_receiving(monitor); - if(0 != ret) - throw std::system_error(-ret, std::system_category(), - "udev_moniotr_enable_receiving"); - - this->enumerate(); - - int fd = udev_monitor_get_fd(monitor); - - _run_monitor = true; - while (_run_monitor) { - fd_set fds; - FD_ZERO(&fds); - FD_SET(_pipe[0], &fds); - FD_SET(fd, &fds); - - if (-1 == select (std::max (_pipe[0], fd)+1, &fds, nullptr, - nullptr, nullptr)) { - if (errno == EINTR) - continue; - throw std::system_error (errno, std::system_category(), - "udev_monitor select"); - } - - if (FD_ISSET(fd, &fds)) { - struct udev_device *device = udev_monitor_receive_device(monitor); - std::string action = udev_device_get_action(device); - std::string devnode = udev_device_get_devnode(device); - - if (action == "add") - spawn_task( - [this, name=devnode]() { - try { - // Wait for device to initialise - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - auto supported_reports = backend::hidpp::getSupportedReports( - RawDevice::getReportDescriptor(name)); - if(supported_reports) - this->addDevice(name); - else - logPrintf(DEBUG, "Unsupported device %s ignored", - name.c_str()); - } catch(std::exception& e) { - logPrintf(WARN, "Error adding device %s: %s", - name.c_str(), e.what()); - } - }); - else if (action == "remove") - spawn_task( - [this, name=devnode]() { - try { - this->removeDevice(name); - } catch(std::exception& e) { - logPrintf(WARN, "Error removing device %s: %s", - name.c_str(), e.what()); - } - }); - - udev_device_unref (device); - } - if (FD_ISSET(_pipe[0], &fds)) { - char c; - if (-1 == read(_pipe[0], &c, sizeof (char))) - throw std::system_error (errno, std::system_category(), - "read pipe"); - break; - } - } -} - -void DeviceMonitor::stop() -{ - _run_monitor = false; - std::lock_guard lock(_running); + udev_device_unref(device); + }, + []() { + throw std::runtime_error("udev hangup"); + }, + []() { + throw std::runtime_error("udev error"); + } + }); } void DeviceMonitor::enumerate() @@ -174,22 +141,39 @@ void DeviceMonitor::enumerate() std::string devnode = udev_device_get_devnode(device); udev_device_unref(device); - spawn_task( - [this, name=devnode]() { - try { - auto supported_reports = backend::hidpp::getSupportedReports( - RawDevice::getReportDescriptor(name)); - if(supported_reports) - this->addDevice(name); - else - logPrintf(DEBUG, "Unsupported device %s ignored", - name.c_str()); - } catch(std::exception& e) { - logPrintf(WARN, "Error adding device %s: %s", - name.c_str(), e.what()); - } - }); + spawn_task([this, devnode]() { _addHandler(devnode); } ); } udev_enumerate_unref(udev_enum); } + +void DeviceMonitor::_addHandler(const std::string& device) +{ + try { + auto supported_reports = backend::hidpp::getSupportedReports( + RawDevice::getReportDescriptor(device)); + if(supported_reports) + this->addDevice(device); + else + logPrintf(DEBUG, "Unsupported device %s ignored", + device.c_str()); + } catch(std::exception& e) { + logPrintf(WARN, "Error adding device %s: %s", + device.c_str(), e.what()); + } +} + +void DeviceMonitor::_removeHandler(const std::string& device) +{ + try { + this->removeDevice(device); + } catch(std::exception& e) { + logPrintf(WARN, "Error removing device %s: %s", + device.c_str(), e.what()); + } +} + +std::shared_ptr DeviceMonitor::ioMonitor() const +{ + return _io_monitor; +} diff --git a/src/logid/backend/raw/DeviceMonitor.h b/src/logid/backend/raw/DeviceMonitor.h index 9b7fc8e..80abf00 100644 --- a/src/logid/backend/raw/DeviceMonitor.h +++ b/src/logid/backend/raw/DeviceMonitor.h @@ -23,28 +23,40 @@ #include #include #include +#include "IOMonitor.h" -struct udev; +extern "C" +{ + struct udev; + struct udev_monitor; +} namespace logid::backend::raw { class DeviceMonitor { public: + virtual ~DeviceMonitor(); + void enumerate(); - void run(); - void stop(); + [[nodiscard]] std::shared_ptr ioMonitor() const; protected: DeviceMonitor(); - virtual ~DeviceMonitor(); + // This should be run once the derived class is ready + void ready(); virtual void addDevice(std::string device) = 0; virtual void removeDevice(std::string device) = 0; private: + void _addHandler(const std::string& device); + void _removeHandler(const std::string& device); + + std::shared_ptr _io_monitor; + struct udev* _udev_context; - int _pipe[2]; - std::atomic _run_monitor; - std::mutex _running; + struct udev_monitor* _udev_monitor; + int _fd; + bool _ready; }; } diff --git a/src/logid/backend/raw/IOMonitor.cpp b/src/logid/backend/raw/IOMonitor.cpp new file mode 100644 index 0000000..f92e6b0 --- /dev/null +++ b/src/logid/backend/raw/IOMonitor.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 +#include "IOMonitor.h" + +extern "C" +{ +#include +#include +#include +} + +using namespace logid::backend::raw; + +IOHandler::IOHandler(std::function r, + std::function hup, + std::function err) : + read (std::move(r)), + hangup (std::move(hup)), + error (std::move(err)) +{ +} + +IOMonitor::IOMonitor() : _epoll_fd (epoll_create1(0)), + _event_fd(eventfd(0, EFD_NONBLOCK)) +{ + if(_epoll_fd < 0) { + if(_event_fd >= 0) + close(_event_fd); + throw std::runtime_error("failed to create epoll fd"); + } + + if(_event_fd < 0) { + if(_epoll_fd >= 0) + close(_epoll_fd); + throw std::runtime_error("failed to create event fd"); + } + + struct epoll_event event{}; + event.events = EPOLLIN; + event.data.fd = _event_fd; + + if(::epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _event_fd, &event)) { + throw std::system_error(errno, std::generic_category()); + } + + _fds.emplace(std::piecewise_construct,std::forward_as_tuple(_event_fd), + std::forward_as_tuple([]() { },[]() { + throw std::runtime_error("eventfd hangup"); + },[]() { + throw std::runtime_error("eventfd error"); + })); + + std::thread([this](){ + _listen(); + }).detach(); +} + +IOMonitor::~IOMonitor() noexcept +{ + std::lock_guard ctl_lock(_ctl_lock); + _stop(); + + if(_event_fd >= 0) + close(_event_fd); + + if(_epoll_fd >= 0) + close(_epoll_fd); +} + +void IOMonitor::_listen() +{ + std::unique_lock run_lock(_run_lock, std::try_to_lock); + if(!run_lock.owns_lock()) + throw std::runtime_error("IOMonitor already listening"); + std::vector events; + + _is_running = true; + + while(_is_running) { + { + std::unique_lock lock(_interrupt_lock); + _interrupt_cv.wait(lock, [this](){ + return !(bool)_interrupting; + }); + + if(!_is_running) + break; + } + + std::lock_guard io_lock(_io_lock); + if(events.size() != _fds.size()) + events.resize(_fds.size()); + int eventc = ::epoll_wait(_epoll_fd, events.data(), events.size(), -1); + for(int i = 0; i < eventc; ++i) { + const auto& handler = _fds.at(events[i].data.fd); + if(events[i].events & EPOLLIN) + handler.read(); + if(events[i].events & EPOLLHUP) + handler.hangup(); + if(events[i].events & EPOLLERR) + handler.error(); + } + } +} + +void IOMonitor::_stop() noexcept +{ + _interrupt(); + _is_running = false; + _continue(); + std::lock_guard run_lock(_run_lock); +} + +bool IOMonitor::_running() const +{ + std::unique_lock run_lock(_run_lock, std::try_to_lock); + return !run_lock.owns_lock(); +} + +void IOMonitor::add(int fd, IOHandler handler) +{ + std::lock_guard lock(_ctl_lock); + _interrupt(); + + struct epoll_event event{}; + event.events = EPOLLIN | EPOLLHUP | EPOLLERR; + event.data.fd = fd; + + // TODO: EPOLL_CTL_MOD + if(_fds.contains(fd)) { + _continue(); + throw std::runtime_error("duplicate io fd"); + } + + if(::epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &event)) { + _continue(); + throw std::system_error(errno, std::generic_category()); + } + _fds.emplace(fd, std::move(handler)); + + _continue(); +} + +void IOMonitor::remove(int fd) noexcept +{ + std::lock_guard lock(_ctl_lock); + _interrupt(); + std::lock_guard io_lock(_io_lock); + + ::epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, nullptr); + _fds.erase(fd); + + _continue(); +} + +void IOMonitor::_interrupt() noexcept +{ + std::unique_lock run_lock(_run_lock, std::try_to_lock); + + _interrupting = true; + + uint64_t counter = 1; + ssize_t ret = ::write(_event_fd, &counter, sizeof(counter)); + assert(ret == sizeof(counter)); + + // Wait for the IO monitor to _stop + std::lock_guard io_lock(_io_lock); + +} + +void IOMonitor::_continue() noexcept +{ + std::unique_lock run_lock(_run_lock, std::try_to_lock); + + uint64_t counter; + ssize_t ret = ::read(_event_fd, &counter, sizeof(counter)); + + assert(ret != -1); + + if(counter == 1) { + _interrupting = false; + _interrupt_cv.notify_all(); + } +} diff --git a/src/logid/backend/raw/IOMonitor.h b/src/logid/backend/raw/IOMonitor.h new file mode 100644 index 0000000..eae487c --- /dev/null +++ b/src/logid/backend/raw/IOMonitor.h @@ -0,0 +1,69 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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 . + * + */ +#ifndef LOGID_BACKEND_RAW_IOMONITOR_H +#define LOGID_BACKEND_RAW_IOMONITOR_H + +#include +#include +#include +#include +#include + +namespace logid::backend::raw { + struct IOHandler { + std::function read; + std::function hangup; + std::function error; + + IOHandler(std::function r, + std::function hup, + std::function err); + }; + + class IOMonitor + { + public: + IOMonitor(); + ~IOMonitor() noexcept; + + void add(int fd, IOHandler handler); + void remove(int fd) noexcept; + private: + void _listen(); // This is a blocking call + void _stop() noexcept; + + bool _running() const; + + void _interrupt() noexcept; + void _continue() noexcept; + + std::map _fds; + std::mutex _io_lock, _ctl_lock; + mutable std::mutex _run_lock; + std::atomic_bool _is_running; + + std::atomic_bool _interrupting; + std::mutex _interrupt_lock; + std::condition_variable _interrupt_cv; + + const int _epoll_fd; + const int _event_fd; + }; +} + +#endif //LOGID_BACKEND_RAW_IOMONITOR_H diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 0c86eb6..77fecc2 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -17,19 +17,15 @@ */ #include "RawDevice.h" +#include "DeviceMonitor.h" +#include "IOMonitor.h" #include "../Error.h" -#include "../hidpp/defs.h" -#include "../dj/defs.h" #include "../../util/log.h" -#include "../hidpp/Report.h" -#include "../../util/thread.h" #include #include #include -#define MAX_DATA_LENGTH 32 - extern "C" { #include @@ -43,101 +39,88 @@ using namespace logid::backend::raw; using namespace logid::backend; using namespace std::chrono; -bool RawDevice::supportedReport(uint8_t id, uint8_t length) +int get_fd(const std::string& path) { - switch(id) { - case hidpp::ReportType::Short: - return length == (hidpp::ShortParamLength + - hidpp::Report::HeaderLength); - case hidpp::ReportType::Long: - return length == (hidpp::LongParamLength + - hidpp::Report::HeaderLength); - case dj::ReportType::Short: - return length == (dj::ShortParamLength + dj::HeaderLength); - case dj::ReportType::Long: - return length == (dj::LongParamLength + dj::HeaderLength); - default: - return false; - } -} - -RawDevice::RawDevice(std::string path, double io_timeout) : - _path (std::move(path)), - _continue_listen (false), _continue_respond (false), - _io_timeout (duration_cast( - duration(io_timeout))) -{ - int ret; - - _fd = ::open(_path.c_str(), O_RDWR); - if (_fd == -1) + int fd = ::open(path.c_str(), O_RDWR | O_NONBLOCK); + if(fd == -1) throw std::system_error(errno, std::system_category(), - "RawDevice open failed"); + "RawDevice open failed"); - hidraw_devinfo devinfo{}; - if (-1 == ::ioctl(_fd, HIDIOCGRAWINFO, &devinfo)) { - int err = errno; - ::close(_fd); - throw std::system_error(err, std::system_category(), - "RawDevice HIDIOCGRAWINFO failed"); - } - _vid = devinfo.vendor; - _pid = devinfo.product; - - char name_buf[256]; - if (-1 == (ret = ::ioctl(_fd, HIDIOCGRAWNAME(sizeof(name_buf)), name_buf) - )) { - int err = errno; - ::close(_fd); - throw std::system_error(err, std::system_category(), - "RawDevice HIDIOCGRAWNAME failed"); - } - _name.assign(name_buf, ret - 1); - - _rdesc = getReportDescriptor(_fd); - - if (-1 == ::pipe(_pipe)) { - int err = errno; - close(_fd); - throw std::system_error(err, std::system_category(), - "RawDevice pipe open failed"); - } - - _continue_listen = false; + return fd; } -RawDevice::~RawDevice() +RawDevice::dev_info get_devinfo(int fd) { - if(_fd != -1) - { - ::close(_fd); - ::close(_pipe[0]); - ::close(_pipe[1]); + hidraw_devinfo devinfo{}; + if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo)) { + int err = errno; + ::close(fd); + throw std::system_error(err, std::system_category(), + "RawDevice HIDIOCGRAWINFO failed"); } + + return {devinfo.vendor, devinfo.product}; } -std::string RawDevice::hidrawPath() const + +std::string get_name(int fd) +{ + ssize_t len; + char name_buf[256]; + if (-1 == (len = ::ioctl(fd, HIDIOCGRAWNAME(sizeof(name_buf)), name_buf))) { + int err = errno; + ::close(fd); + throw std::system_error(err, std::system_category(), + "RawDevice HIDIOCGRAWNAME failed"); + } + return {name_buf, static_cast(len)}; +} + +RawDevice::RawDevice(std::string path, + std::shared_ptr monitor) : + _valid (true), + _path (std::move(path)), + _fd (get_fd(_path)), + _devinfo (get_devinfo(_fd)), + _name (get_name(_fd)), + _rdesc (getReportDescriptor(_fd)), + _io_monitor (monitor->ioMonitor()) +{ + _io_monitor->add(_fd, { + [this]() { _readReports(); }, + [this]() { _valid = false; }, + [this]() { _valid = false; } + }); +} + +RawDevice::~RawDevice() noexcept +{ + _io_monitor->remove(_fd); + ::close(_fd); +} + +const std::string& RawDevice::rawPath() const { return _path; } -std::string RawDevice::name() const +const std::string& RawDevice::name() const { return _name; } -uint16_t RawDevice::vendorId() const +int16_t RawDevice::vendorId() const { - return _vid; + return _devinfo.vid; } -uint16_t RawDevice::productId() const +int16_t RawDevice::productId() const { - return _pid; + return _devinfo.pid; } std::vector RawDevice::getReportDescriptor(std::string path) { - int fd = ::open(path.c_str(), O_RDWR); + int fd = ::open(path.c_str(), O_RDWR | O_NONBLOCK); if (fd == -1) throw std::system_error(errno, std::system_category(), "open failed"); @@ -165,140 +148,16 @@ std::vector RawDevice::getReportDescriptor(int fd) return std::vector(rdesc.value, rdesc.value + rdesc.size); } -std::vector RawDevice::reportDescriptor() const +const std::vector& RawDevice::reportDescriptor() const { return _rdesc; } -std::vector RawDevice::sendReport(const std::vector& report) +void RawDevice::sendReport(const std::vector& report) { - /* If the listener will stop, handle I/O manually. - * Otherwise, push to queue and wait for result. */ - if(_continue_listen) { - std::mutex send_report; - std::unique_lock lock(send_report); - std::condition_variable cv; - bool top_of_queue = false; - auto task = std::make_shared()>> - ( [this, report, &cv, &top_of_queue] () { - top_of_queue = true; - cv.notify_all(); - return this->_respondToReport(report); - }); - auto f = task->get_future(); - _io_queue.push(task); - interruptRead(false); // Alert listener to prioritise - cv.wait(lock, [&top_of_queue]{ return top_of_queue; }); - auto status = f.wait_for(_io_timeout); - if(status == std::future_status::timeout) { - _continue_respond = false; - interruptRead(); - return f.get(); // Expecting an error, but it could work - } - return f.get(); - } - else { - std::exception_ptr _exception; - auto response = std::async(std::launch::deferred, - [this, report]()->std::vector { - return _respondToReport(report); - }); - auto status = response.wait_for(_io_timeout); - if(status == std::future_status::timeout) { - interruptRead(); - if(response.valid()) - response.wait(); - throw TimeoutError(); - } - return response.get(); - } -} + if(!_valid) + throw InvalidDevice(); -// DJ commands are not systematically acknowledged, do not expect a result. -void RawDevice::sendReportNoResponse(const std::vector& report) -{ - /* If the listener will stop, handle I/O manually. - * Otherwise, push to queue and wait for result. */ - if(_continue_listen) { - auto task = std::make_shared()>> - ([this, report]() { - this->_sendReport(report); - return std::vector(); - }); - auto f = task->get_future(); - _io_queue.push(task); - f.get(); - } - else - _sendReport(report); -} - -std::vector RawDevice::_respondToReport - (const std::vector& request) -{ - _sendReport(request); - _continue_respond = true; - - auto start_point = std::chrono::steady_clock::now(); - - while(_continue_respond) { - std::vector response; - auto current_point = std::chrono::steady_clock::now(); - auto timeout = _io_timeout - std::chrono::duration_cast - (current_point - start_point); - if(timeout.count() <= 0) - throw TimeoutError(); - _readReport(response, MAX_DATA_LENGTH, timeout); - - if(!_continue_respond) - throw TimeoutError(); - - // All reports have the device index at byte 2 - if(response[1] != request[1]) { - if(_continue_listen) - this->_handleEvent(response); - continue; - } - - if(hidpp::ReportType::Short == request[0] || - hidpp::ReportType::Long == request[0]) { - if(hidpp::ReportType::Short != response[0] && - hidpp::ReportType::Long != response[0]) { - if(_continue_listen) - this->_handleEvent(response); - continue; - } - - // Error; leave to device to handle - if(response[2] == 0x8f || response[2] == 0xff) - return response; - - bool others_match = true; - for(int i = 2; i < 4; i++) - if(response[i] != request[i]) - others_match = false; - - if(others_match) - return response; - } else if(dj::ReportType::Short == request[0] || - dj::ReportType::Long == request[0]) { - //Error; leave to device ot handle - if(0x7f == response[2]) - return response; - else if(response[2] == request[2]) - return response; - } - - if(_continue_listen) - this->_handleEvent(response); - } - - return {}; -} - -int RawDevice::_sendReport(const std::vector& report) -{ - std::lock_guard lock(_dev_io); if(logid::global_loglevel <= LogLevel::RAWREPORT) { printf("[RAWREPORT] %s OUT: ", _path.c_str()); for(auto &i : report) @@ -306,180 +165,48 @@ int RawDevice::_sendReport(const std::vector& report) printf("\n"); } - assert(supportedReport(report[0], report.size())); - - int ret = ::write(_fd, report.data(), report.size()); - if(ret == -1) { - ///TODO: This seems like a hacky solution - // Try again before failing - ret = ::write(_fd, report.data(), report.size()); - if(ret == -1) - throw std::system_error(errno, std::system_category(), - "_sendReport write failed"); - } - - return ret; -} - -int RawDevice::_readReport(std::vector &report, - std::size_t maxDataLength) -{ - return _readReport(report, maxDataLength, _io_timeout); -} - -int RawDevice::_readReport(std::vector &report, - std::size_t maxDataLength, std::chrono::milliseconds timeout) -{ - std::lock_guard lock(_dev_io); - int ret; - report.resize(maxDataLength); - - timeval timeout_tv{}; - timeout_tv.tv_sec = duration_cast(_io_timeout) - .count(); - timeout_tv.tv_usec = duration_cast( - _io_timeout).count() % - duration_cast(seconds(1)).count(); - - auto timeout_ms = duration_cast(timeout).count(); - - fd_set fds; - do { - FD_ZERO(&fds); - FD_SET(_fd, &fds); - FD_SET(_pipe[0], &fds); - - ret = select(std::max(_fd, _pipe[0]) + 1, - &fds, nullptr, nullptr, - (timeout_ms > 0 ? nullptr : &timeout_tv)); - } while(ret == -1 && errno == EINTR); - - if(ret == -1) + if(write(_fd, report.data(), report.size()) == -1) throw std::system_error(errno, std::system_category(), - "_readReport select failed"); - - if(FD_ISSET(_fd, &fds)) { - ret = read(_fd, report.data(), report.size()); - if(ret == -1) - throw std::system_error(errno, std::system_category(), - "_readReport read failed"); - report.resize(ret); - } - - if(FD_ISSET(_pipe[0], &fds)) { - char c; - ret = read(_pipe[0], &c, sizeof(char)); - if(ret == -1) - throw std::system_error(errno, std::system_category(), - "_readReport read pipe failed"); - } - - if(0 == ret) - throw backend::TimeoutError(); - - if(logid::global_loglevel <= LogLevel::RAWREPORT) { - printf("[RAWREPORT] %s IN: ", _path.c_str()); - for(auto &i : report) - printf("%02x ", i); - printf("\n"); - } - - return ret; + "sendReport write failed"); } -void RawDevice::interruptRead(bool wait_for_halt) +RawDevice::EvHandlerId RawDevice::addEventHandler(RawEventHandler handler) { - char c = 0; - if(-1 == write(_pipe[1], &c, sizeof(char))) - throw std::system_error(errno, std::system_category(), - "interruptRead write pipe failed"); - - // Ensure I/O has halted - if(wait_for_halt) - std::lock_guard lock(_dev_io); + std::unique_lock lock(_event_handler_lock); + _event_handlers.emplace_front(std::move(handler)); + return _event_handlers.cbegin(); } -void RawDevice::listen() +void RawDevice::removeEventHandler(RawDevice::EvHandlerId id) { - std::lock_guard lock(_listening); - _continue_listen = true; - _listen_condition.notify_all(); - while(_continue_listen) { - while(!_io_queue.empty()) { - auto task = _io_queue.front(); - (*task)(); - _io_queue.pop(); + std::unique_lock lock(_event_handler_lock); + _event_handlers.erase(id); +} + +void RawDevice::_readReports() +{ + uint8_t buf[max_data_length]; + ssize_t len; + + while(-1 != (len = ::read(_fd, buf, max_data_length))) { + assert(len <= max_data_length); + std::vector report(buf, buf + len); + + if(logid::global_loglevel <= LogLevel::RAWREPORT) { + printf("[RAWREPORT] %s IN: ", _path.c_str()); + for(auto &i : report) + printf("%02x ", i); + printf("\n"); } - std::vector report; - _readReport(report, MAX_DATA_LENGTH); - this->_handleEvent(report); + _handleEvent(report); } - - // Listener is stopped, handle I/O queue - while(!_io_queue.empty()) { - auto task = _io_queue.front(); - (*task)(); - _io_queue.pop(); - } - - _continue_listen = false; } -void RawDevice::listenAsync() -{ - std::mutex listen_check; - std::unique_lock check_lock(listen_check); - thread::spawn({[this]() { listen(); }}); - - // Block until RawDevice is listening - _listen_condition.wait(check_lock, [this](){ - return (bool)_continue_listen; - }); -} - -void RawDevice::stopListener() -{ - _continue_listen = false; - interruptRead(); -} - -void RawDevice::addEventHandler(const std::string& nickname, - const std::shared_ptr& handler) -{ - std::unique_lock lock(_event_handler_lock); - assert(_event_handlers.find(nickname) == _event_handlers.end()); - assert(handler); - _event_handlers.emplace(nickname, handler); -} - -void RawDevice::removeEventHandler(const std::string &nickname) -{ - std::unique_lock lock(_event_handler_lock); - _event_handlers.erase(nickname); -} - -const std::map>& -RawDevice::eventHandlers() -{ - std::unique_lock lock(_event_handler_lock); - return _event_handlers; -} - -void RawDevice::_handleEvent(std::vector &report) +void RawDevice::_handleEvent(const std::vector& report) { std::unique_lock lock(_event_handler_lock); for(auto& handler : _event_handlers) - if(handler.second->condition(report)) - handler.second->callback(report); -} - -bool RawDevice::isListening() -{ - bool ret = _listening.try_lock(); - - if(ret) - _listening.unlock(); - - return !ret; + if(handler.condition(report)) + handler.callback(report); } diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 0a41caa..4bd68f6 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -26,78 +26,63 @@ #include #include #include +#include #include "defs.h" #include "../../util/mutex_queue.h" namespace logid::backend::raw { + class DeviceMonitor; + class IOMonitor; + class RawDevice { public: - static bool supportedReport(uint8_t id, uint8_t length); + static constexpr int max_data_length = 32; + typedef std::list::const_iterator EvHandlerId; - explicit RawDevice(std::string path, - double io_timeout); - ~RawDevice(); - std::string hidrawPath() const; + struct dev_info { + int16_t vid; + int16_t pid; + }; - std::string name() const; - uint16_t vendorId() const; - uint16_t productId() const; + RawDevice(std::string path, + std::shared_ptr monitor); + ~RawDevice() noexcept; + + [[nodiscard]] const std::string& rawPath() const; + + [[nodiscard]] const std::string& name() const; + [[nodiscard]] int16_t vendorId() const; + [[nodiscard]] int16_t productId() const; static std::vector getReportDescriptor(std::string path); static std::vector getReportDescriptor(int fd); - std::vector reportDescriptor() const; + [[nodiscard]] const std::vector& reportDescriptor() const; - std::vector sendReport(const std::vector& report); - void sendReportNoResponse(const std::vector& report); - void interruptRead(bool wait_for_halt=true); + void sendReport(const std::vector& report); - void listen(); - void listenAsync(); - void stopListener(); - bool isListening(); - - void addEventHandler(const std::string& nickname, - const std::shared_ptr& handler); - void removeEventHandler(const std::string& nickname); - const std::map>& - eventHandlers(); + EvHandlerId addEventHandler(RawEventHandler handler); + void removeEventHandler(EvHandlerId id); private: - std::mutex _dev_io, _listening; - std::string _path; - int _fd; - int _pipe[2]; - uint16_t _vid; - uint16_t _pid; - std::string _name; - std::vector _rdesc; + void _readReports(); - std::atomic _continue_listen; - std::atomic _continue_respond; - std::condition_variable _listen_condition; + std::atomic_bool _valid; - const std::chrono::milliseconds _io_timeout; + const std::string _path; + const int _fd; + const dev_info _devinfo; + const std::string _name; + const std::vector _rdesc; - std::map> - _event_handlers; + std::shared_ptr _io_monitor; + + std::list _event_handlers; std::mutex _event_handler_lock; - void _handleEvent(std::vector& report); - - /* These will only be used internally and processed with a queue */ - int _sendReport(const std::vector& report); - int _readReport(std::vector& report, std::size_t maxDataLength); - int _readReport(std::vector& report, std::size_t maxDataLength, - std::chrono::milliseconds timeout); - - std::vector _respondToReport(const std::vector& - request); - - mutex_queue()>>> - _io_queue; + void _handleEvent(const std::vector& report); }; } -#endif //LOGID_BACKEND_RAWDEVICE_H \ No newline at end of file +#endif //LOGID_BACKEND_RAWDEVICE_H diff --git a/src/logid/backend/raw/defs.h b/src/logid/backend/raw/defs.h index 388d9c6..53f9848 100644 --- a/src/logid/backend/raw/defs.h +++ b/src/logid/backend/raw/defs.h @@ -29,8 +29,14 @@ namespace raw { struct RawEventHandler { - std::function& )> condition; - std::function& )> callback; + std::function&)> condition; + std::function&)> callback; + + RawEventHandler(std::function&)> cond, + std::function&)> call) : + condition (std::move(cond)), callback (std::move(call)) + { + } }; }}} diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index 223546f..4b2b4d1 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -57,7 +57,7 @@ void logid::reload() { log_printf(INFO, "Reloading logid..."); finder_reloading.lock(); - finder->stop(); + finder->_stop(); Configuration* old_config = global_config; global_config = new Configuration(config_file.c_str()); delete(old_config); @@ -157,19 +157,6 @@ int main(int argc, char** argv) std::shared_ptr config; std::shared_ptr virtual_input; - auto server = ipcgull::make_server("pizza.pixl.LogiOps", - "/pizza/pixl/LogiOps", - ipcgull::IPCGULL_USER); - - std::thread( [server]() { - try { - server->start(); - } catch(ipcgull::connection_failed& e) { - logPrintf(ERROR, "Lost IPC connection, terminating."); - std::terminate(); - } - } ).detach(); - // Read config try { config = std::make_shared(options.config_file); @@ -178,6 +165,10 @@ int main(int argc, char** argv) config = std::make_shared(); } + auto server = ipcgull::make_server("pizza.pixl.LogiOps", + "/pizza/pixl/LogiOps", + ipcgull::IPCGULL_USER); + //Create a virtual input device try { virtual_input = std::make_unique(LOGID_VIRTUAL_INPUT_NAME); @@ -186,12 +177,16 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - // Scan devices, create listeners, handlers, etc. + // Device manager runs on its own I/O thread asynchronously auto device_manager = DeviceManager::make(config, virtual_input, server); - device_manager->run(); + device_manager->enumerate(); - server->stop_sync(); + try { + server->start(); + } catch(ipcgull::connection_failed& e) { + logPrintf(ERROR, "Lost IPC connection, terminating."); + } return EXIT_SUCCESS; } From f25a1e4657ea0ad2457c3fb99cab48a26bd74b58 Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 28 Jan 2022 18:28:58 -0500 Subject: [PATCH 17/59] Ignore hidpp responses to kernel driver Also fixes a bug where unconfigured devices would error. --- src/logid/Device.cpp | 9 ++- src/logid/DeviceManager.cpp | 8 ++- src/logid/actions/Action.cpp | 55 +++++++++++++++++++ src/logid/actions/Action.h | 8 +++ src/logid/backend/Error.cpp | 5 -- src/logid/backend/Error.h | 6 -- src/logid/backend/hidpp/Device.cpp | 42 +++++++++++++- src/logid/backend/hidpp/Device.h | 3 +- src/logid/backend/hidpp/Report.cpp | 4 +- src/logid/backend/hidpp/defs.h | 2 +- src/logid/backend/hidpp20/Device.cpp | 8 ++- .../backend/hidpp20/features/DeviceName.cpp | 4 ++ src/logid/backend/hidpp20/features/Root.cpp | 3 + src/logid/backend/raw/RawDevice.cpp | 6 +- src/logid/config/types.h | 5 +- 15 files changed, 141 insertions(+), 27 deletions(-) diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index dc06158..07e005d 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -296,7 +296,12 @@ config::Device& Device::_getConfig( auto& devices = manager->config()->devices; if(!devices.has_value()) devices = decltype(config::Config::devices)(); - auto& device = devices.value()[name]; + + if(!devices.value().count(name)) { + devices.value().emplace(name, config::Device()); + } + + auto& device = devices.value().at(name); if(std::holds_alternative(device)) { config::Device d; d.profiles["default"] = std::get(device); @@ -306,7 +311,7 @@ config::Device& Device::_getConfig( auto& conf = std::get(device); if(conf.profiles.empty()) { - conf.profiles["default"] = std::get(device); + conf.profiles["default"] = {}; conf.default_profile = "default"; } diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 0b03527..a6d0229 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -112,7 +112,13 @@ void DeviceManager::addDevice(std::string path) } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) throw; - } catch(hidpp::Device::InvalidDevice &e) { // Ignore + } catch(hidpp::Device::InvalidDevice &e) { + if(e.code() == hidpp::Device::InvalidDevice::VirtualNode) { + logPrintf(DEBUG, "Ignoring virtual node on %s", + path.c_str()); + return; + } + defaultExists = false; } catch(std::system_error &e) { logPrintf(WARN, "I/O error on %s: %s, skipping device.", diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index b93a28e..aa713ab 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -47,6 +47,61 @@ std::shared_ptr _makeAction(Device* device, return std::make_shared::type>(device, action); } +template +std::shared_ptr _makeAction( + Device *device, const std::string &name, + std::optional& config) +{ + if(name == "pizza.pixl.LogiOps.Action.ChangeDPI") { + config = config::ChangeDPI(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.ChangeHost") { + config = config::ChangeHost(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.CycleDPI") { + config = config::CycleDPI(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.Keypress") { + config = config::KeypressAction(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.None") { + config = config::NoAction(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.ToggleHiresScroll") { + config = config::ToggleHiresScroll(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.ToggleSmartShift") { + config = config::ToggleHiresScroll(); + return Action::makeAction(device, config.value()); + } else if(name == "pizza.pixl.LogiOps.Action.Default") { + return nullptr; + } + + throw InvalidAction(); +} + +std::shared_ptr Action::makeAction( + Device *device, const std::string &name, + std::optional &config) +{ + return _makeAction(device, name, config); +} + +std::shared_ptr Action::makeAction( + Device *device, const std::string &name, + std::optional &config) +{ + try { + return _makeAction(device, name, config); + } catch(actions::InvalidAction& e) { + if(name == "pizza.pixl.LogiOps.Action.Gesture") { + config = config::GestureAction(); + return makeAction(device, config.value()); + } + throw; + } +} + std::shared_ptr Action::makeAction(Device *device, config::BasicAction& action) { diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index 34393d8..1132c4b 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -46,6 +46,14 @@ namespace actions { class Action { public: + static std::shared_ptr makeAction( + Device* device, const std::string& name, + std::optional& config); + + static std::shared_ptr makeAction( + Device* device, const std::string& name, + std::optional& config); + static std::shared_ptr makeAction(Device* device, config::BasicAction& action); diff --git a/src/logid/backend/Error.cpp b/src/logid/backend/Error.cpp index bb4d811..f15fc0e 100644 --- a/src/logid/backend/Error.cpp +++ b/src/logid/backend/Error.cpp @@ -22,8 +22,3 @@ const char *logid::backend::TimeoutError::what() const noexcept { return "Device timed out"; } - -const char *logid::backend::InvalidDevice::what() const noexcept -{ - return "Device has become invalidated"; -} diff --git a/src/logid/backend/Error.h b/src/logid/backend/Error.h index 9c41214..8c391cf 100644 --- a/src/logid/backend/Error.h +++ b/src/logid/backend/Error.h @@ -30,12 +30,6 @@ public: const char* what() const noexcept override; }; -class InvalidDevice : public std::exception -{ -public: - InvalidDevice() = default; - const char* what() const noexcept override; -}; }} #endif //LOGID_BACKEND_ERROR_H \ No newline at end of file diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 1a18a1d..58fd6cf 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -41,6 +41,8 @@ const char* Device::InvalidDevice::what() const noexcept return "Invalid raw device"; case Asleep: return "Device asleep"; + case VirtualNode: + return "Virtual device"; default: return "Invalid device"; } @@ -122,6 +124,35 @@ void Device::_init() if(!supported_reports) throw InvalidDevice(InvalidDevice::NoHIDPPReport); + /* hid_logitech_dj creates virtual /dev/hidraw nodes for receiver + * devices. We should ignore these devices. + */ + if(_index == hidpp::DefaultDevice) { + _raw_handler = _raw_device->addEventHandler({ + [index=this->_index](const std::vector& report)->bool { + return (report[Offset::Type] == Report::Type::Short || + report[Offset::Type] == Report::Type::Long); + }, [this](const std::vector& report)->void { + Report _report(report); + this->handleEvent(_report); + } }); + + try { + auto rsp = sendReport({ReportType::Short, _index, 0, 0, + LOGID_HIDPP_SOFTWARE_ID}); + if(rsp.deviceIndex() != _index) { + throw InvalidDevice(InvalidDevice::VirtualNode); + } + } catch(hidpp10::Error& e) { + // Ignore + } catch(std::exception& e) { + _raw_device->removeEventHandler(_raw_handler); + throw; + } + + _raw_device->removeEventHandler(_raw_handler); + } + _raw_handler = _raw_device->addEventHandler({ [index=this->_index](const std::vector& report)->bool { return (report[Offset::Type] == Report::Type::Short || @@ -227,14 +258,16 @@ Report Device::sendReport(const Report &report) if(!valid) throw TimeoutError(); + std::lock_guard sl(_slot_lock); + { Report::Hidpp10Error error{}; - if(report.isError10(&error)) + if(_report_slot.value().isError10(&error)) throw hidpp10::Error(error.error_code); } { Report::Hidpp20Error error{}; - if(report.isError20(&error)) + if(_report_slot.value().isError20(&error)) throw hidpp20::Error(error.error_code); } return _report_slot.value(); @@ -247,6 +280,11 @@ bool Device::responseReport(const Report &report) return false; } + // Basic check to see if the report is a response + if( (report.swId() != LOGID_HIDPP_SOFTWARE_ID) + && report.subId() < 0x80) + return false; + std::lock_guard lock(_slot_lock); _report_slot = report; _resp_cv.notify_all(); diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 534b7a7..4b63f41 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -53,7 +53,8 @@ namespace hidpp { NoHIDPPReport, InvalidRawDevice, - Asleep + Asleep, + VirtualNode }; InvalidDevice(Reason reason) : _reason (reason) {} virtual const char* what() const noexcept; diff --git a/src/logid/backend/hidpp/Report.cpp b/src/logid/backend/hidpp/Report.cpp index 209847f..83bc19c 100644 --- a/src/logid/backend/hidpp/Report.cpp +++ b/src/logid/backend/hidpp/Report.cpp @@ -246,10 +246,10 @@ uint8_t Report::swId() const return _data[Offset::Function] & 0x0f; } -void Report::setSwId(uint8_t sub_id) +void Report::setSwId(uint8_t sw_id) { _data[Offset::Function] &= 0xf0; - _data[Offset::Function] |= sub_id & 0x0f; + _data[Offset::Function] |= sw_id & 0x0f; } uint8_t Report::address() const diff --git a/src/logid/backend/hidpp/defs.h b/src/logid/backend/hidpp/defs.h index 96a8bf6..4696006 100644 --- a/src/logid/backend/hidpp/defs.h +++ b/src/logid/backend/hidpp/defs.h @@ -19,7 +19,7 @@ #ifndef LOGID_BACKEND_HIDPP_DEFS_H #define LOGID_BACKEND_HIDPP_DEFS_H -#define LOGID_HIDPP_SOFTWARE_ID 1 +#define LOGID_HIDPP_SOFTWARE_ID 2 #include diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index 78cce96..bf7e46d 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -169,12 +169,16 @@ hidpp::Report Device::sendReport(const hidpp::Report& report) bool Device::responseReport(const hidpp::Report& report) { std::lock_guard lock(_response_lock); - uint8_t sw_id = report.swId(); + uint8_t sw_id; bool is_error = false; hidpp::Report::Hidpp20Error hidpp20_error {}; - if(report.isError20(&hidpp20_error)) + if(report.isError20(&hidpp20_error)) { is_error = true; + sw_id = hidpp20_error.software_id; + } else { + sw_id = report.swId(); + } auto response_slot = _responses.find(sw_id); if(response_slot == _responses.end()) diff --git a/src/logid/backend/hidpp20/features/DeviceName.cpp b/src/logid/backend/hidpp20/features/DeviceName.cpp index d6c44bc..8b8e7a4 100644 --- a/src/logid/backend/hidpp20/features/DeviceName.cpp +++ b/src/logid/backend/hidpp20/features/DeviceName.cpp @@ -74,6 +74,10 @@ uint8_t EssentialDeviceName::getNameLength() std::vector params(0); auto response = this->callFunction(DeviceName::Function::GetLength, params); + + if(response[0] == 1) + return 1; + return response[0]; } diff --git a/src/logid/backend/hidpp20/features/Root.cpp b/src/logid/backend/hidpp20/features/Root.cpp index f1aa724..ad97da0 100644 --- a/src/logid/backend/hidpp20/features/Root.cpp +++ b/src/logid/backend/hidpp20/features/Root.cpp @@ -92,5 +92,8 @@ std::tuple EssentialRoot::getVersion() std::vector params(0); auto response = this->callFunction(Root::Function::Ping, params); + if(response[0] == 0x11) + return std::make_tuple(1, 0); + return std::make_tuple(response[0], response[1]); } \ No newline at end of file diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 77fecc2..9d58982 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -155,8 +155,10 @@ const std::vector& RawDevice::reportDescriptor() const void RawDevice::sendReport(const std::vector& report) { - if(!_valid) - throw InvalidDevice(); + if(!_valid) { + // We could throw an error here, but this will likely be closed soon. + return; + } if(logid::global_loglevel <= LogLevel::RAWREPORT) { printf("[RAWREPORT] %s OUT: ", _path.c_str()); diff --git a/src/logid/config/types.h b/src/logid/config/types.h index ad729ae..1969045 100644 --- a/src/logid/config/types.h +++ b/src/logid/config/types.h @@ -382,11 +382,10 @@ namespace logid::config { struct config_io> { static std::optional get(const libconfig::Setting& parent, const std::string& name) { - try { + if(parent.exists(name)) return config_io::get(parent.lookup(name)); - } catch(libconfig::SettingException& e) { + else return {}; - } } static void set(libconfig::Setting& parent, From 3808f0a6cfcf74d83f21a2b3f7b8f26eb43b8872 Mon Sep 17 00:00:00 2001 From: pixl Date: Fri, 28 Jan 2022 20:50:16 -0500 Subject: [PATCH 18/59] Use action interface names as static vars --- src/ipcgull | 2 +- src/logid/actions/Action.cpp | 16 ++++++++-------- src/logid/actions/ChangeDPI.cpp | 3 +++ src/logid/actions/ChangeDPI.h | 2 ++ src/logid/actions/ChangeHostAction.cpp | 3 +++ src/logid/actions/ChangeHostAction.h | 2 ++ src/logid/actions/CycleDPI.cpp | 3 +++ src/logid/actions/CycleDPI.h | 2 ++ src/logid/actions/GestureAction.cpp | 3 +++ src/logid/actions/GestureAction.h | 2 ++ src/logid/actions/KeypressAction.cpp | 3 +++ src/logid/actions/KeypressAction.h | 2 ++ src/logid/actions/NullAction.cpp | 3 +++ src/logid/actions/NullAction.h | 2 ++ src/logid/actions/ToggleHiresScroll.cpp | 3 +++ src/logid/actions/ToggleHiresScroll.h | 2 ++ src/logid/actions/ToggleSmartShift.cpp | 3 +++ src/logid/actions/ToggleSmartShift.h | 2 ++ src/logid/backend/raw/IOMonitor.cpp | 6 +++--- src/logid/backend/raw/IOMonitor.h | 2 ++ 20 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index 2255923..e86f198 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 22559236d8c6e30aac640f79b8d4983467ba5cc8 +Subproject commit e86f1987bc40c840d3cef758619783e5bdec1c41 diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index aa713ab..9123994 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -52,25 +52,25 @@ std::shared_ptr _makeAction( Device *device, const std::string &name, std::optional& config) { - if(name == "pizza.pixl.LogiOps.Action.ChangeDPI") { + if(name == ChangeDPI::interface_name) { config = config::ChangeDPI(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.ChangeHost") { + } else if(name == ChangeHostAction::interface_name) { config = config::ChangeHost(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.CycleDPI") { + } else if(name == CycleDPI::interface_name) { config = config::CycleDPI(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.Keypress") { + } else if(name == KeypressAction::interface_name) { config = config::KeypressAction(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.None") { + } else if(name == NullAction::interface_name) { config = config::NoAction(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.ToggleHiresScroll") { + } else if(name == ToggleHiresScroll::interface_name) { config = config::ToggleHiresScroll(); return Action::makeAction(device, config.value()); - } else if(name == "pizza.pixl.LogiOps.Action.ToggleSmartShift") { + } else if(name == ToggleSmartShift::interface_name) { config = config::ToggleHiresScroll(); return Action::makeAction(device, config.value()); } else if(name == "pizza.pixl.LogiOps.Action.Default") { @@ -94,7 +94,7 @@ std::shared_ptr Action::makeAction( try { return _makeAction(device, name, config); } catch(actions::InvalidAction& e) { - if(name == "pizza.pixl.LogiOps.Action.Gesture") { + if(name == GestureAction::interface_name) { config = config::GestureAction(); return makeAction(device, config.value()); } diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index c1f7f62..00f8217 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -24,6 +24,9 @@ using namespace logid::actions; +const char* ChangeDPI::interface_name = + "pizza.pixl.LogiOps.Action.ChangeDPI"; + ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) : Action(device), _config (config) { diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h index f5d33e8..13b6423 100644 --- a/src/logid/actions/ChangeDPI.h +++ b/src/logid/actions/ChangeDPI.h @@ -27,6 +27,8 @@ namespace logid { class ChangeDPI : public Action { public: + static const char* interface_name; + explicit ChangeDPI(Device* device, config::ChangeDPI& setting); virtual void press(); diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index ad0a8b3..87359c3 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -24,6 +24,9 @@ using namespace logid::actions; using namespace logid::backend; +const char* ChangeHostAction::interface_name = + "pizza.pixl.LogiOps.Action.ChangeHost"; + ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config) : Action(device), _config (config) { diff --git a/src/logid/actions/ChangeHostAction.h b/src/logid/actions/ChangeHostAction.h index 6c293d9..e8a8aca 100644 --- a/src/logid/actions/ChangeHostAction.h +++ b/src/logid/actions/ChangeHostAction.h @@ -28,6 +28,8 @@ namespace actions class ChangeHostAction : public Action { public: + static const char* interface_name; + ChangeHostAction(Device* device, config::ChangeHost& config); virtual void press(); diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index 60c0f04..5113843 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -25,6 +25,9 @@ using namespace logid::actions; using namespace libconfig; +const char* CycleDPI::interface_name = + "pizza.pixl.LogiOps.Action.CycleDPI"; + CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) : Action (device), _config (config), _current_dpi (_config.dpis.begin()) { diff --git a/src/logid/actions/CycleDPI.h b/src/logid/actions/CycleDPI.h index 6f9d482..1f70d61 100644 --- a/src/logid/actions/CycleDPI.h +++ b/src/logid/actions/CycleDPI.h @@ -27,6 +27,8 @@ namespace actions { class CycleDPI : public Action { public: + static const char* interface_name; + explicit CycleDPI(Device* device, config::CycleDPI& setting); virtual void press(); diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index e85fc46..569f6a3 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -24,6 +24,9 @@ using namespace logid::actions; using namespace logid; using namespace logid::backend; +const char* GestureAction::interface_name = + "pizza.pixl.LogiOps.Action.Gesture"; + GestureAction::Direction GestureAction::toDirection(std::string direction) { std::transform(direction.begin(), direction.end(), direction.begin(), diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index 1dff30b..cde4588 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -28,6 +28,8 @@ namespace actions { class GestureAction : public Action { public: + static const char* interface_name; + enum Direction { None, diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index 0dc0b1d..c2db8c2 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -24,6 +24,9 @@ using namespace logid::actions; using namespace logid::backend; +const char* KeypressAction::interface_name = + "pizza.pixl.LogiOps.Action.Keypress"; + KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : Action(device), _config (config) { diff --git a/src/logid/actions/KeypressAction.h b/src/logid/actions/KeypressAction.h index 5ac09d6..0d961b1 100644 --- a/src/logid/actions/KeypressAction.h +++ b/src/logid/actions/KeypressAction.h @@ -27,6 +27,8 @@ namespace actions { class KeypressAction : public Action { public: + static const char* interface_name; + KeypressAction(Device* dev, config::KeypressAction& config); virtual void press(); diff --git a/src/logid/actions/NullAction.cpp b/src/logid/actions/NullAction.cpp index 8cf875f..cdb6972 100644 --- a/src/logid/actions/NullAction.cpp +++ b/src/logid/actions/NullAction.cpp @@ -21,6 +21,9 @@ using namespace logid::actions; +const char* NullAction::interface_name = + "pizza.pixl.LogiOps.Action.None"; + NullAction::NullAction(Device* device) : Action(device) { } diff --git a/src/logid/actions/NullAction.h b/src/logid/actions/NullAction.h index 24f169b..ef483a1 100644 --- a/src/logid/actions/NullAction.h +++ b/src/logid/actions/NullAction.h @@ -26,6 +26,8 @@ namespace actions class NullAction : public Action { public: + static const char* interface_name; + explicit NullAction(Device* device); NullAction(Device* device, [[maybe_unused]] config::NoAction& config) : NullAction(device) { } diff --git a/src/logid/actions/ToggleHiresScroll.cpp b/src/logid/actions/ToggleHiresScroll.cpp index 35e5f8d..7ada225 100644 --- a/src/logid/actions/ToggleHiresScroll.cpp +++ b/src/logid/actions/ToggleHiresScroll.cpp @@ -23,6 +23,9 @@ using namespace logid::actions; using namespace logid::backend; +const char* ToggleHiresScroll::interface_name = + "pizza.pixl.LogiOps.Action.ToggleHiresScroll"; + ToggleHiresScroll::ToggleHiresScroll(Device *dev) : Action (dev) { _hires_scroll = _device->getFeature("hiresscroll"); diff --git a/src/logid/actions/ToggleHiresScroll.h b/src/logid/actions/ToggleHiresScroll.h index 52c41c6..3dec044 100644 --- a/src/logid/actions/ToggleHiresScroll.h +++ b/src/logid/actions/ToggleHiresScroll.h @@ -27,6 +27,8 @@ namespace actions class ToggleHiresScroll : public Action { public: + static const char* interface_name; + explicit ToggleHiresScroll(Device* dev); ToggleHiresScroll(Device* device, [[maybe_unused]] config::ToggleHiresScroll& action) : diff --git a/src/logid/actions/ToggleSmartShift.cpp b/src/logid/actions/ToggleSmartShift.cpp index fe5efe1..407ec7f 100644 --- a/src/logid/actions/ToggleSmartShift.cpp +++ b/src/logid/actions/ToggleSmartShift.cpp @@ -23,6 +23,9 @@ using namespace logid::actions; using namespace logid::backend; +const char* ToggleSmartShift::interface_name = + "pizza.pixl.LogiOps.Action.ToggleSmartShift"; + ToggleSmartShift::ToggleSmartShift(Device *dev) : Action (dev) { _smartshift = _device->getFeature("smartshift"); diff --git a/src/logid/actions/ToggleSmartShift.h b/src/logid/actions/ToggleSmartShift.h index 90c0025..8913ec6 100644 --- a/src/logid/actions/ToggleSmartShift.h +++ b/src/logid/actions/ToggleSmartShift.h @@ -27,6 +27,8 @@ namespace actions { class ToggleSmartShift : public Action { public: + static const char* interface_name; + explicit ToggleSmartShift(Device* dev); ToggleSmartShift(Device* device, [[maybe_unused]] config::ToggleSmartShift& action) : diff --git a/src/logid/backend/raw/IOMonitor.cpp b/src/logid/backend/raw/IOMonitor.cpp index f92e6b0..6114882 100644 --- a/src/logid/backend/raw/IOMonitor.cpp +++ b/src/logid/backend/raw/IOMonitor.cpp @@ -66,9 +66,9 @@ IOMonitor::IOMonitor() : _epoll_fd (epoll_create1(0)), throw std::runtime_error("eventfd error"); })); - std::thread([this](){ + _io_thread = std::make_unique([this](){ _listen(); - }).detach(); + }); } IOMonitor::~IOMonitor() noexcept @@ -124,7 +124,7 @@ void IOMonitor::_stop() noexcept _interrupt(); _is_running = false; _continue(); - std::lock_guard run_lock(_run_lock); + _io_thread->join(); } bool IOMonitor::_running() const diff --git a/src/logid/backend/raw/IOMonitor.h b/src/logid/backend/raw/IOMonitor.h index eae487c..36ec1d0 100644 --- a/src/logid/backend/raw/IOMonitor.h +++ b/src/logid/backend/raw/IOMonitor.h @@ -52,6 +52,8 @@ namespace logid::backend::raw { void _interrupt() noexcept; void _continue() noexcept; + std::unique_ptr _io_thread; + std::map _fds; std::mutex _io_lock, _ctl_lock; mutable std::mutex _run_lock; From 6e8c24b2f9945cb5920a8f32def3924d8691e695 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 29 Jan 2022 00:05:40 -0500 Subject: [PATCH 19/59] Fix a race condition caused by virtual hid nodes When a virtual hidraw node is being tested while the real one is tested, this causes the devices to misidentify reports. This solves that by making the device monitor synchronous. --- src/logid/backend/hidpp/Device.cpp | 6 ++++-- src/logid/backend/hidpp20/EssentialFeature.cpp | 6 ++---- src/logid/backend/hidpp20/features/DeviceName.cpp | 3 --- src/logid/backend/raw/DeviceMonitor.cpp | 6 +++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 58fd6cf..418cbd4 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -138,8 +138,10 @@ void Device::_init() } }); try { - auto rsp = sendReport({ReportType::Short, _index, 0, 0, - LOGID_HIDPP_SOFTWARE_ID}); + auto rsp = sendReport( + {ReportType::Short, _index, + hidpp20::FeatureID::ROOT, hidpp20::Root::Ping, + LOGID_HIDPP_SOFTWARE_ID}); if(rsp.deviceIndex() != _index) { throw InvalidDevice(InvalidDevice::VirtualNode); } diff --git a/src/logid/backend/hidpp20/EssentialFeature.cpp b/src/logid/backend/hidpp20/EssentialFeature.cpp index 11b9751..ffd2442 100644 --- a/src/logid/backend/hidpp20/EssentialFeature.cpp +++ b/src/logid/backend/hidpp20/EssentialFeature.cpp @@ -42,7 +42,7 @@ std::vector EssentialFeature::callFunction(uint8_t function_id, std::copy(params.begin(), params.end(), request.paramBegin()); auto response = _device->sendReport(request); - return std::vector(response.paramBegin(), response.paramEnd()); + return {response.paramBegin(), response.paramEnd()}; } EssentialFeature::EssentialFeature(hidpp::Device* dev, uint16_t _id) : @@ -56,9 +56,7 @@ EssentialFeature::EssentialFeature(hidpp::Device* dev, uint16_t _id) : getFunc_req[0] = (_id >> 8) & 0xff; getFunc_req[1] = _id & 0xff; try { - auto getFunc_resp = this->callFunction(Root::GetFeature, - getFunc_req); - _index = getFunc_resp[0]; + _index = this->callFunction(Root::GetFeature,getFunc_req).at(0); } catch(Error& e) { if(e.code() == Error::InvalidFeatureIndex) throw UnsupportedFeature(_id); diff --git a/src/logid/backend/hidpp20/features/DeviceName.cpp b/src/logid/backend/hidpp20/features/DeviceName.cpp index 8b8e7a4..deed409 100644 --- a/src/logid/backend/hidpp20/features/DeviceName.cpp +++ b/src/logid/backend/hidpp20/features/DeviceName.cpp @@ -75,9 +75,6 @@ uint8_t EssentialDeviceName::getNameLength() auto response = this->callFunction(DeviceName::Function::GetLength, params); - if(response[0] == 1) - return 1; - return response[0]; } diff --git a/src/logid/backend/raw/DeviceMonitor.cpp b/src/logid/backend/raw/DeviceMonitor.cpp index 2a1756f..d8de3c6 100644 --- a/src/logid/backend/raw/DeviceMonitor.cpp +++ b/src/logid/backend/raw/DeviceMonitor.cpp @@ -99,9 +99,9 @@ void DeviceMonitor::ready() std::string devnode = udev_device_get_devnode(device); if (action == "add") - spawn_task([this, devnode]() { _addHandler(devnode); } ); + _addHandler(devnode); else if (action == "remove") - spawn_task([this, devnode]() { _removeHandler(devnode); } ); + _removeHandler(devnode); udev_device_unref(device); }, @@ -141,7 +141,7 @@ void DeviceMonitor::enumerate() std::string devnode = udev_device_get_devnode(device); udev_device_unref(device); - spawn_task([this, devnode]() { _addHandler(devnode); } ); + _addHandler(devnode); } udev_enumerate_unref(udev_enum); From 87fb4371a4d443a68ad7c807c073a7517830ea82 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 29 Jan 2022 00:07:22 -0500 Subject: [PATCH 20/59] Initial action and gesture ipc interfaces --- src/logid/actions/Action.cpp | 54 ++++++++++--------- src/logid/actions/Action.h | 18 ++++--- src/logid/actions/ChangeDPI.cpp | 11 +++- src/logid/actions/ChangeDPI.h | 13 ++++- src/logid/actions/ChangeHostAction.cpp | 11 +++- src/logid/actions/ChangeHostAction.h | 13 ++++- src/logid/actions/CycleDPI.cpp | 10 +++- src/logid/actions/CycleDPI.h | 13 ++++- src/logid/actions/GestureAction.cpp | 33 +++++++++++- src/logid/actions/GestureAction.h | 15 +++++- src/logid/actions/KeypressAction.cpp | 10 +++- src/logid/actions/KeypressAction.h | 14 ++++- src/logid/actions/NullAction.cpp | 10 +++- src/logid/actions/NullAction.h | 14 +++-- src/logid/actions/ToggleHiresScroll.cpp | 10 +++- src/logid/actions/ToggleHiresScroll.h | 15 ++++-- src/logid/actions/ToggleSmartShift.cpp | 10 +++- src/logid/actions/ToggleSmartShift.h | 16 ++++-- src/logid/actions/gesture/AxisGesture.cpp | 6 ++- src/logid/actions/gesture/AxisGesture.h | 4 +- src/logid/actions/gesture/Gesture.cpp | 24 ++++++--- src/logid/actions/gesture/Gesture.h | 9 +++- src/logid/actions/gesture/IntervalGesture.cpp | 8 +-- src/logid/actions/gesture/IntervalGesture.h | 4 +- src/logid/actions/gesture/NullGesture.cpp | 6 ++- src/logid/actions/gesture/NullGesture.h | 4 +- src/logid/actions/gesture/ReleaseGesture.cpp | 8 +-- src/logid/actions/gesture/ReleaseGesture.h | 4 +- .../actions/gesture/ThresholdGesture.cpp | 8 +-- src/logid/actions/gesture/ThresholdGesture.h | 4 +- src/logid/features/HiresScroll.cpp | 13 +++-- src/logid/features/HiresScroll.h | 5 +- src/logid/features/RemapButton.cpp | 5 +- src/logid/features/ThumbWheel.cpp | 24 +++++---- src/logid/features/ThumbWheel.h | 5 ++ 35 files changed, 330 insertions(+), 101 deletions(-) diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index 9123994..722b14c 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -42,37 +42,39 @@ template struct action_type : action_type { }; template -std::shared_ptr _makeAction(Device* device, - T action) { - return std::make_shared::type>(device, action); +std::shared_ptr _makeAction( + Device* device, T action, + const std::shared_ptr& parent) { + return std::make_shared::type>(device, action, parent); } template std::shared_ptr _makeAction( Device *device, const std::string &name, - std::optional& config) + std::optional& config, + const std::shared_ptr& parent) { if(name == ChangeDPI::interface_name) { config = config::ChangeDPI(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == ChangeHostAction::interface_name) { config = config::ChangeHost(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == CycleDPI::interface_name) { config = config::CycleDPI(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == KeypressAction::interface_name) { config = config::KeypressAction(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == NullAction::interface_name) { config = config::NoAction(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == ToggleHiresScroll::interface_name) { config = config::ToggleHiresScroll(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == ToggleSmartShift::interface_name) { config = config::ToggleHiresScroll(); - return Action::makeAction(device, config.value()); + return Action::makeAction(device, config.value(), parent); } else if(name == "pizza.pixl.LogiOps.Action.Default") { return nullptr; } @@ -82,42 +84,46 @@ std::shared_ptr _makeAction( std::shared_ptr Action::makeAction( Device *device, const std::string &name, - std::optional &config) + std::optional &config, + const std::shared_ptr& parent) { - return _makeAction(device, name, config); + return _makeAction(device, name, config, parent); } std::shared_ptr Action::makeAction( Device *device, const std::string &name, - std::optional &config) + std::optional &config, + const std::shared_ptr& parent) { try { - return _makeAction(device, name, config); + return _makeAction(device, name, config, parent); } catch(actions::InvalidAction& e) { if(name == GestureAction::interface_name) { config = config::GestureAction(); - return makeAction(device, config.value()); + return makeAction(device, config.value(), parent); } throw; } } -std::shared_ptr Action::makeAction(Device *device, - config::BasicAction& action) +std::shared_ptr Action::makeAction( + Device *device, config::BasicAction& action, + const std::shared_ptr& parent) { std::shared_ptr ret; - std::visit([&device, &ret](auto&& x) { - ret = _makeAction(device, x); + std::visit([&device, &ret, &parent](auto&& x) { + ret = _makeAction(device, x, parent); }, action); return ret; } -std::shared_ptr Action::makeAction(Device *device, - config::Action& action) +std::shared_ptr Action::makeAction( + Device *device, config::Action& action, + const std::shared_ptr& parent) { std::shared_ptr ret; - std::visit([&device, &ret](auto&& x) { - ret = _makeAction(device, x); + std::visit([&device, &ret, &parent](auto&& x) { + ret = _makeAction(device, x, parent); }, action); return ret; } diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index 1132c4b..d670906 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "../config/schema.h" namespace logid { @@ -48,17 +50,21 @@ namespace actions { public: static std::shared_ptr makeAction( Device* device, const std::string& name, - std::optional& config); + std::optional& config, + const std::shared_ptr& parent); static std::shared_ptr makeAction( Device* device, const std::string& name, - std::optional& config); + std::optional& config, + const std::shared_ptr& parent); - static std::shared_ptr makeAction(Device* device, - config::BasicAction& action); + static std::shared_ptr makeAction( + Device* device, config::BasicAction& action, + const std::shared_ptr& parent); - static std::shared_ptr makeAction(Device* device, - config::Action& action); + static std::shared_ptr makeAction( + Device* device, config::Action& action, + const std::shared_ptr& parent); virtual void press() = 0; virtual void release() = 0; diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index 00f8217..78f05d1 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -27,7 +27,9 @@ using namespace logid::actions; const char* ChangeDPI::interface_name = "pizza.pixl.LogiOps.Action.ChangeDPI"; -ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) : +ChangeDPI::ChangeDPI( + Device *device, config::ChangeDPI& config, + const std::shared_ptr& parent) : Action(device), _config (config) { _dpi = _device->getFeature("dpi"); @@ -36,6 +38,8 @@ ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) : "ChangeDPI action.", _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex()); + + _ipc = parent->make_interface(this); } void ChangeDPI::press() @@ -71,3 +75,8 @@ uint8_t ChangeDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } + +ChangeDPI::IPC::IPC(ChangeDPI *action) : + ipcgull::interface(interface_name, {}, {}, {}), _action (*action) +{ +} diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h index 13b6423..d37dff9 100644 --- a/src/logid/actions/ChangeDPI.h +++ b/src/logid/actions/ChangeDPI.h @@ -29,7 +29,8 @@ namespace logid { public: static const char* interface_name; - explicit ChangeDPI(Device* device, config::ChangeDPI& setting); + ChangeDPI(Device* device, config::ChangeDPI& setting, + const std::shared_ptr& parent); virtual void press(); virtual void release(); @@ -39,6 +40,16 @@ namespace logid { protected: config::ChangeDPI& _config; std::shared_ptr _dpi; + private: + class IPC : public ipcgull::interface + { + public: + IPC(ChangeDPI* action); + private: + ChangeDPI& _action; + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index 87359c3..c0fcc5f 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -27,7 +27,9 @@ using namespace logid::backend; const char* ChangeHostAction::interface_name = "pizza.pixl.LogiOps.Action.ChangeHost"; -ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config) +ChangeHostAction::ChangeHostAction( + Device *device, config::ChangeHost& config, + const std::shared_ptr& parent) : Action(device), _config (config) { if(std::holds_alternative(_config.host)) { @@ -42,6 +44,8 @@ ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config) "ChangeHostAction will not work.", device->hidpp20() .devicePath().c_str(), device->hidpp20().deviceIndex()); } + + _ipc = parent->make_interface(this); } void ChangeHostAction::press() @@ -78,3 +82,8 @@ uint8_t ChangeHostAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } + +ChangeHostAction::IPC::IPC(ChangeHostAction *action) : + ipcgull::interface(interface_name, {}, {}, {}), _action (*action) +{ +} diff --git a/src/logid/actions/ChangeHostAction.h b/src/logid/actions/ChangeHostAction.h index e8a8aca..e5ac8e8 100644 --- a/src/logid/actions/ChangeHostAction.h +++ b/src/logid/actions/ChangeHostAction.h @@ -30,7 +30,8 @@ namespace actions public: static const char* interface_name; - ChangeHostAction(Device* device, config::ChangeHost& config); + ChangeHostAction(Device* device, config::ChangeHost& config, + const std::shared_ptr& parent); virtual void press(); virtual void release(); @@ -40,6 +41,16 @@ namespace actions protected: std::shared_ptr _change_host; config::ChangeHost& _config; + private: + class IPC : public ipcgull::interface + { + public: + IPC(ChangeHostAction* action); + private: + ChangeHostAction& _action; + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index 5113843..a169447 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -28,7 +28,8 @@ using namespace libconfig; const char* CycleDPI::interface_name = "pizza.pixl.LogiOps.Action.CycleDPI"; -CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) : +CycleDPI::CycleDPI(Device* device, config::CycleDPI& config, + const std::shared_ptr& parent) : Action (device), _config (config), _current_dpi (_config.dpis.begin()) { _dpi = _device->getFeature("dpi"); @@ -37,6 +38,8 @@ CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) : "CycleDPI action.", _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex()); + + _ipc = parent->make_interface(this); } void CycleDPI::press() @@ -73,3 +76,8 @@ uint8_t CycleDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } + +CycleDPI::IPC::IPC(CycleDPI *action) : + ipcgull::interface(interface_name, {}, {}, {}), _action (*action) +{ +} diff --git a/src/logid/actions/CycleDPI.h b/src/logid/actions/CycleDPI.h index 1f70d61..d21c3bf 100644 --- a/src/logid/actions/CycleDPI.h +++ b/src/logid/actions/CycleDPI.h @@ -29,7 +29,8 @@ namespace actions { public: static const char* interface_name; - explicit CycleDPI(Device* device, config::CycleDPI& setting); + CycleDPI(Device* device, config::CycleDPI& setting, + const std::shared_ptr& parent); virtual void press(); virtual void release(); @@ -41,6 +42,16 @@ namespace actions { config::CycleDPI& _config; std::shared_ptr _dpi; std::list::const_iterator _current_dpi; + private: + class IPC : public ipcgull::interface + { + public: + IPC(CycleDPI* action); + private: + CycleDPI& _action; + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index 569f6a3..d654d22 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -45,6 +45,25 @@ GestureAction::Direction GestureAction::toDirection(std::string direction) throw std::invalid_argument("direction"); } +std::string GestureAction::fromDirection(Direction direction) +{ + switch(direction) { + case Up: + return "up"; + case Down: + return "down"; + case Left: + return "left"; + case Right: + return "right"; + case None: + return "none"; + } + + // This shouldn't happen + throw InvalidGesture(); +} + GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y) { if(x >= 0 && y >= 0) @@ -57,7 +76,8 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y) return x <= -y ? Up : Right; } -GestureAction::GestureAction(Device* dev, config::GestureAction& config) : +GestureAction::GestureAction(Device* dev, config::GestureAction& config, + const std::shared_ptr& parent) : Action (dev), _config (config) { if(_config.gestures.has_value()) { @@ -66,12 +86,16 @@ GestureAction::GestureAction(Device* dev, config::GestureAction& config) : try { auto direction = toDirection(x.first); _gestures.emplace(direction, - Gesture::makeGesture(dev, x.second)); + Gesture::makeGesture( + dev, x.second, parent, + fromDirection(direction))); } catch(std::invalid_argument& e) { logPrintf(WARN, "%s is not a direction", x.first.c_str()); } } } + + _ipc = parent->make_interface(this); } void GestureAction::press() @@ -193,3 +217,8 @@ uint8_t GestureAction::reprogFlags() const return (hidpp20::ReprogControls::TemporaryDiverted | hidpp20::ReprogControls::RawXYDiverted); } + +GestureAction::IPC::IPC(GestureAction *action) : + ipcgull::interface(interface_name, {}, {}, {}), _action (*action) +{ +} diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index cde4588..a66c732 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -39,9 +39,11 @@ namespace actions { Right }; static Direction toDirection(std::string direction); + static std::string fromDirection(Direction direction); static Direction toDirection(int16_t x, int16_t y); - GestureAction(Device* dev, config::GestureAction& config); + GestureAction(Device* dev, config::GestureAction& config, + const std::shared_ptr& parent); virtual void press(); virtual void release(); @@ -53,6 +55,17 @@ namespace actions { int16_t _x, _y; std::map> _gestures; config::GestureAction& _config; + + private: + class IPC : public ipcgull::interface + { + public: + explicit IPC(GestureAction* action); + private: + GestureAction& _action; + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index c2db8c2..ff6afac 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -27,7 +27,8 @@ using namespace logid::backend; const char* KeypressAction::interface_name = "pizza.pixl.LogiOps.Action.Keypress"; -KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : +KeypressAction::KeypressAction(Device *device, config::KeypressAction& config, + const std::shared_ptr& parent) : Action(device), _config (config) { if(std::holds_alternative(_config.keys)) { @@ -65,6 +66,8 @@ KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : } } } + + _ipc = parent->make_interface(this); } void KeypressAction::press() @@ -85,3 +88,8 @@ uint8_t KeypressAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } + +KeypressAction::IPC::IPC(KeypressAction *action) : ipcgull::interface( + interface_name, {}, {}, {}), _action (*action) +{ +} diff --git a/src/logid/actions/KeypressAction.h b/src/logid/actions/KeypressAction.h index 0d961b1..8cde45d 100644 --- a/src/logid/actions/KeypressAction.h +++ b/src/logid/actions/KeypressAction.h @@ -29,7 +29,9 @@ namespace actions { public: static const char* interface_name; - KeypressAction(Device* dev, config::KeypressAction& config); + KeypressAction(Device* dev, + config::KeypressAction& config, + const std::shared_ptr& parent); virtual void press(); virtual void release(); @@ -38,6 +40,16 @@ namespace actions { protected: config::KeypressAction& _config; std::list _keys; + private: + class IPC : public ipcgull::interface + { + public: + explicit IPC(KeypressAction* action); + private: + KeypressAction& _action; + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/NullAction.cpp b/src/logid/actions/NullAction.cpp index cdb6972..d81d60e 100644 --- a/src/logid/actions/NullAction.cpp +++ b/src/logid/actions/NullAction.cpp @@ -24,7 +24,9 @@ using namespace logid::actions; const char* NullAction::interface_name = "pizza.pixl.LogiOps.Action.None"; -NullAction::NullAction(Device* device) : Action(device) +NullAction::NullAction(Device* device, + const std::shared_ptr& parent) : + Action(device), _ipc (parent->make_interface()) { } @@ -41,4 +43,8 @@ void NullAction::release() uint8_t NullAction::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; -} \ No newline at end of file +} + +NullAction::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) +{ +} diff --git a/src/logid/actions/NullAction.h b/src/logid/actions/NullAction.h index ef483a1..dd95f83 100644 --- a/src/logid/actions/NullAction.h +++ b/src/logid/actions/NullAction.h @@ -28,14 +28,22 @@ namespace actions public: static const char* interface_name; - explicit NullAction(Device* device); - NullAction(Device* device, [[maybe_unused]] config::NoAction& config) : - NullAction(device) { } + NullAction(Device* device, + const std::shared_ptr& parent); + NullAction(Device* device, [[maybe_unused]] config::NoAction& config, + const std::shared_ptr& parent) : + NullAction(device, parent) { } virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; + private: + class IPC : public ipcgull::interface { + public: + IPC(); + }; + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ToggleHiresScroll.cpp b/src/logid/actions/ToggleHiresScroll.cpp index 7ada225..40dfd0c 100644 --- a/src/logid/actions/ToggleHiresScroll.cpp +++ b/src/logid/actions/ToggleHiresScroll.cpp @@ -26,7 +26,9 @@ using namespace logid::backend; const char* ToggleHiresScroll::interface_name = "pizza.pixl.LogiOps.Action.ToggleHiresScroll"; -ToggleHiresScroll::ToggleHiresScroll(Device *dev) : Action (dev) +ToggleHiresScroll::ToggleHiresScroll( + Device *dev, const std::shared_ptr& parent) : + Action (dev), _ipc (parent->make_interface()) { _hires_scroll = _device->getFeature("hiresscroll"); if(!_hires_scroll) @@ -58,4 +60,8 @@ void ToggleHiresScroll::release() uint8_t ToggleHiresScroll::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; -} \ No newline at end of file +} + +ToggleHiresScroll::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) +{ +} diff --git a/src/logid/actions/ToggleHiresScroll.h b/src/logid/actions/ToggleHiresScroll.h index 3dec044..2c1f3b1 100644 --- a/src/logid/actions/ToggleHiresScroll.h +++ b/src/logid/actions/ToggleHiresScroll.h @@ -29,10 +29,11 @@ namespace actions public: static const char* interface_name; - explicit ToggleHiresScroll(Device* dev); + ToggleHiresScroll(Device* dev, const std::shared_ptr& parent); ToggleHiresScroll(Device* device, - [[maybe_unused]] config::ToggleHiresScroll& action) : - ToggleHiresScroll(device) { } + [[maybe_unused]] config::ToggleHiresScroll& action, + const std::shared_ptr& parent) : + ToggleHiresScroll(device, parent) { } virtual void press(); virtual void release(); @@ -40,6 +41,14 @@ namespace actions virtual uint8_t reprogFlags() const; protected: std::shared_ptr _hires_scroll; + private: + class IPC : public ipcgull::interface + { + public: + IPC(); + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ToggleSmartShift.cpp b/src/logid/actions/ToggleSmartShift.cpp index 407ec7f..6767138 100644 --- a/src/logid/actions/ToggleSmartShift.cpp +++ b/src/logid/actions/ToggleSmartShift.cpp @@ -26,7 +26,9 @@ using namespace logid::backend; const char* ToggleSmartShift::interface_name = "pizza.pixl.LogiOps.Action.ToggleSmartShift"; -ToggleSmartShift::ToggleSmartShift(Device *dev) : Action (dev) +ToggleSmartShift::ToggleSmartShift( + Device *dev, const std::shared_ptr& parent) : + Action (dev), _ipc (parent->make_interface()) { _smartshift = _device->getFeature("smartshift"); if(!_smartshift) @@ -58,4 +60,8 @@ void ToggleSmartShift::release() uint8_t ToggleSmartShift::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; -} \ No newline at end of file +} + +ToggleSmartShift::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) +{ +} diff --git a/src/logid/actions/ToggleSmartShift.h b/src/logid/actions/ToggleSmartShift.h index 8913ec6..7013c50 100644 --- a/src/logid/actions/ToggleSmartShift.h +++ b/src/logid/actions/ToggleSmartShift.h @@ -29,10 +29,12 @@ namespace actions { public: static const char* interface_name; - explicit ToggleSmartShift(Device* dev); + ToggleSmartShift(Device* dev, + const std::shared_ptr& parent); ToggleSmartShift(Device* device, - [[maybe_unused]] config::ToggleSmartShift& action) : - ToggleSmartShift(device) { } + [[maybe_unused]] config::ToggleSmartShift& action, + const std::shared_ptr& parent) : + ToggleSmartShift(device, parent) { } virtual void press(); virtual void release(); @@ -40,6 +42,14 @@ namespace actions { virtual uint8_t reprogFlags() const; protected: std::shared_ptr _smartshift; + private: + class IPC : public ipcgull::interface + { + public: + IPC(); + }; + + std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 248fa0c..9d8bd43 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -23,8 +23,10 @@ using namespace logid::actions; -AxisGesture::AxisGesture(Device *device, config::AxisGesture& config) : - Gesture (device), _multiplier (1), _config (config) +AxisGesture::AxisGesture(Device *device, config::AxisGesture& config, + const std::shared_ptr& parent, + const std::string& direction) : + Gesture (device, parent, direction), _multiplier (1), _config (config) { if(std::holds_alternative(_config.axis)) { _input_axis = std::get(_config.axis); diff --git a/src/logid/actions/gesture/AxisGesture.h b/src/logid/actions/gesture/AxisGesture.h index eaf42e6..491c201 100644 --- a/src/logid/actions/gesture/AxisGesture.h +++ b/src/logid/actions/gesture/AxisGesture.h @@ -26,7 +26,9 @@ namespace logid { class AxisGesture : public Gesture { public: - AxisGesture(Device* device, config::AxisGesture& config); + AxisGesture(Device* device, config::AxisGesture& config, + const std::shared_ptr& parent, + const std::string& direction); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/Gesture.cpp b/src/logid/actions/gesture/Gesture.cpp index 55982ef..9bc9dc2 100644 --- a/src/logid/actions/gesture/Gesture.cpp +++ b/src/logid/actions/gesture/Gesture.cpp @@ -27,7 +27,10 @@ using namespace logid; using namespace logid::actions; -Gesture::Gesture(Device *device) : _device (device) +Gesture::Gesture(Device *device, + const std::shared_ptr& parent, + const std::string& direction) : _device (device), + _node (parent->make_child(direction)) { } @@ -43,17 +46,22 @@ template struct gesture_type : gesture_type { }; template -std::shared_ptr _makeGesture(Device* device, - T gesture) { - return std::make_shared::type>(device, gesture); +std::shared_ptr _makeGesture( + Device* device, T gesture, + const std::shared_ptr& parent, + const std::string& direction) { + return std::make_shared::type>( + device, gesture, parent, std::move(direction)); } -std::shared_ptr Gesture::makeGesture(Device *device, - config::Gesture& gesture) +std::shared_ptr Gesture::makeGesture( + Device *device, config::Gesture& gesture, + const std::shared_ptr& parent, + const std::string& direction) { std::shared_ptr ret; - std::visit([&device, &ret](auto&& x) { - ret = _makeGesture(device, x); + std::visit([&device, &ret, &parent, &direction](auto&& x) { + ret = _makeGesture(device, x, parent, direction); }, gesture); return ret; } diff --git a/src/logid/actions/gesture/Gesture.h b/src/logid/actions/gesture/Gesture.h index 58c39d5..6fc8816 100644 --- a/src/logid/actions/gesture/Gesture.h +++ b/src/logid/actions/gesture/Gesture.h @@ -52,11 +52,16 @@ namespace actions virtual ~Gesture() = default; static std::shared_ptr makeGesture(Device* device, - config::Gesture& gesture); + config::Gesture& gesture, + const std::shared_ptr& parent, + const std::string& direction); protected: - explicit Gesture(Device* device); + explicit Gesture(Device* device, + const std::shared_ptr& parent, + const std::string& direction); Device* _device; + std::shared_ptr _node; }; }} diff --git a/src/logid/actions/gesture/IntervalGesture.cpp b/src/logid/actions/gesture/IntervalGesture.cpp index 6f9988a..0acca9c 100644 --- a/src/logid/actions/gesture/IntervalGesture.cpp +++ b/src/logid/actions/gesture/IntervalGesture.cpp @@ -21,12 +21,14 @@ using namespace logid::actions; -IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config) : - Gesture (device), _config (config) +IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config, + const std::shared_ptr& parent, + const std::string& direction) : + Gesture (device, parent, direction), _config (config) { if(config.action) { try { - _action = Action::makeAction(device, config.action.value()); + _action = Action::makeAction(device, config.action.value(), _node); } catch(InvalidAction& e) { logPrintf(WARN, "Mapping gesture to invalid action"); } diff --git a/src/logid/actions/gesture/IntervalGesture.h b/src/logid/actions/gesture/IntervalGesture.h index cb68cd2..5ee4ecd 100644 --- a/src/logid/actions/gesture/IntervalGesture.h +++ b/src/logid/actions/gesture/IntervalGesture.h @@ -26,7 +26,9 @@ namespace actions class IntervalGesture : public Gesture { public: - IntervalGesture(Device* device, config::IntervalGesture& config); + IntervalGesture(Device* device, config::IntervalGesture& config, + const std::shared_ptr& parent, + const std::string& direction); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/NullGesture.cpp b/src/logid/actions/gesture/NullGesture.cpp index 515746f..2b2c6ea 100644 --- a/src/logid/actions/gesture/NullGesture.cpp +++ b/src/logid/actions/gesture/NullGesture.cpp @@ -21,8 +21,10 @@ using namespace logid::actions; NullGesture::NullGesture(Device *device, - config::NoGesture& config) : - Gesture (device), _config (config) + config::NoGesture& config, + const std::shared_ptr& parent, + const std::string& direction) : + Gesture (device, parent, direction), _config (config) { } diff --git a/src/logid/actions/gesture/NullGesture.h b/src/logid/actions/gesture/NullGesture.h index 89b0158..9f08bab 100644 --- a/src/logid/actions/gesture/NullGesture.h +++ b/src/logid/actions/gesture/NullGesture.h @@ -27,7 +27,9 @@ namespace actions { public: NullGesture(Device* device, - config::NoGesture& config); + config::NoGesture& config, + const std::shared_ptr& parent, + const std::string& direction); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/ReleaseGesture.cpp b/src/logid/actions/gesture/ReleaseGesture.cpp index e09989b..ca663c1 100644 --- a/src/logid/actions/gesture/ReleaseGesture.cpp +++ b/src/logid/actions/gesture/ReleaseGesture.cpp @@ -20,11 +20,13 @@ using namespace logid::actions; -ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config) : - Gesture (device), _config (config) +ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config, + const std::shared_ptr& parent, + const std::string& direction) : + Gesture (device, parent, direction), _config (config) { if(_config.action.has_value()) - _action = Action::makeAction(device, _config.action.value()); + _action = Action::makeAction(device, _config.action.value(), _node); } void ReleaseGesture::press(bool init_threshold) diff --git a/src/logid/actions/gesture/ReleaseGesture.h b/src/logid/actions/gesture/ReleaseGesture.h index 24166a7..f02c566 100644 --- a/src/logid/actions/gesture/ReleaseGesture.h +++ b/src/logid/actions/gesture/ReleaseGesture.h @@ -26,7 +26,9 @@ namespace actions class ReleaseGesture : public Gesture { public: - ReleaseGesture(Device* device, config::ReleaseGesture& config); + ReleaseGesture(Device* device, config::ReleaseGesture& config, + const std::shared_ptr& parent, + const std::string& direction); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/ThresholdGesture.cpp b/src/logid/actions/gesture/ThresholdGesture.cpp index ccae5a9..3e79dd8 100644 --- a/src/logid/actions/gesture/ThresholdGesture.cpp +++ b/src/logid/actions/gesture/ThresholdGesture.cpp @@ -21,12 +21,14 @@ using namespace logid::actions; ThresholdGesture::ThresholdGesture(Device *device, - config::ThresholdGesture& config) : - Gesture (device), _config (config) + config::ThresholdGesture& config, + const std::shared_ptr& parent, + const std::string& direction) : + Gesture (device, parent, direction), _config (config) { if(config.action) { try { - _action = Action::makeAction(device, config.action.value()); + _action = Action::makeAction(device, config.action.value(), _node); } catch(InvalidAction& e) { logPrintf(WARN, "Mapping gesture to invalid action"); } diff --git a/src/logid/actions/gesture/ThresholdGesture.h b/src/logid/actions/gesture/ThresholdGesture.h index 501117d..802cbb5 100644 --- a/src/logid/actions/gesture/ThresholdGesture.h +++ b/src/logid/actions/gesture/ThresholdGesture.h @@ -26,7 +26,9 @@ namespace actions class ThresholdGesture : public Gesture { public: - ThresholdGesture(Device* device, config::ThresholdGesture& config); + ThresholdGesture(Device* device, config::ThresholdGesture& config, + const std::shared_ptr& parent, + const std::string& direction); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index b52b950..15f2cae 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -26,7 +26,8 @@ using namespace logid::backend; #define MOVE_EVENTHANDLER_NAME "HIRES_SCROLL" HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), - _config (dev->activeProfile().hiresscroll), _mode (0), _mask (0) + _config (dev->activeProfile().hiresscroll), _mode (0), _mask (0), + _node (dev->ipcNode()->make_child("hires")) { if(_config.has_value()) { if(std::holds_alternative(_config.value())) { @@ -54,8 +55,8 @@ HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), _mode |= hidpp20::HiresScroll::Mode::Target; } - _makeAction(_up_action, conf.up); - _makeAction(_down_action, conf.down); + _makeAction(_up_action, conf.up, "up"); + _makeAction(_down_action, conf.down, "down"); } try { @@ -110,10 +111,12 @@ void HiresScroll::setMode(uint8_t mode) } void HiresScroll::_makeAction(std::shared_ptr &gesture, - std::optional &config) + std::optional &config, + const std::string& direction) { if(config.has_value()) { - gesture = actions::Gesture::makeGesture(_device, config.value()); + gesture = actions::Gesture::makeGesture(_device, config.value(), + _node, direction); try { auto axis = std::dynamic_pointer_cast( gesture); diff --git a/src/logid/features/HiresScroll.h b/src/logid/features/HiresScroll.h index 1f74825..0ebdc4d 100644 --- a/src/logid/features/HiresScroll.h +++ b/src/logid/features/HiresScroll.h @@ -37,7 +37,8 @@ namespace features void setMode(uint8_t mode); private: void _makeAction(std::shared_ptr& gesture, - std::optional& config); + std::optional& config, + const std::string& direction); void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event); std::shared_ptr _hires_scroll; @@ -51,6 +52,8 @@ namespace features std::shared_ptr _up_action; std::shared_ptr _down_action; + + std::shared_ptr _node; }; }} diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index 647e127..b485ac8 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -168,19 +168,20 @@ Button::Button(Info info, int index, std::shared_ptr root, config::Button &config) : _node (root->make_child(std::to_string(index))), - _interface (_node->make_interface(this, info)), _device (device), _conf_func (std::move(conf_func)), _config (config), _info (info) { if(_config.action.has_value()) { try { - _action = Action::makeAction(_device, _config.action.value()); + _action = Action::makeAction(_device, _config.action.value(), _node); } catch(std::exception& e) { logPrintf(WARN, "Error creating button action: %s", e.what()); } } + + _interface = _node->make_interface(this, _info); } void Button::press() const { diff --git a/src/logid/features/ThumbWheel.cpp b/src/logid/features/ThumbWheel.cpp index 458de92..f2d81d0 100644 --- a/src/logid/features/ThumbWheel.cpp +++ b/src/logid/features/ThumbWheel.cpp @@ -30,11 +30,12 @@ using namespace logid; #define SCROLL_EVENTHANDLER_NAME "THUMB_WHEEL" std::shared_ptr _genAction( - Device* dev, std::optional& conf) + Device* dev, std::optional& conf, + const std::shared_ptr& parent) { if(conf.has_value()) { try { - return actions::Action::makeAction(dev, conf.value()); + return actions::Action::makeAction(dev, conf.value(), parent); } catch(actions::InvalidAction& e) { logPrintf(WARN, "Mapping thumb wheel to invalid action"); } @@ -44,11 +45,12 @@ std::shared_ptr _genAction( } std::shared_ptr _genGesture( - Device* dev, std::optional& conf) + Device* dev, std::optional& conf, + const std::shared_ptr& parent, const std::string& direction) { if(conf.has_value()) { try { - return actions::Gesture::makeGesture(dev, conf.value()); + return actions::Gesture::makeGesture(dev, conf.value(), parent, direction); } catch (actions::InvalidAction &e) { logPrintf(WARN, "Mapping thumb wheel to invalid gesture"); } @@ -58,15 +60,19 @@ std::shared_ptr _genGesture( } ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), + _node (dev->ipcNode()->make_child("thumbwheel")), + _proxy_node (_node->make_child("proxy")), + _tap_node (_node->make_child("tap")), + _touch_node (_node->make_child("touch")), _config (dev->activeProfile().thumbwheel) { if(_config.has_value()) { auto& conf = _config.value(); - _left_action = _genGesture(dev, conf.left); - _right_action = _genGesture(dev, conf.right); - _touch_action = _genAction(dev, conf.touch); - _tap_action = _genAction(dev, conf.tap); - _proxy_action = _genAction(dev, conf.proxy); + _left_action = _genGesture(dev, conf.left, _node, "left"); + _right_action = _genGesture(dev, conf.right, _node, "right"); + _touch_action = _genAction(dev, conf.touch, _touch_node); + _tap_action = _genAction(dev, conf.tap, _tap_node); + _proxy_action = _genAction(dev, conf.proxy, _proxy_node); } try { diff --git a/src/logid/features/ThumbWheel.h b/src/logid/features/ThumbWheel.h index f76fd33..a71f8ef 100644 --- a/src/logid/features/ThumbWheel.h +++ b/src/logid/features/ThumbWheel.h @@ -40,11 +40,16 @@ namespace features std::shared_ptr _thumb_wheel; backend::hidpp20::ThumbWheel::ThumbwheelInfo _wheel_info; + std::shared_ptr _node; + std::shared_ptr _left_action; std::shared_ptr _right_action; std::shared_ptr _proxy_action; + std::shared_ptr _proxy_node; std::shared_ptr _tap_action; + std::shared_ptr _tap_node; std::shared_ptr _touch_action; + std::shared_ptr _touch_node; int8_t _last_direction = 0; bool _last_proxy = false; From d9c64892be868574e9af2a67ac0d89168f75aeeb Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 29 Jan 2022 00:46:26 -0500 Subject: [PATCH 21/59] Fix device monitor deadlock --- src/logid/backend/raw/DeviceMonitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logid/backend/raw/DeviceMonitor.cpp b/src/logid/backend/raw/DeviceMonitor.cpp index d8de3c6..145d37a 100644 --- a/src/logid/backend/raw/DeviceMonitor.cpp +++ b/src/logid/backend/raw/DeviceMonitor.cpp @@ -99,9 +99,9 @@ void DeviceMonitor::ready() std::string devnode = udev_device_get_devnode(device); if (action == "add") - _addHandler(devnode); + spawn_task([this, devnode]() { _addHandler(devnode); }); else if (action == "remove") - _removeHandler(devnode); + spawn_task([this, devnode]() { _removeHandler(devnode); }); udev_device_unref(device); }, From c69ae325d39cb2e1b937e6fd6674df0c1efbe6a7 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 29 Jan 2022 00:48:16 -0500 Subject: [PATCH 22/59] Remove old multi-threading code --- src/logid/CMakeLists.txt | 1 - src/logid/backend/raw/RawDevice.h | 1 - src/logid/util/mutex_queue.h | 55 ----------------------- src/logid/util/thread.cpp | 72 ------------------------------- src/logid/util/thread.h | 57 ------------------------ 5 files changed, 186 deletions(-) delete mode 100644 src/logid/util/mutex_queue.h delete mode 100644 src/logid/util/thread.cpp delete mode 100644 src/logid/util/thread.h diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index aca7539..89b0957 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -65,7 +65,6 @@ add_executable(logid backend/hidpp20/features/WirelessDeviceStatus.cpp backend/hidpp20/features/ThumbWheel.cpp backend/dj/Report.cpp - util/thread.cpp util/task.cpp util/ExceptionHandler.cpp) diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 4bd68f6..fabfd30 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -29,7 +29,6 @@ #include #include "defs.h" -#include "../../util/mutex_queue.h" namespace logid::backend::raw { diff --git a/src/logid/util/mutex_queue.h b/src/logid/util/mutex_queue.h deleted file mode 100644 index 95e6f8c..0000000 --- a/src/logid/util/mutex_queue.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 . - * - */ - -#ifndef MUTEX_QUEUE_H -#define MUTEX_QUEUE_H - -#include -#include - -template -class mutex_queue -{ -public: - mutex_queue() = default; - bool empty() - { - std::lock_guard lock(_mutex); - return _queue.empty(); - } - data& front() - { - std::lock_guard lock(_mutex); - return _queue.front(); - } - void push(const data& _data) - { - std::lock_guard lock(_mutex); - _queue.push(_data); - } - void pop() - { - std::lock_guard lock(_mutex); - _queue.pop(); - } -private: - std::queue _queue; - std::mutex _mutex; -}; - -#endif //MUTEX_QUEUE_H \ No newline at end of file diff --git a/src/logid/util/thread.cpp b/src/logid/util/thread.cpp deleted file mode 100644 index be496dc..0000000 --- a/src/logid/util/thread.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 "thread.h" - -using namespace logid; - -thread::thread(const std::function& function, - const std::function& exception_handler) - : _function (std::make_shared>(function)), - _exception_handler (std::make_shared> (exception_handler)) -{ -} - -thread::~thread() -{ - if(_thread) - if(_thread->joinable()) - _thread->detach(); -} - -void thread::spawn(const std::function& function, - const std::function& exception_handler) -{ - std::thread([function, exception_handler](){ - thread t(function, exception_handler); - t.runSync(); - }).detach(); -} - -void thread::run() -{ - _thread = std::make_shared( - [f=this->_function,eh=this->_exception_handler]() { - try { - (*f)(); - } catch (std::exception& e) { - (*eh)(e); - } - }); -} - -void thread::wait() -{ - if(_thread) - if(_thread->joinable()) - _thread->join(); -} - -void thread::runSync() -{ - try { - (*_function)(); - } catch(std::exception& e) { - (*_exception_handler)(e); - } -} \ No newline at end of file diff --git a/src/logid/util/thread.h b/src/logid/util/thread.h deleted file mode 100644 index 311a1f6..0000000 --- a/src/logid/util/thread.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2019-2020 PixlOne - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY 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 . - * - */ -#ifndef LOGID_THREAD_H -#define LOGID_THREAD_H - -#include -#include -#include -#include "ExceptionHandler.h" - -namespace logid -{ - class thread - { - public: - explicit thread(const std::function& function, - const std::function& - exception_handler={[](std::exception& e) - {ExceptionHandler::Default(e);}}); - - ~thread(); - - /* This function spawns a new thread and forgets about it, - * safe equivalent to std::thread{...}.detach() - */ - static void spawn(const std::function& function, - const std::function& - exception_handler={[](std::exception& e) - {ExceptionHandler::Default(e);}}); - - void run(); - void wait(); - void runSync(); - private: - std::shared_ptr> _function; - std::shared_ptr> - _exception_handler; - std::shared_ptr _thread = nullptr; - }; -} - -#endif //LOGID_THREAD_H From 605ccdc07d96d4a88cdad5a5a19df306e97b0cea Mon Sep 17 00:00:00 2001 From: pixl Date: Mon, 14 Feb 2022 01:03:56 -0500 Subject: [PATCH 23/59] Add several IPC interfaces --- src/ipcgull | 2 +- src/logid/Configuration.cpp | 7 ++ src/logid/Configuration.h | 8 ++ src/logid/Device.cpp | 13 +- src/logid/Device.h | 6 +- src/logid/DeviceManager.cpp | 1 + src/logid/DeviceManager.h | 1 + src/logid/InputDevice.cpp | 25 ++++ src/logid/InputDevice.h | 4 + src/logid/actions/Action.cpp | 17 ++- src/logid/actions/Action.h | 7 +- src/logid/actions/ChangeDPI.cpp | 16 +-- src/logid/actions/ChangeDPI.h | 10 -- src/logid/actions/ChangeHostAction.cpp | 26 ++-- src/logid/actions/ChangeHostAction.h | 10 -- src/logid/actions/CycleDPI.cpp | 37 +++--- src/logid/actions/CycleDPI.h | 10 -- src/logid/actions/GestureAction.cpp | 56 +++++++-- src/logid/actions/GestureAction.h | 15 +-- src/logid/actions/KeypressAction.cpp | 98 ++++++++++----- src/logid/actions/KeypressAction.h | 14 +-- src/logid/actions/NullAction.cpp | 16 +-- src/logid/actions/NullAction.h | 6 - src/logid/actions/ToggleHiresScroll.cpp | 12 +- src/logid/actions/ToggleHiresScroll.h | 8 -- src/logid/actions/ToggleSmartShift.cpp | 12 +- src/logid/actions/ToggleSmartShift.h | 8 -- src/logid/actions/gesture/AxisGesture.cpp | 40 ++++--- src/logid/actions/gesture/AxisGesture.h | 7 +- src/logid/actions/gesture/Gesture.cpp | 49 ++++++-- src/logid/actions/gesture/Gesture.h | 18 +-- src/logid/actions/gesture/IntervalGesture.cpp | 16 ++- src/logid/actions/gesture/IntervalGesture.h | 17 ++- src/logid/actions/gesture/NullGesture.cpp | 7 +- src/logid/actions/gesture/NullGesture.h | 5 +- src/logid/actions/gesture/ReleaseGesture.cpp | 7 +- src/logid/actions/gesture/ReleaseGesture.h | 5 +- .../actions/gesture/ThresholdGesture.cpp | 11 +- src/logid/actions/gesture/ThresholdGesture.h | 5 +- src/logid/backend/raw/IOMonitor.cpp | 6 +- src/logid/config/group.h | 4 +- src/logid/config/map.h | 20 +++- src/logid/config/schema.h | 29 +++-- src/logid/config/types.h | 30 +++-- src/logid/features/HiresScroll.cpp | 2 +- src/logid/features/RemapButton.cpp | 113 +++++++++++++++--- src/logid/features/RemapButton.h | 38 +++++- src/logid/features/SmartShift.cpp | 94 ++++++++++++++- src/logid/features/SmartShift.h | 27 ++++- src/logid/features/ThumbWheel.cpp | 11 +- src/logid/features/ThumbWheel.h | 1 + 51 files changed, 672 insertions(+), 335 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index e86f198..200df3c 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit e86f1987bc40c840d3cef758619783e5bdec1c41 +Subproject commit 200df3c202739de5249b2fd7c43900fcb25c01cb diff --git a/src/logid/Configuration.cpp b/src/logid/Configuration.cpp index b87df91..63e8817 100644 --- a/src/logid/Configuration.cpp +++ b/src/logid/Configuration.cpp @@ -62,4 +62,11 @@ void Configuration::save() _config_file.c_str(), e.what()); throw; } +} + +Configuration::IPC::IPC(Configuration *config) : + ipcgull::interface("pizza.pixl.LogiOps.Config", { + {"Save", {config, &Configuration::save}} + }, {}, {}) +{ } \ No newline at end of file diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index 213d654..41cfbae 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "config/schema.h" @@ -44,6 +45,13 @@ namespace logid // Reloading is not safe, references will be invalidated //void reload(); void save(); + + class IPC : public ipcgull::interface + { + public: + IPC(Configuration* config); + }; + private: std::string _config_file; libconfig::Config _config; diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 07e005d..fd8ad71 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -67,7 +67,7 @@ std::shared_ptr Device::make( std::move(manager)); ret->_self = ret; ret->_ipc_node->manage(ret); - ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); return ret; } @@ -81,7 +81,7 @@ std::shared_ptr Device::make( std::move(manager)); ret->_self = ret; ret->_ipc_node->manage(ret); - ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); return ret; } @@ -92,7 +92,7 @@ std::shared_ptr Device::make( auto ret = std::make_shared<_Device>(receiver, index, std::move(manager)); ret->_self = ret; ret->_ipc_node->manage(ret); - ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); + ret->_ipc_interface = ret->_ipc_node->make_interface(ret.get()); return ret; } @@ -265,7 +265,7 @@ void Device::_makeResetMechanism() } } -Device::DeviceIPC::DeviceIPC(Device* device) : +Device::IPC::IPC(Device* device) : ipcgull::interface( "pizza.pixl.LogiOps.Device", {}, @@ -274,7 +274,8 @@ Device::DeviceIPC::DeviceIPC(Device* device) : ipcgull::property_readable, device->name())}, {"ProductID", ipcgull::property( ipcgull::property_readable, device->pid())}, - {"Active", device->_awake} + {"Active", device->_awake}, + {"DefaultProfile", device->_config.default_profile} }, { {"StatusChanged", ipcgull::signal::make_signal({"active"})} @@ -282,7 +283,7 @@ Device::DeviceIPC::DeviceIPC(Device* device) : { } -void Device::DeviceIPC::notifyStatus() const +void Device::IPC::notifyStatus() const { emit_signal("StatusChanged", (bool)(_device._awake)); } diff --git a/src/logid/Device.h b/src/logid/Device.h index 503ab44..2af5397 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -142,17 +142,17 @@ namespace logid const DeviceNickname _nickname; std::shared_ptr _ipc_node; - class DeviceIPC : public ipcgull::interface { + class IPC : public ipcgull::interface { private: Device& _device; public: - DeviceIPC(Device* device); + IPC(Device* device); void notifyStatus() const; }; ipcgull::property _awake; std::mutex _state_lock; - std::shared_ptr _ipc_interface; + std::shared_ptr _ipc_interface; std::weak_ptr _self; }; diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index a6d0229..bb669f5 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -52,6 +52,7 @@ DeviceManager::DeviceManager(std::shared_ptr config, { _ipc_devices = _root_node->make_interface(this); _ipc_receivers = _root_node->make_interface(this); + _ipc_config = _root_node->make_interface(_config.get()); _device_node->add_server(_server); _receiver_node->add_server(_server); _root_node->add_server(_server); diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index aecc991..0c9f680 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -88,6 +88,7 @@ namespace logid std::shared_ptr _device_node; std::shared_ptr _receiver_node; + std::shared_ptr _ipc_config; std::shared_ptr _ipc_devices; std::shared_ptr _ipc_receivers; diff --git a/src/logid/InputDevice.cpp b/src/logid/InputDevice.cpp index 131514c..20646e2 100644 --- a/src/logid/InputDevice.cpp +++ b/src/logid/InputDevice.cpp @@ -33,6 +33,11 @@ InputDevice::InvalidEventCode::InvalidEventCode(const std::string& name) : { } +InputDevice::InvalidEventCode::InvalidEventCode(uint code) : + _what ("Invalid event code " + std::to_string(code)) +{ +} + const char* InputDevice::InvalidEventCode::what() const noexcept { return _what.c_str(); @@ -115,11 +120,21 @@ void InputDevice::releaseKey(uint code) _sendEvent(EV_KEY, code, 0); } +std::string InputDevice::toKeyName(uint code) +{ + return _toEventName(EV_KEY, code); +} + uint InputDevice::toKeyCode(const std::string& name) { return _toEventCode(EV_KEY, name); } +std::string InputDevice::toAxisName(uint code) +{ + return _toEventName(EV_REL, code); +} + uint InputDevice::toAxisCode(const std::string& name) { return _toEventCode(EV_REL, name); @@ -141,6 +156,16 @@ int InputDevice::getLowResAxis(const uint axis_code) return -1; } +std::string InputDevice::_toEventName(uint type, uint code) +{ + const char* ret = libevdev_event_code_get_name(type, code); + + if(!ret) + throw InvalidEventCode(code); + + return {ret}; +} + uint InputDevice::_toEventCode(uint type, const std::string& name) { int code = libevdev_event_code_from_name(type, name.c_str()); diff --git a/src/logid/InputDevice.h b/src/logid/InputDevice.h index 17e5045..9994787 100644 --- a/src/logid/InputDevice.h +++ b/src/logid/InputDevice.h @@ -37,6 +37,7 @@ namespace logid { public: explicit InvalidEventCode(const std::string& name); + explicit InvalidEventCode(uint code); const char* what() const noexcept override; private: const std::string _what; @@ -50,7 +51,9 @@ namespace logid void pressKey(uint code); void releaseKey(uint code); + static std::string toKeyName(uint code); static uint toKeyCode(const std::string& name); + static std::string toAxisName(uint code); static uint toAxisCode(const std::string& name); static int getLowResAxis(uint axis_code); @@ -58,6 +61,7 @@ namespace logid void _sendEvent(uint type, uint code, int value); void _enableEvent(uint type, uint name); + static std::string _toEventName(uint type, uint code); static uint _toEventCode(uint type, const std::string& name); bool registered_keys[KEY_CNT]; diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index 722b14c..26601d7 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -43,9 +43,11 @@ struct action_type : action_type { }; template std::shared_ptr _makeAction( - Device* device, T action, - const std::shared_ptr& parent) { - return std::make_shared::type>(device, action, parent); + Device* device, T& action, + const std::shared_ptr& parent) +{ + return parent->make_interface::type>( + device, std::forward(action), parent); } template @@ -75,7 +77,8 @@ std::shared_ptr _makeAction( } else if(name == ToggleSmartShift::interface_name) { config = config::ToggleHiresScroll(); return Action::makeAction(device, config.value(), parent); - } else if(name == "pizza.pixl.LogiOps.Action.Default") { + } else if(name == "Default") { + config.reset(); return nullptr; } @@ -127,3 +130,9 @@ std::shared_ptr Action::makeAction( }, action); return ret; } + +Action::Action(Device* device, const std::string& name, tables t) : + ipcgull::interface("pizza.pixl.LogiOps.Action." + name, std::move(t)), + _device (device), _pressed (false) +{ +} diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index d670906..240c4d8 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -45,7 +45,7 @@ namespace actions { std::string _action; }; - class Action + class Action : public ipcgull::interface { public: static std::shared_ptr makeAction( @@ -84,9 +84,8 @@ namespace actions { virtual ~Action() = default; protected: - explicit Action(Device* device) : _device (device), _pressed (false) - { - } + Action(Device* device, const std::string& name, tables t={}); + Device* _device; std::atomic _pressed; }; diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index 78f05d1..782f1de 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -24,13 +24,12 @@ using namespace logid::actions; -const char* ChangeDPI::interface_name = - "pizza.pixl.LogiOps.Action.ChangeDPI"; +const char* ChangeDPI::interface_name = "ChangeDPI"; ChangeDPI::ChangeDPI( Device *device, config::ChangeDPI& config, const std::shared_ptr& parent) : - Action(device), _config (config) + Action(device, interface_name), _config (config) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -38,19 +37,17 @@ ChangeDPI::ChangeDPI( "ChangeDPI action.", _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex()); - - _ipc = parent->make_interface(this); } void ChangeDPI::press() { _pressed = true; - if(_dpi) { + if(_dpi && _config.inc.has_value()) { spawn_task( [this]{ try { uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0)); - _dpi->setDPI(last_dpi + _config.inc, + _dpi->setDPI(last_dpi + _config.inc.value(), _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) @@ -75,8 +72,3 @@ uint8_t ChangeDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeDPI::IPC::IPC(ChangeDPI *action) : - ipcgull::interface(interface_name, {}, {}, {}), _action (*action) -{ -} diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h index d37dff9..4f83065 100644 --- a/src/logid/actions/ChangeDPI.h +++ b/src/logid/actions/ChangeDPI.h @@ -40,16 +40,6 @@ namespace logid { protected: config::ChangeDPI& _config; std::shared_ptr _dpi; - private: - class IPC : public ipcgull::interface - { - public: - IPC(ChangeDPI* action); - private: - ChangeDPI& _action; - }; - - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index c0fcc5f..9b34830 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -24,16 +24,15 @@ using namespace logid::actions; using namespace logid::backend; -const char* ChangeHostAction::interface_name = - "pizza.pixl.LogiOps.Action.ChangeHost"; +const char* ChangeHostAction::interface_name = "ChangeHost"; ChangeHostAction::ChangeHostAction( Device *device, config::ChangeHost& config, - const std::shared_ptr& parent) - : Action(device), _config (config) + [[maybe_unused]] const std::shared_ptr& parent) + : Action(device, interface_name), _config (config) { - if(std::holds_alternative(_config.host)) { - auto& host = std::get(_config.host); + if(std::holds_alternative(_config.host.value())) { + auto& host = std::get(_config.host.value()); std::transform(host.begin(), host.end(), host.begin(), ::tolower); } @@ -44,8 +43,6 @@ ChangeHostAction::ChangeHostAction( "ChangeHostAction will not work.", device->hidpp20() .devicePath().c_str(), device->hidpp20().deviceIndex()); } - - _ipc = parent->make_interface(this); } void ChangeHostAction::press() @@ -55,13 +52,13 @@ void ChangeHostAction::press() void ChangeHostAction::release() { - if(_change_host) { + if(_change_host && _config.host.has_value()) { spawn_task( [this] { auto host_info = _change_host->getHostInfo(); int next_host; - if(std::holds_alternative(_config.host)) { - const auto& host = std::get(_config.host); + if(std::holds_alternative(_config.host.value())) { + const auto& host = std::get(_config.host.value()); if(host == "next") next_host = host_info.currentHost + 1; else if(host == "prev" || host == "previous") @@ -69,7 +66,7 @@ void ChangeHostAction::release() else next_host = host_info.currentHost; } else { - next_host = std::get(_config.host)-1; + next_host = std::get(_config.host.value())-1; } next_host %= host_info.hostCount; if(next_host != host_info.currentHost) @@ -82,8 +79,3 @@ uint8_t ChangeHostAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeHostAction::IPC::IPC(ChangeHostAction *action) : - ipcgull::interface(interface_name, {}, {}, {}), _action (*action) -{ -} diff --git a/src/logid/actions/ChangeHostAction.h b/src/logid/actions/ChangeHostAction.h index e5ac8e8..1f26f04 100644 --- a/src/logid/actions/ChangeHostAction.h +++ b/src/logid/actions/ChangeHostAction.h @@ -41,16 +41,6 @@ namespace actions protected: std::shared_ptr _change_host; config::ChangeHost& _config; - private: - class IPC : public ipcgull::interface - { - public: - IPC(ChangeHostAction* action); - private: - ChangeHostAction& _action; - }; - - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index a169447..010a8e6 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -25,12 +25,12 @@ using namespace logid::actions; using namespace libconfig; -const char* CycleDPI::interface_name = - "pizza.pixl.LogiOps.Action.CycleDPI"; +const char* CycleDPI::interface_name = "CycleDPI"; CycleDPI::CycleDPI(Device* device, config::CycleDPI& config, const std::shared_ptr& parent) : - Action (device), _config (config), _current_dpi (_config.dpis.begin()) + Action (device, interface_name), + _config (config) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -39,27 +39,29 @@ CycleDPI::CycleDPI(Device* device, config::CycleDPI& config, _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex()); - _ipc = parent->make_interface(this); + if(_config.dpis.has_value()) { + _current_dpi = _config.dpis.value().begin(); + } } void CycleDPI::press() { _pressed = true; - if(_dpi && !_config.dpis.empty()) { - spawn_task( - [this](){ - std::lock_guard lock(_dpi_lock); - ++_current_dpi; - if(_current_dpi == _config.dpis.end()) - _current_dpi = _config.dpis.begin(); + std::lock_guard lock(_dpi_lock); + if(_dpi && _config.dpis.has_value() && _config.dpis.value().empty()) { + ++_current_dpi; + if(_current_dpi == _config.dpis.value().end()) + _current_dpi = _config.dpis.value().begin(); + + spawn_task([this, dpi=*_current_dpi]{ try { - _dpi->setDPI(*_current_dpi, _config.sensor.value_or(0)); + _dpi->setDPI(dpi, _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) logPrintf(WARN, "%s:%d: Could not set DPI to %d for " - "sensor %d", _device->hidpp20().devicePath().c_str(), - _device->hidpp20().deviceIndex(), *_current_dpi, - _config.sensor.value_or(0)); + "sensor %d", _device->hidpp20().devicePath().c_str(), + _device->hidpp20().deviceIndex(), dpi, + _config.sensor.value_or(0)); else throw e; } @@ -76,8 +78,3 @@ uint8_t CycleDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -CycleDPI::IPC::IPC(CycleDPI *action) : - ipcgull::interface(interface_name, {}, {}, {}), _action (*action) -{ -} diff --git a/src/logid/actions/CycleDPI.h b/src/logid/actions/CycleDPI.h index d21c3bf..8f2cbfa 100644 --- a/src/logid/actions/CycleDPI.h +++ b/src/logid/actions/CycleDPI.h @@ -42,16 +42,6 @@ namespace actions { config::CycleDPI& _config; std::shared_ptr _dpi; std::list::const_iterator _current_dpi; - private: - class IPC : public ipcgull::interface - { - public: - IPC(CycleDPI* action); - private: - CycleDPI& _action; - }; - - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index d654d22..fd9afd4 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -24,8 +24,7 @@ using namespace logid::actions; using namespace logid; using namespace logid::backend; -const char* GestureAction::interface_name = - "pizza.pixl.LogiOps.Action.Gesture"; +const char* GestureAction::interface_name = "Gesture"; GestureAction::Direction GestureAction::toDirection(std::string direction) { @@ -78,7 +77,14 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y) GestureAction::GestureAction(Device* dev, config::GestureAction& config, const std::shared_ptr& parent) : - Action (dev), _config (config) + Action (dev, interface_name, + { + { + {"SetGesture", {this, &GestureAction::setGesture, + {"direction", "type"}}} + }, {}, {} + }), + _node (parent->make_child("gestures")), _config (config) { if(_config.gestures.has_value()) { auto& gestures = _config.gestures.value(); @@ -87,19 +93,20 @@ GestureAction::GestureAction(Device* dev, config::GestureAction& config, auto direction = toDirection(x.first); _gestures.emplace(direction, Gesture::makeGesture( - dev, x.second, parent, - fromDirection(direction))); + dev, x.second, + _node->make_child( + fromDirection(direction)))); } catch(std::invalid_argument& e) { logPrintf(WARN, "%s is not a direction", x.first.c_str()); } } } - - _ipc = parent->make_interface(this); } void GestureAction::press() { + std::lock_guard lock(_config_lock); + _pressed = true; _x = 0, _y = 0; for(auto& gesture : _gestures) @@ -108,6 +115,8 @@ void GestureAction::press() void GestureAction::release() { + std::lock_guard lock(_config_lock); + _pressed = false; bool threshold_met = false; @@ -147,6 +156,8 @@ void GestureAction::release() void GestureAction::move(int16_t x, int16_t y) { + std::lock_guard lock(_config_lock); + auto new_x = _x + x, new_y = _y + y; if(abs(x) > 0) { @@ -218,7 +229,34 @@ uint8_t GestureAction::reprogFlags() const hidpp20::ReprogControls::RawXYDiverted); } -GestureAction::IPC::IPC(GestureAction *action) : - ipcgull::interface(interface_name, {}, {}, {}), _action (*action) +void GestureAction::setGesture(const std::string &direction, + const std::string &type) { + std::lock_guard lock(_config_lock); + + Direction d = toDirection(direction); + + auto it = _gestures.find(d); + + if(it != _gestures.end()) { + if(pressed()) { + auto current = toDirection(_x, _y); + if(it->second) + it->second->release(current == d); + } + } + + auto dir_name = fromDirection(d); + + _gestures[d].reset(); + try { + _gestures[d] = Gesture::makeGesture( + _device, type, _config.gestures.value()[dir_name], + _node->make_child(dir_name)); + } catch (InvalidGesture& e) { + _gestures[d] = Gesture::makeGesture( + _device, _config.gestures.value()[dir_name], + _node->make_child(dir_name)); + throw std::invalid_argument("Invalid gesture type"); + } } diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index a66c732..2dfc603 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -51,21 +51,14 @@ namespace actions { virtual uint8_t reprogFlags() const; + void setGesture(const std::string& direction, + const std::string& type); protected: int16_t _x, _y; + std::shared_ptr _node; std::map> _gestures; config::GestureAction& _config; - - private: - class IPC : public ipcgull::interface - { - public: - explicit IPC(GestureAction* action); - private: - GestureAction& _action; - }; - - std::shared_ptr _ipc; + mutable std::mutex _config_lock; }; }} diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index ff6afac..909ed37 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -24,15 +24,48 @@ using namespace logid::actions; using namespace logid::backend; -const char* KeypressAction::interface_name = - "pizza.pixl.LogiOps.Action.Keypress"; +const char* KeypressAction::interface_name = "Keypress"; -KeypressAction::KeypressAction(Device *device, config::KeypressAction& config, - const std::shared_ptr& parent) : - Action(device), _config (config) +KeypressAction::KeypressAction( + Device *device, config::KeypressAction& config, + [[maybe_unused]] const std::shared_ptr& parent) : + Action(device, interface_name, { + { + {"GetKeys", {this, &KeypressAction::getKeys, {"keys"}}}, + {"SetKeys", {this, &KeypressAction::setKeys, {"keys"}}} + }, {}, {} + }), _config (config) { - if(std::holds_alternative(_config.keys)) { - const auto& key = std::get(_config.keys); + _setConfig(); +} + +void KeypressAction::press() +{ + std::lock_guard lock(_config_lock); + _pressed = true; + for(auto& key : _keys) + _device->virtualInput()->pressKey(key); +} + +void KeypressAction::release() +{ + std::lock_guard lock(_config_lock); + _pressed = false; + for(auto& key : _keys) + _device->virtualInput()->releaseKey(key); +} + +void KeypressAction::_setConfig() +{ + _keys.clear(); + + if(!_config.keys.has_value()) + return; + + auto& config = _config.keys.value(); + + if(std::holds_alternative(config)) { + const auto& key = std::get(config); try { auto code = _device->virtualInput()->toKeyCode(key); _device->virtualInput()->registerKey(code); @@ -40,14 +73,14 @@ KeypressAction::KeypressAction(Device *device, config::KeypressAction& config, } catch(InputDevice::InvalidEventCode& e) { logPrintf(WARN, "Invalid keycode %s, skipping.", key.c_str()); } - } else if(std::holds_alternative(_config.keys)) { - const auto& key = std::get(_config.keys); + } else if(std::holds_alternative(_config.keys.value())) { + const auto& key = std::get(config); _device->virtualInput()->registerKey(key); _keys.emplace_back(key); - } else if(std::holds_alternative>>(_config.keys)) { - const auto& keys = std::get>>( - _config.keys); + } else if(std::holds_alternative< + std::list>>(config)) { + const auto& keys = std::get< + std::list>>(config); for(const auto& key : keys) { if(std::holds_alternative(key)) { const auto& key_str = std::get(key); @@ -66,22 +99,6 @@ KeypressAction::KeypressAction(Device *device, config::KeypressAction& config, } } } - - _ipc = parent->make_interface(this); -} - -void KeypressAction::press() -{ - _pressed = true; - for(auto& key : _keys) - _device->virtualInput()->pressKey(key); -} - -void KeypressAction::release() -{ - _pressed = false; - for(auto& key : _keys) - _device->virtualInput()->releaseKey(key); } uint8_t KeypressAction::reprogFlags() const @@ -89,7 +106,26 @@ uint8_t KeypressAction::reprogFlags() const return hidpp20::ReprogControls::TemporaryDiverted; } -KeypressAction::IPC::IPC(KeypressAction *action) : ipcgull::interface( - interface_name, {}, {}, {}), _action (*action) +std::vector KeypressAction::getKeys() const { + std::lock_guard lock(_config_lock); + std::vector ret; + for(auto& x : _keys) + ret.push_back(InputDevice::toKeyName(x)); + + return ret; +} + +void KeypressAction::setKeys(const std::vector &keys) +{ + std::lock_guard lock(_config_lock); + if(_pressed) + for(auto& key : _keys) + _device->virtualInput()->releaseKey(key); + _config.keys = std::list>(); + auto& config = std::get>>( + _config.keys.value()); + for(auto& x : keys) + config.emplace_back(x); + _setConfig(); } diff --git a/src/logid/actions/KeypressAction.h b/src/logid/actions/KeypressAction.h index 8cde45d..e55fc62 100644 --- a/src/logid/actions/KeypressAction.h +++ b/src/logid/actions/KeypressAction.h @@ -36,20 +36,16 @@ namespace actions { virtual void press(); virtual void release(); + [[nodiscard]] std::vector getKeys() const; + void setKeys(const std::vector& keys); + virtual uint8_t reprogFlags() const; protected: + mutable std::mutex _config_lock; config::KeypressAction& _config; std::list _keys; - private: - class IPC : public ipcgull::interface - { - public: - explicit IPC(KeypressAction* action); - private: - KeypressAction& _action; - }; - std::shared_ptr _ipc; + void _setConfig(); }; }} diff --git a/src/logid/actions/NullAction.cpp b/src/logid/actions/NullAction.cpp index d81d60e..0fe6729 100644 --- a/src/logid/actions/NullAction.cpp +++ b/src/logid/actions/NullAction.cpp @@ -21,12 +21,12 @@ using namespace logid::actions; -const char* NullAction::interface_name = - "pizza.pixl.LogiOps.Action.None"; +const char* NullAction::interface_name = "None"; -NullAction::NullAction(Device* device, - const std::shared_ptr& parent) : - Action(device), _ipc (parent->make_interface()) +NullAction::NullAction( + Device* device, + [[maybe_unused]] const std::shared_ptr& parent) : + Action(device, interface_name) { } @@ -43,8 +43,4 @@ void NullAction::release() uint8_t NullAction::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; -} - -NullAction::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) -{ -} +} \ No newline at end of file diff --git a/src/logid/actions/NullAction.h b/src/logid/actions/NullAction.h index dd95f83..2262c30 100644 --- a/src/logid/actions/NullAction.h +++ b/src/logid/actions/NullAction.h @@ -38,12 +38,6 @@ namespace actions virtual void release(); virtual uint8_t reprogFlags() const; - private: - class IPC : public ipcgull::interface { - public: - IPC(); - }; - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ToggleHiresScroll.cpp b/src/logid/actions/ToggleHiresScroll.cpp index 40dfd0c..dfcb1c3 100644 --- a/src/logid/actions/ToggleHiresScroll.cpp +++ b/src/logid/actions/ToggleHiresScroll.cpp @@ -23,12 +23,12 @@ using namespace logid::actions; using namespace logid::backend; -const char* ToggleHiresScroll::interface_name = - "pizza.pixl.LogiOps.Action.ToggleHiresScroll"; +const char* ToggleHiresScroll::interface_name = "ToggleHiresScroll"; ToggleHiresScroll::ToggleHiresScroll( - Device *dev, const std::shared_ptr& parent) : - Action (dev), _ipc (parent->make_interface()) + Device *dev, + [[maybe_unused]] const std::shared_ptr& parent) : + Action (dev, interface_name) { _hires_scroll = _device->getFeature("hiresscroll"); if(!_hires_scroll) @@ -61,7 +61,3 @@ uint8_t ToggleHiresScroll::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -ToggleHiresScroll::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) -{ -} diff --git a/src/logid/actions/ToggleHiresScroll.h b/src/logid/actions/ToggleHiresScroll.h index 2c1f3b1..c79d846 100644 --- a/src/logid/actions/ToggleHiresScroll.h +++ b/src/logid/actions/ToggleHiresScroll.h @@ -41,14 +41,6 @@ namespace actions virtual uint8_t reprogFlags() const; protected: std::shared_ptr _hires_scroll; - private: - class IPC : public ipcgull::interface - { - public: - IPC(); - }; - - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/ToggleSmartShift.cpp b/src/logid/actions/ToggleSmartShift.cpp index 6767138..efd3da6 100644 --- a/src/logid/actions/ToggleSmartShift.cpp +++ b/src/logid/actions/ToggleSmartShift.cpp @@ -23,12 +23,12 @@ using namespace logid::actions; using namespace logid::backend; -const char* ToggleSmartShift::interface_name = - "pizza.pixl.LogiOps.Action.ToggleSmartShift"; +const char* ToggleSmartShift::interface_name = "ToggleSmartShift"; ToggleSmartShift::ToggleSmartShift( - Device *dev, const std::shared_ptr& parent) : - Action (dev), _ipc (parent->make_interface()) + Device *dev, + [[maybe_unused]] const std::shared_ptr& parent) : + Action (dev, interface_name) { _smartshift = _device->getFeature("smartshift"); if(!_smartshift) @@ -61,7 +61,3 @@ uint8_t ToggleSmartShift::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -ToggleSmartShift::IPC::IPC() : ipcgull::interface(interface_name, {}, {}, {}) -{ -} diff --git a/src/logid/actions/ToggleSmartShift.h b/src/logid/actions/ToggleSmartShift.h index 7013c50..98c51a0 100644 --- a/src/logid/actions/ToggleSmartShift.h +++ b/src/logid/actions/ToggleSmartShift.h @@ -42,14 +42,6 @@ namespace actions { virtual uint8_t reprogFlags() const; protected: std::shared_ptr _smartshift; - private: - class IPC : public ipcgull::interface - { - public: - IPC(); - }; - - std::shared_ptr _ipc; }; }} diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 9d8bd43..1338cf1 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -23,24 +23,29 @@ using namespace logid::actions; +const char* AxisGesture::interface_name = "Axis"; + AxisGesture::AxisGesture(Device *device, config::AxisGesture& config, - const std::shared_ptr& parent, - const std::string& direction) : - Gesture (device, parent, direction), _multiplier (1), _config (config) + const std::shared_ptr& parent) : + Gesture (device, parent, interface_name), _multiplier (1), _config (config) { - if(std::holds_alternative(_config.axis)) { - _input_axis = std::get(_config.axis); - } else { - const auto& axis = std::get(_config.axis); - try { - _input_axis = _device->virtualInput()->toAxisCode(axis); - _device->virtualInput()->registerAxis(_input_axis); - } catch(InputDevice::InvalidEventCode& e) { - logPrintf(WARN, "Invalid axis %s."); - throw InvalidGesture(); + if(_config.axis.has_value()) { + if(std::holds_alternative(_config.axis.value())) { + _input_axis = std::get(_config.axis.value()); + } else { + const auto& axis = std::get(_config.axis.value()); + try { + _input_axis = _device->virtualInput()->toAxisCode(axis); + _device->virtualInput()->registerAxis(_input_axis.value()); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid axis %s."); + } } + } - _device->virtualInput()->registerAxis(_input_axis); + + if(_input_axis.has_value()) + _device->virtualInput()->registerAxis(_input_axis.value()); } void AxisGesture::press(bool init_threshold) @@ -59,6 +64,9 @@ void AxisGesture::release(bool primary) void AxisGesture::move(int16_t axis) { + if(!_input_axis.has_value()) + return; + const auto threshold = _config.threshold.value_or( defaults::gesture_threshold); int16_t new_axis = _axis+axis; @@ -90,7 +98,7 @@ void AxisGesture::move(int16_t axis) if(low_res_axis != -1) { int lowres_movement = 0, hires_movement = move_floor; - _device->virtualInput()->moveAxis(_input_axis, hires_movement); + _device->virtualInput()->moveAxis(_input_axis.value(), hires_movement); hires_remainder += hires_movement; if(abs(hires_remainder) >= 60) { lowres_movement = hires_remainder/120; @@ -102,7 +110,7 @@ void AxisGesture::move(int16_t axis) _hires_remainder = hires_remainder; } else { - _device->virtualInput()->moveAxis(_input_axis, move_floor); + _device->virtualInput()->moveAxis(_input_axis.value(), move_floor); } } _axis = new_axis; diff --git a/src/logid/actions/gesture/AxisGesture.h b/src/logid/actions/gesture/AxisGesture.h index 491c201..29d20bc 100644 --- a/src/logid/actions/gesture/AxisGesture.h +++ b/src/logid/actions/gesture/AxisGesture.h @@ -26,9 +26,10 @@ namespace logid { class AxisGesture : public Gesture { public: + static const char* interface_name; + AxisGesture(Device* device, config::AxisGesture& config, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -43,7 +44,7 @@ namespace logid { int16_t _axis; double _axis_remainder; int _hires_remainder; - uint _input_axis; + std::optional _input_axis; double _multiplier; config::AxisGesture& _config; }; diff --git a/src/logid/actions/gesture/Gesture.cpp b/src/logid/actions/gesture/Gesture.cpp index 9bc9dc2..85168ec 100644 --- a/src/logid/actions/gesture/Gesture.cpp +++ b/src/logid/actions/gesture/Gesture.cpp @@ -17,6 +17,7 @@ */ #include +#include #include "Gesture.h" #include "ReleaseGesture.h" #include "ThresholdGesture.h" @@ -28,9 +29,10 @@ using namespace logid; using namespace logid::actions; Gesture::Gesture(Device *device, - const std::shared_ptr& parent, - const std::string& direction) : _device (device), - _node (parent->make_child(direction)) + std::shared_ptr node, + const std::string& name, tables t) : + ipcgull::interface("pizza.pixl.LogiOps.Gesture." + name, std::move(t)), + _node (std::move(node)), _device (device) { } @@ -48,20 +50,41 @@ struct gesture_type : gesture_type { }; template std::shared_ptr _makeGesture( Device* device, T gesture, - const std::shared_ptr& parent, - const std::string& direction) { - return std::make_shared::type>( - device, gesture, parent, std::move(direction)); + const std::shared_ptr& parent) { + return parent->make_interface::type>( + device, gesture, parent); } std::shared_ptr Gesture::makeGesture( Device *device, config::Gesture& gesture, - const std::shared_ptr& parent, - const std::string& direction) + const std::shared_ptr& parent) { - std::shared_ptr ret; - std::visit([&device, &ret, &parent, &direction](auto&& x) { - ret = _makeGesture(device, x, parent, direction); + return std::visit([&device, &parent](auto&& x) { + return _makeGesture(device, x, parent); }, gesture); - return ret; +} + +std::shared_ptr Gesture::makeGesture( + Device *device, const std::string& type, + config::Gesture& config, + const std::shared_ptr &parent) +{ + if(type == AxisGesture::interface_name) { + config = config::AxisGesture(); + return makeGesture(device, config, parent); + } else if(type == IntervalGesture::interface_name) { + config = config::IntervalGesture(); + return makeGesture(device, config, parent); + } else if(type == ReleaseGesture::interface_name) { + config = config::IntervalGesture(); + return makeGesture(device, config, parent); + } else if(type == ThresholdGesture::interface_name) { + config = config::ThresholdGesture(); + return makeGesture(device, config, parent); + } else if(type == NullGesture::interface_name) { + config = config::NoGesture(); + return makeGesture(device, config, parent); + } + + throw InvalidGesture(); } diff --git a/src/logid/actions/gesture/Gesture.h b/src/logid/actions/gesture/Gesture.h index 6fc8816..b2e036b 100644 --- a/src/logid/actions/gesture/Gesture.h +++ b/src/logid/actions/gesture/Gesture.h @@ -39,7 +39,7 @@ namespace actions std::string _what; }; - class Gesture + class Gesture : public ipcgull::interface { public: virtual void press(bool init_threshold=false) = 0; @@ -53,15 +53,19 @@ namespace actions static std::shared_ptr makeGesture(Device* device, config::Gesture& gesture, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); + + static std::shared_ptr makeGesture( + Device* device, const std::string& type, + config::Gesture& gesture, + const std::shared_ptr& parent); protected: - explicit Gesture(Device* device, - const std::shared_ptr& parent, - const std::string& direction); + Gesture(Device* device, + std::shared_ptr parent, + const std::string& name, tables t={}); + const std::shared_ptr _node; Device* _device; - std::shared_ptr _node; }; }} diff --git a/src/logid/actions/gesture/IntervalGesture.cpp b/src/logid/actions/gesture/IntervalGesture.cpp index 0acca9c..8ec68e0 100644 --- a/src/logid/actions/gesture/IntervalGesture.cpp +++ b/src/logid/actions/gesture/IntervalGesture.cpp @@ -21,10 +21,13 @@ using namespace logid::actions; -IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config, - const std::shared_ptr& parent, - const std::string& direction) : - Gesture (device, parent, direction), _config (config) +const char* IntervalGesture::interface_name = "OnInterval"; + +IntervalGesture::IntervalGesture( + Device *device, config::IntervalGesture& config, + const std::shared_ptr& parent) : + Gesture (device, parent, interface_name), + _axis (0), _interval_pass_count (0), _config (config) { if(config.action) { try { @@ -50,6 +53,9 @@ void IntervalGesture::release(bool primary) void IntervalGesture::move(int16_t axis) { + if(!_config.interval.has_value()) + return; + const auto threshold = _config.threshold.value_or(defaults::gesture_threshold); _axis += axis; @@ -57,7 +63,7 @@ void IntervalGesture::move(int16_t axis) return; int16_t new_interval_count = (_axis - threshold)/ - _config.interval; + _config.interval.value(); if(new_interval_count > _interval_pass_count) { if(_action) { _action->press(); diff --git a/src/logid/actions/gesture/IntervalGesture.h b/src/logid/actions/gesture/IntervalGesture.h index 5ee4ecd..75356b6 100644 --- a/src/logid/actions/gesture/IntervalGesture.h +++ b/src/logid/actions/gesture/IntervalGesture.h @@ -26,9 +26,10 @@ namespace actions class IntervalGesture : public Gesture { public: + static const char* interface_name; + IntervalGesture(Device* device, config::IntervalGesture& config, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -42,6 +43,18 @@ namespace actions int16_t _interval_pass_count; std::shared_ptr _action; config::IntervalGesture& _config; + private: + class IPC : public ipcgull::interface + { + public: + IPC(IntervalGesture* parent); + + void setAction(const std::string& type); + void setInterval(int interval); + void setThreshold(int threshold); + private: + IntervalGesture& parent; + }; }; }} diff --git a/src/logid/actions/gesture/NullGesture.cpp b/src/logid/actions/gesture/NullGesture.cpp index 2b2c6ea..c8edbb1 100644 --- a/src/logid/actions/gesture/NullGesture.cpp +++ b/src/logid/actions/gesture/NullGesture.cpp @@ -20,11 +20,12 @@ using namespace logid::actions; +const char* NullGesture::interface_name = "None"; + NullGesture::NullGesture(Device *device, config::NoGesture& config, - const std::shared_ptr& parent, - const std::string& direction) : - Gesture (device, parent, direction), _config (config) + const std::shared_ptr& parent) : + Gesture (device, parent, interface_name), _config (config) { } diff --git a/src/logid/actions/gesture/NullGesture.h b/src/logid/actions/gesture/NullGesture.h index 9f08bab..9f8ce15 100644 --- a/src/logid/actions/gesture/NullGesture.h +++ b/src/logid/actions/gesture/NullGesture.h @@ -26,10 +26,11 @@ namespace actions class NullGesture : public Gesture { public: + static const char* interface_name; + NullGesture(Device* device, config::NoGesture& config, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/ReleaseGesture.cpp b/src/logid/actions/gesture/ReleaseGesture.cpp index ca663c1..2949965 100644 --- a/src/logid/actions/gesture/ReleaseGesture.cpp +++ b/src/logid/actions/gesture/ReleaseGesture.cpp @@ -20,10 +20,11 @@ using namespace logid::actions; +const char* ReleaseGesture::interface_name = "OnRelease"; + ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config, - const std::shared_ptr& parent, - const std::string& direction) : - Gesture (device, parent, direction), _config (config) + const std::shared_ptr& parent) : + Gesture (device, parent, interface_name), _config (config) { if(_config.action.has_value()) _action = Action::makeAction(device, _config.action.value(), _node); diff --git a/src/logid/actions/gesture/ReleaseGesture.h b/src/logid/actions/gesture/ReleaseGesture.h index f02c566..e0c9284 100644 --- a/src/logid/actions/gesture/ReleaseGesture.h +++ b/src/logid/actions/gesture/ReleaseGesture.h @@ -26,9 +26,10 @@ namespace actions class ReleaseGesture : public Gesture { public: + static const char* interface_name; + ReleaseGesture(Device* device, config::ReleaseGesture& config, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/actions/gesture/ThresholdGesture.cpp b/src/logid/actions/gesture/ThresholdGesture.cpp index 3e79dd8..d29db07 100644 --- a/src/logid/actions/gesture/ThresholdGesture.cpp +++ b/src/logid/actions/gesture/ThresholdGesture.cpp @@ -20,11 +20,12 @@ using namespace logid::actions; -ThresholdGesture::ThresholdGesture(Device *device, - config::ThresholdGesture& config, - const std::shared_ptr& parent, - const std::string& direction) : - Gesture (device, parent, direction), _config (config) +const char* ThresholdGesture::interface_name = "OnRelease"; + +ThresholdGesture::ThresholdGesture( + Device *device, config::ThresholdGesture& config, + const std::shared_ptr& parent ) : + Gesture (device, parent, interface_name), _config (config) { if(config.action) { try { diff --git a/src/logid/actions/gesture/ThresholdGesture.h b/src/logid/actions/gesture/ThresholdGesture.h index 802cbb5..be071ee 100644 --- a/src/logid/actions/gesture/ThresholdGesture.h +++ b/src/logid/actions/gesture/ThresholdGesture.h @@ -26,9 +26,10 @@ namespace actions class ThresholdGesture : public Gesture { public: + static const char* interface_name; + ThresholdGesture(Device* device, config::ThresholdGesture& config, - const std::shared_ptr& parent, - const std::string& direction); + const std::shared_ptr& parent); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); diff --git a/src/logid/backend/raw/IOMonitor.cpp b/src/logid/backend/raw/IOMonitor.cpp index 6114882..9cc23c2 100644 --- a/src/logid/backend/raw/IOMonitor.cpp +++ b/src/logid/backend/raw/IOMonitor.cpp @@ -85,9 +85,7 @@ IOMonitor::~IOMonitor() noexcept void IOMonitor::_listen() { - std::unique_lock run_lock(_run_lock, std::try_to_lock); - if(!run_lock.owns_lock()) - throw std::runtime_error("IOMonitor already listening"); + std::lock_guard run_lock(_run_lock); std::vector events; _is_running = true; @@ -130,7 +128,7 @@ void IOMonitor::_stop() noexcept bool IOMonitor::_running() const { std::unique_lock run_lock(_run_lock, std::try_to_lock); - return !run_lock.owns_lock(); + return !run_lock.owns_lock() || _is_running; } void IOMonitor::add(int fd, IOHandler handler) diff --git a/src/logid/config/group.h b/src/logid/config/group.h index 9c419ed..174e241 100644 --- a/src/logid/config/group.h +++ b/src/logid/config/group.h @@ -34,7 +34,7 @@ namespace logid::config { void set(libconfig::Setting& parent, const T& t); template - T get(const libconfig::Setting& parent, const std::string& name); + auto get(const libconfig::Setting& parent, const std::string& name); template void append(libconfig::Setting& list, const T& t); @@ -189,7 +189,7 @@ namespace logid::config { } void _save(libconfig::Setting& setting) const override { - set(setting, _signature, _sig_field); + set(setting, _sig_field, _signature); _setter(setting, this, _names); } diff --git a/src/logid/config/map.h b/src/logid/config/map.h index 8543bc3..9b309b8 100644 --- a/src/logid/config/map.h +++ b/src/logid/config/map.h @@ -33,13 +33,27 @@ namespace logid::config { char value[N]; }; + template + struct less_caseless { + constexpr bool operator()(const T& a, const T& b) const noexcept { + auto a_it = a.begin(), b_it = b.begin(); + for(; a_it != a.end() && b_it != b.end(); ++a_it, ++b_it) { + if(tolower(*a_it) != tolower(*b_it)) + return tolower(*a_it) < tolower(*b_it); + } + return b_it != b.end(); + } + }; + // Warning: map must be a variant of groups or a group - template - class map : public std::map { + template ::key_compare, + typename Allocator=typename std::map::allocator_type> + class map : public std::map { public: template map(Args... args) : - std::map(std::forward(args)...) { } + std::map(std::forward(args)...) { } }; } diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h index 3fe3f52..da17f2d 100644 --- a/src/logid/config/schema.h +++ b/src/logid/config/schema.h @@ -46,11 +46,14 @@ namespace logid::config { struct KeypressAction : public signed_group { typedef actions::KeypressAction action; - std::variant>> keys; + std::optional< + std::variant>>> keys; KeypressAction() : signed_group( "type", "Keypress", - {"keys"}, &KeypressAction::keys) { } + {"keys"}, &KeypressAction::keys) + { + } }; struct ToggleSmartShift : public signed_group { @@ -67,7 +70,7 @@ namespace logid::config { struct CycleDPI : public signed_group { typedef actions::CycleDPI action; - std::list dpis; + std::optional> dpis; std::optional sensor; CycleDPI() : signed_group( "type", "CycleDPI", @@ -78,7 +81,7 @@ namespace logid::config { struct ChangeDPI : public signed_group { typedef actions::ChangeDPI action; - int inc; + std::optional inc; std::optional sensor; ChangeDPI() : signed_group( "type", "ChangeDPI", @@ -89,7 +92,7 @@ namespace logid::config { struct ChangeHost : public signed_group { typedef actions::ChangeHostAction action; - std::variant host; + std::optional> host; ChangeHost() : signed_group( "type", "ChangeHost", {"host"}, &ChangeHost::host) { } @@ -108,7 +111,7 @@ namespace logid::config { struct AxisGesture : public signed_group { typedef actions::AxisGesture gesture; std::optional threshold; - std::variant axis; + std::optional> axis; std::optional axis_multiplier; AxisGesture() : signed_group("mode", "Axis", @@ -122,7 +125,7 @@ namespace logid::config { typedef actions::IntervalGesture gesture; std::optional threshold; std::optional action; - int interval; + std::optional interval; protected: IntervalGesture(const std::string& name) : signed_group( "mode", name, @@ -180,7 +183,8 @@ namespace logid::config { struct GestureAction : public signed_group { typedef actions::GestureAction action; - std::optional> gestures; + std::optional>> gestures; GestureAction() : signed_group( "type", "Gestures", @@ -263,12 +267,15 @@ namespace logid::config { }; struct Device : public group { - std::string default_profile; + ipcgull::property default_profile; map profiles; Device() : group({"default_profile", "profiles"}, &Device::default_profile, - &Device::profiles) { } + &Device::profiles), + default_profile(ipcgull::property_full_permissions, "") + { + } }; struct Config : public group { diff --git a/src/logid/config/types.h b/src/logid/config/types.h index 1969045..955fb75 100644 --- a/src/logid/config/types.h +++ b/src/logid/config/types.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "group.h" #include "map.h" #include "../util/log.h" @@ -74,6 +75,9 @@ namespace logid::config { } }; + template + struct config_io> : public config_io { }; + template struct primitive_io { static T get(const libconfig::Setting& parent, @@ -328,11 +332,13 @@ namespace logid::config { } }; - template - struct config_io> { - static map get(const libconfig::Setting& setting) { + template + struct config_io> { + static map get( + const libconfig::Setting& setting) { const auto size = setting.getLength(); - map t; + map t; for(int i = 0; i < size; ++i) { auto& s = setting[i]; try { @@ -343,13 +349,13 @@ namespace logid::config { return t; } - static map get(const libconfig::Setting& parent, - const std::string& name) { + static map get( + const libconfig::Setting& parent, const std::string& name) { return get(parent.lookup(name)); } static void set(libconfig::Setting& setting, - const map& t) { + const map& t) { while(setting.getLength() != 0) setting.remove((int)0); for(auto& x : t) { @@ -361,7 +367,7 @@ namespace logid::config { static void set(libconfig::Setting& parent, const std::string& name, - const map& t) { + const map& t) { if (!parent.exists(name)) { parent.add(name, libconfig::Setting::TypeList); } else if(!parent.lookup(name).isArray()) { @@ -372,7 +378,7 @@ namespace logid::config { } static void append(libconfig::Setting& list, - const map& t) { + const map& t) { auto& s = list.add(libconfig::Setting::TypeList); set(s, t); } @@ -428,16 +434,16 @@ namespace logid::config { template void append(libconfig::Setting& list, const T& t) { - config_io::set(list, t); + config_io::append(list, t); } template - T get(const libconfig::Setting& setting) { + auto get(const libconfig::Setting& setting) { return config_io::get(setting); } template - T get(const libconfig::Setting& parent, const std::string& name) { + auto get(const libconfig::Setting& parent, const std::string& name) { return config_io::get(parent, name); } } diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index 15f2cae..bbfd7d4 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -116,7 +116,7 @@ void HiresScroll::_makeAction(std::shared_ptr &gesture, { if(config.has_value()) { gesture = actions::Gesture::makeGesture(_device, config.value(), - _node, direction); + _node->make_child(direction)); try { auto axis = std::dynamic_pointer_cast( gesture); diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index b485ac8..c8b5034 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -16,6 +16,7 @@ * */ #include +#include "../actions/GestureAction.h" #include "../Device.h" #include "RemapButton.h" #include "../backend/hidpp20/Error.h" @@ -67,14 +68,14 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), } _reprog_controls->setControlReporting(info.controlID, report); }; - _buttons.emplace(std::piecewise_construct, - std::forward_as_tuple(control.second.controlID), - std::forward_as_tuple(control.second, i, - _device, func, - _ipc_node, - _config.value()[control.first])); + _buttons.emplace(control.second.controlID, + Button::make(control.second, i, + _device, func, _ipc_node, + _config.value()[control.first])); } + _ipc_interface = _device->ipcNode()->make_interface(this); + if(global_loglevel <= DEBUG) { #define FLAG(x) (control.second.flags & hidpp20::ReprogControls::x ? \ "YES" : "") @@ -104,7 +105,7 @@ RemapButton::~RemapButton() void RemapButton::configure() { for(const auto& button : _buttons) - button.second.configure(); + button.second->configure(); } void RemapButton::listen() @@ -127,8 +128,8 @@ void RemapButton::listen() else { // RawXY auto divertedXY = _reprog_controls->divertedRawXYEvent(report); for(const auto& button : this->_buttons) - if(button.second.pressed()) - button.second.move(divertedXY.x, divertedXY.y); + if(button.second->pressed()) + button.second->move(divertedXY.x, divertedXY.y); } }; @@ -149,7 +150,7 @@ void RemapButton::_buttonEvent(const std::set& new_state) } else { auto action = _buttons.find(i); if(action != _buttons.end()) - action->second.press(); + action->second->press(); } } @@ -157,12 +158,34 @@ void RemapButton::_buttonEvent(const std::set& new_state) for(auto& i : _pressed_buttons) { auto action = _buttons.find(i); if(action != _buttons.end()) - action->second.release(); + action->second->release(); } _pressed_buttons = new_state; } +namespace logid::features { + class _Button : public Button { + public: + template + explicit _Button(Args&&... args) : Button(std::forward(args)...) + { + } + }; +} + +std::shared_ptr