diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt
index b2616c84..31bebae4 100644
--- a/src/logid/CMakeLists.txt
+++ b/src/logid/CMakeLists.txt
@@ -1,120 +1,120 @@
-cmake_minimum_required(VERSION 3.12)
-project(logid)
-
-# C++20 is only needed for string literal template parameters
-set(CMAKE_CXX_STANDARD 20)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake")
-
-find_package(Threads REQUIRED)
-find_package(PkgConfig REQUIRED)
-
-add_executable(logid
- logid.cpp
- util/log.cpp
- config/config.cpp
- InputDevice.cpp
- DeviceManager.cpp
- Device.cpp
- Receiver.cpp
- Configuration.cpp
- features/DPI.cpp
- features/SmartShift.cpp
- features/HiresScroll.cpp
- features/RemapButton.cpp
- features/DeviceStatus.cpp
- features/ThumbWheel.cpp
- actions/Action.cpp
- actions/NullAction.cpp
- actions/KeypressAction.cpp
- actions/ToggleHiresScroll.cpp
- actions/ToggleSmartShift.cpp
- actions/CycleDPI.cpp
- actions/ChangeDPI.cpp
- actions/GestureAction.cpp
- actions/ChangeHostAction.cpp
- actions/ChangeProfile.cpp
- actions/gesture/Gesture.cpp
- actions/gesture/ReleaseGesture.cpp
- actions/gesture/ThresholdGesture.cpp
- actions/gesture/IntervalGesture.cpp
- actions/gesture/AxisGesture.cpp
- actions/gesture/NullGesture.cpp
- backend/Error.cpp
- backend/raw/DeviceMonitor.cpp
- backend/raw/RawDevice.cpp
- backend/raw/IOMonitor.cpp
- backend/hidpp10/Receiver.cpp
- backend/hidpp10/ReceiverMonitor.cpp
- backend/hidpp/Device.cpp
- backend/hidpp/Report.cpp
- backend/hidpp10/Error.cpp
- backend/hidpp10/Device.cpp
- backend/hidpp20/Device.cpp
- backend/hidpp20/Error.cpp
- backend/hidpp20/Feature.cpp
- backend/hidpp20/EssentialFeature.cpp
- backend/hidpp20/features/Root.cpp
- backend/hidpp20/features/FeatureSet.cpp
- backend/hidpp20/features/DeviceName.cpp
- backend/hidpp20/features/Reset.cpp
- backend/hidpp20/features/AdjustableDPI.cpp
- backend/hidpp20/features/SmartShift.cpp
- backend/hidpp20/features/ReprogControls.cpp
- backend/hidpp20/features/HiresScroll.cpp
- backend/hidpp20/features/ChangeHost.cpp
- backend/hidpp20/features/WirelessDeviceStatus.cpp
- backend/hidpp20/features/ThumbWheel.cpp
- util/task.cpp
- util/ExceptionHandler.cpp)
-
-set_target_properties(logid PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-
-pkg_check_modules(PC_EVDEV libevdev REQUIRED)
-pkg_check_modules(SYSTEMD "systemd")
-pkg_check_modules(LIBCONFIG libconfig REQUIRED)
-pkg_check_modules(LIBUDEV libudev REQUIRED)
-
-find_path(EVDEV_INCLUDE_DIR libevdev/libevdev.h
- HINTS ${PC_EVDEV_INCLUDE_DIRS} ${PC_EVDEV_INCLUDEDIR})
-find_library(EVDEV_LIBRARY
- NAMES evdev libevdev)
-
-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} ipcgull)
-
-install(TARGETS logid DESTINATION bin)
-
-if (SYSTEMD_FOUND)
- if ("${SYSTEMD_SERVICES_INSTALL_DIR}" STREQUAL "")
- execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
- --variable=systemdsystemunitdir systemd
- OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
- string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_SERVICES_INSTALL_DIR
- "${SYSTEMD_SERVICES_INSTALL_DIR}")
- endif ()
-
- # Install systemd service
- configure_file(logid.service.in ${CMAKE_BINARY_DIR}/logid.service)
- message(STATUS "systemd units will be installed at ${SYSTEMD_SERVICES_INSTALL_DIR}")
- install(FILES ${CMAKE_BINARY_DIR}/logid.service
- DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR}
- COMPONENT cp)
-elseif (NOT SYSTEMD_FOUND AND SYSTEMD_SERVICES_INSTALL_DIR)
- message(FATAL_ERROR "systemd is not found w/ pkg-config but SYSTEMD_SERVICES_INSTALL_DIR is defined.")
-endif ()
-
-# Install DBus conf
-# TODO: Is there a better way of setting the system policy directory?
-set(DBUS_SYSTEM_POLICY_INSTALL_DIR "/usr/share/dbus-1/system.d")
-configure_file(logiops-dbus.conf.in ${CMAKE_BINARY_DIR}/pizza.pixl.LogiOps.conf)
-message(STATUS "dbus system policy will be installed at ${DBUS_SYSTEM_POLICY_INSTALL_DIR}")
-install(FILES ${CMAKE_BINARY_DIR}/pizza.pixl.LogiOps.conf
- DESTINATION ${DBUS_SYSTEM_POLICY_INSTALL_DIR}
- COMPONENT cp)
+cmake_minimum_required(VERSION 3.12)
+project(logid)
+
+# C++20 is only needed for string literal template parameters
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake")
+
+find_package(Threads REQUIRED)
+find_package(PkgConfig REQUIRED)
+
+add_executable(logid
+ logid.cpp
+ util/log.cpp
+ config/config.cpp
+ InputDevice.cpp
+ DeviceManager.cpp
+ Device.cpp
+ Receiver.cpp
+ Configuration.cpp
+ features/DPI.cpp
+ features/SmartShift.cpp
+ features/HiresScroll.cpp
+ features/RemapButton.cpp
+ features/DeviceStatus.cpp
+ features/ThumbWheel.cpp
+ actions/Action.cpp
+ actions/NullAction.cpp
+ actions/KeypressAction.cpp
+ actions/ToggleHiresScroll.cpp
+ actions/ToggleSmartShift.cpp
+ actions/CycleDPI.cpp
+ actions/ChangeDPI.cpp
+ actions/GestureAction.cpp
+ actions/ChangeHostAction.cpp
+ actions/ChangeProfile.cpp
+ actions/gesture/Gesture.cpp
+ actions/gesture/ReleaseGesture.cpp
+ actions/gesture/ThresholdGesture.cpp
+ actions/gesture/IntervalGesture.cpp
+ actions/gesture/AxisGesture.cpp
+ actions/gesture/NullGesture.cpp
+ backend/Error.cpp
+ backend/raw/DeviceMonitor.cpp
+ backend/raw/RawDevice.cpp
+ backend/raw/IOMonitor.cpp
+ backend/hidpp10/Receiver.cpp
+ backend/hidpp10/ReceiverMonitor.cpp
+ backend/hidpp/Device.cpp
+ backend/hidpp/Report.cpp
+ backend/hidpp10/Error.cpp
+ backend/hidpp10/Device.cpp
+ backend/hidpp20/Device.cpp
+ backend/hidpp20/Error.cpp
+ backend/hidpp20/Feature.cpp
+ backend/hidpp20/EssentialFeature.cpp
+ backend/hidpp20/features/Root.cpp
+ backend/hidpp20/features/FeatureSet.cpp
+ backend/hidpp20/features/DeviceName.cpp
+ backend/hidpp20/features/Reset.cpp
+ backend/hidpp20/features/AdjustableDPI.cpp
+ backend/hidpp20/features/SmartShift.cpp
+ backend/hidpp20/features/ReprogControls.cpp
+ backend/hidpp20/features/HiresScroll.cpp
+ backend/hidpp20/features/ChangeHost.cpp
+ backend/hidpp20/features/WirelessDeviceStatus.cpp
+ backend/hidpp20/features/ThumbWheel.cpp
+ util/task.cpp
+ util/ExceptionHandler.cpp)
+
+set_target_properties(logid PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+
+pkg_check_modules(PC_EVDEV libevdev REQUIRED)
+pkg_check_modules(SYSTEMD "systemd")
+pkg_check_modules(LIBCONFIG libconfig REQUIRED)
+pkg_check_modules(LIBUDEV libudev REQUIRED)
+
+find_path(EVDEV_INCLUDE_DIR libevdev/libevdev.h
+ HINTS ${PC_EVDEV_INCLUDE_DIRS} ${PC_EVDEV_INCLUDEDIR})
+find_library(EVDEV_LIBRARY
+ NAMES evdev libevdev)
+
+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} ipcgull)
+
+install(TARGETS logid DESTINATION bin)
+
+if (SYSTEMD_FOUND)
+ if ("${SYSTEMD_SERVICES_INSTALL_DIR}" STREQUAL "")
+ execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
+ --variable=systemdsystemunitdir systemd
+ OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
+ string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_SERVICES_INSTALL_DIR
+ "${SYSTEMD_SERVICES_INSTALL_DIR}")
+ endif ()
+
+ # Install systemd service
+ configure_file(logid.service.in ${CMAKE_BINARY_DIR}/logid.service)
+ message(STATUS "systemd units will be installed at ${SYSTEMD_SERVICES_INSTALL_DIR}")
+ install(FILES ${CMAKE_BINARY_DIR}/logid.service
+ DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR}
+ COMPONENT cp)
+elseif (NOT SYSTEMD_FOUND AND SYSTEMD_SERVICES_INSTALL_DIR)
+ message(FATAL_ERROR "systemd is not found w/ pkg-config but SYSTEMD_SERVICES_INSTALL_DIR is defined.")
+endif ()
+
+# Install DBus conf
+# TODO: Is there a better way of setting the system policy directory?
+set(DBUS_SYSTEM_POLICY_INSTALL_DIR "/usr/share/dbus-1/system.d")
+configure_file(logiops-dbus.conf.in ${CMAKE_BINARY_DIR}/pizza.pixl.LogiOps.conf)
+message(STATUS "dbus system policy will be installed at ${DBUS_SYSTEM_POLICY_INSTALL_DIR}")
+install(FILES ${CMAKE_BINARY_DIR}/pizza.pixl.LogiOps.conf
+ DESTINATION ${DBUS_SYSTEM_POLICY_INSTALL_DIR}
+ COMPONENT cp)
diff --git a/src/logid/Configuration.cpp b/src/logid/Configuration.cpp
index e49b5eaf..9c437f3a 100644
--- a/src/logid/Configuration.cpp
+++ b/src/logid/Configuration.cpp
@@ -1,76 +1,76 @@
-/*
- * Copyright 2019-2023 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
-#include
-#include
-#include
-
-using namespace logid;
-using namespace libconfig;
-using namespace logid::config;
-
-Configuration::Configuration(std::string config_file) :
- _config_file(std::move(config_file)) {
- if (std::filesystem::exists(_config_file)) {
- try {
- _config.readFile(_config_file.c_str());
- } catch (const FileIOException& 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;
- }
-
- Config::operator=(get(_config.getRoot()));
- } else {
- logPrintf(INFO, "Config file does not exist, using empty config.");
- }
-
- if (!devices.has_value())
- devices.emplace();
-}
-
-Configuration::Configuration() {
- devices.emplace();
-}
-
-void Configuration::save() {
- config::set(_config.getRoot(), *this);
- try {
- _config.writeFile(_config_file.c_str());
- } 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;
- }
-}
-
-Configuration::IPC::IPC(Configuration* config) :
- ipcgull::interface(SERVICE_ROOT_NAME ".Config", {
- {"Save", {config, &Configuration::save}}
- }, {}, {}) {
-}
+/*
+ * Copyright 2019-2023 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
+#include
+#include
+#include
+
+using namespace logid;
+using namespace libconfig;
+using namespace logid::config;
+
+Configuration::Configuration(std::string config_file) :
+ _config_file(std::move(config_file)) {
+ if (std::filesystem::exists(_config_file)) {
+ try {
+ _config.readFile(_config_file.c_str());
+ } catch (const FileIOException& 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;
+ }
+
+ Config::operator=(get(_config.getRoot()));
+ } else {
+ logPrintf(INFO, "Config file does not exist, using empty config.");
+ }
+
+ if (!devices.has_value())
+ devices.emplace();
+}
+
+Configuration::Configuration() {
+ devices.emplace();
+}
+
+void Configuration::save() {
+ config::set(_config.getRoot(), *this);
+ try {
+ _config.writeFile(_config_file.c_str());
+ } 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;
+ }
+}
+
+Configuration::IPC::IPC(Configuration* config) :
+ ipcgull::interface(SERVICE_ROOT_NAME ".Config", {
+ {"Save", {config, &Configuration::save}}
+ }, {}, {}) {
+}
diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h
index 3a6a1e67..262ef82e 100644
--- a/src/logid/Configuration.h
+++ b/src/logid/Configuration.h
@@ -1,58 +1,58 @@
-/*
- * Copyright 2019-2023 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_CONFIGURATION_H
-#define LOGID_CONFIGURATION_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace logid {
- namespace defaults {
- static constexpr double io_timeout = 500;
- static constexpr int workers = 4;
- static constexpr int gesture_threshold = 50;
- }
-
- class Configuration : public config::Config {
- public:
- explicit Configuration(std::string config_file);
-
- Configuration();
-
- // Reloading is not safe, references will be invalidated
- //void reload();
- void save();
-
- class IPC : public ipcgull::interface {
- public:
- explicit IPC(Configuration* config);
- };
-
- private:
- std::string _config_file;
- libconfig::Config _config;
- };
-
-}
-
-#endif //LOGID_CONFIGURATION_H
+/*
+ * Copyright 2019-2023 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_CONFIGURATION_H
+#define LOGID_CONFIGURATION_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace logid {
+ namespace defaults {
+ static constexpr double io_timeout = 500;
+ static constexpr int workers = 4;
+ static constexpr int gesture_threshold = 50;
+ }
+
+ class Configuration : public config::Config {
+ public:
+ explicit Configuration(std::string config_file);
+
+ Configuration();
+
+ // Reloading is not safe, references will be invalidated
+ //void reload();
+ void save();
+
+ class IPC : public ipcgull::interface {
+ public:
+ explicit IPC(Configuration* config);
+ };
+
+ private:
+ std::string _config_file;
+ libconfig::Config _config;
+ };
+
+}
+
+#endif //LOGID_CONFIGURATION_H
diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp
index 20b679d0..0134e286 100644
--- a/src/logid/Device.cpp
+++ b/src/logid/Device.cpp
@@ -1,366 +1,366 @@
-/*
- * Copyright 2019-2023 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-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 DeviceWrapper : public Device {
- public:
- template
- explicit DeviceWrapper(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(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(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(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) :
- _hidpp20(hidpp20::Device::make(path, index, manager,
- manager->config()->io_timeout.value_or(
- defaults::io_timeout))),
- _path(std::move(path)), _index(index),
- _config(_getConfig(manager, _hidpp20->name())),
- _profile_name(ipcgull::property_readable, ""),
- _manager(manager),
- _nickname(manager),
- _ipc_node(manager->devicesNode()->make_child(_nickname)),
- _awake(ipcgull::property_readable, true) {
- _init();
-}
-
-Device::Device(std::shared_ptr raw_device,
- hidpp::DeviceIndex index, const std::shared_ptr& manager) :
- _hidpp20(hidpp20::Device::make(
- 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())),
- _profile_name(ipcgull::property_readable, ""),
- _manager(manager),
- _nickname(manager),
- _ipc_node(manager->devicesNode()->make_child(_nickname)),
- _awake(ipcgull::property_readable, true) {
- _init();
-}
-
-Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
- const std::shared_ptr& manager) :
- _hidpp20(hidpp20::Device::make(
- receiver->rawReceiver(), index,
- manager->config()->io_timeout.value_or(defaults::io_timeout))),
- _path(receiver->path()), _index(index),
- _config(_getConfig(manager, _hidpp20->name())),
- _profile_name(ipcgull::property_readable, ""),
- _manager(manager),
- _nickname(manager),
- _ipc_node(manager->devicesNode()->make_child(_nickname)),
- _awake(ipcgull::property_readable, true) {
- _init();
-}
-
-void Device::_init() {
- logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(),
- hidpp20().devicePath().c_str(), _index);
-
- {
- std::unique_lock lock(_profile_mutex);
- _profile = _config.profiles.find(_config.default_profile);
- if (_profile == _config.profiles.end())
- _profile = _config.profiles.insert({_config.default_profile, {}}).first;
- _profile_name = _config.default_profile;
- }
-
- _addFeature("dpi");
- _addFeature("smartshift");
- _addFeature("hiresscroll");
- _addFeature("remapbutton");
- _addFeature("devicestatus");
- _addFeature("thumbwheel");
-
- _makeResetMechanism();
- reset();
-
- for (auto& feature: _features) {
- feature.second->configure();
- feature.second->listen();
- }
-}
-
-std::string Device::name() {
- return _hidpp20->name();
-}
-
-uint16_t Device::pid() {
- return _hidpp20->pid();
-}
-
-void Device::sleep() {
- 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);
-
- reconfigure();
-
- if (!_awake) {
- _awake = true;
- _ipc_interface->notifyStatus();
- }
-
- logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index);
-}
-
-void Device::reconfigure() {
- reset();
-
- for (auto& feature: _features)
- feature.second->configure();
-}
-
-void Device::reset() {
- if (_reset_mechanism)
- (*_reset_mechanism)();
- else
- logPrintf(DEBUG, "%s:%d tried to reset, but no reset mechanism was "
- "available.", _path.c_str(), _index);
-}
-
-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();
- }
-}
-
-std::shared_ptr Device::ipcNode() const {
- return _ipc_node;
-}
-
-std::vector Device::getProfiles() const {
- std::shared_lock lock(_profile_mutex);
-
- std::vector ret;
- for (auto& profile : _config.profiles) {
- ret.push_back(profile.first);
- }
-
- return ret;
-}
-
-void Device::setProfile(const std::string& profile) {
- std::unique_lock lock(_profile_mutex);
-
- _profile = _config.profiles.find(profile);
- if (_profile == _config.profiles.end())
- _profile = _config.profiles.insert({profile, {}}).first;
- _profile_name = profile;
-
- for (auto& feature : _features)
- feature.second->setProfile(_profile->second);
-
- reconfigure();
-}
-
-void Device::setProfileDelayed(const std::string& profile) {
- run_task([self_weak = _self, profile](){
- if (auto self = self_weak.lock())
- self->setProfile(profile);
- });
-}
-
-void Device::removeProfile(const std::string& profile) {
- std::unique_lock lock(_profile_mutex);
-
- if (profile == (std::string)_profile_name)
- throw std::invalid_argument("cannot remove active profile");
- else if (profile == (std::string)_config.default_profile)
- throw std::invalid_argument("cannot remove default profile");
-
- _config.profiles.erase(profile);
-}
-
-void Device::clearProfile(const std::string& profile) {
- std::unique_lock lock(_profile_mutex);
-
- if (profile == (std::string)_profile_name) {
- _profile->second = config::Profile();
-
- for (auto& feature : _features)
- feature.second->setProfile(_profile->second);
-
- reconfigure();
- } else {
- auto it = _config.profiles.find(profile);
- if (it != _config.profiles.end()) {
- it->second = config::Profile();
- } else {
- throw std::invalid_argument("unknown profile");
- }
- }
-}
-
-config::Profile& Device::activeProfile() {
- std::shared_lock lock(_profile_mutex);
- return _profile->second;
-}
-
-hidpp20::Device& Device::hidpp20() {
- return *_hidpp20;
-}
-
-void Device::_makeResetMechanism() {
- try {
- hidpp20::Reset reset(_hidpp20.get());
- _reset_mechanism = std::make_unique>(
- [dev = _hidpp20] {
- hidpp20::Reset reset(dev.get());
- reset.reset(reset.getProfile());
- });
- } catch (hidpp20::UnsupportedFeature& e) {
- // Reset unsupported, ignore.
- }
-}
-
-Device::IPC::IPC(Device* device) :
- ipcgull::interface(
- SERVICE_ROOT_NAME ".Device",
- {
- {"GetProfiles", {device, &Device::getProfiles, {"profiles"}}},
- {"SetProfile", {device, &Device::setProfile, {"profile"}}},
- {"RemoveProfile", {device, &Device::removeProfile, {"profile"}}},
- {"ClearProfile", {device, &Device::clearProfile, {"profile"}}}
- },
- {
- {"Name", ipcgull::property(
- ipcgull::property_readable, device->name())},
- {"ProductID", ipcgull::property(
- ipcgull::property_readable, device->pid())},
- {"Active", device->_awake},
- {"DefaultProfile", device->_config.default_profile},
- {"ActiveProfile", device->_profile_name}
- }, {
- {"StatusChanged", ipcgull::signal::make_signal({"active"})}
- }), _device(*device) {
-}
-
-void Device::IPC::notifyStatus() const {
- emit_signal("StatusChanged", (bool) (_device._awake));
-}
-
-config::Device& Device::_getConfig(
- const std::shared_ptr& manager,
- const std::string& name) {
- static std::mutex config_mutex;
- std::lock_guard lock(config_mutex);
- auto& devices = manager->config()->devices.value();
-
- if (!devices.count(name)) {
- devices.emplace(name, config::Device());
- }
-
- auto& device = devices.at(name);
- if (std::holds_alternative(device)) {
- config::Device d;
- d.profiles["default"] = std::get(device);
- d.default_profile = "default";
- device = std::move(d);
- }
-
- auto& conf = std::get(device);
- if (conf.profiles.empty()) {
- conf.profiles["default"] = {};
- conf.default_profile = "default";
- }
-
- return conf;
-}
+/*
+ * Copyright 2019-2023 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 DeviceWrapper : public Device {
+ public:
+ template
+ explicit DeviceWrapper(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(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(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(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) :
+ _hidpp20(hidpp20::Device::make(path, index, manager,
+ manager->config()->io_timeout.value_or(
+ defaults::io_timeout))),
+ _path(std::move(path)), _index(index),
+ _config(_getConfig(manager, _hidpp20->name())),
+ _profile_name(ipcgull::property_readable, ""),
+ _manager(manager),
+ _nickname(manager),
+ _ipc_node(manager->devicesNode()->make_child(_nickname)),
+ _awake(ipcgull::property_readable, true) {
+ _init();
+}
+
+Device::Device(std::shared_ptr raw_device,
+ hidpp::DeviceIndex index, const std::shared_ptr& manager) :
+ _hidpp20(hidpp20::Device::make(
+ 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())),
+ _profile_name(ipcgull::property_readable, ""),
+ _manager(manager),
+ _nickname(manager),
+ _ipc_node(manager->devicesNode()->make_child(_nickname)),
+ _awake(ipcgull::property_readable, true) {
+ _init();
+}
+
+Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
+ const std::shared_ptr& manager) :
+ _hidpp20(hidpp20::Device::make(
+ receiver->rawReceiver(), index,
+ manager->config()->io_timeout.value_or(defaults::io_timeout))),
+ _path(receiver->path()), _index(index),
+ _config(_getConfig(manager, _hidpp20->name())),
+ _profile_name(ipcgull::property_readable, ""),
+ _manager(manager),
+ _nickname(manager),
+ _ipc_node(manager->devicesNode()->make_child(_nickname)),
+ _awake(ipcgull::property_readable, true) {
+ _init();
+}
+
+void Device::_init() {
+ logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(),
+ hidpp20().devicePath().c_str(), _index);
+
+ {
+ std::unique_lock lock(_profile_mutex);
+ _profile = _config.profiles.find(_config.default_profile);
+ if (_profile == _config.profiles.end())
+ _profile = _config.profiles.insert({_config.default_profile, {}}).first;
+ _profile_name = _config.default_profile;
+ }
+
+ _addFeature("dpi");
+ _addFeature("smartshift");
+ _addFeature("hiresscroll");
+ _addFeature("remapbutton");
+ _addFeature("devicestatus");
+ _addFeature("thumbwheel");
+
+ _makeResetMechanism();
+ reset();
+
+ for (auto& feature: _features) {
+ feature.second->configure();
+ feature.second->listen();
+ }
+}
+
+std::string Device::name() {
+ return _hidpp20->name();
+}
+
+uint16_t Device::pid() {
+ return _hidpp20->pid();
+}
+
+void Device::sleep() {
+ 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);
+
+ reconfigure();
+
+ if (!_awake) {
+ _awake = true;
+ _ipc_interface->notifyStatus();
+ }
+
+ logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index);
+}
+
+void Device::reconfigure() {
+ reset();
+
+ for (auto& feature: _features)
+ feature.second->configure();
+}
+
+void Device::reset() {
+ if (_reset_mechanism)
+ (*_reset_mechanism)();
+ else
+ logPrintf(DEBUG, "%s:%d tried to reset, but no reset mechanism was "
+ "available.", _path.c_str(), _index);
+}
+
+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();
+ }
+}
+
+std::shared_ptr Device::ipcNode() const {
+ return _ipc_node;
+}
+
+std::vector Device::getProfiles() const {
+ std::shared_lock lock(_profile_mutex);
+
+ std::vector ret;
+ for (auto& profile : _config.profiles) {
+ ret.push_back(profile.first);
+ }
+
+ return ret;
+}
+
+void Device::setProfile(const std::string& profile) {
+ std::unique_lock lock(_profile_mutex);
+
+ _profile = _config.profiles.find(profile);
+ if (_profile == _config.profiles.end())
+ _profile = _config.profiles.insert({profile, {}}).first;
+ _profile_name = profile;
+
+ for (auto& feature : _features)
+ feature.second->setProfile(_profile->second);
+
+ reconfigure();
+}
+
+void Device::setProfileDelayed(const std::string& profile) {
+ run_task([self_weak = _self, profile](){
+ if (auto self = self_weak.lock())
+ self->setProfile(profile);
+ });
+}
+
+void Device::removeProfile(const std::string& profile) {
+ std::unique_lock lock(_profile_mutex);
+
+ if (profile == (std::string)_profile_name)
+ throw std::invalid_argument("cannot remove active profile");
+ else if (profile == (std::string)_config.default_profile)
+ throw std::invalid_argument("cannot remove default profile");
+
+ _config.profiles.erase(profile);
+}
+
+void Device::clearProfile(const std::string& profile) {
+ std::unique_lock lock(_profile_mutex);
+
+ if (profile == (std::string)_profile_name) {
+ _profile->second = config::Profile();
+
+ for (auto& feature : _features)
+ feature.second->setProfile(_profile->second);
+
+ reconfigure();
+ } else {
+ auto it = _config.profiles.find(profile);
+ if (it != _config.profiles.end()) {
+ it->second = config::Profile();
+ } else {
+ throw std::invalid_argument("unknown profile");
+ }
+ }
+}
+
+config::Profile& Device::activeProfile() {
+ std::shared_lock lock(_profile_mutex);
+ return _profile->second;
+}
+
+hidpp20::Device& Device::hidpp20() {
+ return *_hidpp20;
+}
+
+void Device::_makeResetMechanism() {
+ try {
+ hidpp20::Reset reset(_hidpp20.get());
+ _reset_mechanism = std::make_unique>(
+ [dev = _hidpp20] {
+ hidpp20::Reset reset(dev.get());
+ reset.reset(reset.getProfile());
+ });
+ } catch (hidpp20::UnsupportedFeature& e) {
+ // Reset unsupported, ignore.
+ }
+}
+
+Device::IPC::IPC(Device* device) :
+ ipcgull::interface(
+ SERVICE_ROOT_NAME ".Device",
+ {
+ {"GetProfiles", {device, &Device::getProfiles, {"profiles"}}},
+ {"SetProfile", {device, &Device::setProfile, {"profile"}}},
+ {"RemoveProfile", {device, &Device::removeProfile, {"profile"}}},
+ {"ClearProfile", {device, &Device::clearProfile, {"profile"}}}
+ },
+ {
+ {"Name", ipcgull::property(
+ ipcgull::property_readable, device->name())},
+ {"ProductID", ipcgull::property(
+ ipcgull::property_readable, device->pid())},
+ {"Active", device->_awake},
+ {"DefaultProfile", device->_config.default_profile},
+ {"ActiveProfile", device->_profile_name}
+ }, {
+ {"StatusChanged", ipcgull::signal::make_signal({"active"})}
+ }), _device(*device) {
+}
+
+void Device::IPC::notifyStatus() const {
+ emit_signal("StatusChanged", (bool) (_device._awake));
+}
+
+config::Device& Device::_getConfig(
+ const std::shared_ptr& manager,
+ const std::string& name) {
+ static std::mutex config_mutex;
+ std::lock_guard lock(config_mutex);
+ auto& devices = manager->config()->devices.value();
+
+ if (!devices.count(name)) {
+ devices.emplace(name, config::Device());
+ }
+
+ auto& device = devices.at(name);
+ if (std::holds_alternative(device)) {
+ config::Device d;
+ d.profiles["default"] = std::get(device);
+ d.default_profile = "default";
+ device = std::move(d);
+ }
+
+ auto& conf = std::get(device);
+ if (conf.profiles.empty()) {
+ conf.profiles["default"] = {};
+ conf.default_profile = "default";
+ }
+
+ return conf;
+}
diff --git a/src/logid/Device.h b/src/logid/Device.h
index 99da6dc9..a6012584 100644
--- a/src/logid/Device.h
+++ b/src/logid/Device.h
@@ -1,187 +1,187 @@
-/*
- * Copyright 2019-2023 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_DEVICE_H
-#define LOGID_DEVICE_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace logid {
- class DeviceManager;
-
- class Device;
-
- 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;
- };
-
- /* 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 {
- public:
- std::string name();
-
- uint16_t pid();
-
- [[nodiscard]] config::Profile& activeProfile();
-
- [[nodiscard]] std::vector getProfiles() const;
-
- void setProfile(const std::string& profile);
-
- void setProfileDelayed(const std::string& profile);
-
- void removeProfile(const std::string& profile);
-
- void clearProfile(const std::string& profile);
-
- 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();
-
- void reconfigure();
-
- void reset();
-
- [[nodiscard]] std::shared_ptr virtualInput() const;
-
- [[nodiscard]] std::shared_ptr ipcNode() const;
-
- template
- std::shared_ptr getFeature(const std::string& name) {
- auto it = _features.find(name);
- if (it == _features.end())
- return nullptr;
- try {
- return std::dynamic_pointer_cast(it->second);
- } catch (std::bad_cast& e) {
- return nullptr;
- }
- }
-
- Device(const Device&) = delete;
-
- Device(Device&&) = delete;
-
- private:
- friend class DeviceWrapper;
-
- Device(std::string path, backend::hidpp::DeviceIndex index,
- const std::shared_ptr& manager);
-
- Device(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);
-
- static config::Device& _getConfig(
- const std::shared_ptr& manager,
- const std::string& name);
-
- void _init();
-
- /* Adds a feature without calling an error if unsupported */
- template
- void _addFeature(std::string name) {
- try {
- _features.emplace(name, features::DeviceFeature::make(this));
- } catch (features::UnsupportedFeature& e) {
- }
- }
-
- std::shared_ptr _hidpp20;
- std::string _path;
- backend::hidpp::DeviceIndex _index;
- std::map> _features;
-
- config::Device& _config;
- mutable std::shared_mutex _profile_mutex;
- ipcgull::property _profile_name;
- std::map::iterator _profile;
-
- const std::weak_ptr _manager;
-
- void _makeResetMechanism();
-
- std::unique_ptr> _reset_mechanism;
-
- const DeviceNickname _nickname;
- std::shared_ptr _ipc_node;
-
- class IPC : public ipcgull::interface {
- private:
- Device& _device;
- public:
- explicit IPC(Device* device);
-
- void notifyStatus() const;
- };
-
- ipcgull::property _awake;
- std::mutex _state_lock;
-
- std::weak_ptr _self;
-
- std::shared_ptr _ipc_interface;
- };
-}
-
-#endif //LOGID_DEVICE_H
+/*
+ * Copyright 2019-2023 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_DEVICE_H
+#define LOGID_DEVICE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace logid {
+ class DeviceManager;
+
+ class Device;
+
+ 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;
+ };
+
+ /* 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 {
+ public:
+ std::string name();
+
+ uint16_t pid();
+
+ [[nodiscard]] config::Profile& activeProfile();
+
+ [[nodiscard]] std::vector getProfiles() const;
+
+ void setProfile(const std::string& profile);
+
+ void setProfileDelayed(const std::string& profile);
+
+ void removeProfile(const std::string& profile);
+
+ void clearProfile(const std::string& profile);
+
+ 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();
+
+ void reconfigure();
+
+ void reset();
+
+ [[nodiscard]] std::shared_ptr virtualInput() const;
+
+ [[nodiscard]] std::shared_ptr ipcNode() const;
+
+ template
+ std::shared_ptr getFeature(const std::string& name) {
+ auto it = _features.find(name);
+ if (it == _features.end())
+ return nullptr;
+ try {
+ return std::dynamic_pointer_cast(it->second);
+ } catch (std::bad_cast& e) {
+ return nullptr;
+ }
+ }
+
+ Device(const Device&) = delete;
+
+ Device(Device&&) = delete;
+
+ private:
+ friend class DeviceWrapper;
+
+ Device(std::string path, backend::hidpp::DeviceIndex index,
+ const std::shared_ptr& manager);
+
+ Device(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);
+
+ static config::Device& _getConfig(
+ const std::shared_ptr& manager,
+ const std::string& name);
+
+ void _init();
+
+ /* Adds a feature without calling an error if unsupported */
+ template
+ void _addFeature(std::string name) {
+ try {
+ _features.emplace(name, features::DeviceFeature::make(this));
+ } catch (features::UnsupportedFeature& e) {
+ }
+ }
+
+ std::shared_ptr _hidpp20;
+ std::string _path;
+ backend::hidpp::DeviceIndex _index;
+ std::map> _features;
+
+ config::Device& _config;
+ mutable std::shared_mutex _profile_mutex;
+ ipcgull::property _profile_name;
+ std::map::iterator _profile;
+
+ const std::weak_ptr _manager;
+
+ void _makeResetMechanism();
+
+ std::unique_ptr> _reset_mechanism;
+
+ const DeviceNickname _nickname;
+ std::shared_ptr _ipc_node;
+
+ class IPC : public ipcgull::interface {
+ private:
+ Device& _device;
+ public:
+ explicit IPC(Device* device);
+
+ void notifyStatus() const;
+ };
+
+ ipcgull::property _awake;
+ std::mutex _state_lock;
+
+ std::weak_ptr _self;
+
+ std::shared_ptr _ipc_interface;
+ };
+}
+
+#endif //LOGID_DEVICE_H
diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp
index e41ac306..ee2959e2 100644
--- a/src/logid/DeviceManager.cpp
+++ b/src/logid/DeviceManager.cpp
@@ -1,320 +1,320 @@
-/*
- * Copyright 2019-2023 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
-#include
-#include
-#include
-#include
-#include
-
-using namespace logid;
-using namespace logid::backend;
-
-DeviceManager::DeviceManager(std::shared_ptr config,
- std::shared_ptr virtual_input,
- std::shared_ptr server) :
- backend::raw::DeviceMonitor(),
- _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(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);
-}
-
-std::shared_ptr DeviceManager::config() const {
- return _config;
-}
-
-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;
- bool isReceiver = false;
-
- // Check if device is ignored before continuing
- {
- auto raw_dev = raw::RawDevice::make(path, self().lock());
- 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;
- }
- }
-
- try {
- auto device = hidpp::Device::make(
- path, hidpp::DefaultDevice, self().lock(),
- config()->io_timeout.value_or(defaults::io_timeout));
- isReceiver = device->version() == std::make_tuple(1, 0);
- } catch (hidpp20::Error& e) {
- if (e.code() != hidpp20::Error::UnknownDevice)
- throw DeviceNotReady();
- defaultExists = false;
- } catch (hidpp10::Error& e) {
- if (e.code() != hidpp10::Error::UnknownDevice)
- throw DeviceNotReady();
- defaultExists = false;
- } catch (hidpp::Device::InvalidDevice& e) {
- if (e.code() == hidpp::Device::InvalidDevice::VirtualNode) {
- logPrintf(DEBUG, "Ignoring virtual node on %s", path.c_str());
- } else if (e.code() == hidpp::Device::InvalidDevice::Asleep) {
- /* May be a valid device, wait */
- throw DeviceNotReady();
- }
-
- return;
- } catch (std::system_error& e) {
- logPrintf(WARN, "I/O error on %s: %s, skipping device.", path.c_str(), e.what());
- return;
- } catch (TimeoutError& e) {
- /* Ready and valid non-default devices should throw an UnknownDevice error */
- throw DeviceNotReady();
- }
-
- if (isReceiver) {
- logPrintf(INFO, "Detected receiver at %s", path.c_str());
- auto receiver = Receiver::make(path, self().lock());
- std::lock_guard lock(_map_lock);
- _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 = 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) {
- if (e.code() != hidpp10::Error::UnknownDevice)
- throw DeviceNotReady();
- } catch (hidpp20::Error& e) {
- if (e.code() != hidpp20::Error::UnknownDevice)
- throw DeviceNotReady();
- } catch (hidpp::Device::InvalidDevice& e) {
- if (e.code() == hidpp::Device::InvalidDevice::Asleep)
- throw DeviceNotReady();
- } catch (std::system_error& e) {
- // This error should have been thrown previously
- logPrintf(WARN, "I/O error on %s: %s", path.c_str(), e.what());
- } catch (TimeoutError& e) {
- throw DeviceNotReady();
- }
- }
- }
-}
-
-void DeviceManager::addExternalDevice(const std::shared_ptr& d) {
- _ipc_devices->deviceAdded(d);
-}
-
-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()) {
- _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(DeviceManager* manager) :
- ipcgull::interface(
- SERVICE_ROOT_NAME ".Devices",
- {
- {"Enumerate", {manager, &DeviceManager::listDevices, {"devices"}}}
- },
- {},
- {
- {"DeviceAdded",
- ipcgull::make_signal>(
- {"device"})},
- {"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);
-}
-
-void DeviceManager::DevicesIPC::deviceRemoved(
- const std::shared_ptr& d) {
- emit_signal("DeviceRemoved", d);
-}
-
-DeviceManager::ReceiversIPC::ReceiversIPC(DeviceManager* manager) :
- ipcgull::interface(
- SERVICE_ROOT_NAME ".Receivers",
- {
- {"Enumerate", {manager, &DeviceManager::listReceivers,
- {"receivers"}}}
- },
- {},
- {
- {"ReceiverAdded",
- ipcgull::make_signal>(
- {"receiver"})},
- {"ReceiverRemoved",
- ipcgull::make_signal>(
- {"receiver"})}
- }) {
-}
-
-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