Code cleanup and reformatting

This commit is contained in:
pixl 2023-04-27 17:53:35 -04:00
parent 9af666f863
commit 9efd121387
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
124 changed files with 3128 additions and 3478 deletions

View File

@ -76,7 +76,7 @@ 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})
HINTS ${PC_EVDEV_INCLUDE_DIRS} ${PC_EVDEV_INCLUDEDIR})
find_library(EVDEV_LIBRARY
NAMES evdev libevdev)
@ -92,15 +92,15 @@ install(TARGETS logid DESTINATION bin)
if (SYSTEMD_FOUND AND "${SYSTEMD_SERVICES_INSTALL_DIR}" STREQUAL "")
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
--variable=systemdsystemunitdir systemd
OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
--variable=systemdsystemunitdir systemd
OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_SERVICES_INSTALL_DIR
"${SYSTEMD_SERVICES_INSTALL_DIR}")
"${SYSTEMD_SERVICES_INSTALL_DIR}")
configure_file(logid.service.cmake ${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)
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()
endif ()

View File

@ -18,7 +18,6 @@
#include <utility>
#include <vector>
#include <map>
#include "Configuration.h"
#include "util/log.h"
@ -28,15 +27,14 @@ using namespace libconfig;
using namespace logid::config;
Configuration::Configuration(std::string config_file) :
_config_file (std::move(config_file))
{
_config_file(std::move(config_file)) {
try {
_config.readFile(_config_file);
} catch(const FileIOException &e) {
} catch (const FileIOException& e) {
logPrintf(ERROR, "I/O Error while reading %s: %s", _config_file.c_str(),
e.what());
throw;
} catch(const ParseException &e) {
} catch (const ParseException& e) {
logPrintf(ERROR, "Parse error in %s, line %d: %s", e.getFile(),
e.getLine(), e.getError());
throw;
@ -44,29 +42,27 @@ Configuration::Configuration(std::string config_file) :
Config::operator=(get<Config>(_config.getRoot()));
if(!devices.has_value())
if (!devices.has_value())
devices = decltype(config::Config::devices)();
}
void Configuration::save()
{
void Configuration::save() {
config::set(_config.getRoot(), *this);
try {
_config.writeFile(_config_file);
} catch(const FileIOException &e) {
} 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) {
} catch (const std::exception& e) {
logPrintf(ERROR, "Error while writing %s: %s",
_config_file.c_str(), e.what());
throw;
}
}
Configuration::IPC::IPC(Configuration *config) :
Configuration::IPC::IPC(Configuration* config) :
ipcgull::interface("pizza.pixl.LogiOps.Config", {
{"Save", {config, &Configuration::save}}
}, {}, {})
{
}, {}, {}) {
}

View File

@ -28,28 +28,25 @@
#include "config/schema.h"
namespace logid
{
namespace logid {
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
{
class Configuration : public config::Config {
public:
explicit Configuration(std::string config_file);
Configuration() = default;
// Reloading is not safe, references will be invalidated
//void reload();
void save();
class IPC : public ipcgull::interface
{
class IPC : public ipcgull::interface {
public:
IPC(Configuration* config);
explicit IPC(Configuration* config);
};
private:

View File

@ -34,37 +34,34 @@ using namespace logid;
using namespace logid::backend;
DeviceNickname::DeviceNickname(const std::shared_ptr<DeviceManager>& manager) :
_nickname (manager->newDeviceNickname()), _manager (manager)
{
_nickname(manager->newDeviceNickname()), _manager(manager) {
}
DeviceNickname::operator std::string() const {
return std::to_string(_nickname);
}
DeviceNickname::~DeviceNickname()
{
if(auto manager = _manager.lock()) {
DeviceNickname::~DeviceNickname() {
if (auto manager = _manager.lock()) {
std::lock_guard<std::mutex> lock(manager->_nick_lock);
manager->_device_nicknames.erase(_nickname);
}
}
namespace logid {
class _Device : public Device {
class DeviceWrapper : public Device {
public:
template <typename... Args>
_Device(Args... args) : Device(std::forward<Args>(args)...) { }
template<typename... Args>
explicit DeviceWrapper(Args... args) : Device(std::forward<Args>(args)...) {}
};
}
std::shared_ptr<Device> Device::make(
std::string path, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(std::move(path),
index,
std::move(manager));
std::shared_ptr<DeviceManager> manager) {
auto ret = std::make_shared<DeviceWrapper>(std::move(path),
index,
std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<IPC>(ret.get());
@ -74,11 +71,10 @@ std::shared_ptr<Device> Device::make(
std::shared_ptr<Device> Device::make(
std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(std::move(raw_device),
index,
std::move(manager));
std::shared_ptr<DeviceManager> manager) {
auto ret = std::make_shared<DeviceWrapper>(std::move(raw_device),
index,
std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<IPC>(ret.get());
@ -87,9 +83,8 @@ std::shared_ptr<Device> Device::make(
std::shared_ptr<Device> Device::make(
Receiver* receiver, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(receiver, index, std::move(manager));
std::shared_ptr<DeviceManager> manager) {
auto ret = std::make_shared<DeviceWrapper>(receiver, index, std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<IPC>(ret.get());
@ -97,59 +92,54 @@ std::shared_ptr<Device> Device::make(
}
Device::Device(std::string path, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager) :
_hidpp20 (path, index, manager,
manager->config()->io_timeout.value_or(defaults::io_timeout)),
_path (std::move(path)), _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)
{
const std::shared_ptr<DeviceManager>& manager) :
_hidpp20(path, index, manager,
manager->config()->io_timeout.value_or(defaults::io_timeout)),
_path(std::move(path)), _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(std::shared_ptr<backend::raw::RawDevice> raw_device,
hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager) :
hidpp::DeviceIndex index, const std::shared_ptr<DeviceManager>& manager) :
_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)
{
_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<DeviceManager> manager) :
_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),
_manager (manager),
_nickname (manager),
_ipc_node (manager->devicesNode()->make_child(_nickname)),
_awake (ipcgull::property_readable, true)
{
const std::shared_ptr<DeviceManager>& manager) :
_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),
_manager(manager),
_nickname(manager),
_ipc_node(manager->devicesNode()->make_child(_nickname)),
_awake(ipcgull::property_readable, true) {
_init();
}
void Device::_init()
{
void Device::_init() {
logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(),
hidpp20().devicePath().c_str(), _index);
hidpp20().devicePath().c_str(), _index);
_profile = _config.profiles.find(_config.default_profile);
if(_profile == _config.profiles.end())
if (_profile == _config.profiles.end())
_profile = _config.profiles.insert({_config.default_profile, {}}).first;
_addFeature<features::DPI>("dpi");
@ -162,61 +152,55 @@ void Device::_init()
_makeResetMechanism();
reset();
for(auto& feature: _features) {
for (auto& feature: _features) {
feature.second->configure();
feature.second->listen();
}
}
std::string Device::name()
{
std::string Device::name() {
return _hidpp20.name();
}
uint16_t Device::pid()
{
uint16_t Device::pid() {
return _hidpp20.pid();
}
void Device::sleep()
{
void Device::sleep() {
std::lock_guard<std::mutex> lock(_state_lock);
if(_awake) {
if (_awake) {
logPrintf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
_awake = false;
_ipc_interface->notifyStatus();
}
}
void Device::wakeup()
{
void Device::wakeup() {
std::lock_guard<std::mutex> lock(_state_lock);
logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
reset();
for(auto& feature: _features)
for (auto& feature: _features)
feature.second->configure();
if(!_awake) {
if (!_awake) {
_awake = true;
_ipc_interface->notifyStatus();
}
}
void Device::reset()
{
if(_reset_mechanism)
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<InputDevice> Device::virtualInput() const
{
if(auto manager = _manager.lock()) {
std::shared_ptr<InputDevice> Device::virtualInput() const {
if (auto manager = _manager.lock()) {
return manager->virtualInput();
} else {
logPrintf(ERROR, "Device manager lost");
@ -227,8 +211,7 @@ std::shared_ptr<InputDevice> Device::virtualInput() const
}
}
std::shared_ptr<ipcgull::node> Device::ipcNode() const
{
std::shared_ptr<ipcgull::node> Device::ipcNode() const {
return _ipc_node;
}
@ -237,30 +220,27 @@ std::shared_ptr<ipcgull::node> Device::ipcNode() const
return _config;
}*/
config::Profile& Device::activeProfile()
{
return _profile->second;
}
const config::Profile& Device::activeProfile() const
{
config::Profile& Device::activeProfile() {
return _profile->second;
}
hidpp20::Device& Device::hidpp20()
{
const config::Profile& Device::activeProfile() const {
return _profile->second;
}
hidpp20::Device& Device::hidpp20() {
return _hidpp20;
}
void Device::_makeResetMechanism()
{
void Device::_makeResetMechanism() {
try {
hidpp20::Reset reset(&_hidpp20);
_reset_mechanism = std::make_unique<std::function<void()>>(
[dev=&this->_hidpp20]{
[dev = &this->_hidpp20] {
hidpp20::Reset reset(dev);
reset.reset(reset.getProfile());
reset.reset(reset.getProfile());
});
} catch(hidpp20::UnsupportedFeature& e) {
} catch (hidpp20::UnsupportedFeature& e) {
// Reset unsupported, ignore.
}
}
@ -270,40 +250,37 @@ Device::IPC::IPC(Device* device) :
"pizza.pixl.LogiOps.Device",
{},
{
{"Name", ipcgull::property<std::string>(
ipcgull::property_readable, device->name())},
{"ProductID", ipcgull::property<uint16_t>(
ipcgull::property_readable, device->pid())},
{"Active", device->_awake},
{"DefaultProfile", device->_config.default_profile}
{"Name", ipcgull::property<std::string>(
ipcgull::property_readable, device->name())},
{"ProductID", ipcgull::property<uint16_t>(
ipcgull::property_readable, device->pid())},
{"Active", device->_awake},
{"DefaultProfile", device->_config.default_profile}
}, {
{"StatusChanged",
ipcgull::signal::make_signal<bool>({"active"})}
}), _device (*device)
{
}), _device(*device) {
}
void Device::IPC::notifyStatus() const
{
emit_signal("StatusChanged", (bool)(_device._awake));
void Device::IPC::notifyStatus() const {
emit_signal("StatusChanged", (bool) (_device._awake));
}
config::Device& Device::_getConfig(
const std::shared_ptr<DeviceManager>& manager,
const std::string& name)
{
const std::string& name) {
static std::mutex config_mutex;
std::lock_guard<std::mutex> lock(config_mutex);
auto& devices = manager->config()->devices;
if(!devices.has_value())
if (!devices.has_value())
devices = decltype(config::Config::devices)();
if(!devices.value().count(name)) {
if (!devices.value().count(name)) {
devices.value().emplace(name, config::Device());
}
auto& device = devices.value().at(name);
if(std::holds_alternative<config::Profile>(device)) {
if (std::holds_alternative<config::Profile>(device)) {
config::Device d;
d.profiles["default"] = std::get<config::Profile>(device);
d.default_profile = "default";
@ -311,7 +288,7 @@ config::Device& Device::_getConfig(
}
auto& conf = std::get<config::Device>(device);
if(conf.profiles.empty()) {
if (conf.profiles.empty()) {
conf.profiles["default"] = {};
conf.default_profile = "default";
}

View File

@ -27,21 +27,27 @@
#include "Configuration.h"
#include "util/log.h"
namespace logid
{
namespace logid {
class DeviceManager;
class Device;
class Receiver;
class InputDevice;
class DeviceNickname {
public:
explicit DeviceNickname(const std::shared_ptr<DeviceManager>& manager);
DeviceNickname() = delete;
DeviceNickname(const DeviceNickname&) = delete;
~DeviceNickname();
operator std::string() const;
private:
const int _nickname;
const std::weak_ptr<DeviceManager> _manager;
@ -51,63 +57,70 @@ namespace logid
* Currently, the logid::Device class has a hardcoded requirement
* for an HID++ 2.0 device.
*/
class Device : public ipcgull::object
{
private:
class Config;
class Device : public ipcgull::object {
public:
std::string name();
uint16_t pid();
//config::Device& config();
config::Profile& activeProfile();
const config::Profile& activeProfile() const;
[[nodiscard]] const config::Profile& activeProfile() const;
backend::hidpp20::Device& hidpp20();
static std::shared_ptr<Device> make(
std::string path,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
static std::shared_ptr<Device> make(
std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
static std::shared_ptr<Device> make(
Receiver* receiver,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
void wakeup();
void sleep();
void reset();
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
[[nodiscard]] std::shared_ptr<ipcgull::node> ipcNode() const;
template<typename T>
std::shared_ptr<T> getFeature(std::string name) {
std::shared_ptr<T> getFeature(const std::string& name) {
auto it = _features.find(name);
if(it == _features.end())
if (it == _features.end())
return nullptr;
try {
return std::dynamic_pointer_cast<T>(it->second);
} catch(std::bad_cast& e) {
} catch (std::bad_cast& e) {
logPrintf(ERROR, "bad_cast while getting device feature %s: %s",
name.c_str(), e.what());
name.c_str(), e.what());
return nullptr;
}
}
private:
friend class _Device;
friend class DeviceWrapper;
Device(std::string path, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
const std::shared_ptr<DeviceManager>& manager);
Device(std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
const std::shared_ptr<DeviceManager>& manager);
Device(Receiver* receiver, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
const std::shared_ptr<DeviceManager>& manager);
static config::Device& _getConfig(
const std::shared_ptr<DeviceManager>& manager,
@ -117,8 +130,7 @@ namespace logid
/* Adds a feature without calling an error if unsupported */
template<typename T>
void _addFeature(std::string name)
{
void _addFeature(std::string name) {
try {
_features.emplace(name, std::make_shared<T>(this));
} catch (features::UnsupportedFeature& e) {
@ -129,7 +141,7 @@ namespace logid
std::string _path;
backend::hidpp::DeviceIndex _index;
std::map<std::string, std::shared_ptr<features::DeviceFeature>>
_features;
_features;
config::Device& _config;
std::map<std::string, config::Profile>::iterator _profile;
@ -137,6 +149,7 @@ namespace logid
const std::weak_ptr<DeviceManager> _manager;
void _makeResetMechanism();
std::unique_ptr<std::function<void()>> _reset_mechanism;
const DeviceNickname _nickname;
@ -146,7 +159,8 @@ namespace logid
private:
Device& _device;
public:
IPC(Device* device);
explicit IPC(Device* device);
void notifyStatus() const;
};

View File

@ -31,25 +31,23 @@ using namespace logid;
using namespace logid::backend;
namespace logid {
class _DeviceManager : public logid::DeviceManager
{
class DevManagerWrapper : public logid::DeviceManager {
public:
template <typename... Args>
explicit _DeviceManager(Args... args) :
DeviceManager(std::forward<Args>(args)...) { }
template<typename... Args>
explicit DevManagerWrapper(Args... args) :
DeviceManager(std::forward<Args>(args)...) {}
};
}
DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input,
std::shared_ptr<ipcgull::server> 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"))
{
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<DevicesIPC>(this);
_ipc_receivers = _root_node->make_interface<ReceiversIPC>(this);
_ipc_config = _root_node->make_interface<Configuration::IPC>(_config.get());
@ -62,45 +60,39 @@ DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<DeviceManager> DeviceManager::make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input,
const std::shared_ptr<ipcgull::server>& server)
{
auto ret = std::make_shared<_DeviceManager>(config, virtual_input, server);
const std::shared_ptr<ipcgull::server>& server) {
auto ret = std::make_shared<DevManagerWrapper>(config, virtual_input, server);
ret->_self = ret;
return ret;
}
std::shared_ptr<Configuration> DeviceManager::config() const
{
std::shared_ptr<Configuration> DeviceManager::config() const {
return _config;
}
std::shared_ptr<InputDevice> DeviceManager::virtualInput() const
{
std::shared_ptr<InputDevice> DeviceManager::virtualInput() const {
return _virtual_input;
}
std::shared_ptr<const ipcgull::node> DeviceManager::devicesNode() const
{
std::shared_ptr<const ipcgull::node> DeviceManager::devicesNode() const {
return _device_node;
}
std::shared_ptr<const ipcgull::node> DeviceManager::receiversNode() const
{
std::shared_ptr<const ipcgull::node> DeviceManager::receiversNode() const {
return _receiver_node;
}
void DeviceManager::addDevice(std::string path)
{
void DeviceManager::addDevice(std::string path) {
bool defaultExists = true;
bool isReceiver = false;
// Check if device is ignored before continuing
{
raw::RawDevice raw_dev(path, _self.lock());
if(config()->ignore.has_value() &&
config()->ignore.value().contains(raw_dev.productId())) {
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());
path.c_str(), raw_dev.productId());
return;
}
}
@ -110,92 +102,88 @@ void DeviceManager::addDevice(std::string path)
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) {
if(e.code() != hidpp10::Error::UnknownDevice)
} catch (hidpp10::Error& e) {
if (e.code() != hidpp10::Error::UnknownDevice)
throw;
} catch(hidpp::Device::InvalidDevice &e) {
if(e.code() == hidpp::Device::InvalidDevice::VirtualNode) {
} 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) {
} catch (std::system_error& e) {
logPrintf(WARN, "I/O error on %s: %s, skipping device.",
path.c_str(), e.what());
path.c_str(), e.what());
return;
} catch (TimeoutError &e) {
} catch (TimeoutError& e) {
logPrintf(WARN, "Device %s timed out.", path.c_str());
defaultExists = false;
}
if(isReceiver) {
if (isReceiver) {
logPrintf(INFO, "Detected receiver at %s", path.c_str());
auto receiver = Receiver::make(path, _self.lock());
std::lock_guard<std::mutex> 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) {
/* 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<std::mutex> lock(_map_lock);
_devices.emplace(path, device);
_devices.emplace(path, device);
_ipc_devices->deviceAdded(device);
} else {
try {
auto device = Device::make(path,
hidpp::CordedDevice, _self.lock());
hidpp::CordedDevice, _self.lock());
std::lock_guard<std::mutex> lock(_map_lock);
_devices.emplace(path, device);
_ipc_devices->deviceAdded(device);
} catch(hidpp10::Error &e) {
if(e.code() != hidpp10::Error::UnknownDevice)
} catch (hidpp10::Error& e) {
if (e.code() != hidpp10::Error::UnknownDevice)
throw;
else
logPrintf(WARN,
"HID++ 1.0 error while trying to initialize %s:"
"%s", path.c_str(), e.what());
} catch(hidpp::Device::InvalidDevice &e) { // Ignore
} catch(std::system_error &e) {
"HID++ 1.0 error while trying to initialize %s:"
"%s", path.c_str(), e.what());
} catch (hidpp::Device::InvalidDevice& e) { // Ignore
} 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());
e.what());
}
}
}
}
void DeviceManager::addExternalDevice(const std::shared_ptr<Device> &d)
{
void DeviceManager::addExternalDevice(const std::shared_ptr<Device>& d) {
_ipc_devices->deviceAdded(d);
}
void DeviceManager::removeExternalDevice(const std::shared_ptr<Device> &d)
{
void DeviceManager::removeExternalDevice(const std::shared_ptr<Device>& d) {
_ipc_devices->deviceRemoved(d);
}
std::mutex& DeviceManager::mutex() const
{
std::mutex& DeviceManager::mutex() const {
return _map_lock;
}
void DeviceManager::removeDevice(std::string path)
{
void DeviceManager::removeDevice(std::string path) {
std::lock_guard<std::mutex> lock(_map_lock);
auto receiver = _receivers.find(path);
if(receiver != _receivers.end()) {
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()) {
if (device != _devices.end()) {
_ipc_devices->deviceRemoved(device->second);
_devices.erase(device);
logPrintf(INFO, "Device on %s disconnected", path.c_str());
@ -204,42 +192,39 @@ void DeviceManager::removeDevice(std::string path)
}
DeviceManager::DevicesIPC::DevicesIPC(DeviceManager* manager) :
ipcgull::interface(
"pizza.pixl.LogiOps.Devices",
{
{"Enumerate",{manager, &DeviceManager::listDevices,{"devices"}}}
},
{},
{
{"DeviceAdded",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})},
{"DeviceRemoved",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})}
})
{
ipcgull::interface(
"pizza.pixl.LogiOps.Devices",
{
{"Enumerate", {manager, &DeviceManager::listDevices, {"devices"}}}
},
{},
{
{"DeviceAdded",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})},
{"DeviceRemoved",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})}
}) {
}
std::vector<std::shared_ptr<Device>> DeviceManager::listDevices() const
{
std::vector<std::shared_ptr<Device>> DeviceManager::listDevices() const {
std::lock_guard<std::mutex> lock(_map_lock);
std::vector<std::shared_ptr<Device>> devices;
for(auto& x : _devices)
for (auto& x: _devices)
devices.emplace_back(x.second);
for(auto& x : _receivers) {
for(auto& d : x.second->devices())
for (auto& x: _receivers) {
for (auto& d: x.second->devices())
devices.emplace_back(d.second);
}
return devices;
}
std::vector<std::shared_ptr<Receiver>> DeviceManager::listReceivers() const
{
std::vector<std::shared_ptr<Receiver>> DeviceManager::listReceivers() const {
std::lock_guard<std::mutex> lock(_map_lock);
std::vector<std::shared_ptr<Receiver>> receivers;
for(auto& x : _receivers)
for (auto& x: _receivers)
receivers.emplace_back(x.second);
return receivers;
}
@ -255,22 +240,21 @@ void DeviceManager::DevicesIPC::deviceRemoved(
}
DeviceManager::ReceiversIPC::ReceiversIPC(DeviceManager* manager) :
ipcgull::interface(
"pizza.pixl.LogiOps.Receivers",
{
{"Enumerate",{manager, &DeviceManager::listReceivers,
{"receivers"}}}
},
{},
{
{"ReceiverAdded",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"receiver"})},
{"ReceiverRemoved",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"receiver"})}
})
{
ipcgull::interface(
"pizza.pixl.LogiOps.Receivers",
{
{"Enumerate", {manager, &DeviceManager::listReceivers,
{"receivers"}}}
},
{},
{
{"ReceiverAdded",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"receiver"})},
{"ReceiverRemoved",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"receiver"})}
}) {
}
void DeviceManager::ReceiversIPC::receiverAdded(
@ -283,13 +267,12 @@ void DeviceManager::ReceiversIPC::receiverRemoved(
emit_signal("ReceiverRemoved", r);
}
int DeviceManager::newDeviceNickname()
{
int DeviceManager::newDeviceNickname() {
std::lock_guard<std::mutex> lock(_nick_lock);
auto begin = _device_nicknames.begin();
if(begin != _device_nicknames.end()) {
if(*begin != 0) {
if (begin != _device_nicknames.end()) {
if (*begin != 0) {
_device_nicknames.insert(0);
return 0;
}
@ -300,9 +283,9 @@ int DeviceManager::newDeviceNickname()
[](int l, int r) { return l + 1 < r; });
if(i == _device_nicknames.end()) {
if (i == _device_nicknames.end()) {
auto end = _device_nicknames.rbegin();
if(end != _device_nicknames.rend()) {
if (end != _device_nicknames.rend()) {
auto ret = *end + 1;
assert(ret > 0);
_device_nicknames.insert(ret);
@ -319,13 +302,12 @@ int DeviceManager::newDeviceNickname()
return ret;
}
int DeviceManager::newReceiverNickname()
{
int DeviceManager::newReceiverNickname() {
std::lock_guard<std::mutex> lock(_nick_lock);
auto begin = _receiver_nicknames.begin();
if(begin != _receiver_nicknames.end()) {
if(*begin != 0) {
if (begin != _receiver_nicknames.end()) {
if (*begin != 0) {
_receiver_nicknames.insert(0);
return 0;
}
@ -335,9 +317,9 @@ int DeviceManager::newReceiverNickname()
_receiver_nicknames.end(),
[](int l, int r) { return l + 1 < r; });
if(i == _receiver_nicknames.end()) {
if (i == _receiver_nicknames.end()) {
auto end = _receiver_nicknames.rbegin();
if(end != _receiver_nicknames.rend()) {
if (end != _receiver_nicknames.rend()) {
auto ret = *end + 1;
assert(ret > 0);
_receiver_nicknames.insert(ret);

View File

@ -30,50 +30,63 @@
#include "Device.h"
#include "Receiver.h"
namespace logid
{
namespace logid {
class InputDevice;
class DeviceManager : public backend::raw::DeviceMonitor
{
class DeviceManager : public backend::raw::DeviceMonitor {
public:
static std::shared_ptr<DeviceManager> make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input,
const std::shared_ptr<ipcgull::server>& server);
[[nodiscard]] std::shared_ptr<Configuration> config() const;
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
[[nodiscard]] std::shared_ptr<const ipcgull::node> devicesNode() const;
[[nodiscard]] std::shared_ptr<const ipcgull::node>
receiversNode() const;
receiversNode() const;
void addExternalDevice(const std::shared_ptr<Device>& d);
void removeExternalDevice(const std::shared_ptr<Device>& 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:
explicit DevicesIPC(DeviceManager* manager);
void deviceAdded(const std::shared_ptr<Device>& d);
void deviceRemoved(const std::shared_ptr<Device>& d);
};
[[nodiscard]]
std::vector<std::shared_ptr<Device>> listDevices() const;
class ReceiversIPC : public ipcgull::interface {
public:
explicit ReceiversIPC(DeviceManager* manager);
void receiverAdded(const std::shared_ptr<Receiver>& r);
void receiverRemoved(const std::shared_ptr<Receiver>& r);
};
[[nodiscard]]
std::vector<std::shared_ptr<Receiver>> listReceivers() const;
friend class _DeviceManager;
friend class DevManagerWrapper;
DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input,
std::shared_ptr<ipcgull::server> server);
@ -98,9 +111,11 @@ namespace logid
mutable std::mutex _map_lock;
friend class DeviceNickname;
friend class ReceiverNickname;
[[nodiscard]] int newDeviceNickname();
[[nodiscard]] int newReceiverNickname();
std::mutex _nick_lock;

View File

@ -29,22 +29,18 @@ extern "C"
using namespace logid;
InputDevice::InvalidEventCode::InvalidEventCode(const std::string& name) :
_what ("Invalid event code " + name)
{
_what("Invalid event code " + name) {
}
InputDevice::InvalidEventCode::InvalidEventCode(uint code) :
_what ("Invalid event code " + std::to_string(code))
{
_what("Invalid event code " + std::to_string(code)) {
}
const char* InputDevice::InvalidEventCode::what() const noexcept
{
const char* InputDevice::InvalidEventCode::what() const noexcept {
return _what.c_str();
}
InputDevice::InputDevice(const char* name)
{
InputDevice::InputDevice(const char* name) {
device = libevdev_new();
libevdev_set_name(device, name);
@ -61,30 +57,28 @@ InputDevice::InputDevice(const char* name)
}
}
for (unsigned int i = 0; i < REL_CNT; i++)
registered_axis[i] = false;
for (bool& axis: registered_axis)
axis = false;
libevdev_enable_event_type(device, EV_REL);
int err = libevdev_uinput_create_from_device(device,
LIBEVDEV_UINPUT_OPEN_MANAGED, &ui_device);
LIBEVDEV_UINPUT_OPEN_MANAGED, &ui_device);
if(err != 0) {
if (err != 0) {
libevdev_free(device);
throw std::system_error(-err, std::generic_category());
}
}
InputDevice::~InputDevice()
{
InputDevice::~InputDevice() {
libevdev_uinput_destroy(ui_device);
libevdev_free(device);
}
void InputDevice::registerKey(uint code)
{
void InputDevice::registerKey(uint code) {
// TODO: Maybe print error message, if wrong code is passed?
if(code >= KEY_CNT || registered_keys[code]) {
if (code >= KEY_CNT || registered_keys[code]) {
return;
}
@ -93,10 +87,9 @@ void InputDevice::registerKey(uint code)
registered_keys[code] = true;
}
void InputDevice::registerAxis(uint axis)
{
void InputDevice::registerAxis(uint axis) {
// TODO: Maybe print error message, if wrong code is passed?
if(axis >= REL_CNT || registered_axis[axis]) {
if (axis >= REL_CNT || registered_axis[axis]) {
return;
}
@ -105,87 +98,76 @@ void InputDevice::registerAxis(uint axis)
registered_axis[axis] = true;
}
void InputDevice::moveAxis(uint axis, int movement)
{
void InputDevice::moveAxis(uint axis, int movement) {
_sendEvent(EV_REL, axis, movement);
}
void InputDevice::pressKey(uint code)
{
void InputDevice::pressKey(uint code) {
_sendEvent(EV_KEY, code, 1);
}
void InputDevice::releaseKey(uint code)
{
void InputDevice::releaseKey(uint code) {
_sendEvent(EV_KEY, code, 0);
}
std::string InputDevice::toKeyName(uint code)
{
std::string InputDevice::toKeyName(uint code) {
return _toEventName(EV_KEY, code);
}
uint InputDevice::toKeyCode(const std::string& name)
{
uint InputDevice::toKeyCode(const std::string& name) {
return _toEventCode(EV_KEY, name);
}
std::string InputDevice::toAxisName(uint code)
{
std::string InputDevice::toAxisName(uint code) {
return _toEventName(EV_REL, code);
}
uint InputDevice::toAxisCode(const std::string& name)
{
uint InputDevice::toAxisCode(const std::string& name) {
return _toEventCode(EV_REL, name);
}
/* Returns -1 if axis_code is not hi-res */
int InputDevice::getLowResAxis(const uint axis_code)
{
int InputDevice::getLowResAxis(const uint axis_code) {
/* Some systems don't have these hi-res axes */
#ifdef REL_WHEEL_HI_RES
if(axis_code == REL_WHEEL_HI_RES)
if (axis_code == REL_WHEEL_HI_RES)
return REL_WHEEL;
#endif
#ifdef REL_HWHEEL_HI_RES
if(axis_code == REL_HWHEEL_HI_RES)
if (axis_code == REL_HWHEEL_HI_RES)
return REL_HWHEEL;
#endif
return -1;
}
std::string InputDevice::_toEventName(uint type, uint code)
{
std::string InputDevice::_toEventName(uint type, uint code) {
const char* ret = libevdev_event_code_get_name(type, code);
if(!ret)
if (!ret)
throw InvalidEventCode(code);
return {ret};
}
uint InputDevice::_toEventCode(uint type, const std::string& name)
{
uint InputDevice::_toEventCode(uint type, const std::string& name) {
int code = libevdev_event_code_from_name(type, name.c_str());
if(code == -1)
if (code == -1)
throw InvalidEventCode(name);
return code;
}
void InputDevice::_enableEvent(const uint type, const uint code)
{
void InputDevice::_enableEvent(const uint type, const uint code) {
libevdev_uinput_destroy(ui_device);
libevdev_enable_event_code(device, type, code, nullptr);
int err = libevdev_uinput_create_from_device(device,
LIBEVDEV_UINPUT_OPEN_MANAGED, &ui_device);
LIBEVDEV_UINPUT_OPEN_MANAGED, &ui_device);
if(err != 0) {
if (err != 0) {
libevdev_free(device);
device = nullptr;
ui_device = nullptr;
@ -193,8 +175,7 @@ void InputDevice::_enableEvent(const uint type, const uint code)
}
}
void InputDevice::_sendEvent(uint type, uint code, int value)
{
void InputDevice::_sendEvent(uint type, uint code, int value) {
libevdev_uinput_write_event(ui_device, type, code, value);
libevdev_uinput_write_event(ui_device, EV_SYN, SYN_REPORT, 0);
}

View File

@ -28,44 +28,56 @@ extern "C"
#include <libevdev/libevdev-uinput.h>
}
namespace logid
{
class InputDevice
{
namespace logid {
class InputDevice {
public:
class InvalidEventCode : public std::exception
{
class InvalidEventCode : public std::exception {
public:
explicit InvalidEventCode(const std::string& name);
explicit InvalidEventCode(uint code);
const char* what() const noexcept override;
private:
const std::string _what;
};
explicit InputDevice(const char *name);
explicit InputDevice(const char* name);
~InputDevice();
void registerKey(uint code);
void registerAxis(uint axis);
void moveAxis(uint axis, int movement);
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);
private:
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];
bool registered_axis[REL_CNT];
bool registered_keys[KEY_CNT]{};
bool registered_axis[REL_CNT]{};
libevdev* device;
libevdev_uinput* ui_device{};
};

View File

@ -28,34 +28,32 @@ using namespace logid::backend;
ReceiverNickname::ReceiverNickname(
const std::shared_ptr<DeviceManager>& manager) :
_nickname (manager->newReceiverNickname()), _manager (manager)
{
_nickname(manager->newReceiverNickname()), _manager(manager) {
}
ReceiverNickname::operator std::string() const {
return std::to_string(_nickname);
}
ReceiverNickname::~ReceiverNickname()
{
if(auto manager = _manager.lock()) {
ReceiverNickname::~ReceiverNickname() {
if (auto manager = _manager.lock()) {
std::lock_guard<std::mutex> lock(manager->_nick_lock);
manager->_receiver_nicknames.erase(_nickname);
}
}
namespace logid {
class _Receiver : public Receiver {
class ReceiverWrapper : public Receiver {
public:
template <typename... Args>
_Receiver(Args... args) : Receiver(std::forward<Args>(args)...) { }
template<typename... Args>
explicit ReceiverWrapper(Args... args) : Receiver(std::forward<Args>(args)...) {}
};
}
std::shared_ptr<Receiver> Receiver::make(
const std::string &path,
const std::shared_ptr<DeviceManager> &manager) {
auto ret = std::make_shared<_Receiver>(path, manager);
const std::string& path,
const std::shared_ptr<DeviceManager>& manager) {
auto ret = std::make_shared<ReceiverWrapper>(path, manager);
ret->_self = ret;
ret->_ipc_node->manage(ret);
return ret;
@ -64,13 +62,12 @@ std::shared_ptr<Receiver> Receiver::make(
Receiver::Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager) :
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<ReceiverIPC>(this))
{
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<ReceiverIPC>(this)) {
ready();
}
@ -78,20 +75,18 @@ const Receiver::DeviceList& Receiver::devices() const {
return _devices;
}
Receiver::~Receiver()
{
if(auto manager = _manager.lock()) {
for(auto& d : _devices)
Receiver::~Receiver() noexcept {
if (auto manager = _manager.lock()) {
for (auto& d: _devices)
manager->removeExternalDevice(d.second);
}
}
void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
{
void Receiver::addDevice(hidpp::DeviceConnectionEvent event) {
std::unique_lock<std::mutex> lock(_devices_change);
auto manager = _manager.lock();
if(!manager) {
if (!manager) {
logPrintf(ERROR, "Orphan Receiver, missing DeviceManager");
logPrintf(ERROR,
"Fatal error, file a bug report. Program will now exit.");
@ -100,7 +95,7 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
try {
// Check if device is ignored before continuing
if(manager->config()->ignore.value_or(
if (manager->config()->ignore.value_or(
std::set<uint16_t>()).contains(event.pid)) {
logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.",
_path.c_str(), event.index, event.pid);
@ -108,15 +103,15 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
}
auto dev = _devices.find(event.index);
if(dev != _devices.end()) {
if(event.linkEstablished)
if (dev != _devices.end()) {
if (event.linkEstablished)
dev->second->wakeup();
else
dev->second->sleep();
return;
}
if(!event.linkEstablished)
if (!event.linkEstablished)
return;
hidpp::Device hidpp_device(
@ -125,9 +120,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
auto version = hidpp_device.version();
if(std::get<0>(version) < 2) {
if (std::get<0>(version) < 2) {
logPrintf(INFO, "Unsupported HID++ 1.0 device on %s:%d connected.",
_path.c_str(), event.index);
_path.c_str(), event.index);
return;
}
@ -136,46 +131,42 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
_devices.emplace(event.index, device);
manager->addExternalDevice(device);
} catch(hidpp10::Error &e) {
} catch (hidpp10::Error& e) {
logPrintf(ERROR,
"Caught HID++ 1.0 error while trying to initialize "
"%s:%d: %s", _path.c_str(), event.index, e.what());
} catch(hidpp20::Error &e) {
"Caught HID++ 1.0 error while trying to initialize "
"%s:%d: %s", _path.c_str(), event.index, e.what());
} catch (hidpp20::Error& e) {
logPrintf(ERROR, "Caught HID++ 2.0 error while trying to initialize "
"%s:%d: %s", _path.c_str(), event.index, e.what());
} catch(TimeoutError &e) {
if(!event.fromTimeoutCheck)
"%s:%d: %s", _path.c_str(), event.index, e.what());
} catch (TimeoutError& e) {
if (!event.fromTimeoutCheck)
logPrintf(DEBUG, "%s:%d timed out, waiting for input from device to"
" initialize.", _path.c_str(), event.index);
waitForDevice(event.index);
}
}
void Receiver::removeDevice(hidpp::DeviceIndex index)
{
void Receiver::removeDevice(hidpp::DeviceIndex index) {
std::unique_lock<std::mutex> lock(_devices_change);
std::unique_lock<std::mutex> manager_lock;
if(auto manager = _manager.lock())
if (auto manager = _manager.lock())
manager_lock = std::unique_lock<std::mutex>(manager->mutex());
auto device = _devices.find(index);
if(device != _devices.end()) {
if(auto manager = _manager.lock())
if (device != _devices.end()) {
if (auto manager = _manager.lock())
manager->removeExternalDevice(device->second);
_devices.erase(device);
}
}
const std::string& Receiver::path() const
{
const std::string& Receiver::path() const {
return _path;
}
std::shared_ptr<dj::Receiver> Receiver::rawReceiver()
{
std::shared_ptr<dj::Receiver> Receiver::rawReceiver() {
return receiver();
}
Receiver::ReceiverIPC::ReceiverIPC(Receiver *receiver) :
ipcgull::interface("pizza.pixl.LogiOps.Receiver", {}, {}, {})
{
Receiver::ReceiverIPC::ReceiverIPC(Receiver* receiver) :
ipcgull::interface("pizza.pixl.LogiOps.Receiver", {}, {}, {}) {
}

View File

@ -23,42 +23,49 @@
#include "backend/dj/ReceiverMonitor.h"
#include "Device.h"
namespace logid
{
namespace logid {
class ReceiverNickname {
public:
explicit ReceiverNickname(const std::shared_ptr<DeviceManager>& manager);
ReceiverNickname() = delete;
ReceiverNickname(const ReceiverNickname&) = delete;
~ReceiverNickname();
operator std::string() const;
private:
const int _nickname;
const std::weak_ptr<DeviceManager> _manager;
};
class Receiver : public backend::dj::ReceiverMonitor,
public ipcgull::object
{
public ipcgull::object {
public:
typedef std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>>
DeviceList;
DeviceList;
~Receiver();
~Receiver() noexcept override;
static std::shared_ptr<Receiver> make(
const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
const std::string& path() const;
[[nodiscard]] const std::string& path() const;
std::shared_ptr<backend::dj::Receiver> rawReceiver();
[[nodiscard]] const DeviceList& devices() const;
protected:
void addDevice(backend::hidpp::DeviceConnectionEvent event) override;
void removeDevice(backend::hidpp::DeviceIndex index) override;
private:
friend class _Receiver;
friend class ReceiverWrapper;
Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
@ -73,7 +80,7 @@ namespace logid
class ReceiverIPC : public ipcgull::interface {
public:
ReceiverIPC(Receiver* receiver);
explicit ReceiverIPC(Receiver* receiver);
};
std::shared_ptr<ipcgull::interface> _ipc_interface;

View File

@ -30,73 +30,73 @@
using namespace logid;
using namespace logid::actions;
template <typename T>
struct action_type {
typedef typename T::action type;
};
namespace logid::actions {
template<typename T>
struct action_type {
typedef typename T::action type;
};
template <typename T>
struct action_type<const T> : action_type<T> { };
template<typename T>
struct action_type<const T> : action_type<T> {
};
template <typename T>
struct action_type<T&> : action_type<T> { };
template<typename T>
struct action_type<T&> : action_type<T> {
};
template <typename T>
std::shared_ptr<Action> _makeAction(
Device* device, T& action,
const std::shared_ptr<ipcgull::node>& parent)
{
return parent->make_interface<typename action_type<T>::type>(
device, std::forward<T&>(action), parent);
}
template <typename T>
std::shared_ptr<Action> _makeAction(
Device *device, const std::string &name,
std::optional<T>& config,
const std::shared_ptr<ipcgull::node>& parent)
{
if(name == ChangeDPI::interface_name) {
config = config::ChangeDPI();
} else if(name == ChangeHostAction::interface_name) {
config = config::ChangeHost();
} else if(name == CycleDPI::interface_name) {
config = config::CycleDPI();
} else if(name == KeypressAction::interface_name) {
config = config::KeypressAction();
} else if(name == NullAction::interface_name) {
config = config::NoAction();
} else if(name == ChangeHostAction::interface_name) {
config = config::ChangeHost();
} else if(name == ToggleHiresScroll::interface_name) {
config = config::ToggleHiresScroll();
} else if(name == ToggleSmartShift::interface_name) {
config = config::ToggleHiresScroll();
} else if(name == "Default") {
config.reset();
return nullptr;
template<typename T>
std::shared_ptr<Action> _makeAction(
Device* device, T& action,
const std::shared_ptr<ipcgull::node>& parent) {
return parent->make_interface<typename action_type<T>::type>(
device, std::forward<T&>(action), parent);
}
return Action::makeAction(device, config.value(), parent);
template<typename T>
std::shared_ptr<Action> _makeAction(
Device* device, const std::string& name,
std::optional<T>& config,
const std::shared_ptr<ipcgull::node>& parent) {
if (name == ChangeDPI::interface_name) {
config = config::ChangeDPI();
} else if (name == CycleDPI::interface_name) {
config = config::CycleDPI();
} else if (name == KeypressAction::interface_name) {
config = config::KeypressAction();
} else if (name == NullAction::interface_name) {
config = config::NoAction();
} else if (name == ChangeHostAction::interface_name) {
config = config::ChangeHost();
} else if (name == ToggleHiresScroll::interface_name) {
config = config::ToggleHiresScroll();
} else if (name == ToggleSmartShift::interface_name) {
config = config::ToggleSmartShift();
} else if (name == "Default") {
config.reset();
return nullptr;
} else {
throw InvalidAction(name);
}
return Action::makeAction(device, config.value(), parent);
}
}
std::shared_ptr<Action> Action::makeAction(
Device *device, const std::string &name,
std::optional<config::BasicAction> &config,
const std::shared_ptr<ipcgull::node>& parent)
{
Device* device, const std::string& name,
std::optional<config::BasicAction>& config,
const std::shared_ptr<ipcgull::node>& parent) {
return _makeAction(device, name, config, parent);
}
std::shared_ptr<Action> Action::makeAction(
Device *device, const std::string &name,
std::optional<config::Action> &config,
const std::shared_ptr<ipcgull::node>& parent)
{
Device* device, const std::string& name,
std::optional<config::Action>& config,
const std::shared_ptr<ipcgull::node>& parent) {
try {
return _makeAction(device, name, config, parent);
} catch(actions::InvalidAction& e) {
if(name == GestureAction::interface_name) {
} catch (actions::InvalidAction& e) {
if (name == GestureAction::interface_name) {
config = config::GestureAction();
return makeAction(device, config.value(), parent);
}
@ -105,9 +105,8 @@ std::shared_ptr<Action> Action::makeAction(
}
std::shared_ptr<Action> Action::makeAction(
Device *device, config::BasicAction& action,
const std::shared_ptr<ipcgull::node>& parent)
{
Device* device, config::BasicAction& action,
const std::shared_ptr<ipcgull::node>& parent) {
std::shared_ptr<Action> ret;
std::visit([&device, &ret, &parent](auto&& x) {
ret = _makeAction(device, x, parent);
@ -116,9 +115,8 @@ std::shared_ptr<Action> Action::makeAction(
}
std::shared_ptr<Action> Action::makeAction(
Device *device, config::Action& action,
const std::shared_ptr<ipcgull::node>& parent)
{
Device* device, config::Action& action,
const std::shared_ptr<ipcgull::node>& parent) {
std::shared_ptr<Action> ret;
std::visit([&device, &ret, &parent](auto&& x) {
ret = _makeAction(device, x, parent);
@ -127,7 +125,6 @@ std::shared_ptr<Action> Action::makeAction(
}
Action::Action(Device* device, const std::string& name, tables t) :
ipcgull::interface("pizza.pixl.LogiOps.Action." + name, std::move(t)),
_device (device), _pressed (false)
{
ipcgull::interface("pizza.pixl.LogiOps.Action." + name, std::move(t)),
_device(device), _pressed(false) {
}

View File

@ -21,32 +21,31 @@
#include <atomic>
#include <libconfig.h++>
#include <memory>
#include <utility>
#include <ipcgull/node.h>
#include <ipcgull/interface.h>
#include "../config/schema.h"
namespace logid {
class Device;
namespace actions {
class InvalidAction : public std::exception
{
}
namespace logid::actions {
class InvalidAction : public std::exception {
public:
InvalidAction()
{
}
explicit InvalidAction(std::string& action) : _action (action)
{
}
const char* what() const noexcept override
{
InvalidAction() = default;
InvalidAction(std::string action) : _action(std::move(action)) {}
[[nodiscard]] const char* what() const noexcept override {
return _action.c_str();
}
private:
std::string _action;
};
class Action : public ipcgull::interface
{
class Action : public ipcgull::interface {
public:
static std::shared_ptr<Action> makeAction(
Device* device, const std::string& name,
@ -67,28 +66,29 @@ namespace actions {
const std::shared_ptr<ipcgull::node>& parent);
virtual void press() = 0;
virtual void release() = 0;
virtual void move(int16_t x, int16_t y)
{
virtual void move(int16_t x, int16_t y) {
// Suppress unused warning
(void)x; (void)y;
(void) x;
(void) y;
}
virtual bool pressed()
{
virtual bool pressed() {
return _pressed;
}
virtual uint8_t reprogFlags() const = 0;
[[nodiscard]] virtual uint8_t reprogFlags() const = 0;
virtual ~Action() = default;
protected:
Action(Device* device, const std::string& name, tables t={});
Action(Device* device, const std::string& name, tables t = {});
Device* _device;
std::atomic<bool> _pressed;
};
}}
}
#endif //LOGID_ACTION_H

View File

@ -25,35 +25,33 @@ using namespace logid::actions;
const char* ChangeDPI::interface_name = "ChangeDPI";
ChangeDPI::ChangeDPI(
Device *device, config::ChangeDPI& config,
Device* device, config::ChangeDPI& config,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action(device, interface_name, {
{
{"GetConfig", {this, &ChangeDPI::getConfig, {"change", "sensor"}}},
{"SetChange", {this, &ChangeDPI::setChange, {"change"}}},
{"SetSensor", {this, &ChangeDPI::setSensor, {"sensor", "reset"}}},
}, {}, {} }), _config (config)
{
Action(device, interface_name, {
{
{"GetConfig", {this, &ChangeDPI::getConfig, {"change", "sensor"}}},
{"SetChange", {this, &ChangeDPI::setChange, {"change"}}},
{"SetSensor", {this, &ChangeDPI::setSensor, {"sensor", "reset"}}},
},
{},
{}}), _config(config) {
_dpi = _device->getFeature<features::DPI>("dpi");
if(!_dpi)
if (!_dpi)
logPrintf(WARN, "%s:%d: DPI feature not found, cannot use "
"ChangeDPI action.",
_device->hidpp20().devicePath().c_str(),
_device->hidpp20().deviceIndex());
}
std::tuple<int16_t, uint16_t> ChangeDPI::getConfig() const
{
std::tuple<int16_t, uint16_t> ChangeDPI::getConfig() const {
return {_config.inc.value_or(0), _config.sensor.value_or(0)};
}
void ChangeDPI::setChange(int16_t change)
{
void ChangeDPI::setChange(int16_t change) {
_config.inc = change;
}
void ChangeDPI::setSensor(uint8_t sensor, bool reset)
{
void ChangeDPI::setSensor(uint8_t sensor, bool reset) {
if (reset) {
_config.sensor.reset();
} else {
@ -61,36 +59,33 @@ void ChangeDPI::setSensor(uint8_t sensor, bool reset)
}
}
void ChangeDPI::press()
{
void ChangeDPI::press() {
_pressed = true;
if(_dpi && _config.inc.has_value()) {
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.value(),
_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.value_or(0));
else
throw e;
}
});
[this] {
try {
uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0));
_dpi->setDPI(last_dpi + _config.inc.value(),
_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.value_or(0));
else
throw e;
}
});
}
}
void ChangeDPI::release()
{
void ChangeDPI::release() {
_pressed = false;
}
uint8_t ChangeDPI::reprogFlags() const
{
uint8_t ChangeDPI::reprogFlags() const {
return backend::hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -23,27 +23,29 @@
#include "../features/DPI.h"
namespace logid::actions {
class ChangeDPI : public Action
{
public:
static const char* interface_name;
class ChangeDPI : public Action {
public:
static const char* interface_name;
ChangeDPI(Device* device, config::ChangeDPI& setting,
const std::shared_ptr<ipcgull::node>& parent);
ChangeDPI(Device* device, config::ChangeDPI& setting,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press();
virtual void release();
void press() final;
[[nodiscard]] std::tuple<int16_t, uint16_t> getConfig() const;
void setChange(int16_t change);
void setSensor(uint8_t sensor, bool reset);
void release() final;
virtual uint8_t reprogFlags() const;
[[nodiscard]] std::tuple<int16_t, uint16_t> getConfig() const;
protected:
config::ChangeDPI& _config;
std::shared_ptr<features::DPI> _dpi;
};
}
void setChange(int16_t change);
void setSensor(uint8_t sensor, bool reset);
[[nodiscard]] uint8_t reprogFlags() const final;
protected:
config::ChangeDPI& _config;
std::shared_ptr<features::DPI> _dpi;
};
}
#endif //LOGID_ACTION_CHANGEDPI_H

View File

@ -27,17 +27,18 @@ using namespace logid::backend;
const char* ChangeHostAction::interface_name = "ChangeHost";
ChangeHostAction::ChangeHostAction(
Device *device, config::ChangeHost& config,
Device* device, config::ChangeHost& config,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent)
: Action(device, interface_name, {
: Action(device, interface_name, {
{
{"GetHost", {this, &ChangeHostAction::getHost, {"host"}}},
{"SetHost", {this, &ChangeHostAction::setHost, {"host"}}}
}, {}, {}
}), _config (config)
{
},
{},
{}
}), _config(config) {
if (_config.host.has_value()) {
if(std::holds_alternative<std::string>(_config.host.value())) {
if (std::holds_alternative<std::string>(_config.host.value())) {
auto& host = std::get<std::string>(_config.host.value());
std::transform(host.begin(), host.end(),
host.begin(), ::tolower);
@ -48,13 +49,12 @@ ChangeHostAction::ChangeHostAction(
} catch (hidpp20::UnsupportedFeature& e) {
logPrintf(WARN, "%s:%d: ChangeHost feature not supported, "
"ChangeHostAction will not work.", device->hidpp20()
.devicePath().c_str(), device->hidpp20().deviceIndex());
.devicePath().c_str(), device->hidpp20().deviceIndex());
}
}
std::string ChangeHostAction::getHost() const
{
if(_config.host.has_value()) {
std::string ChangeHostAction::getHost() const {
if (_config.host.has_value()) {
if (std::holds_alternative<std::string>(_config.host.value()))
return std::get<std::string>(_config.host.value());
else
@ -64,8 +64,7 @@ std::string ChangeHostAction::getHost() const
}
}
void ChangeHostAction::setHost(std::string host)
{
void ChangeHostAction::setHost(std::string host) {
std::transform(host.begin(), host.end(),
host.begin(), ::tolower);
if (host == "next" || host == "prev" || host == "previous") {
@ -75,37 +74,34 @@ void ChangeHostAction::setHost(std::string host)
}
}
void ChangeHostAction::press()
{
void ChangeHostAction::press() {
// Do nothing, wait until release
}
void ChangeHostAction::release()
{
if(_change_host && _config.host.has_value()) {
void ChangeHostAction::release() {
if (_change_host && _config.host.has_value()) {
spawn_task(
[this] {
auto host_info = _change_host->getHostInfo();
int next_host;
if(std::holds_alternative<std::string>(_config.host.value())) {
const auto& host = std::get<std::string>(_config.host.value());
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<int>(_config.host.value())-1;
}
next_host %= host_info.hostCount;
if(next_host != host_info.currentHost)
_change_host->setHost(next_host);
});
[this] {
auto host_info = _change_host->getHostInfo();
int next_host;
if (std::holds_alternative<std::string>(_config.host.value())) {
const auto& host = std::get<std::string>(_config.host.value());
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<int>(_config.host.value()) - 1;
}
next_host %= host_info.hostCount;
if (next_host != host_info.currentHost)
_change_host->setHost(next_host);
});
}
}
uint8_t ChangeHostAction::reprogFlags() const
{
uint8_t ChangeHostAction::reprogFlags() const {
return hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -22,24 +22,23 @@
#include "Action.h"
#include "../backend/hidpp20/features/ChangeHost.h"
namespace logid::actions
{
class ChangeHostAction : public Action
{
namespace logid::actions {
class ChangeHostAction : public Action {
public:
static const char* interface_name;
ChangeHostAction(Device* device, config::ChangeHost& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press();
virtual void release();
void press() final;
void release() final;
[[nodiscard]] std::string getHost() const;
void setHost(std::string host);
virtual uint8_t reprogFlags() const;
[[nodiscard]] uint8_t reprogFlags() const final;
protected:
std::shared_ptr<backend::hidpp20::ChangeHost> _change_host;

View File

@ -18,8 +18,6 @@
#include "CycleDPI.h"
#include "../Device.h"
#include "../util/task.h"
#include "../util/log.h"
#include "../backend/hidpp20/Error.h"
#include "../backend/hidpp20/features/ReprogControls.h"
using namespace logid::actions;
@ -29,53 +27,51 @@ const char* CycleDPI::interface_name = "CycleDPI";
CycleDPI::CycleDPI(Device* device, config::CycleDPI& config,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action (device, interface_name, {
{
{"GetDPIs", {this, &CycleDPI::getDPIs, {"dpis"}}},
{"SetDPIs", {this, &CycleDPI::setDPIs, {"dpis"}}}
}, {}, {}
}),
_config (config)
{
Action(device, interface_name, {
{
{"GetDPIs", {this, &CycleDPI::getDPIs, {"dpis"}}},
{"SetDPIs", {this, &CycleDPI::setDPIs, {"dpis"}}}
},
{},
{}
}),
_config(config) {
_dpi = _device->getFeature<features::DPI>("dpi");
if(!_dpi)
if (!_dpi)
logPrintf(WARN, "%s:%d: DPI feature not found, cannot use "
"CycleDPI action.",
_device->hidpp20().devicePath().c_str(),
_device->hidpp20().deviceIndex());
if(_config.dpis.has_value()) {
_current_dpi = _config.dpis.value().begin();
if (_config.dpis.has_value()) {
_current_dpi = _config.dpis.value().begin();
}
}
std::vector<int> CycleDPI::getDPIs() const
{
std::vector<int> CycleDPI::getDPIs() const {
auto dpis = _config.dpis.value_or(std::list<int>());
return {dpis.begin(), dpis.end()};
}
void CycleDPI::setDPIs(const std::vector<int>& dpis)
{
void CycleDPI::setDPIs(const std::vector<int>& dpis) {
std::lock_guard<std::mutex> lock(_dpi_lock);
_config.dpis.emplace(dpis.begin(), dpis.end());
_current_dpi = _config.dpis->cbegin();
}
void CycleDPI::press()
{
void CycleDPI::press() {
_pressed = true;
std::lock_guard<std::mutex> lock(_dpi_lock);
if(_dpi && _config.dpis.has_value() && _config.dpis.value().empty()) {
if (_dpi && _config.dpis.has_value() && _config.dpis.value().empty()) {
++_current_dpi;
if(_current_dpi == _config.dpis.value().end())
if (_current_dpi == _config.dpis.value().end())
_current_dpi = _config.dpis.value().begin();
spawn_task([this, dpi=*_current_dpi]{
spawn_task([this, dpi = *_current_dpi] {
try {
_dpi->setDPI(dpi, _config.sensor.value_or(0));
} catch (backend::hidpp20::Error& e) {
if(e.code() == backend::hidpp20::Error::InvalidArgument)
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,
@ -87,12 +83,10 @@ void CycleDPI::press()
}
}
void CycleDPI::release()
{
void CycleDPI::release() {
_pressed = false;
}
uint8_t CycleDPI::reprogFlags() const
{
uint8_t CycleDPI::reprogFlags() const {
return backend::hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -23,21 +23,22 @@
#include "../features/DPI.h"
namespace logid::actions {
class CycleDPI : public Action
{
class CycleDPI : public Action {
public:
static const char* interface_name;
CycleDPI(Device* device, config::CycleDPI& setting,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press();
virtual void release();
void press() final;
void release() final;
[[nodiscard]] std::vector<int> getDPIs() const;
void setDPIs(const std::vector<int>& dpis);
virtual uint8_t reprogFlags() const;
[[nodiscard]] uint8_t reprogFlags() const final;
protected:
std::mutex _dpi_lock;

View File

@ -26,50 +26,47 @@ using namespace logid::backend;
const char* GestureAction::interface_name = "Gesture";
GestureAction::Direction GestureAction::toDirection(std::string direction)
{
GestureAction::Direction GestureAction::toDirection(std::string direction) {
std::transform(direction.begin(), direction.end(), direction.begin(),
::tolower);
if(direction == "up")
::tolower);
if (direction == "up")
return Up;
else if(direction == "down")
else if (direction == "down")
return Down;
else if(direction == "left")
else if (direction == "left")
return Left;
else if(direction == "right")
else if (direction == "right")
return Right;
else if(direction == "none")
else if (direction == "none")
return None;
else
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";
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)
GestureAction::Direction GestureAction::toDirection(int32_t x, int32_t y) {
if (x >= 0 && y >= 0)
return x >= y ? Right : Down;
else if(x < 0 && y >= 0)
else if (x < 0 && y >= 0)
return -x <= y ? Down : Left;
else if(x <= 0 && y < 0)
else if (x <= 0 /* && y < 0 */)
return x <= y ? Left : Up;
else
return x <= -y ? Up : Right;
@ -77,18 +74,19 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y)
GestureAction::GestureAction(Device* dev, config::GestureAction& config,
const std::shared_ptr<ipcgull::node>& parent) :
Action (dev, interface_name,
{
{
{"SetGesture", {this, &GestureAction::setGesture,
{"direction", "type"}}}
}, {}, {}
}),
_node (parent->make_child("gestures")), _config (config)
{
if(_config.gestures.has_value()) {
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();
for(auto& x : gestures) {
for (auto& x: gestures) {
try {
auto direction = toDirection(x.first);
_gestures.emplace(direction,
@ -96,25 +94,23 @@ GestureAction::GestureAction(Device* dev, config::GestureAction& config,
dev, x.second,
_node->make_child(
fromDirection(direction))));
} catch(std::invalid_argument& e) {
} catch (std::invalid_argument& e) {
logPrintf(WARN, "%s is not a direction", x.first.c_str());
}
}
}
}
void GestureAction::press()
{
void GestureAction::press() {
std::lock_guard<std::mutex> lock(_config_lock);
_pressed = true;
_x = 0, _y = 0;
for(auto& gesture : _gestures)
gesture.second->press();
for (auto& gesture: _gestures)
gesture.second->press(false);
}
void GestureAction::release()
{
void GestureAction::release() {
std::lock_guard<std::mutex> lock(_config_lock);
_pressed = false;
@ -122,16 +118,16 @@ void GestureAction::release()
auto d = toDirection(_x, _y);
auto primary_gesture = _gestures.find(d);
if(primary_gesture != _gestures.end()) {
if (primary_gesture != _gestures.end()) {
threshold_met = primary_gesture->second->metThreshold();
primary_gesture->second->release(true);
}
for(auto& gesture : _gestures) {
if(gesture.first == d)
for (auto& gesture: _gestures) {
if (gesture.first == d)
continue;
if(!threshold_met) {
if(gesture.second->metThreshold()) {
if (!threshold_met) {
if (gesture.second->metThreshold()) {
// If the primary gesture did not meet its threshold, use the
// secondary one.
threshold_met = true;
@ -143,105 +139,103 @@ void GestureAction::release()
}
}
if(!threshold_met) {
if (!threshold_met) {
try {
auto none = _gestures.at(None);
if(none) {
none->press();
none->release();
if (none) {
none->press(false);
none->release(false);
}
} catch(std::out_of_range& e) { }
} catch (std::out_of_range& e) {}
}
}
void GestureAction::move(int16_t x, int16_t y)
{
void GestureAction::move(int16_t x, int16_t y) {
std::lock_guard<std::mutex> lock(_config_lock);
auto new_x = _x + x, new_y = _y + y;
int32_t new_x = _x + x, new_y = _y + y;
if(abs(x) > 0) {
if(_x < 0 && new_x >= 0) { // Left -> Origin/Right
if (abs(x) > 0) {
if (_x < 0 && new_x >= 0) { // Left -> Origin/Right
auto left = _gestures.find(Left);
if(left != _gestures.end() && left->second)
left->second->move(_x);
if(new_x) { // Ignore to origin
if (left != _gestures.end() && left->second)
left->second->move((int16_t) _x);
if (new_x) { // Ignore to origin
auto right = _gestures.find(Right);
if(right != _gestures.end() && right->second)
right->second->move(new_x);
if (right != _gestures.end() && right->second)
right->second->move((int16_t) new_x);
}
} else if(_x > 0 && new_x <= 0) { // Right -> Origin/Left
} else if (_x > 0 && new_x <= 0) { // Right -> Origin/Left
auto right = _gestures.find(Right);
if(right != _gestures.end() && right->second)
right->second->move(-_x);
if(new_x) { // Ignore to origin
if (right != _gestures.end() && right->second)
right->second->move((int16_t) -_x);
if (new_x) { // Ignore to origin
auto left = _gestures.find(Left);
if(left != _gestures.end() && left->second)
left->second->move(-new_x);
if (left != _gestures.end() && left->second)
left->second->move((int16_t) -new_x);
}
} else if(new_x < 0) { // Origin/Left to Left
} else if (new_x < 0) { // Origin/Left to Left
auto left = _gestures.find(Left);
if(left != _gestures.end() && left->second)
left->second->move(-x);
} else if(new_x > 0) { // Origin/Right to Right
if (left != _gestures.end() && left->second)
left->second->move((int16_t) -x);
} else if (new_x > 0) { // Origin/Right to Right
auto right = _gestures.find(Right);
if(right != _gestures.end() && right->second)
if (right != _gestures.end() && right->second)
right->second->move(x);
}
}
if(abs(y) > 0) {
if(_y > 0 && new_y <= 0) { // Up -> Origin/Down
if (abs(y) > 0) {
if (_y > 0 && new_y <= 0) { // Up -> Origin/Down
auto up = _gestures.find(Up);
if(up != _gestures.end() && up->second)
up->second->move(_y);
if(new_y) { // Ignore to origin
if (up != _gestures.end() && up->second)
up->second->move((int16_t) _y);
if (new_y) { // Ignore to origin
auto down = _gestures.find(Down);
if(down != _gestures.end() && down->second)
down->second->move(new_y);
if (down != _gestures.end() && down->second)
down->second->move((int16_t) new_y);
}
} else if(_y < 0 && new_y >= 0) { // Down -> Origin/Up
} else if (_y < 0 && new_y >= 0) { // Down -> Origin/Up
auto down = _gestures.find(Down);
if(down != _gestures.end() && down->second)
down->second->move(-_y);
if(new_y) { // Ignore to origin
if (down != _gestures.end() && down->second)
down->second->move((int16_t) -_y);
if (new_y) { // Ignore to origin
auto up = _gestures.find(Up);
if(up != _gestures.end() && up->second)
up->second->move(-new_y);
if (up != _gestures.end() && up->second)
up->second->move((int16_t) -new_y);
}
} else if(new_y < 0) { // Origin/Up to Up
} else if (new_y < 0) { // Origin/Up to Up
auto up = _gestures.find(Up);
if(up != _gestures.end() && up->second)
up->second->move(-y);
} else if(new_y > 0) {// Origin/Down to Down
if (up != _gestures.end() && up->second)
up->second->move((int16_t) -y);
} else if (new_y > 0) {// Origin/Down to Down
auto down = _gestures.find(Down);
if(down != _gestures.end() && down->second)
if (down != _gestures.end() && down->second)
down->second->move(y);
}
}
_x = new_x; _y = new_y;
_x = new_x;
_y = new_y;
}
uint8_t GestureAction::reprogFlags() const
{
uint8_t GestureAction::reprogFlags() const {
return (hidpp20::ReprogControls::TemporaryDiverted |
hidpp20::ReprogControls::RawXYDiverted);
hidpp20::ReprogControls::RawXYDiverted);
}
void GestureAction::setGesture(const std::string &direction,
const std::string &type)
{
void GestureAction::setGesture(const std::string& direction,
const std::string& type) {
std::lock_guard<std::mutex> lock(_config_lock);
Direction d = toDirection(direction);
auto it = _gestures.find(d);
if(it != _gestures.end()) {
if(pressed()) {
if (it != _gestures.end()) {
if (pressed()) {
auto current = toDirection(_x, _y);
if(it->second)
if (it->second)
it->second->release(current == d);
}
}

View File

@ -23,43 +23,46 @@
#include "Action.h"
#include "gesture/Gesture.h"
namespace logid {
namespace actions {
class GestureAction : public Action
{
namespace logid::actions {
class GestureAction : public Action {
public:
static const char* interface_name;
enum Direction
{
enum Direction {
None,
Up,
Down,
Left,
Right
};
static Direction toDirection(std::string direction);
static std::string fromDirection(Direction direction);
static Direction toDirection(int16_t x, int16_t y);
static Direction toDirection(int32_t x, int32_t y);
GestureAction(Device* dev, config::GestureAction& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press();
virtual void release();
virtual void move(int16_t x, int16_t y);
void press() final;
virtual uint8_t reprogFlags() const;
void release() final;
void move(int16_t x, int16_t y) final;
uint8_t reprogFlags() const final;
void setGesture(const std::string& direction,
const std::string& type);
protected:
int16_t _x, _y;
int32_t _x{}, _y{};
std::shared_ptr<ipcgull::node> _node;
std::map<Direction, std::shared_ptr<Gesture>> _gestures;
config::GestureAction& _config;
mutable std::mutex _config_lock;
};
}}
}
#endif //LOGID_ACTION_GESTUREACTION_H

View File

@ -17,7 +17,6 @@
*/
#include "KeypressAction.h"
#include "../Device.h"
#include "../util/log.h"
#include "../InputDevice.h"
#include "../backend/hidpp20/features/ReprogControls.h"
@ -27,72 +26,70 @@ using namespace logid::backend;
const char* KeypressAction::interface_name = "Keypress";
KeypressAction::KeypressAction(
Device *device, config::KeypressAction& config,
Device* device, config::KeypressAction& config,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action(device, interface_name, {
{
{"GetKeys", {this, &KeypressAction::getKeys, {"keys"}}},
{"SetKeys", {this, &KeypressAction::setKeys, {"keys"}}}
}, {}, {}
}), _config (config)
{
Action(device, interface_name, {
{
{"GetKeys", {this, &KeypressAction::getKeys, {"keys"}}},
{"SetKeys", {this, &KeypressAction::setKeys, {"keys"}}}
},
{},
{}
}), _config(config) {
_setConfig();
}
void KeypressAction::press()
{
void KeypressAction::press() {
std::lock_guard<std::mutex> lock(_config_lock);
_pressed = true;
for(auto& key : _keys)
for (auto& key: _keys)
_device->virtualInput()->pressKey(key);
}
void KeypressAction::release()
{
void KeypressAction::release() {
std::lock_guard<std::mutex> lock(_config_lock);
_pressed = false;
for(auto& key : _keys)
for (auto& key: _keys)
_device->virtualInput()->releaseKey(key);
}
void KeypressAction::_setConfig()
{
void KeypressAction::_setConfig() {
_keys.clear();
if(!_config.keys.has_value())
if (!_config.keys.has_value())
return;
auto& config = _config.keys.value();
if(std::holds_alternative<std::string>(config)) {
if (std::holds_alternative<std::string>(config)) {
const auto& key = std::get<std::string>(config);
try {
auto code = _device->virtualInput()->toKeyCode(key);
_device->virtualInput()->registerKey(code);
_keys.emplace_back(code);
} catch(InputDevice::InvalidEventCode& e) {
} catch (InputDevice::InvalidEventCode& e) {
logPrintf(WARN, "Invalid keycode %s, skipping.", key.c_str());
}
} else if(std::holds_alternative<uint>(_config.keys.value())) {
} else if (std::holds_alternative<uint>(_config.keys.value())) {
const auto& key = std::get<uint>(config);
_device->virtualInput()->registerKey(key);
_keys.emplace_back(key);
} else if(std::holds_alternative<
} else if (std::holds_alternative<
std::list<std::variant<uint, std::string>>>(config)) {
const auto& keys = std::get<
std::list<std::variant<uint, std::string>>>(config);
for(const auto& key : keys) {
if(std::holds_alternative<std::string>(key)) {
for (const auto& key: keys) {
if (std::holds_alternative<std::string>(key)) {
const auto& key_str = std::get<std::string>(key);
try {
auto code = _device->virtualInput()->toKeyCode(key_str);
_device->virtualInput()->registerKey(code);
_keys.emplace_back(code);
} catch(InputDevice::InvalidEventCode& e) {
} catch (InputDevice::InvalidEventCode& e) {
logPrintf(WARN, "Invalid keycode %s, skipping.",
key_str.c_str());
}
} else if(std::holds_alternative<uint>(key)) {
} else if (std::holds_alternative<uint>(key)) {
auto& code = std::get<uint>(key);
_device->virtualInput()->registerKey(code);
_keys.emplace_back(code);
@ -101,31 +98,28 @@ void KeypressAction::_setConfig()
}
}
uint8_t KeypressAction::reprogFlags() const
{
uint8_t KeypressAction::reprogFlags() const {
return hidpp20::ReprogControls::TemporaryDiverted;
}
std::vector<std::string> KeypressAction::getKeys() const
{
std::vector<std::string> KeypressAction::getKeys() const {
std::lock_guard<std::mutex> lock(_config_lock);
std::vector<std::string> ret;
for(auto& x : _keys)
for (auto& x: _keys)
ret.push_back(InputDevice::toKeyName(x));
return ret;
}
void KeypressAction::setKeys(const std::vector<std::string> &keys)
{
void KeypressAction::setKeys(const std::vector<std::string>& keys) {
std::lock_guard<std::mutex> lock(_config_lock);
if(_pressed)
for(auto& key : _keys)
if (_pressed)
for (auto& key: _keys)
_device->virtualInput()->releaseKey(key);
_config.keys = std::list<std::variant<uint, std::string>>();
auto& config = std::get<std::list<std::variant<uint, std::string>>>(
_config.keys.value());
for(auto& x : keys)
for (auto& x: keys)
config.emplace_back(x);
_setConfig();
}

View File

@ -22,10 +22,8 @@
#include <libconfig.h++>
#include "Action.h"
namespace logid {
namespace actions {
class KeypressAction : public Action
{
namespace logid::actions {
class KeypressAction : public Action {
public:
static const char* interface_name;
@ -33,13 +31,16 @@ namespace actions {
config::KeypressAction& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press();
virtual void release();
void press() final;
void release() final;
[[nodiscard]] std::vector<std::string> getKeys() const;
void setKeys(const std::vector<std::string>& keys);
virtual uint8_t reprogFlags() const;
[[nodiscard]] uint8_t reprogFlags() const final;
protected:
mutable std::mutex _config_lock;
config::KeypressAction& _config;
@ -47,6 +48,6 @@ namespace actions {
void _setConfig();
};
}}
}
#endif //LOGID_ACTION_KEYPRESS_H

View File

@ -26,21 +26,17 @@ const char* NullAction::interface_name = "None";
NullAction::NullAction(
Device* device,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action(device, interface_name)
{
Action(device, interface_name) {
}
void NullAction::press()
{
void NullAction::press() {
_pressed = true;
}
void NullAction::release()
{
void NullAction::release() {
_pressed = false;
}
uint8_t NullAction::reprogFlags() const
{
uint8_t NullAction::reprogFlags() const {
return backend::hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -20,26 +20,25 @@
#include "Action.h"
namespace logid {
namespace actions
{
class NullAction : public Action
{
namespace logid::actions {
class NullAction : public Action {
public:
static const char* interface_name;
NullAction(Device* device,
const std::shared_ptr<ipcgull::node>& parent);
NullAction(Device* device, [[maybe_unused]] config::NoAction& config,
const std::shared_ptr<ipcgull::node>& parent) :
NullAction(device, parent) { }
NullAction(device, parent) {}
virtual void press();
virtual void release();
void press() final;
virtual uint8_t reprogFlags() const;
void release() final;
[[nodiscard]] uint8_t reprogFlags() const final;
};
}}
}
#endif //LOGID_ACTION_NULL_H

View File

@ -26,38 +26,33 @@ using namespace logid::backend;
const char* ToggleHiresScroll::interface_name = "ToggleHiresScroll";
ToggleHiresScroll::ToggleHiresScroll(
Device *dev,
Device* dev,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action (dev, interface_name)
{
Action(dev, interface_name) {
_hires_scroll = _device->getFeature<features::HiresScroll>("hiresscroll");
if(!_hires_scroll)
if (!_hires_scroll)
logPrintf(WARN, "%s:%d: HiresScroll feature not found, cannot use "
"ToggleHiresScroll action.",
_device->hidpp20().devicePath().c_str(),
_device->hidpp20().devicePath().c_str());
}
void ToggleHiresScroll::press()
{
void ToggleHiresScroll::press() {
_pressed = true;
if(_hires_scroll)
{
if (_hires_scroll) {
spawn_task(
[hires=this->_hires_scroll](){
auto mode = hires->getMode();
mode ^= backend::hidpp20::HiresScroll::HiRes;
hires->setMode(mode);
});
[hires = this->_hires_scroll]() {
auto mode = hires->getMode();
mode ^= backend::hidpp20::HiresScroll::HiRes;
hires->setMode(mode);
});
}
}
void ToggleHiresScroll::release()
{
void ToggleHiresScroll::release() {
_pressed = false;
}
uint8_t ToggleHiresScroll::reprogFlags() const
{
uint8_t ToggleHiresScroll::reprogFlags() const {
return hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -21,27 +21,27 @@
#include "Action.h"
#include "../features/HiresScroll.h"
namespace logid {
namespace actions
{
class ToggleHiresScroll : public Action
{
namespace logid::actions {
class ToggleHiresScroll : public Action {
public:
static const char* interface_name;
ToggleHiresScroll(Device* dev, const std::shared_ptr<ipcgull::node>& parent);
ToggleHiresScroll(Device* device,
[[maybe_unused]] config::ToggleHiresScroll& action,
const std::shared_ptr<ipcgull::node>& parent) :
ToggleHiresScroll(device, parent) { }
ToggleHiresScroll(device, parent) {}
virtual void press();
virtual void release();
void press() final;
void release() final;
[[nodiscard]] uint8_t reprogFlags() const final;
virtual uint8_t reprogFlags() const;
protected:
std::shared_ptr<features::HiresScroll> _hires_scroll;
};
}}
}
#endif //LOGID_ACTION_TOGGLEHIRESSCROLL_H

View File

@ -26,38 +26,34 @@ using namespace logid::backend;
const char* ToggleSmartShift::interface_name = "ToggleSmartShift";
ToggleSmartShift::ToggleSmartShift(
Device *dev,
Device* dev,
[[maybe_unused]] const std::shared_ptr<ipcgull::node>& parent) :
Action (dev, interface_name)
{
Action(dev, interface_name) {
_smartshift = _device->getFeature<features::SmartShift>("smartshift");
if(!_smartshift)
if (!_smartshift)
logPrintf(WARN, "%s:%d: SmartShift feature not found, cannot use "
"ToggleSmartShift action.",
_device->hidpp20().devicePath().c_str(),
_device->hidpp20().deviceIndex());
_device->hidpp20().devicePath().c_str(),
_device->hidpp20().deviceIndex());
}
void ToggleSmartShift::press()
{
void ToggleSmartShift::press() {
_pressed = true;
if(_smartshift) {
if (_smartshift) {
spawn_task(
[ss=this->_smartshift](){
auto status = ss->getStatus();
status.setActive = true;
status.active = !status.active;
ss->setStatus(status);
});
[ss = this->_smartshift]() {
auto status = ss->getStatus();
status.setActive = true;
status.active = !status.active;
ss->setStatus(status);
});
}
}
void ToggleSmartShift::release()
{
void ToggleSmartShift::release() {
_pressed = false;
}
uint8_t ToggleSmartShift::reprogFlags() const
{
uint8_t ToggleSmartShift::reprogFlags() const {
return hidpp20::ReprogControls::TemporaryDiverted;
}

View File

@ -22,27 +22,28 @@
#include "Action.h"
#include "../features/SmartShift.h"
namespace logid {
namespace actions {
class ToggleSmartShift : public Action
{
namespace logid::actions {
class ToggleSmartShift : public Action {
public:
static const char* interface_name;
ToggleSmartShift(Device* dev,
const std::shared_ptr<ipcgull::node>& parent);
ToggleSmartShift(Device* device,
[[maybe_unused]] config::ToggleSmartShift& action,
const std::shared_ptr<ipcgull::node>& parent) :
ToggleSmartShift(device, parent) { }
ToggleSmartShift(device, parent) {}
virtual void press();
virtual void release();
void press() final;
void release() final;
[[nodiscard]] uint8_t reprogFlags() const final;
virtual uint8_t reprogFlags() const;
protected:
std::shared_ptr<features::SmartShift> _smartshift;
};
}}
}
#endif //LOGID_ACTION_TOGGLESMARTSHIFT_H

View File

@ -19,66 +19,64 @@
#include "AxisGesture.h"
#include "../../Device.h"
#include "../../InputDevice.h"
#include "../../util/log.h"
using namespace logid::actions;
const char* AxisGesture::interface_name = "Axis";
AxisGesture::AxisGesture(Device *device, config::AxisGesture& config,
AxisGesture::AxisGesture(Device* device, config::AxisGesture& config,
const std::shared_ptr<ipcgull::node>& parent) :
Gesture (device, parent, interface_name), _multiplier (1), _config (config)
{
if(_config.axis.has_value()) {
if(std::holds_alternative<uint>(_config.axis.value())) {
Gesture(device, parent, interface_name), _multiplier(1), _config(config) {
if (_config.axis.has_value()) {
if (std::holds_alternative<uint>(_config.axis.value())) {
_input_axis = std::get<uint>(_config.axis.value());
} else {
const auto& axis = std::get<std::string>(_config.axis.value());
try {
_input_axis = _device->virtualInput()->toAxisCode(axis);
_device->virtualInput()->registerAxis(_input_axis.value());
} catch(InputDevice::InvalidEventCode& e) {
} catch (InputDevice::InvalidEventCode& e) {
logPrintf(WARN, "Invalid axis %s.");
}
}
}
if(_input_axis.has_value())
if (_input_axis.has_value())
_device->virtualInput()->registerAxis(_input_axis.value());
}
void AxisGesture::press(bool init_threshold)
{
_axis = init_threshold ?
_config.threshold.value_or(defaults::gesture_threshold) : 0;
void AxisGesture::press(bool init_threshold) {
if (init_threshold) {
_axis = (int32_t) (_config.threshold.value_or(defaults::gesture_threshold));
} else {
_axis = 0;
}
_axis_remainder = 0;
_hires_remainder = 0;
}
void AxisGesture::release(bool primary)
{
void AxisGesture::release(bool primary) {
// Do nothing
(void)primary; // Suppress unused warning
(void) primary; // Suppress unused warning
}
void AxisGesture::move(int16_t axis)
{
if(!_input_axis.has_value())
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;
int32_t new_axis = _axis + axis;
int low_res_axis = InputDevice::getLowResAxis(axis);
int hires_remainder = _hires_remainder;
if(new_axis > threshold) {
if (new_axis > threshold) {
double move = axis;
if(_axis < threshold)
if (_axis < threshold)
move = new_axis - threshold;
bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0;
if(negative_multiplier)
if (negative_multiplier)
move *= -_config.axis_multiplier.value_or(1);
else
move *= _config.axis_multiplier.value_or(1);
@ -87,48 +85,45 @@ void AxisGesture::move(int16_t axis)
double move_floor = floor(move);
_axis_remainder = move - move_floor;
if(_axis_remainder >= 1) {
if (_axis_remainder >= 1) {
double int_remainder = floor(_axis_remainder);
move_floor += int_remainder;
_axis_remainder -= int_remainder;
}
if(negative_multiplier)
if (negative_multiplier)
move_floor = -move_floor;
if(low_res_axis != -1) {
int lowres_movement = 0, hires_movement = move_floor;
if (low_res_axis != -1) {
int lowres_movement, hires_movement = (int) move_floor;
_device->virtualInput()->moveAxis(_input_axis.value(), hires_movement);
hires_remainder += hires_movement;
if(abs(hires_remainder) >= 60) {
lowres_movement = hires_remainder/120;
if(lowres_movement == 0)
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;
hires_remainder -= lowres_movement * 120;
_device->virtualInput()->moveAxis(low_res_axis, lowres_movement);
}
_hires_remainder = hires_remainder;
} else {
_device->virtualInput()->moveAxis(_input_axis.value(), move_floor);
_device->virtualInput()->moveAxis(_input_axis.value(), (int) move_floor);
}
}
_axis = new_axis;
}
bool AxisGesture::metThreshold() const
{
bool AxisGesture::metThreshold() const {
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
}
bool AxisGesture::wheelCompatibility() const
{
bool AxisGesture::wheelCompatibility() const {
return true;
}
void AxisGesture::setHiresMultiplier(double multiplier)
{
if(InputDevice::getLowResAxis(_axis) != -1) {
void AxisGesture::setHiresMultiplier(double multiplier) {
if (InputDevice::getLowResAxis(_axis) != -1) {
_multiplier = multiplier;
}
}

View File

@ -20,34 +20,34 @@
#include "Gesture.h"
namespace logid {
namespace actions
{
class AxisGesture : public Gesture
{
public:
static const char* interface_name;
namespace logid::actions {
class AxisGesture : public Gesture {
public:
static const char* interface_name;
AxisGesture(Device* device, config::AxisGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
AxisGesture(Device* device, config::AxisGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press(bool init_threshold=false);
virtual void release(bool primary=false);
virtual void move(int16_t axis);
void press(bool init_threshold) final;
virtual bool wheelCompatibility() const;
virtual bool metThreshold() const;
void release(bool primary) final;
void setHiresMultiplier(double multiplier);
void move(int16_t axis) final;
protected:
int16_t _axis;
double _axis_remainder;
int _hires_remainder;
std::optional<uint> _input_axis;
double _multiplier;
config::AxisGesture& _config;
};
}}
[[nodiscard]] bool wheelCompatibility() const final;
[[nodiscard]] bool metThreshold() const final;
void setHiresMultiplier(double multiplier);
protected:
int32_t _axis{};
double _axis_remainder{};
int _hires_remainder{};
std::optional<uint> _input_axis;
double _multiplier;
config::AxisGesture& _config;
};
}
#endif //LOGID_ACTION_AXISGESTURE_H

View File

@ -27,56 +27,57 @@
using namespace logid;
using namespace logid::actions;
Gesture::Gesture(Device *device,
Gesture::Gesture(Device* device,
std::shared_ptr<ipcgull::node> node,
const std::string& name, tables t) :
ipcgull::interface("pizza.pixl.LogiOps.Gesture." + name, std::move(t)),
_node (std::move(node)), _device (device)
{
_node(std::move(node)), _device(device) {
}
template <typename T>
struct gesture_type {
typedef typename T::gesture type;
};
namespace {
template<typename T>
struct gesture_type {
typedef typename T::gesture type;
};
template <typename T>
struct gesture_type<const T> : gesture_type<T> { };
template<typename T>
struct gesture_type<const T> : gesture_type<T> {
};
template <typename T>
struct gesture_type<T&> : gesture_type<T> { };
template<typename T>
struct gesture_type<T&> : gesture_type<T> {
};
template <typename T>
std::shared_ptr<Gesture> _makeGesture(
Device* device, T gesture,
const std::shared_ptr<ipcgull::node>& parent) {
return parent->make_interface<typename gesture_type<T>::type>(
device, gesture, parent);
template<typename T>
std::shared_ptr<Gesture> _makeGesture(
Device* device, T gesture,
const std::shared_ptr<ipcgull::node>& parent) {
return parent->make_interface<typename gesture_type<T>::type>(
device, gesture, parent);
}
}
std::shared_ptr<Gesture> Gesture::makeGesture(
Device *device, config::Gesture& gesture,
const std::shared_ptr<ipcgull::node>& parent)
{
Device* device, config::Gesture& gesture,
const std::shared_ptr<ipcgull::node>& parent) {
return std::visit([&device, &parent](auto&& x) {
return _makeGesture(device, x, parent);
}, gesture);
}
std::shared_ptr<Gesture> Gesture::makeGesture(
Device *device, const std::string& type,
Device* device, const std::string& type,
config::Gesture& config,
const std::shared_ptr<ipcgull::node> &parent)
{
if(type == AxisGesture::interface_name) {
const std::shared_ptr<ipcgull::node>& parent) {
if (type == AxisGesture::interface_name) {
config = config::AxisGesture();
} else if(type == IntervalGesture::interface_name) {
} else if (type == IntervalGesture::interface_name) {
config = config::IntervalGesture();
} else if(type == ReleaseGesture::interface_name) {
} else if (type == ReleaseGesture::interface_name) {
config = config::ReleaseGesture();
} else if(type == ThresholdGesture::interface_name) {
} else if (type == ThresholdGesture::interface_name) {
config = config::ThresholdGesture();
} else if(type == NullGesture::interface_name) {
} else if (type == NullGesture::interface_name) {
config = config::NoGesture();
} else {
throw InvalidGesture();

View File

@ -18,42 +18,41 @@
#ifndef LOGID_ACTION_GESTURE_H
#define LOGID_ACTION_GESTURE_H
#include <utility>
#include "../Action.h"
#define LOGID_GESTURE_DEFAULT_THRESHOLD 50
namespace logid {
namespace actions
{
class InvalidGesture : public std::exception
{
namespace logid::actions {
class InvalidGesture : public std::exception {
public:
explicit InvalidGesture(std::string what="") : _what (what)
{
explicit InvalidGesture(std::string what = "") : _what(std::move(what)) {
}
virtual const char* what() const noexcept
{
[[nodiscard]] const char* what() const noexcept override {
return _what.c_str();
}
private:
std::string _what;
};
class Gesture : public ipcgull::interface
{
class Gesture : public ipcgull::interface {
public:
virtual void press(bool init_threshold=false) = 0;
virtual void release(bool primary=false) = 0;
virtual void press(bool init_threshold) = 0;
virtual void release(bool primary) = 0;
virtual void move(int16_t axis) = 0;
virtual bool wheelCompatibility() const = 0;
virtual bool metThreshold() const = 0;
[[nodiscard]] virtual bool wheelCompatibility() const = 0;
[[nodiscard]] virtual bool metThreshold() const = 0;
virtual ~Gesture() = default;
static std::shared_ptr<Gesture> makeGesture(Device* device,
config::Gesture& gesture,
const std::shared_ptr<ipcgull::node>& parent);
config::Gesture& gesture,
const std::shared_ptr<ipcgull::node>& parent);
static std::shared_ptr<Gesture> makeGesture(
Device* device, const std::string& type,
@ -63,10 +62,11 @@ namespace actions
protected:
Gesture(Device* device,
std::shared_ptr<ipcgull::node> parent,
const std::string& name, tables t={});
const std::string& name, tables t = {});
const std::shared_ptr<ipcgull::node> _node;
Device* _device;
};
}}
}
#endif //LOGID_ACTION_GESTURE_H

View File

@ -16,7 +16,6 @@
*
*/
#include "IntervalGesture.h"
#include "../../util/log.h"
#include "../../Configuration.h"
using namespace logid::actions;
@ -24,48 +23,46 @@ using namespace logid::actions;
const char* IntervalGesture::interface_name = "OnInterval";
IntervalGesture::IntervalGesture(
Device *device, config::IntervalGesture& config,
Device* device, config::IntervalGesture& config,
const std::shared_ptr<ipcgull::node>& parent) :
Gesture (device, parent, interface_name),
_axis (0), _interval_pass_count (0), _config (config)
{
if(config.action) {
Gesture(device, parent, interface_name),
_axis(0), _interval_pass_count(0), _config(config) {
if (config.action) {
try {
_action = Action::makeAction(device, config.action.value(), _node);
} catch(InvalidAction& e) {
} catch (InvalidAction& e) {
logPrintf(WARN, "Mapping gesture to invalid action");
}
}
}
void IntervalGesture::press(bool init_threshold)
{
_axis = init_threshold ?
_config.threshold.value_or(defaults::gesture_threshold) : 0;
void IntervalGesture::press(bool init_threshold) {
if (init_threshold) {
_axis = (int32_t) _config.threshold.value_or(defaults::gesture_threshold);
} else {
_axis = 0;
}
_interval_pass_count = 0;
}
void IntervalGesture::release(bool primary)
{
void IntervalGesture::release(bool primary) {
// Do nothing
(void)primary; // Suppress unused warning
(void) primary; // Suppress unused warning
}
void IntervalGesture::move(int16_t axis)
{
if(!_config.interval.has_value())
void IntervalGesture::move(int16_t axis) {
if (!_config.interval.has_value())
return;
const auto threshold =
_config.threshold.value_or(defaults::gesture_threshold);
_axis += axis;
if(_axis < threshold)
if (_axis < threshold)
return;
int16_t new_interval_count = (_axis - threshold)/
_config.interval.value();
if(new_interval_count > _interval_pass_count) {
if(_action) {
int32_t new_interval_count = (_axis - threshold) / _config.interval.value();
if (new_interval_count > _interval_pass_count) {
if (_action) {
_action->press();
_action->release();
}
@ -73,12 +70,10 @@ void IntervalGesture::move(int16_t axis)
_interval_pass_count = new_interval_count;
}
bool IntervalGesture::wheelCompatibility() const
{
bool IntervalGesture::wheelCompatibility() const {
return true;
}
bool IntervalGesture::metThreshold() const
{
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);;
bool IntervalGesture::metThreshold() const {
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
}

View File

@ -20,42 +20,44 @@
#include "Gesture.h"
namespace logid {
namespace actions
{
class IntervalGesture : public Gesture
{
namespace logid::actions {
class IntervalGesture : public Gesture {
public:
static const char* interface_name;
IntervalGesture(Device* device, config::IntervalGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press(bool init_threshold=false);
virtual void release(bool primary=false);
virtual void move(int16_t axis);
void press(bool init_threshold) final;
virtual bool wheelCompatibility() const;
virtual bool metThreshold() const;
void release(bool primary) final;
void move(int16_t axis) final;
[[nodiscard]] bool wheelCompatibility() const final;
[[nodiscard]] bool metThreshold() const final;
protected:
int16_t _axis;
int16_t _interval_pass_count;
int32_t _axis;
int32_t _interval_pass_count;
std::shared_ptr<Action> _action;
config::IntervalGesture& _config;
private:
class IPC : public ipcgull::interface
{
class IPC : public ipcgull::interface {
public:
IPC(IntervalGesture* parent);
explicit IPC(IntervalGesture* parent);
void setAction(const std::string& type);
void setInterval(int interval);
void setThreshold(int threshold);
private:
IntervalGesture& parent;
};
};
}}
}
#endif //LOGID_ACTION_INTERVALGESTURE_H

View File

@ -22,36 +22,30 @@ using namespace logid::actions;
const char* NullGesture::interface_name = "None";
NullGesture::NullGesture(Device *device,
NullGesture::NullGesture(Device* device,
config::NoGesture& config,
const std::shared_ptr<ipcgull::node>& parent) :
Gesture (device, parent, interface_name), _config (config)
{
Gesture(device, parent, interface_name), _config(config) {
}
void NullGesture::press(bool init_threshold)
{
void NullGesture::press(bool init_threshold) {
_axis = init_threshold ? _config.threshold.value_or(
defaults::gesture_threshold) : 0;
}
void NullGesture::release(bool primary)
{
void NullGesture::release(bool primary) {
// Do nothing
(void)primary; // Suppress unused warning
(void) primary; // Suppress unused warning
}
void NullGesture::move(int16_t axis)
{
void NullGesture::move(int16_t axis) {
_axis += axis;
}
bool NullGesture::wheelCompatibility() const
{
bool NullGesture::wheelCompatibility() const {
return true;
}
bool NullGesture::metThreshold() const
{
bool NullGesture::metThreshold() const {
return _axis > _config.threshold.value_or(defaults::gesture_threshold);
}

View File

@ -20,11 +20,8 @@
#include "Gesture.h"
namespace logid {
namespace actions
{
class NullGesture : public Gesture
{
namespace logid::actions {
class NullGesture : public Gesture {
public:
static const char* interface_name;
@ -32,16 +29,20 @@ namespace actions
config::NoGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press(bool init_threshold=false);
virtual void release(bool primary=false);
virtual void move(int16_t axis);
void press(bool init_threshold) final;
void release(bool primary) final;
void move(int16_t axis) final;
[[nodiscard]] bool wheelCompatibility() const final;
[[nodiscard]] bool metThreshold() const final;
virtual bool wheelCompatibility() const;
virtual bool metThreshold() const;
protected:
int16_t _axis;
int32_t _axis{};
config::NoGesture& _config;
};
}}
}
#endif //LOGID_ACTION_NULLGESTURE_H

View File

@ -22,41 +22,38 @@ using namespace logid::actions;
const char* ReleaseGesture::interface_name = "OnRelease";
ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config,
ReleaseGesture::ReleaseGesture(Device* device, config::ReleaseGesture& config,
const std::shared_ptr<ipcgull::node>& parent) :
Gesture (device, parent, interface_name), _config (config)
{
if(_config.action.has_value())
Gesture(device, parent, interface_name), _config(config) {
if (_config.action.has_value())
_action = Action::makeAction(device, _config.action.value(), _node);
}
void ReleaseGesture::press(bool init_threshold)
{
_axis = init_threshold ? _config.threshold.value_or(
defaults::gesture_threshold) : 0;
void ReleaseGesture::press(bool init_threshold) {
if (init_threshold) {
_axis = (int32_t) (_config.threshold.value_or(defaults::gesture_threshold));
} else {
_axis = 0;
}
}
void ReleaseGesture::release(bool primary)
{
if(metThreshold() && primary) {
if(_action) {
void ReleaseGesture::release(bool primary) {
if (metThreshold() && primary) {
if (_action) {
_action->press();
_action->release();
}
}
}
void ReleaseGesture::move(int16_t axis)
{
void ReleaseGesture::move(int16_t axis) {
_axis += axis;
}
bool ReleaseGesture::wheelCompatibility() const
{
bool ReleaseGesture::wheelCompatibility() const {
return false;
}
bool ReleaseGesture::metThreshold() const
{
bool ReleaseGesture::metThreshold() const {
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
}

View File

@ -20,29 +20,29 @@
#include "Gesture.h"
namespace logid {
namespace actions
{
class ReleaseGesture : public Gesture
{
namespace logid::actions {
class ReleaseGesture : public Gesture {
public:
static const char* interface_name;
ReleaseGesture(Device* device, config::ReleaseGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press(bool init_threshold=false);
virtual void release(bool primary=false);
virtual void move(int16_t axis);
void press(bool init_threshold) final;
virtual bool wheelCompatibility() const;
virtual bool metThreshold() const;
void release(bool primary) final;
void move(int16_t axis) final;
[[nodiscard]] bool wheelCompatibility() const final;
[[nodiscard]] bool metThreshold() const final;
protected:
int16_t _axis;
int32_t _axis{};
std::shared_ptr<Action> _action;
config::ReleaseGesture& _config;
};
}}
}
#endif //LOGID_ACTION_RELEASEGESTURE_H

View File

@ -23,39 +23,34 @@ using namespace logid::actions;
const char* ThresholdGesture::interface_name = "OnRelease";
ThresholdGesture::ThresholdGesture(
Device *device, config::ThresholdGesture& config,
const std::shared_ptr<ipcgull::node>& parent ) :
Gesture (device, parent, interface_name), _config (config)
{
if(config.action) {
Device* device, config::ThresholdGesture& config,
const std::shared_ptr<ipcgull::node>& parent) :
Gesture(device, parent, interface_name), _config(config) {
if (config.action) {
try {
_action = Action::makeAction(device, config.action.value(), _node);
} catch(InvalidAction& e) {
} catch (InvalidAction& e) {
logPrintf(WARN, "Mapping gesture to invalid action");
}
}
}
void ThresholdGesture::press(bool init_threshold)
{
_axis = init_threshold ?
_config.threshold.value_or(defaults::gesture_threshold) : 0;
void ThresholdGesture::press(bool init_threshold) {
_axis = init_threshold ? (int32_t) _config.threshold.value_or(defaults::gesture_threshold) : 0;
this->_executed = false;
}
void ThresholdGesture::release(bool primary)
{
(void)primary; // Suppress unused warning
void ThresholdGesture::release(bool primary) {
(void) primary; // Suppress unused warning
this->_executed = false;
}
void ThresholdGesture::move(int16_t axis)
{
void ThresholdGesture::move(int16_t axis) {
_axis += axis;
if(!this->_executed && metThreshold()) {
if(_action) {
if (!this->_executed && metThreshold()) {
if (_action) {
_action->press();
_action->release();
}
@ -63,12 +58,10 @@ void ThresholdGesture::move(int16_t axis)
}
}
bool ThresholdGesture::metThreshold() const
{
bool ThresholdGesture::metThreshold() const {
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
}
bool ThresholdGesture::wheelCompatibility() const
{
bool ThresholdGesture::wheelCompatibility() const {
return false;
}

View File

@ -20,33 +20,32 @@
#include "Gesture.h"
namespace logid {
namespace actions
{
class ThresholdGesture : public Gesture
{
namespace logid::actions {
class ThresholdGesture : public Gesture {
public:
static const char* interface_name;
ThresholdGesture(Device* device, config::ThresholdGesture& config,
const std::shared_ptr<ipcgull::node>& parent);
virtual void press(bool init_threshold=false);
virtual void release(bool primary=false);
virtual void move(int16_t axis);
void press(bool init_threshold) final;
virtual bool metThreshold() const;
void release(bool primary) final;
virtual bool wheelCompatibility() const;
void move(int16_t axis) final;
[[nodiscard]] bool metThreshold() const final;
[[nodiscard]] bool wheelCompatibility() const final;
protected:
int16_t _axis;
int32_t _axis{};
std::shared_ptr<actions::Action> _action;
config::ThresholdGesture& _config;
private:
bool _executed = false;
};
}}
}
#endif //LOGID_ACTION_THRESHOLDGESTURE_H

View File

@ -18,7 +18,6 @@
#include "Error.h"
const char *logid::backend::TimeoutError::what() const noexcept
{
const char* logid::backend::TimeoutError::what() const noexcept {
return "Device timed out";
}

View File

@ -21,15 +21,13 @@
#include <stdexcept>
namespace logid {
namespace backend {
class TimeoutError: public std::exception
{
public:
TimeoutError() = default;
const char* what() const noexcept override;
};
namespace logid::backend {
class TimeoutError : public std::exception {
public:
TimeoutError() = default;
}}
[[nodiscard]] const char* what() const noexcept override;
};
}
#endif //LOGID_BACKEND_ERROR_H

View File

@ -20,23 +20,20 @@
using namespace logid::backend::dj;
Error::Error(uint8_t code) : _code (code)
{
Error::Error(uint8_t code) : _code(code) {
}
const char* Error::what() const noexcept
{
switch(_code) {
case Unknown:
return "Unknown";
case KeepAliveTimeout:
return "Keep-alive timeout";
default:
return "Reserved";
const char* Error::what() const noexcept {
switch (_code) {
case Unknown:
return "Unknown";
case KeepAliveTimeout:
return "Keep-alive timeout";
default:
return "Reserved";
}
}
uint8_t Error::code() const noexcept
{
uint8_t Error::code() const noexcept {
return _code;
}

View File

@ -22,27 +22,23 @@
#include <cstdint>
#include <stdexcept>
namespace logid {
namespace backend {
namespace dj
{
class Error : public std::exception
{
namespace logid::backend::dj {
class Error : public std::exception {
public:
enum ErrorCode : uint8_t
{
enum ErrorCode : uint8_t {
Unknown = 0x00,
KeepAliveTimeout = 0x01
};
explicit Error(uint8_t code);
const char* what() const noexcept override;
uint8_t code() const noexcept;
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] uint8_t code() const noexcept;
private:
uint8_t _code;
};
}}}
}
#endif //LOGID_BACKEND_DJ_ERROR_H

View File

@ -24,74 +24,73 @@
using namespace logid::backend::dj;
using namespace logid::backend;
InvalidReceiver::InvalidReceiver(Reason reason) : _reason (reason)
{
InvalidReceiver::InvalidReceiver(Reason reason) : _reason(reason) {
}
const char* InvalidReceiver::what() const noexcept
{
switch(_reason) {
case NoDJReports:
return "No DJ reports";
default:
return "Invalid receiver";
const char* InvalidReceiver::what() const noexcept {
switch (_reason) {
case NoDJReports:
return "No DJ reports";
default:
return "Invalid receiver";
}
}
InvalidReceiver::Reason InvalidReceiver::code() const noexcept
{
InvalidReceiver::Reason InvalidReceiver::code() const noexcept {
return _reason;
}
Receiver::Receiver(std::string path,
const std::shared_ptr<raw::DeviceMonitor>& monitor,
double timeout) :
_raw_device (std::make_shared<raw::RawDevice>(std::move(path), monitor)),
_hidpp10_device (_raw_device, hidpp::DefaultDevice, timeout)
{
if(!supportsDjReports(_raw_device->reportDescriptor()))
_raw_device(std::make_shared<raw::RawDevice>(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<uint8_t>& report)->bool {
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long);
},
[this](const std::vector<uint8_t>& report)->void {
hidpp::Report _report(report);
this->_handleHidppEvent(_report);
}
});
_raw_hidpp_handler = _raw_device->addEventHandler(
{
[](const std::vector<uint8_t>& report) -> bool {
return (report[hidpp::Offset::Type] ==
hidpp::Report::Type::Short ||
report[hidpp::Offset::Type] ==
hidpp::Report::Type::Long);
},
[this](const std::vector<uint8_t>& 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<uint8_t>& report)->bool {
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long);
},
[this](const std::vector<uint8_t>& report)->void {
Report _report(report);
this->_handleDjEvent(_report);
}
});
_raw_dj_handler = _raw_device->addEventHandler(
{
[](const std::vector<uint8_t>& report) -> bool {
return (report[Offset::Type] ==
Report::Type::Short ||
report[Offset::Type] ==
Report::Type::Long);
},
[this](const std::vector<uint8_t>& report) -> void {
Report _report(report);
this->_handleDjEvent(_report);
}
});
}
Receiver::~Receiver()
{
Receiver::~Receiver() {
_raw_device->removeEventHandler(_raw_dj_handler);
_raw_device->removeEventHandler(_raw_hidpp_handler);
}
void Receiver::enumerateDj()
{
_sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
void Receiver::enumerateDj() {
_sendDjRequest(hidpp::DefaultDevice, GetPairedDevices, {});
}
Receiver::NotificationFlags Receiver::getHidppNotifications()
{
Receiver::NotificationFlags Receiver::getHidppNotifications() {
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {},
hidpp::ReportType::Short);
hidpp::ReportType::Short);
NotificationFlags flags{};
flags.deviceBatteryStatus = response[0] & (1 << 4);
@ -101,41 +100,37 @@ Receiver::NotificationFlags Receiver::getHidppNotifications()
return flags;
}
void Receiver::enableHidppNotifications(NotificationFlags flags)
{
void Receiver::enableHidppNotifications(NotificationFlags flags) {
std::vector<uint8_t> request(3);
if(flags.deviceBatteryStatus)
if (flags.deviceBatteryStatus)
request[0] |= (1 << 4);
if(flags.receiverWirelessNotifications)
if (flags.receiverWirelessNotifications)
request[1] |= 1;
if(flags.receiverSoftwarePresent)
if (flags.receiverSoftwarePresent)
request[1] |= (1 << 3);
_hidpp10_device.setRegister(EnableHidppNotifications, request,
hidpp::ReportType::Short);
hidpp::ReportType::Short);
}
void Receiver::enumerateHidpp()
{
void Receiver::enumerateHidpp() {
/* This isn't in the documentation but this is how solaar does it
* All I know is that when (p0 & 2), devices are enumerated
*/
_hidpp10_device.setRegister(ConnectionState, {2},
hidpp::ReportType::Short);
hidpp::ReportType::Short);
}
///TODO: Investigate usage
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
{
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index) {
auto response = _hidpp10_device.getRegister(ConnectionState, {index},
hidpp::ReportType::Short);
hidpp::ReportType::Short);
return response[0];
}
void Receiver::startPairing(uint8_t timeout)
{
void Receiver::startPairing(uint8_t timeout) {
///TODO: Device number == Device index?
std::vector<uint8_t> request(3);
@ -144,11 +139,10 @@ void Receiver::startPairing(uint8_t timeout)
request[2] = timeout;
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
hidpp::ReportType::Short);
}
void Receiver::stopPairing()
{
void Receiver::stopPairing() {
///TODO: Device number == Device index?
std::vector<uint8_t> request(3);
@ -156,11 +150,10 @@ void Receiver::stopPairing()
request[1] = hidpp::DefaultDevice;
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
hidpp::ReportType::Short);
}
void Receiver::disconnect(hidpp::DeviceIndex index)
{
void Receiver::disconnect(hidpp::DeviceIndex index) {
///TODO: Device number == Device index?
std::vector<uint8_t> request(3);
@ -168,30 +161,28 @@ void Receiver::disconnect(hidpp::DeviceIndex index)
request[1] = index;
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
hidpp::ReportType::Short);
}
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
{
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity() {
auto response = _hidpp10_device.getRegister(DeviceActivity, {},
hidpp::ReportType::Long);
hidpp::ReportType::Long);
std::map<hidpp::DeviceIndex, uint8_t> device_activity;
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
for (uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
device_activity[static_cast<hidpp::DeviceIndex>(i)] = response[i];
return device_activity;
}
struct Receiver::PairingInfo
Receiver::getPairingInfo(hidpp::DeviceIndex index)
{
Receiver::getPairingInfo(hidpp::DeviceIndex index) {
std::vector<uint8_t> request(1);
request[0] = index;
request[0] += 0x1f;
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
hidpp::ReportType::Long);
struct PairingInfo info{};
info.destinationId = response[1];
@ -204,26 +195,25 @@ struct Receiver::PairingInfo
}
struct Receiver::ExtendedPairingInfo
Receiver::getExtendedPairingInfo(hidpp::DeviceIndex index)
{
Receiver::getExtendedPairingInfo(hidpp::DeviceIndex index) {
std::vector<uint8_t> request(1);
request[0] = index;
request[0] += 0x2f;
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
hidpp::ReportType::Long);
ExtendedPairingInfo info{};
info.serialNumber = 0;
for(uint8_t i = 0; i < 4; i++)
info.serialNumber |= (response[i+1] << 8*i);
for (uint8_t i = 0; i < 4; i++)
info.serialNumber |= (response[i + 1] << 8 * i);
for(uint8_t i = 0; i < 4; i++)
for (uint8_t i = 0; i < 4; i++)
info.reportTypes[i] = response[i + 5];
uint8_t psl = response[8] & 0xf;
if(psl > 0xc)
if (psl > 0xc)
info.powerSwitchLocation = PowerSwitchLocation::Reserved;
else
info.powerSwitchLocation = static_cast<PowerSwitchLocation>(psl);
@ -231,35 +221,32 @@ struct Receiver::ExtendedPairingInfo
return info;
}
std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
{
std::string Receiver::getDeviceName(hidpp::DeviceIndex index) {
std::vector<uint8_t> request(1);
request[0] = index;
request[0] += 0x3f;
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
hidpp::ReportType::Long);
uint8_t size = response[1];
assert(size <= 14);
std::string name(size, ' ');
for(std::size_t i = 0; i < size; i++)
name[i] = response[i + 2];
for (std::size_t i = 0; i < size; i++)
name[i] = (char) (response[i + 2]);
return name;
}
hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(const hidpp::Report&
report)
{
report) {
assert(report.subId() == DeviceDisconnection);
return report.deviceIndex();
}
hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(const
hidpp::Report &report)
{
hidpp::Report& report) {
assert(report.subId() == DeviceConnection);
hidpp::DeviceConnectionEvent event{};
@ -269,75 +256,66 @@ hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(const
event.deviceType = static_cast<DeviceType::DeviceType>(
report.paramBegin()[0] & 0x0f);
event.softwarePresent = report.paramBegin()[0] & (1<<4);
event.encrypted = report.paramBegin()[0] & (1<<5);
event.linkEstablished = !(report.paramBegin()[0] & (1<<6));
event.withPayload = report.paramBegin()[0] & (1<<7);
event.softwarePresent = report.paramBegin()[0] & (1 << 4);
event.encrypted = report.paramBegin()[0] & (1 << 5);
event.linkEstablished = !(report.paramBegin()[0] & (1 << 6));
event.withPayload = report.paramBegin()[0] & (1 << 7);
event.fromTimeoutCheck = false;
event.pid =(report.paramBegin()[2] << 8);
event.pid = (report.paramBegin()[2] << 8);
event.pid |= report.paramBegin()[1];
return event;
}
void Receiver::_handleDjEvent(Report& report)
{
for(auto& handler : _dj_event_handlers)
if(handler.second->condition(report))
void Receiver::_handleDjEvent(Report& report) {
for (auto& handler: _dj_event_handlers)
if (handler.second->condition(report))
handler.second->callback(report);
}
void Receiver::_handleHidppEvent(hidpp::Report &report)
{
for(auto& handler : _hidpp_event_handlers)
if(handler.second->condition(report))
void Receiver::_handleHidppEvent(hidpp::Report& report) {
for (auto& handler: _hidpp_event_handlers)
if (handler.second->condition(report))
handler.second->callback(report);
}
void Receiver::addDjEventHandler(const std::string& nickname,
const std::shared_ptr<EventHandler>& handler)
{
const std::shared_ptr<EventHandler>& handler) {
assert(_dj_event_handlers.find(nickname) == _dj_event_handlers.end());
_dj_event_handlers.emplace(nickname, handler);
}
void Receiver::removeDjEventHandler(const std::string &nickname)
{
void Receiver::removeDjEventHandler(const std::string& nickname) {
_dj_event_handlers.erase(nickname);
}
const std::map<std::string, std::shared_ptr<EventHandler>>&
Receiver::djEventHandlers()
{
Receiver::djEventHandlers() {
return _dj_event_handlers;
}
void Receiver::addHidppEventHandler(const std::string& nickname,
const std::shared_ptr<hidpp::EventHandler>& handler)
{
const std::shared_ptr<hidpp::EventHandler>& handler) {
assert(_hidpp_event_handlers.find(nickname) == _hidpp_event_handlers.end());
_hidpp_event_handlers.emplace(nickname, handler);
}
void Receiver::removeHidppEventHandler(const std::string &nickname)
{
void Receiver::removeHidppEventHandler(const std::string& nickname) {
_hidpp_event_handlers.erase(nickname);
}
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
Receiver::hidppEventHandlers()
{
Receiver::hidppEventHandlers() {
return _hidpp_event_handlers;
}
void Receiver::_sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
const std::vector<uint8_t>&& params)
{
const std::vector<uint8_t>&& params) {
assert(params.size() <= LongParamLength);
Report::Type type = params.size() <= ShortParamLength ?
ReportType::Short : ReportType::Long;
ReportType::Short : ReportType::Long;
Report request(type, index, function);
@ -346,8 +324,7 @@ void Receiver::_sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
_raw_device->sendReport(request.rawData());
}
Receiver::ConnectionStatusEvent Receiver::connectionStatusEvent(Report& report)
{
Receiver::ConnectionStatusEvent Receiver::connectionStatusEvent(Report& report) {
assert(report.feature() == ConnectionStatus);
ConnectionStatusEvent event{};
event.index = report.index();
@ -355,7 +332,6 @@ Receiver::ConnectionStatusEvent Receiver::connectionStatusEvent(Report& report)
return event;
}
std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const
{
std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const {
return _raw_device;
}

View File

@ -25,55 +25,51 @@
#include "../hidpp/Report.h"
#include "../hidpp10/Device.h"
namespace logid {
namespace backend {
namespace dj
{
struct EventHandler
{
namespace logid::backend::dj {
struct EventHandler {
std::function<bool(const Report&)> condition;
std::function<void(const Report&)> callback;
};
class InvalidReceiver : public std::exception
{
class InvalidReceiver : public std::exception {
public:
enum Reason
{
enum Reason {
NoDJReports
};
explicit InvalidReceiver(Reason reason);
const char* what() const noexcept override;
Reason code() const noexcept;
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] Reason code() const noexcept;
private:
Reason _reason;
};
class Receiver final
{
class Receiver final {
public:
Receiver(std::string path,
const std::shared_ptr<raw::DeviceMonitor>& monitor,
double timeout);
~Receiver();
enum DjEvents : uint8_t
{
enum DjEvents : uint8_t {
DeviceDisconnection = 0x40,
DeviceConnection = 0x41,
ConnectionStatus = 0x42
};
enum DjCommands : uint8_t
{
SwitchAndKeepAlive = 0x80,
enum DjCommands : uint8_t {
/* Kernel driver should handle this */
SwitchAndKeepAlive [[maybe_unused]] = 0x80,
GetPairedDevices = 0x81
};
void enumerateDj();
struct ConnectionStatusEvent
{
struct ConnectionStatusEvent {
hidpp::DeviceIndex index;
bool linkLost;
};
@ -85,16 +81,14 @@ namespace dj
* to have a separate hidpp10::Receiver class for these functions.
*/
enum HidppEvents : uint8_t
{
enum HidppEvents : uint8_t {
// These events are identical to their DJ counterparts
// DeviceDisconnection = 0x40,
// DeviceConnection = 0x41,
LockingChange = 0x4a
};
enum HidppRegisters : uint8_t
{
enum HidppRegisters : uint8_t {
EnableHidppNotifications = 0x00,
ConnectionState = 0x02,
DevicePairing = 0xb2,
@ -102,35 +96,36 @@ namespace dj
PairingInfo = 0xb5
};
struct NotificationFlags
{
struct NotificationFlags {
bool deviceBatteryStatus;
bool receiverWirelessNotifications;
bool receiverSoftwarePresent;
};
NotificationFlags getHidppNotifications();
void enableHidppNotifications(NotificationFlags flags);
void enumerateHidpp();
uint8_t getConnectionState(hidpp::DeviceIndex index);
void startPairing(uint8_t timeout = 0);
void stopPairing();
void disconnect(hidpp::DeviceIndex index);
std::map<hidpp::DeviceIndex, uint8_t> getDeviceActivity();
struct PairingInfo
{
struct PairingInfo {
uint8_t destinationId;
uint8_t reportInterval;
uint16_t pid;
DeviceType::DeviceType deviceType;
};
enum class PowerSwitchLocation : uint8_t
{
enum class PowerSwitchLocation : uint8_t {
Reserved = 0x0,
Base = 0x1,
TopCase = 0x2,
@ -146,42 +141,49 @@ namespace dj
BottomEdge = 0xc
};
struct ExtendedPairingInfo
{
struct ExtendedPairingInfo {
uint32_t serialNumber;
uint8_t reportTypes[4];
PowerSwitchLocation powerSwitchLocation;
};
struct PairingInfo getPairingInfo(hidpp::DeviceIndex index);
struct ExtendedPairingInfo getExtendedPairingInfo(hidpp::DeviceIndex
index);
index);
std::string getDeviceName(hidpp::DeviceIndex index);
static hidpp::DeviceIndex deviceDisconnectionEvent(
const hidpp::Report& report);
static hidpp::DeviceConnectionEvent deviceConnectionEvent(
const hidpp::Report& report);
void addDjEventHandler(const std::string& nickname,
const std::shared_ptr<EventHandler>& handler);
const std::shared_ptr<EventHandler>& handler);
void removeDjEventHandler(const std::string& nickname);
const std::map<std::string, std::shared_ptr<EventHandler>>&
djEventHandlers();
void addHidppEventHandler(const std::string& nickname,
const std::shared_ptr<hidpp::EventHandler>& handler);
void removeHidppEventHandler(const std::string& nickname);
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
hidppEventHandlers();
const std::shared_ptr<hidpp::EventHandler>& handler);
void removeHidppEventHandler(const std::string& nickname);
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
hidppEventHandlers();
[[nodiscard]] std::shared_ptr<raw::RawDevice> rawDevice() const;
std::shared_ptr<raw::RawDevice> rawDevice() const;
private:
void _sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
const std::vector<uint8_t>&& params);
const std::vector<uint8_t>&& params);
void _handleDjEvent(dj::Report& report);
void _handleHidppEvent(hidpp::Report& report);
raw::RawDevice::EvHandlerId _raw_hidpp_handler;
@ -197,20 +199,18 @@ namespace dj
};
}
namespace hidpp
{
struct DeviceConnectionEvent
{
namespace logid::backend::hidpp {
struct DeviceConnectionEvent {
hidpp::DeviceIndex index;
uint16_t pid;
uint16_t pid{};
dj::DeviceType::DeviceType deviceType;
bool unifying;
bool softwarePresent;
bool encrypted;
bool linkEstablished;
bool withPayload;
bool unifying{};
bool softwarePresent{};
bool encrypted{};
bool linkEstablished{};
bool withPayload{};
bool fromTimeoutCheck = false; // Fake field
};
}}}
}
#endif //LOGID_BACKEND_DJ_RECEIVER_H

View File

@ -26,112 +26,111 @@
using namespace logid::backend::dj;
ReceiverMonitor::ReceiverMonitor(std::string path,
std::shared_ptr<raw::DeviceMonitor> monitor,
double timeout):
_receiver (std::make_shared<Receiver>(
std::move(path), std::move(monitor), timeout))
{
assert(_receiver->hidppEventHandlers().find("RECVMON") ==
_receiver->hidppEventHandlers().end());
assert(_receiver->djEventHandlers().find("RECVMON") ==
_receiver->djEventHandlers().end());
const std::shared_ptr<raw::DeviceMonitor>& monitor,
double timeout) :
_receiver(std::make_shared<Receiver>(
std::move(path), monitor, timeout)) {
assert(!_receiver->hidppEventHandlers().contains(ev_handler_name));
assert(!_receiver->djEventHandlers().contains(ev_handler_name));
Receiver::NotificationFlags notification_flags{
true,
true,
true};
_receiver->enableHidppNotifications(notification_flags);
true,
true,
true};
_receiver->enableHidppNotifications(notification_flags);
}
ReceiverMonitor::~ReceiverMonitor()
{
_receiver->removeHidppEventHandler("RECVMON");
ReceiverMonitor::~ReceiverMonitor() {
_receiver->removeHidppEventHandler(ev_handler_name);
}
void ReceiverMonitor::ready()
{
if(_receiver->hidppEventHandlers().find("RECVMON") ==
_receiver->hidppEventHandlers().end()) {
void ReceiverMonitor::ready() {
if (!_receiver->hidppEventHandlers().contains(ev_handler_name)) {
std::shared_ptr<hidpp::EventHandler> event_handler =
std::make_shared<hidpp::EventHandler>();
event_handler->condition = [](hidpp::Report &report) -> bool {
event_handler->condition = [](hidpp::Report& report) -> bool {
return (report.subId() == Receiver::DeviceConnection ||
report.subId() == Receiver::DeviceDisconnection);
};
event_handler->callback = [this](hidpp::Report &report) -> void {
event_handler->callback = [this](hidpp::Report& report) -> void {
/* Running in a new thread prevents deadlocks since the
* receiver may be enumerating.
*/
spawn_task([this, report,
path= this->_receiver->rawDevice()->rawPath()]() {
path = this->_receiver->rawDevice()->rawPath()]() {
if (report.subId() == Receiver::DeviceConnection) {
try {
this->addDevice(this->_receiver->deviceConnectionEvent
(report));
} catch(std::exception& e) {
} 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) {
} else if (report.subId() == Receiver::DeviceDisconnection) {
try {
this->removeDevice(this->_receiver->
deviceDisconnectionEvent(report));
} catch(std::exception& e) {
} catch (std::exception& e) {
logPrintf(ERROR, "Failed to remove device %d from "
"receiver on %s: %s", report.deviceIndex(),
path.c_str(), e.what());
path.c_str(), e.what());
}
}
});
};
_receiver->addHidppEventHandler("RECVMON", event_handler);
_receiver->addHidppEventHandler(ev_handler_name, event_handler);
}
enumerate();
}
void ReceiverMonitor::enumerate()
{
void ReceiverMonitor::enumerate() {
_receiver->enumerateHidpp();
}
void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index)
{
void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) {
auto handler_id = std::make_shared<raw::RawDevice::EvHandlerId>();
*handler_id = _receiver->rawDevice()->addEventHandler({
[index](const std::vector<uint8_t>& report)->bool {
return report[Offset::DeviceIndex] == index;
},
[this, index, handler_id](
[[maybe_unused]] const std::vector<uint8_t>& report) {
hidpp::DeviceConnectionEvent event{};
event.withPayload = false;
event.linkEstablished = true;
event.index = index;
event.fromTimeoutCheck = true;
*handler_id = _receiver->rawDevice()->addEventHandler(
{
[index](const std::vector<uint8_t>& report) -> bool {
return report[Offset::DeviceIndex] ==
index;
},
[this, index, handler_id](
[[maybe_unused]] const std::vector<uint8_t>& report) {
hidpp::DeviceConnectionEvent event{};
event.withPayload = false;
event.linkEstablished = true;
event.index = index;
event.fromTimeoutCheck = true;
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());
}
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<Receiver> ReceiverMonitor::receiver() const
{
std::shared_ptr<Receiver> ReceiverMonitor::receiver() const {
return _receiver;
}

View File

@ -24,38 +24,42 @@
#include "Receiver.h"
#include "../hidpp/defs.h"
namespace logid {
namespace backend {
namespace dj
{
namespace logid::backend::dj {
// This class will run on the RawDevice thread,
class ReceiverMonitor
{
class ReceiverMonitor {
public:
ReceiverMonitor(std::string path,
std::shared_ptr<raw::DeviceMonitor> monitor,
const std::shared_ptr<raw::DeviceMonitor>& monitor,
double timeout);
virtual ~ReceiverMonitor();
void enumerate();
protected:
void ready();
virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0;
virtual void removeDevice(hidpp::DeviceIndex index) = 0;
void waitForDevice(hidpp::DeviceIndex index);
// Internal methods for derived class
void _pair(uint8_t timeout = 0);
void _stopPairing();
void _unpair();
[[nodiscard]] std::shared_ptr<Receiver> receiver() const;
private:
static constexpr const char* ev_handler_name = "receiver_monitor";
std::shared_ptr<Receiver> _receiver;
};
}}}
}
#endif //LOGID_BACKEND_DJ_RECEIVERMONITOR_H

View File

@ -66,41 +66,38 @@ static const std::array<uint8_t, 39> DJReportDesc2 = {
0xC0 // End Collection
};
bool dj::supportsDjReports(const std::vector<uint8_t>& rdesc)
{
auto it = std::search(rdesc.begin(), rdesc.end(),
DJReportDesc.begin(), DJReportDesc.end());
if(it == rdesc.end())
it = std::search(rdesc.begin(), rdesc.end(),
bool dj::supportsDjReports(const std::vector<uint8_t>& report_desc) {
auto it = std::search(report_desc.begin(), report_desc.end(),
DJReportDesc.begin(), DJReportDesc.end());
if (it == report_desc.end())
it = std::search(report_desc.begin(), report_desc.end(),
DJReportDesc2.begin(), DJReportDesc2.end());
return it != rdesc.end();
return it != report_desc.end();
}
Report::Report(const std::vector<uint8_t>& data) : _data (data)
{
switch(data[Offset::Type]) {
case ReportType::Short:
_data.resize(HeaderLength+ShortParamLength);
break;
case ReportType::Long:
_data.resize(HeaderLength+LongParamLength);
break;
default:
assert(false);
Report::Report(const std::vector<uint8_t>& data) : _data(data) {
switch (data[Offset::Type]) {
case ReportType::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case ReportType::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
assert(false);
}
}
Report::Report(Report::Type type, hidpp::DeviceIndex index, uint8_t feature)
{
switch(type) {
case ReportType::Short:
_data.resize(HeaderLength+ShortParamLength);
break;
case ReportType::Long:
_data.resize(HeaderLength+LongParamLength);
break;
default:
assert(false);
Report::Report(Report::Type type, hidpp::DeviceIndex index, uint8_t feature) {
switch (type) {
case ReportType::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case ReportType::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
assert(false);
}
_data[Offset::Type] = type;
@ -109,27 +106,22 @@ Report::Report(Report::Type type, hidpp::DeviceIndex index, uint8_t feature)
}
Report::Type Report::type() const
{
Report::Type Report::type() const {
return static_cast<Type>(_data[Offset::Type]);
}
hidpp::DeviceIndex Report::index() const
{
hidpp::DeviceIndex Report::index() const {
return static_cast<hidpp::DeviceIndex>(_data[Offset::DeviceIndex]);
}
uint8_t Report::feature() const
{
uint8_t Report::feature() const {
return _data[Offset::Feature];
}
std::vector<uint8_t>::iterator Report::paramBegin()
{
std::vector<uint8_t>::iterator Report::paramBegin() {
return _data.begin() + Offset::Parameters;
}
std::vector<uint8_t> Report::rawData() const
{
const std::vector<uint8_t>& Report::rawData() const {
return _data;
}

View File

@ -24,30 +24,34 @@
#include "defs.h"
#include "../hidpp/defs.h"
namespace logid::backend::dj
{
namespace Offset
{
namespace logid::backend::dj {
namespace Offset {
static constexpr uint8_t Type = 0;
static constexpr uint8_t DeviceIndex = 1;
static constexpr uint8_t Feature = 2;
static constexpr uint8_t Parameters = 3;
}
bool supportsDjReports(const std::vector<uint8_t>& rdesc);
class Report
{
bool supportsDjReports(const std::vector<uint8_t>& report_desc);
class Report {
public:
typedef ReportType::ReportType Type;
explicit Report(const std::vector<uint8_t>& data);
Report(Type type, hidpp::DeviceIndex index, uint8_t feature);
Type type() const;
hidpp::DeviceIndex index() const;
uint8_t feature() const;
[[nodiscard]] Type type() const;
[[nodiscard]] hidpp::DeviceIndex index() const;
[[nodiscard]] uint8_t feature() const;
std::vector<uint8_t>::iterator paramBegin();
std::vector<uint8_t> rawData() const;
[[nodiscard]] const std::vector<uint8_t>& rawData() const;
private:
std::vector<uint8_t> _data;
};

View File

@ -21,23 +21,16 @@
#include <cstdint>
namespace logid {
namespace backend {
namespace dj
{
namespace ReportType
{
enum ReportType : uint8_t
{
namespace logid::backend::dj {
namespace ReportType {
enum ReportType : uint8_t {
Short = 0x20,
Long = 0x21
};
}
namespace DeviceType
{
enum DeviceType : uint8_t
{
namespace DeviceType {
enum DeviceType : uint8_t {
Unknown = 0x00,
Keyboard = 0x01,
Mouse = 0x02,
@ -49,11 +42,12 @@ namespace dj
};
}
[[maybe_unused]]
static constexpr uint8_t ErrorFeature = 0x7f;
static constexpr std::size_t HeaderLength = 3;
static constexpr std::size_t ShortParamLength = 12;
static constexpr std::size_t LongParamLength = 29;
}}}
}
#endif //LOGID_BACKEND_DJ_DEFS_H

View File

@ -22,7 +22,6 @@
#include "Report.h"
#include "../hidpp20/features/Root.h"
#include "../hidpp20/features/DeviceName.h"
#include "../hidpp20/Error.h"
#include "../hidpp10/Error.h"
#include "../Error.h"
#include "../dj/Receiver.h"
@ -32,122 +31,115 @@ using namespace logid::backend::hidpp;
using namespace std::chrono;
const char* Device::InvalidDevice::what() const noexcept
{
switch(_reason) {
case NoHIDPPReport:
return "Invalid HID++ device";
case InvalidRawDevice:
return "Invalid raw device";
case Asleep:
return "Device asleep";
case VirtualNode:
return "Virtual device";
default:
return "Invalid device";
const char* Device::InvalidDevice::what() const noexcept {
switch (_reason) {
case NoHIDPPReport:
return "Invalid HID++ device";
case InvalidRawDevice:
return "Invalid raw device";
case Asleep:
return "Device asleep";
case VirtualNode:
return "Virtual device";
default:
return "Invalid device";
}
}
Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
{
Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept {
return _reason;
}
Device::Device(const std::string& path, DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout):
io_timeout (duration_cast<milliseconds>(
duration<double, std::milli>(timeout))),
_raw_device (std::make_shared<raw::RawDevice>(path, std::move(monitor))),
_receiver (nullptr), _path (path), _index (index)
{
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
io_timeout(duration_cast<milliseconds>(
duration<double, std::milli>(timeout))),
_raw_device(std::make_shared<raw::RawDevice>(path, std::move(monitor))),
_receiver(nullptr), _path(path), _index(index) {
_init();
}
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
double timeout) :
io_timeout (duration_cast<milliseconds>(
io_timeout(duration_cast<milliseconds>(
duration<double, std::milli>(timeout))),
_raw_device (std::move(raw_device)), _receiver (nullptr),
_path (_raw_device->rawPath()), _index (index)
{
_raw_device(std::move(raw_device)), _receiver(nullptr),
_path(_raw_device->rawPath()), _index(index) {
_init();
}
Device::Device(std::shared_ptr<dj::Receiver> receiver,
hidpp::DeviceConnectionEvent event, double timeout) :
io_timeout (duration_cast<milliseconds>(
Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceConnectionEvent event, double timeout) :
io_timeout(duration_cast<milliseconds>(
duration<double, std::milli>(timeout))),
_raw_device (receiver->rawDevice()), _receiver (receiver),
_path (receiver->rawDevice()->rawPath()), _index (event.index)
{
_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)
if (!event.linkEstablished)
throw InvalidDevice(InvalidDevice::Asleep);
if(!event.fromTimeoutCheck)
if (!event.fromTimeoutCheck)
_pid = event.pid;
else
_pid = receiver->getPairingInfo(_index).pid;
_init();
}
Device::Device(std::shared_ptr<dj::Receiver> receiver,
DeviceIndex index, double timeout) :
io_timeout (duration_cast<milliseconds>(
Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
DeviceIndex index, double timeout) :
io_timeout(duration_cast<milliseconds>(
duration<double, std::milli>(timeout))),
_raw_device (receiver->rawDevice()),
_receiver (receiver), _path (receiver->rawDevice()->rawPath()),
_index (index)
{
_raw_device(receiver->rawDevice()),
_receiver(receiver), _path(receiver->rawDevice()->rawPath()),
_index(index) {
_pid = receiver->getPairingInfo(_index).pid;
_init();
}
std::string Device::devicePath() const
{
const std::string& Device::devicePath() const {
return _path;
}
DeviceIndex Device::deviceIndex() const
{
DeviceIndex Device::deviceIndex() const {
return _index;
}
std::tuple<uint8_t, uint8_t> Device::version() const
{
const std::tuple<uint8_t, uint8_t>& Device::version() const {
return _version;
}
void Device::_init()
{
void Device::_init() {
supported_reports = getSupportedReports(_raw_device->reportDescriptor());
if(!supported_reports)
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<uint8_t>& report)->bool {
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long);
}, [this](const std::vector<uint8_t>& report)->void {
Report _report(report);
this->handleEvent(_report);
} });
if (_index == hidpp::DefaultDevice) {
_raw_handler = _raw_device->addEventHandler(
{
[](
const std::vector<uint8_t>& report) -> bool {
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long);
},
[this](const std::vector<uint8_t>& report) -> void {
Report _report(report);
this->handleEvent(_report);
}});
try {
auto rsp = sendReport(
{ReportType::Short, _index,
hidpp20::FeatureID::ROOT, hidpp20::Root::Ping,
LOGID_HIDPP_SOFTWARE_ID});
if(rsp.deviceIndex() != _index) {
if (rsp.deviceIndex() != _index) {
throw InvalidDevice(InvalidDevice::VirtualNode);
}
} catch(hidpp10::Error& e) {
} catch (hidpp10::Error& e) {
// Ignore
} catch(std::exception& e) {
} catch (std::exception& e) {
_raw_device->removeEventHandler(_raw_handler);
throw;
}
@ -155,90 +147,92 @@ void Device::_init()
_raw_device->removeEventHandler(_raw_handler);
}
_raw_handler = _raw_device->addEventHandler({
[index=this->_index](const std::vector<uint8_t>& report)->bool {
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long) &&
(report[Offset::DeviceIndex] == index);
}, [this](const std::vector<uint8_t>& report)->void {
Report _report(report);
this->handleEvent(_report);
} });
_raw_handler = _raw_device->addEventHandler(
{
[index = this->_index](
const std::vector<uint8_t>& report) -> bool {
return (report[Offset::Type] ==
Report::Type::Short ||
report[Offset::Type] ==
Report::Type::Long) &&
(report[Offset::DeviceIndex] ==
index);
},
[this](const std::vector<uint8_t>& report) -> void {
Report _report(report);
this->handleEvent(_report);
}});
try {
try {
hidpp20::EssentialRoot root(this);
hidpp20::Root root(this);
_version = root.getVersion();
} catch(hidpp10::Error &e) {
} catch (hidpp10::Error& e) {
// Valid HID++ 1.0 devices should send an InvalidSubID error
if(e.code() != hidpp10::Error::InvalidSubID)
if (e.code() != hidpp10::Error::InvalidSubID)
throw;
// HID++ 2.0 is not supported, assume HID++ 1.0
_version = std::make_tuple(1, 0);
}
if(!_receiver) {
if (!_receiver) {
_pid = _raw_device->productId();
if(std::get<0>(_version) >= 2) {
if (std::get<0>(_version) >= 2) {
try {
hidpp20::EssentialDeviceName deviceName(this);
hidpp20::DeviceName deviceName(this);
_name = deviceName.getName();
} catch(hidpp20::UnsupportedFeature &e) {
} catch (hidpp20::UnsupportedFeature& e) {
_name = _raw_device->name();
}
} else {
_name = _raw_device->name();
}
} else {
if(std::get<0>(_version) >= 2) {
if (std::get<0>(_version) >= 2) {
try {
hidpp20::EssentialDeviceName deviceName(this);
hidpp20::DeviceName deviceName(this);
_name = deviceName.getName();
} catch(hidpp20::UnsupportedFeature &e) {
} catch (hidpp20::UnsupportedFeature& e) {
_name = _receiver->getDeviceName(_index);
}
} else {
_name = _receiver->getDeviceName(_index);
}
}
} catch(std::exception& e) {
} catch (std::exception& e) {
_raw_device->removeEventHandler(_raw_handler);
throw;
}
}
Device::~Device()
{
Device::~Device() {
_raw_device->removeEventHandler(_raw_handler);
}
Device::EvHandlerId Device::addEventHandler(EventHandler handler)
{
Device::EvHandlerId Device::addEventHandler(EventHandler handler) {
std::lock_guard<std::mutex> lock(_event_handler_lock);
_event_handlers.emplace_front(std::move(handler));
return _event_handlers.cbegin();
}
void Device::removeEventHandler(EvHandlerId id)
{
void Device::removeEventHandler(EvHandlerId id) {
std::lock_guard<std::mutex> lock(_event_handler_lock);
_event_handlers.erase(id);
}
void Device::handleEvent(Report& report)
{
if(responseReport(report))
void Device::handleEvent(Report& report) {
if (responseReport(report))
return;
std::lock_guard<std::mutex> lock(_event_handler_lock);
for(auto& handler : _event_handlers)
if(handler.condition(report))
for (auto& handler: _event_handlers)
if (handler.condition(report))
handler.callback(report);
}
Report Device::sendReport(const Report &report)
{
Report Device::sendReport(const Report& report) {
std::lock_guard<std::mutex> lock(_send_lock);
{
std::lock_guard<std::mutex> sl(_slot_lock);
@ -247,39 +241,38 @@ Report Device::sendReport(const Report &report)
sendReportNoResponse(report);
std::unique_lock<std::mutex> wait(_resp_wait_lock);
bool valid = _resp_cv.wait_for(
wait, io_timeout, [this](){
wait, io_timeout, [this]() {
std::lock_guard<std::mutex> sl(_slot_lock);
return _report_slot.has_value();
});
if(!valid)
if (!valid)
throw TimeoutError();
std::lock_guard<std::mutex> sl(_slot_lock);
{
Report::Hidpp10Error error{};
if(_report_slot.value().isError10(&error))
if (_report_slot.value().isError10(&error))
throw hidpp10::Error(error.error_code);
}
{
Report::Hidpp20Error error{};
if(_report_slot.value().isError20(&error))
if (_report_slot.value().isError20(&error))
throw hidpp20::Error(error.error_code);
}
return _report_slot.value();
}
bool Device::responseReport(const Report &report)
{
if(_send_lock.try_lock()) {
bool Device::responseReport(const Report& report) {
if (_send_lock.try_lock()) {
_send_lock.unlock();
return false;
}
// Basic check to see if the report is a response
if( (report.swId() != LOGID_HIDPP_SOFTWARE_ID)
&& report.subId() < 0x80)
if ((report.swId() != LOGID_HIDPP_SOFTWARE_ID)
&& report.subId() < 0x80)
return false;
std::lock_guard lock(_slot_lock);
@ -288,18 +281,15 @@ bool Device::responseReport(const Report &report)
return true;
}
void Device::sendReportNoResponse(Report report)
{
void Device::sendReportNoResponse(Report report) {
reportFixup(report);
_raw_device->sendReport(report.rawReport());
}
void Device::reportFixup(Report& report)
{
switch(report.type())
{
void Device::reportFixup(Report& report) const {
switch (report.type()) {
case Report::Type::Short:
if(!(supported_reports & HIDPP_REPORT_SHORT_SUPPORTED))
if (!(supported_reports & HIDPP_REPORT_SHORT_SUPPORTED))
report.setType(Report::Type::Long);
break;
case Report::Type::Long:
@ -308,12 +298,10 @@ void Device::reportFixup(Report& report)
}
}
std::string Device::name() const
{
const std::string& Device::name() const {
return _name;
}
uint16_t Device::pid() const
{
uint16_t Device::pid() const {
return _pid;
}

View File

@ -28,72 +28,80 @@
#include "Report.h"
#include "defs.h"
namespace logid {
namespace backend {
namespace dj
{
namespace logid::backend::dj {
// Need to define here for a constructor
class Receiver;
}
namespace hidpp
{
namespace logid::backend::hidpp {
struct DeviceConnectionEvent;
struct EventHandler
{
struct EventHandler {
std::function<bool(Report&)> condition;
std::function<void(Report&)> callback;
};
class Device
{
class Device {
public:
typedef std::list<EventHandler>::const_iterator EvHandlerId;
class InvalidDevice : std::exception
{
class InvalidDevice : std::exception {
public:
enum Reason
{
enum Reason {
NoHIDPPReport,
InvalidRawDevice,
Asleep,
VirtualNode
};
InvalidDevice(Reason reason) : _reason (reason) {}
virtual const char* what() const noexcept;
virtual Reason code() const noexcept;
explicit InvalidDevice(Reason reason) : _reason(reason) {}
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] virtual Reason code() const noexcept;
private:
Reason _reason;
};
Device(const std::string& path, DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
double timeout);
Device(std::shared_ptr<dj::Receiver> receiver,
Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceConnectionEvent event, double timeout);
Device(std::shared_ptr<dj::Receiver> receiver,
Device(const std::shared_ptr<dj::Receiver>& receiver,
DeviceIndex index, double timeout);
virtual ~Device();
std::string devicePath() const;
DeviceIndex deviceIndex() const;
std::tuple<uint8_t, uint8_t> version() const;
[[nodiscard]] const std::string& devicePath() const;
std::string name() const;
uint16_t pid() const;
[[nodiscard]] DeviceIndex deviceIndex() const;
[[nodiscard]] const std::tuple<uint8_t, uint8_t>& version() const;
[[nodiscard]] const std::string& name() const;
[[nodiscard]] uint16_t pid() const;
EvHandlerId addEventHandler(EventHandler handler);
void removeEventHandler(EvHandlerId id);
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);
void reportFixup(Report& report) const;
const std::chrono::milliseconds io_timeout;
uint8_t supported_reports;
@ -119,6 +127,6 @@ namespace hidpp
std::mutex _event_handler_lock;
std::list<EventHandler> _event_handlers;
};
} } }
}
#endif //LOGID_BACKEND_HIDPP_DEVICE_H

View File

@ -28,107 +28,103 @@ using namespace logid::backend;
/* Report descriptors were sourced from cvuchener/hidpp */
static const std::array<uint8_t, 22> ShortReportDesc = {
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
static const std::array<uint8_t, 22> LongReportDesc = {
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x75, 0x08, // Report Size (8)
0x95, 0x13, // Report Count (19)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x75, 0x08, // Report Size (8)
0x95, 0x13, // Report Count (19)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
/* Alternative versions from the G602 */
static const std::array<uint8_t, 22> ShortReportDesc2 = {
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
static const std::array<uint8_t, 22> LongReportDesc2 = {
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x95, 0x13, // Report Count (19)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x95, 0x13, // Report Count (19)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
uint8_t hidpp::getSupportedReports(const std::vector<uint8_t>& rdesc)
{
uint8_t hidpp::getSupportedReports(const std::vector<uint8_t>& report_desc) {
uint8_t ret = 0;
auto it = std::search(rdesc.begin(), rdesc.end(),
ShortReportDesc.begin(), ShortReportDesc.end());
if(it == rdesc.end())
it = std::search(rdesc.begin(), rdesc.end(),
ShortReportDesc2.begin(), ShortReportDesc2.end());
if(it != rdesc.end())
auto it = std::search(report_desc.begin(), report_desc.end(),
ShortReportDesc.begin(), ShortReportDesc.end());
if (it == report_desc.end())
it = std::search(report_desc.begin(), report_desc.end(),
ShortReportDesc2.begin(), ShortReportDesc2.end());
if (it != report_desc.end())
ret |= HIDPP_REPORT_SHORT_SUPPORTED;
it = std::search(rdesc.begin(), rdesc.end(),
LongReportDesc.begin(), LongReportDesc.end());
if(it == rdesc.end())
it = std::search(rdesc.begin(), rdesc.end(),
LongReportDesc2.begin(), LongReportDesc2.end());
if(it != rdesc.end())
it = std::search(report_desc.begin(), report_desc.end(),
LongReportDesc.begin(), LongReportDesc.end());
if (it == report_desc.end())
it = std::search(report_desc.begin(), report_desc.end(),
LongReportDesc2.begin(), LongReportDesc2.end());
if (it != report_desc.end())
ret |= HIDPP_REPORT_LONG_SUPPORTED;
return ret;
}
const char *Report::InvalidReportID::what() const noexcept
{
const char* Report::InvalidReportID::what() const noexcept {
return "Invalid report ID";
}
const char *Report::InvalidReportLength::what() const noexcept
{
const char* Report::InvalidReportLength::what() const noexcept {
return "Invalid report length";
}
Report::Report(Report::Type type, DeviceIndex device_index,
uint8_t sub_id, uint8_t address)
{
switch(type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
uint8_t sub_id, uint8_t address) {
switch (type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
}
_data[Offset::Type] = type;
@ -138,163 +134,141 @@ Report::Report(Report::Type type, DeviceIndex device_index,
}
Report::Report(Report::Type type, DeviceIndex device_index,
uint8_t feature_index, uint8_t function, uint8_t sw_id)
{
uint8_t feature_index, uint8_t function, uint8_t sw_id) {
assert(function <= 0x0f);
assert(sw_id <= 0x0f);
switch(type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
switch (type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
}
_data[Offset::Type] = type;
_data[Offset::DeviceIndex] = device_index;
_data[Offset::Feature] = feature_index;
_data[Offset::Function] = (function & 0x0f) << 4 |
(sw_id & 0x0f);
(sw_id & 0x0f);
}
Report::Report(const std::vector<uint8_t>& data) :
_data (data)
{
_data(data) {
_data.resize(HeaderLength + LongParamLength);
// Truncating data is entirely valid here.
switch(_data[Offset::Type]) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
switch (_data[Offset::Type]) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
}
}
Report::Type Report::type() const
{
Report::Type Report::type() const {
return static_cast<Report::Type>(_data[Offset::Type]);
}
void Report::setType(Report::Type type)
{
switch(type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
void Report::setType(Report::Type type) {
switch (type) {
case Type::Short:
_data.resize(HeaderLength + ShortParamLength);
break;
case Type::Long:
_data.resize(HeaderLength + LongParamLength);
break;
default:
throw InvalidReportID();
}
_data[Offset::Type] = type;
}
hidpp::DeviceIndex Report::deviceIndex() const
{
hidpp::DeviceIndex Report::deviceIndex() const {
return static_cast<hidpp::DeviceIndex>(_data[Offset::DeviceIndex]);
}
void Report::setDeviceIndex(hidpp::DeviceIndex index)
{
[[maybe_unused]] void Report::setDeviceIndex(hidpp::DeviceIndex index) {
_data[Offset::DeviceIndex] = index;
}
uint8_t Report::feature() const
{
uint8_t Report::feature() const {
return _data[Offset::Feature];
}
void Report::setFeature(uint8_t feature)
{
[[maybe_unused]] void Report::setFeature(uint8_t feature) {
_data[Offset::Parameters] = feature;
}
uint8_t Report::subId() const
{
uint8_t Report::subId() const {
return _data[Offset::SubID];
}
void Report::setSubId(uint8_t sub_id)
{
[[maybe_unused]] void Report::setSubId(uint8_t sub_id) {
_data[Offset::SubID] = sub_id;
}
uint8_t Report::function() const
{
uint8_t Report::function() const {
return (_data[Offset::Function] >> 4) & 0x0f;
}
void Report::setFunction(uint8_t function)
{
[[maybe_unused]] void Report::setFunction(uint8_t function) {
_data[Offset::Function] &= 0x0f;
_data[Offset::Function] |= (function & 0x0f) << 4;
}
uint8_t Report::swId() const
{
uint8_t Report::swId() const {
return _data[Offset::Function] & 0x0f;
}
void Report::setSwId(uint8_t sw_id)
{
void Report::setSwId(uint8_t sw_id) {
_data[Offset::Function] &= 0xf0;
_data[Offset::Function] |= sw_id & 0x0f;
}
uint8_t Report::address() const
{
uint8_t Report::address() const {
return _data[Offset::Address];
}
void Report::setAddress(uint8_t address)
{
[[maybe_unused]] void Report::setAddress(uint8_t address) {
_data[Offset::Address] = address;
}
std::vector<uint8_t>::iterator Report::paramBegin()
{
std::vector<uint8_t>::iterator Report::paramBegin() {
return _data.begin() + Offset::Parameters;
}
std::vector<uint8_t>::iterator Report::paramEnd()
{
std::vector<uint8_t>::iterator Report::paramEnd() {
return _data.end();
}
std::vector<uint8_t>::const_iterator Report::paramBegin() const
{
std::vector<uint8_t>::const_iterator Report::paramBegin() const {
return _data.begin() + Offset::Parameters;
}
std::vector<uint8_t>::const_iterator Report::paramEnd() const
{
std::vector<uint8_t>::const_iterator Report::paramEnd() const {
return _data.end();
}
void Report::setParams(const std::vector<uint8_t>& _params)
{
assert(_params.size() <= _data.size()-HeaderLength);
void Report::setParams(const std::vector<uint8_t>& _params) {
assert(_params.size() <= _data.size() - HeaderLength);
for(std::size_t i = 0; i < _params.size(); i++)
for (std::size_t i = 0; i < _params.size(); i++)
_data[Offset::Parameters + i] = _params[i];
}
bool Report::isError10(Report::Hidpp10Error *error) const
{
bool Report::isError10(Report::Hidpp10Error* error) const {
assert(error != nullptr);
if(_data[Offset::Type] != Type::Short ||
if (_data[Offset::Type] != Type::Short ||
_data[Offset::SubID] != hidpp10::ErrorID)
return false;
@ -305,18 +279,21 @@ bool Report::isError10(Report::Hidpp10Error *error) const
return true;
}
bool Report::isError20(Report::Hidpp20Error* error) const
{
bool Report::isError20(Report::Hidpp20Error* error) const {
assert(error != nullptr);
if(_data[Offset::Type] != Type::Long ||
if (_data[Offset::Type] != Type::Long ||
_data[Offset::Feature] != hidpp20::ErrorID)
return false;
error->feature_index= _data[3];
error->feature_index = _data[3];
error->function = (_data[4] >> 4) & 0x0f;
error->software_id = _data[4] & 0x0f;
error->error_code = _data[5];
return true;
}
}
const std::vector<uint8_t>& Report::rawReport() const {
return _data;
}

View File

@ -25,17 +25,13 @@
/* Some devices only support a subset of these reports */
#define HIDPP_REPORT_SHORT_SUPPORTED 1U
#define HIDPP_REPORT_LONG_SUPPORTED 1U<<1U
#define HIDPP_REPORT_LONG_SUPPORTED 1U<<1U
/* Very long reports exist, however they have not been encountered so far */
namespace logid {
namespace backend {
namespace hidpp
{
uint8_t getSupportedReports(const std::vector<uint8_t>& rdesc);
namespace logid::backend::hidpp {
uint8_t getSupportedReports(const std::vector<uint8_t>& report_desc);
namespace Offset
{
namespace Offset {
static constexpr uint8_t Type = 0;
static constexpr uint8_t DeviceIndex = 1;
static constexpr uint8_t SubID = 2;
@ -45,23 +41,22 @@ namespace hidpp
static constexpr uint8_t Parameters = 4;
}
class Report
{
class Report {
public:
typedef ReportType::ReportType Type;
class InvalidReportID: public std::exception
{
class InvalidReportID : public std::exception {
public:
InvalidReportID() = default;
const char* what() const noexcept override;
[[nodiscard]] const char* what() const noexcept override;
};
class InvalidReportLength: public std::exception
{
class InvalidReportLength : public std::exception {
public:
InvalidReportLength() = default;;
const char* what() const noexcept override;
InvalidReportLength() = default;
[[nodiscard]] const char* what() const noexcept override;
};
static constexpr std::size_t MaxDataLength = 20;
@ -69,57 +64,70 @@ namespace hidpp
Report(Report::Type type, DeviceIndex device_index,
uint8_t sub_id,
uint8_t address);
Report(Report::Type type, DeviceIndex device_index,
uint8_t feature_index,
uint8_t function,
uint8_t sw_id);
uint8_t feature_index,
uint8_t function,
uint8_t sw_id);
explicit Report(const std::vector<uint8_t>& data);
Report::Type type() const;
[[nodiscard]] Report::Type type() const;
void setType(Report::Type type);
DeviceIndex deviceIndex() const;
void setDeviceIndex(DeviceIndex index);
[[nodiscard]] DeviceIndex deviceIndex() const;
uint8_t feature() const;
void setFeature(uint8_t feature);
[[maybe_unused]] void setDeviceIndex(DeviceIndex index);
uint8_t subId() const;
void setSubId(uint8_t sub_id);
[[nodiscard]] uint8_t feature() const;
uint8_t function() const;
void setFunction(uint8_t function);
[[maybe_unused]] void setFeature(uint8_t feature);
[[nodiscard]] uint8_t subId() const;
[[maybe_unused]] void setSubId(uint8_t sub_id);
[[nodiscard]] uint8_t function() const;
[[maybe_unused]] void setFunction(uint8_t function);
[[nodiscard]] uint8_t swId() const;
uint8_t swId() const;
void setSwId(uint8_t sw_id);
uint8_t address() const;
void setAddress(uint8_t address);
[[nodiscard]] uint8_t address() const;
[[maybe_unused]] void setAddress(uint8_t address);
[[nodiscard]] std::vector<uint8_t>::iterator paramBegin();
[[nodiscard]] std::vector<uint8_t>::iterator paramEnd();
[[nodiscard]] std::vector<uint8_t>::const_iterator paramBegin() const;
[[nodiscard]] std::vector<uint8_t>::const_iterator paramEnd() const;
std::vector<uint8_t>::iterator paramBegin();
std::vector<uint8_t>::iterator paramEnd();
std::vector<uint8_t>::const_iterator paramBegin() const;
std::vector<uint8_t>::const_iterator paramEnd() const;
void setParams(const std::vector<uint8_t>& _params);
struct Hidpp10Error
{
struct Hidpp10Error {
uint8_t sub_id, address, error_code;
};
bool isError10(Hidpp10Error* error) const;
struct Hidpp20Error
{
struct Hidpp20Error {
uint8_t feature_index, function, software_id, error_code;
};
bool isError20(Hidpp20Error* error) const;
std::vector<uint8_t> rawReport() const { return _data; }
[[nodiscard]] const std::vector<uint8_t>& rawReport() const;
static constexpr std::size_t HeaderLength = 4;
private:
std::vector<uint8_t> _data;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP_REPORT_H

View File

@ -23,33 +23,27 @@
#include <cstdint>
namespace logid {
namespace backend {
namespace hidpp
{
namespace ReportType
{
enum ReportType : uint8_t
{
namespace logid::backend::hidpp {
namespace ReportType {
enum ReportType : uint8_t {
Short = 0x10,
Long = 0x11
};
}
enum DeviceIndex: uint8_t
{
enum DeviceIndex : uint8_t {
DefaultDevice = 0xff,
CordedDevice = 0,
WirelessDevice1 = 1,
WirelessDevice2 = 2,
WirelessDevice3 = 3,
WirelessDevice4 = 4,
WirelessDevice5 = 5,
WirelessDevice2 [[maybe_unused]] = 2,
WirelessDevice3 [[maybe_unused]] = 3,
WirelessDevice4 [[maybe_unused]] = 4,
WirelessDevice5 [[maybe_unused]] = 5,
WirelessDevice6 = 6,
};
static constexpr std::size_t ShortParamLength = 3;
static constexpr std::size_t LongParamLength = 16;
} } }
}
#endif //LOGID_BACKEND_HIDPP_DEFS_H

View File

@ -25,44 +25,40 @@
using namespace logid::backend;
using namespace logid::backend::hidpp10;
Device::Device(const std::string &path,
Device::Device(const std::string& path,
hidpp::DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
hidpp::Device(path, index, std::move(monitor), timeout)
{
hidpp::Device(path, index, std::move(monitor), timeout) {
assert(version() == std::make_tuple(1, 0));
}
Device::Device(std::shared_ptr<raw::RawDevice> raw_dev,
hidpp::DeviceIndex index,
double timeout) : hidpp::Device(std::move(raw_dev), index, timeout)
{
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<dj::Receiver> receiver,
Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceIndex index,
double timeout)
: hidpp::Device(std::move(receiver), index, timeout)
{
: hidpp::Device(receiver, index, timeout) {
assert(version() == std::make_tuple(1, 0));
}
hidpp::Report Device::sendReport(const hidpp::Report& report)
{
hidpp::Report Device::sendReport(const hidpp::Report& report) {
decltype(_responses)::iterator response_slot;
while(true) {
while (true) {
{
std::lock_guard<std::mutex> lock(_response_lock);
response_slot = _responses.find(report.subId());
if(response_slot == _responses.end()) {
if (response_slot == _responses.end()) {
response_slot = _responses.emplace(
report.subId(), std::optional<Response>()).first;
break;
}
}
std::unique_lock<std::mutex> lock(_response_wait_lock);
_response_cv.wait(lock, [this, sub_id=report.subId()](){
_response_cv.wait(lock, [this, sub_id = report.subId()]() {
std::lock_guard<std::mutex> lock(_response_lock);
return _responses.find(sub_id) != _responses.end();
});
@ -70,13 +66,14 @@ hidpp::Report Device::sendReport(const hidpp::Report& report)
sendReportNoResponse(report);
std::unique_lock<std::mutex> wait(_response_wait_lock);
bool valid = _response_cv.wait_for(wait, io_timeout,
[this, &response_slot]() {
std::lock_guard<std::mutex> lock(_response_lock);
return response_slot->second.has_value();
});
bool valid = _response_cv.wait_for(
wait, io_timeout,
[this, &response_slot]() {
std::lock_guard<std::mutex> lock(_response_lock);
return response_slot->second.has_value();
});
if(!valid) {
if (!valid) {
std::lock_guard<std::mutex> lock(_response_lock);
_responses.erase(response_slot);
throw TimeoutError();
@ -86,20 +83,19 @@ hidpp::Report Device::sendReport(const hidpp::Report& report)
assert(response_slot->second.has_value());
auto response = response_slot->second.value();
_responses.erase(response_slot);
if(std::holds_alternative<hidpp::Report>(response))
if (std::holds_alternative<hidpp::Report>(response))
return std::get<hidpp::Report>(response);
else // if(std::holds_alternative<Error::ErrorCode>(response))
throw Error(std::get<Error::ErrorCode>(response));
}
bool Device::responseReport(const hidpp::Report& report)
{
bool Device::responseReport(const hidpp::Report& report) {
std::lock_guard<std::mutex> lock(_response_lock);
uint8_t sub_id;
bool is_error = false;
hidpp::Report::Hidpp10Error hidpp10_error {};
if(report.isError10(&hidpp10_error)) {
hidpp::Report::Hidpp10Error hidpp10_error{};
if (report.isError10(&hidpp10_error)) {
sub_id = hidpp10_error.sub_id;
is_error = true;
} else {
@ -107,10 +103,10 @@ bool Device::responseReport(const hidpp::Report& report)
}
auto response_slot = _responses.find(sub_id);
if(response_slot == _responses.end())
if (response_slot == _responses.end())
return false;
if(is_error) {
if (is_error) {
response_slot->second = static_cast<Error::ErrorCode>(
hidpp10_error.error_code);
} else {
@ -122,20 +118,19 @@ bool Device::responseReport(const hidpp::Report& report)
}
std::vector<uint8_t> Device::getRegister(uint8_t address,
const std::vector<uint8_t>& params, hidpp::Report::Type type)
{
const std::vector<uint8_t>& params,
hidpp::Report::Type type) {
assert(params.size() <= hidpp::LongParamLength);
uint8_t sub_id = type == hidpp::Report::Type::Short ?
GetRegisterShort : GetRegisterLong;
GetRegisterShort : GetRegisterLong;
return accessRegister(sub_id, address, params);
}
std::vector<uint8_t> Device::setRegister(uint8_t address,
const std::vector<uint8_t>& params,
hidpp::Report::Type type)
{
hidpp::Report::Type type) {
assert(params.size() <= hidpp::LongParamLength);
uint8_t sub_id = type == hidpp::Report::Type::Short ?
@ -145,10 +140,9 @@ std::vector<uint8_t> Device::setRegister(uint8_t address,
}
std::vector<uint8_t> Device::accessRegister(uint8_t sub_id, uint8_t address,
const std::vector<uint8_t> &params)
{
const std::vector<uint8_t>& params) {
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
hidpp::Report request(type, deviceIndex(), sub_id, address);
std::copy(params.begin(), params.end(), request.paramBegin());

View File

@ -25,29 +25,31 @@
#include "../hidpp/Device.h"
#include "Error.h"
namespace logid {
namespace backend {
namespace hidpp10
{
class Device : public hidpp::Device
{
namespace logid::backend::hidpp10 {
class Device : public hidpp::Device {
public:
Device(const std::string& path, hidpp::DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
Device(std::shared_ptr<raw::RawDevice> raw_dev,
hidpp::DeviceIndex index, double timeout);
Device(std::shared_ptr<dj::Receiver> receiver,
hidpp::DeviceIndex index, double timeout);
Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceIndex index, double timeout);
hidpp::Report sendReport(const hidpp::Report& report) final;
std::vector<uint8_t> getRegister(uint8_t address,
const std::vector<uint8_t>& params, hidpp::Report::Type type);
const std::vector<uint8_t>& params,
hidpp::Report::Type type);
std::vector<uint8_t> setRegister(uint8_t address,
const std::vector<uint8_t>& params, hidpp::Report::Type type);
const std::vector<uint8_t>& params,
hidpp::Report::Type type);
protected:
bool responseReport(const hidpp::Report& report) final;
private:
std::mutex _response_lock;
std::mutex _response_wait_lock;
@ -57,8 +59,8 @@ namespace hidpp10
std::map<uint8_t, std::optional<Response>> _responses;
std::vector<uint8_t> accessRegister(uint8_t sub_id,
uint8_t address, const std::vector<uint8_t>& params);
uint8_t address, const std::vector<uint8_t>& params);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP10_DEVICE_H

View File

@ -22,46 +22,43 @@
using namespace logid::backend::hidpp10;
Error::Error(uint8_t code): _code(code)
{
Error::Error(uint8_t code) : _code(code) {
assert(code != Success);
}
const char* Error::what() const noexcept
{
switch(_code) {
case Success:
return "Success";
case InvalidSubID:
return "Invalid sub ID";
case InvalidAddress:
return "Invalid address";
case InvalidValue:
return "Invalid value";
case ConnectFail:
return "Connection failure";
case TooManyDevices:
return "Too many devices";
case AlreadyExists:
return "Already exists";
case Busy:
return "Busy";
case UnknownDevice:
return "Unknown device";
case ResourceError:
return "Resource error";
case RequestUnavailable:
return "Request unavailable";
case InvalidParameterValue:
return "Invalid parameter value";
case WrongPINCode:
return "Wrong PIN code";
default:
return "Unknown error code";
const char* Error::what() const noexcept {
switch (_code) {
case Success:
return "Success";
case InvalidSubID:
return "Invalid sub ID";
case InvalidAddress:
return "Invalid address";
case InvalidValue:
return "Invalid value";
case ConnectFail:
return "Connection failure";
case TooManyDevices:
return "Too many devices";
case AlreadyExists:
return "Already exists";
case Busy:
return "Busy";
case UnknownDevice:
return "Unknown device";
case ResourceError:
return "Resource error";
case RequestUnavailable:
return "Request unavailable";
case InvalidParameterValue:
return "Invalid parameter value";
case WrongPINCode:
return "Wrong PIN code";
default:
return "Unknown error code";
}
}
uint8_t Error::code() const noexcept
{
uint8_t Error::code() const noexcept {
return _code;
}

View File

@ -20,17 +20,14 @@
#define LOGID_BACKEND_HIDPP10_ERROR_H
#include <cstdint>
#include <exception>
namespace logid {
namespace backend {
namespace hidpp10 {
namespace logid::backend::hidpp10 {
static constexpr uint8_t ErrorID = 0x8f;
class Error: public std::exception
{
class Error : public std::exception {
public:
enum ErrorCode: uint8_t
{
enum ErrorCode : uint8_t {
Success = 0x00,
InvalidSubID = 0x01,
InvalidAddress = 0x02,
@ -48,12 +45,13 @@ namespace hidpp10 {
explicit Error(uint8_t code);
const char* what() const noexcept override;
uint8_t code() const noexcept;
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] uint8_t code() const noexcept;
private:
uint8_t _code;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP10_ERROR_H

View File

@ -19,17 +19,13 @@
#ifndef LOGID_BACKEND_HIDPP10_DEFS_H
#define LOGID_BACKEND_HIDPP10_DEFS_H
namespace logid {
namespace backend {
namespace hidpp10
{
enum SubID: uint8_t
{
namespace logid::backend::hidpp10 {
enum SubID : uint8_t {
SetRegisterShort = 0x80,
GetRegisterShort = 0x81,
SetRegisterLong = 0x82,
GetRegisterLong = 0x83
};
}}}
}
#endif //LOGID_BACKEND_HIDPP10_DEFS_H

View File

@ -19,7 +19,6 @@
#include <cassert>
#include "Device.h"
#include "../hidpp/defs.h"
#include "../Error.h"
#include "../dj/Receiver.h"
@ -28,68 +27,62 @@ using namespace logid::backend::hidpp20;
Device::Device(const std::string& path, hidpp::DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
hidpp::Device(path, index,
std::move(monitor), timeout)
{
hidpp::Device(path, index,
std::move(monitor), timeout) {
// TODO: Fix version check
if(std::get<0>(version()) < 2)
if (std::get<0>(version()) < 2)
throw std::runtime_error("Invalid HID++ version");
}
Device::Device(std::shared_ptr<raw::RawDevice> raw_device,
hidpp::DeviceIndex index, double timeout) :
hidpp::Device(std::move(raw_device), index, timeout)
{
if(std::get<0>(version()) < 2)
hidpp::Device(std::move(raw_device), index, timeout) {
if (std::get<0>(version()) < 2)
throw std::runtime_error("Invalid HID++ version");
}
Device::Device(std::shared_ptr<dj::Receiver> receiver,
Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceConnectionEvent event, double timeout) :
hidpp::Device(std::move(receiver), event, timeout)
{
if(std::get<0>(version()) < 2)
hidpp::Device(receiver, event, timeout) {
if (std::get<0>(version()) < 2)
throw std::runtime_error("Invalid HID++ version");
}
Device::Device(std::shared_ptr<dj::Receiver> receiver,
Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceIndex index, double timeout)
: hidpp::Device(std::move(receiver), index, timeout)
{
if(std::get<0>(version()) < 2)
: hidpp::Device(receiver, index, timeout) {
if (std::get<0>(version()) < 2)
throw std::runtime_error("Invalid HID++ version");
}
std::vector<uint8_t> Device::callFunction(uint8_t feature_index,
uint8_t function, std::vector<uint8_t>& params)
{
uint8_t function, std::vector<uint8_t>& params) {
hidpp::Report::Type type;
assert(params.size() <= hidpp::LongParamLength);
if(params.size() <= hidpp::ShortParamLength)
if (params.size() <= hidpp::ShortParamLength)
type = hidpp::Report::Type::Short;
else if(params.size() <= hidpp::LongParamLength)
else if (params.size() <= hidpp::LongParamLength)
type = hidpp::Report::Type::Long;
else
throw hidpp::Report::InvalidReportID();
hidpp::Report request(type, deviceIndex(), feature_index, function,
LOGID_HIDPP_SOFTWARE_ID);
LOGID_HIDPP_SOFTWARE_ID);
std::copy(params.begin(), params.end(), request.paramBegin());
auto response = this->sendReport(request);
return std::vector<uint8_t>(response.paramBegin(), response.paramEnd());
return {response.paramBegin(), response.paramEnd()};
}
void Device::callFunctionNoResponse(uint8_t feature_index, uint8_t function,
std::vector<uint8_t> &params)
{
std::vector<uint8_t>& params) {
hidpp::Report::Type type;
assert(params.size() <= hidpp::LongParamLength);
if(params.size() <= hidpp::ShortParamLength)
if (params.size() <= hidpp::ShortParamLength)
type = hidpp::Report::Type::Short;
else if(params.size() <= hidpp::LongParamLength)
else if (params.size() <= hidpp::LongParamLength)
type = hidpp::Report::Type::Long;
else
throw hidpp::Report::InvalidReportID();
@ -101,21 +94,20 @@ void Device::callFunctionNoResponse(uint8_t feature_index, uint8_t function,
this->sendReportNoResponse(request);
}
hidpp::Report Device::sendReport(const hidpp::Report& report)
{
hidpp::Report Device::sendReport(const hidpp::Report& report) {
decltype(_responses)::iterator response_slot;
while(true) {
while (true) {
{
std::lock_guard lock(_response_lock);
if(_responses.empty()) {
if (_responses.empty()) {
response_slot = _responses.emplace(
2, std::optional<Response>()).first;
break;
} else if(_responses.size() < response_slots) {
} else if (_responses.size() < response_slots) {
uint8_t i = 0;
for(auto& x : _responses) {
if(x.first != i + 1) {
for (auto& x: _responses) {
if (x.first != i + 1) {
++i;
break;
}
@ -130,7 +122,7 @@ hidpp::Report Device::sendReport(const hidpp::Report& report)
}
std::unique_lock<std::mutex> lock(_response_wait_lock);
_response_cv.wait(lock, [this, sub_id=report.subId()](){
_response_cv.wait(lock, [this, sub_id = report.subId()]() {
std::lock_guard<std::mutex> lock(_response_lock);
return _responses.size() < response_slots;
});
@ -138,19 +130,19 @@ hidpp::Report Device::sendReport(const hidpp::Report& report)
{
std::lock_guard<std::mutex> lock(_response_lock);
hidpp::Report mod_report {report};
hidpp::Report mod_report{report};
mod_report.setSwId(response_slot->first);
sendReportNoResponse(std::move(mod_report));
}
std::unique_lock<std::mutex> wait(_response_wait_lock);
bool valid = _response_cv.wait_for(wait, io_timeout,
[this, &response_slot]() {
std::lock_guard<std::mutex> lock(_response_lock);
return response_slot->second.has_value();
});
[this, &response_slot]() {
std::lock_guard<std::mutex> lock(_response_lock);
return response_slot->second.has_value();
});
if(!valid) {
if (!valid) {
std::lock_guard<std::mutex> lock(_response_lock);
_responses.erase(response_slot);
throw TimeoutError();
@ -160,20 +152,19 @@ hidpp::Report Device::sendReport(const hidpp::Report& report)
assert(response_slot->second.has_value());
auto response = response_slot->second.value();
_responses.erase(response_slot);
if(std::holds_alternative<hidpp::Report>(response))
if (std::holds_alternative<hidpp::Report>(response))
return std::get<hidpp::Report>(response);
else // if(std::holds_alternative<Error::ErrorCode>(response))
throw Error(std::get<Error::ErrorCode>(response));
}
bool Device::responseReport(const hidpp::Report& report)
{
bool Device::responseReport(const hidpp::Report& report) {
std::lock_guard<std::mutex> lock(_response_lock);
uint8_t sw_id;
bool is_error = false;
hidpp::Report::Hidpp20Error hidpp20_error {};
if(report.isError20(&hidpp20_error)) {
hidpp::Report::Hidpp20Error hidpp20_error{};
if (report.isError20(&hidpp20_error)) {
is_error = true;
sw_id = hidpp20_error.software_id;
} else {
@ -181,10 +172,10 @@ bool Device::responseReport(const hidpp::Report& report)
}
auto response_slot = _responses.find(sw_id);
if(response_slot == _responses.end())
if (response_slot == _responses.end())
return false;
if(is_error) {
if (is_error) {
response_slot->second = static_cast<Error::ErrorCode>(
hidpp20_error.error_code);
} else {

View File

@ -26,32 +26,34 @@
#include "../hidpp/Device.h"
#include "Error.h"
namespace logid {
namespace backend {
namespace hidpp20 {
class Device : public hidpp::Device
{
namespace logid::backend::hidpp20 {
class Device : public hidpp::Device {
public:
Device(const std::string& path, hidpp::DeviceIndex index,
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
Device(std::shared_ptr<raw::RawDevice> raw_device,
hidpp::DeviceIndex index, double timeout);
Device(std::shared_ptr<dj::Receiver> receiver,
Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceConnectionEvent event, double timeout);
Device(std::shared_ptr<dj::Receiver> receiver,
Device(const std::shared_ptr<dj::Receiver>& receiver,
hidpp::DeviceIndex index, double timeout);
std::vector<uint8_t> callFunction(uint8_t feature_index,
uint8_t function,
std::vector<uint8_t>& params);
uint8_t function,
std::vector<uint8_t>& params);
void callFunctionNoResponse(uint8_t feature_index,
uint8_t function,
std::vector<uint8_t>& params);
uint8_t function,
std::vector<uint8_t>& 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;
@ -61,6 +63,6 @@ namespace hidpp20 {
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
std::map<uint8_t, std::optional<Response>> _responses;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_DEVICE_H

View File

@ -21,42 +21,39 @@
using namespace logid::backend::hidpp20;
Error::Error(uint8_t code) : _code (code)
{
Error::Error(uint8_t code) : _code(code) {
assert(_code != NoError);
}
const char* Error::what() const noexcept
{
switch(_code) {
case NoError:
return "No error";
case Unknown:
return "Unknown";
case InvalidArgument:
return "Invalid argument";
case OutOfRange:
return "Out of range";
case HardwareError:
return "Hardware error";
case LogitechInternal:
return "Logitech internal feature";
case InvalidFeatureIndex:
return "Invalid feature index";
case InvalidFunctionID:
return "Invalid function ID";
case Busy:
return "Busy";
case Unsupported:
return "Unsupported";
case UnknownDevice:
return "Unknown device";
default:
return "Unknown error code";
const char* Error::what() const noexcept {
switch (_code) {
case NoError:
return "No error";
case Unknown:
return "Unknown";
case InvalidArgument:
return "Invalid argument";
case OutOfRange:
return "Out of range";
case HardwareError:
return "Hardware error";
case LogitechInternal:
return "Logitech internal feature";
case InvalidFeatureIndex:
return "Invalid feature index";
case InvalidFunctionID:
return "Invalid function ID";
case Busy:
return "Busy";
case Unsupported:
return "Unsupported";
case UnknownDevice:
return "Unknown device";
default:
return "Unknown error code";
}
}
uint8_t Error::code() const noexcept
{
uint8_t Error::code() const noexcept {
return _code;
}

View File

@ -22,15 +22,12 @@
#include <stdexcept>
#include <cstdint>
namespace logid {
namespace backend {
namespace hidpp20 {
namespace logid::backend::hidpp20 {
static constexpr uint8_t ErrorID = 0xFF;
class Error: public std::exception
{
class Error : public std::exception {
public:
enum ErrorCode: uint8_t {
enum ErrorCode : uint8_t {
NoError = 0,
Unknown = 1,
InvalidArgument = 2,
@ -46,12 +43,13 @@ namespace hidpp20 {
explicit Error(uint8_t code);
const char* what() const noexcept override;
uint8_t code() const noexcept;
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] uint8_t code() const noexcept;
private:
uint8_t _code;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_ERROR_H

View File

@ -25,14 +25,13 @@
using namespace logid::backend::hidpp20;
std::vector<uint8_t> EssentialFeature::callFunction(uint8_t function_id,
std::vector<uint8_t>& params)
{
std::vector<uint8_t>& params) {
hidpp::Report::Type type;
assert(params.size() <= hidpp::LongParamLength);
if(params.size() <= hidpp::ShortParamLength)
if (params.size() <= hidpp::ShortParamLength)
type = hidpp::Report::Type::Short;
else if(params.size() <= hidpp::LongParamLength)
else if (params.size() <= hidpp::LongParamLength)
type = hidpp::Report::Type::Long;
else
throw hidpp::Report::InvalidReportID();
@ -46,25 +45,23 @@ std::vector<uint8_t> EssentialFeature::callFunction(uint8_t function_id,
}
EssentialFeature::EssentialFeature(hidpp::Device* dev, uint16_t _id) :
_device (dev)
{
_device(dev) {
_index = hidpp20::FeatureID::ROOT;
if(_id)
{
if (_id) {
std::vector<uint8_t> getFunc_req(2);
getFunc_req[0] = (_id >> 8) & 0xff;
getFunc_req[1] = _id & 0xff;
try {
_index = this->callFunction(Root::GetFeature,getFunc_req).at(0);
} catch(Error& e) {
if(e.code() == Error::InvalidFeatureIndex)
_index = this->callFunction(Root::GetFeature, getFunc_req).at(0);
} catch (Error& e) {
if (e.code() == Error::InvalidFeatureIndex)
throw UnsupportedFeature(_id);
throw e;
}
// 0 if not found
if(!_index)
if (!_index)
throw UnsupportedFeature(_id);
}
}

View File

@ -27,24 +27,23 @@
#include "Device.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class EssentialFeature
{
namespace logid::backend::hidpp20 {
class EssentialFeature {
public:
static const uint16_t ID;
virtual uint16_t getID() = 0;
protected:
EssentialFeature(hidpp::Device* dev, uint16_t _id);
std::vector<uint8_t> callFunction(uint8_t function_id,
std::vector<uint8_t>& params);
std::vector<uint8_t>& params);
private:
hidpp::Device* _device;
uint8_t _index;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_ESSENTIAL_FEATURE_H

View File

@ -23,55 +23,47 @@
using namespace logid::backend::hidpp20;
const char* UnsupportedFeature::what() const noexcept
{
const char* UnsupportedFeature::what() const noexcept {
return "Unsupported feature";
}
uint16_t UnsupportedFeature::code() const noexcept
{
uint16_t UnsupportedFeature::code() const noexcept {
return _f_id;
}
std::vector<uint8_t> Feature::callFunction(uint8_t function_id,
std::vector<uint8_t>& params)
{
std::vector<uint8_t>& params) {
return _device->callFunction(_index, function_id, params);
}
void Feature::callFunctionNoResponse(uint8_t function_id,
std::vector<uint8_t>& params)
{
std::vector<uint8_t>& params) {
_device->callFunctionNoResponse(_index, function_id, params);
}
Feature::Feature(Device* dev, uint16_t _id) : _device (dev)
{
Feature::Feature(Device* dev, uint16_t _id) : _device(dev) {
_index = hidpp20::FeatureID::ROOT;
if(_id)
{
if (_id) {
std::vector<uint8_t> getFunc_req(2);
getFunc_req[0] = (_id >> 8) & 0xff;
getFunc_req[1] = _id & 0xff;
try {
auto getFunc_resp = this->callFunction(Root::GetFeature,
getFunc_req);
auto getFunc_resp = this->callFunction(Root::GetFeature, getFunc_req);
_index = getFunc_resp[0];
} catch(Error& e) {
if(e.code() == Error::InvalidFeatureIndex)
} catch (Error& e) {
if (e.code() == Error::InvalidFeatureIndex)
throw UnsupportedFeature(_id);
throw e;
}
// 0 if not found
if(!_index)
if (!_index)
throw UnsupportedFeature(_id);
}
}
uint8_t Feature::featureIndex()
{
uint8_t Feature::featureIndex() {
return _index;
}

View File

@ -22,36 +22,40 @@
#include <cstdint>
#include "Device.h"
namespace logid {
namespace backend {
namespace hidpp20 {
class UnsupportedFeature : public std::exception
{
namespace logid::backend::hidpp20 {
class UnsupportedFeature : public std::exception {
public:
explicit UnsupportedFeature(uint16_t ID) : _f_id (ID) {}
const char* what() const noexcept override;
uint16_t code() const noexcept;
explicit UnsupportedFeature(uint16_t ID) : _f_id(ID) {}
[[nodiscard]] const char* what() const noexcept override;
[[nodiscard]] uint16_t code() const noexcept;
private:
uint16_t _f_id;
};
class Feature
{
class Feature {
public:
static const uint16_t ID;
virtual uint16_t getID() = 0;
uint8_t featureIndex();
virtual ~Feature() = default;
protected:
explicit Feature(Device* dev, uint16_t _id);
std::vector<uint8_t> callFunction(uint8_t function_id,
std::vector<uint8_t>& params);
void callFunctionNoResponse(uint8_t function_id,
std::vector<uint8_t>& params);
std::vector<uint8_t> callFunction(uint8_t function_id, std::vector<uint8_t>& params);
void callFunctionNoResponse(uint8_t function_id, std::vector<uint8_t>& params);
private:
Device* _device;
uint8_t _index;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_H

View File

@ -21,9 +21,7 @@
#include <cstdint>
namespace logid {
namespace backend {
namespace hidpp20 {
namespace logid::backend::hidpp20 {
struct feature_info {
uint16_t feature_id;
bool obsolete;
@ -31,10 +29,8 @@ namespace hidpp20 {
bool hidden;
};
namespace FeatureID
{
enum FeatureID : uint16_t
{
namespace FeatureID {
enum FeatureID : uint16_t {
ROOT = 0x0000,
FEATURE_SET = 0x0001,
FEATURE_INFO = 0x0002,
@ -127,6 +123,6 @@ namespace hidpp20 {
};
}
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATUREDEFS

View File

@ -19,31 +19,28 @@
using namespace logid::backend::hidpp20;
AdjustableDPI::AdjustableDPI(Device* dev) : Feature(dev, ID)
{
AdjustableDPI::AdjustableDPI(Device* dev) : Feature(dev, ID) {
}
uint8_t AdjustableDPI::getSensorCount()
{
uint8_t AdjustableDPI::getSensorCount() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetSensorCount, params);
return response[0];
}
AdjustableDPI::SensorDPIList AdjustableDPI::getSensorDPIList(uint8_t sensor)
{
AdjustableDPI::SensorDPIList AdjustableDPI::getSensorDPIList(uint8_t sensor) {
SensorDPIList dpi_list{};
std::vector<uint8_t> params(1);
params[0] = sensor;
auto response = callFunction(GetSensorDPIList, params);
dpi_list.dpiStep = false;
for(std::size_t i = 1; i < response.size(); i+=2) {
for (std::size_t i = 1; i < response.size(); i += 2) {
uint16_t dpi = response[i + 1];
dpi |= (response[i] << 8);
if(!dpi)
if (!dpi)
break;
if(dpi >= 0xe000) {
if (dpi >= 0xe000) {
dpi_list.isRange = true;
dpi_list.dpiStep = dpi - 0xe000;
} else {
@ -54,8 +51,7 @@ AdjustableDPI::SensorDPIList AdjustableDPI::getSensorDPIList(uint8_t sensor)
return dpi_list;
}
uint16_t AdjustableDPI::getDefaultSensorDPI(uint8_t sensor)
{
uint16_t AdjustableDPI::getDefaultSensorDPI(uint8_t sensor) {
std::vector<uint8_t> params(1);
params[0] = sensor;
auto response = callFunction(GetSensorDPI, params);
@ -66,8 +62,7 @@ uint16_t AdjustableDPI::getDefaultSensorDPI(uint8_t sensor)
return default_dpi;
}
uint16_t AdjustableDPI::getSensorDPI(uint8_t sensor)
{
uint16_t AdjustableDPI::getSensorDPI(uint8_t sensor) {
std::vector<uint8_t> params(1);
params[0] = sensor;
auto response = callFunction(GetSensorDPI, params);
@ -78,8 +73,7 @@ uint16_t AdjustableDPI::getSensorDPI(uint8_t sensor)
return dpi;
}
void AdjustableDPI::setSensorDPI(uint8_t sensor, uint16_t dpi)
{
void AdjustableDPI::setSensorDPI(uint8_t sensor, uint16_t dpi) {
std::vector<uint8_t> params(3);
params[0] = sensor;
params[1] = (dpi >> 8);

View File

@ -21,15 +21,12 @@
#include "../feature_defs.h"
#include "../Feature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class AdjustableDPI : public Feature
{
namespace logid::backend::hidpp20 {
class AdjustableDPI : public Feature {
public:
static const uint16_t ID = FeatureID::ADJUSTABLE_DPI;
virtual uint16_t getID() { return ID; }
[[nodiscard]] uint16_t getID() final { return ID; }
enum Function {
GetSensorCount = 0,
@ -38,23 +35,24 @@ namespace hidpp20
SetSensorDPI = 3
};
AdjustableDPI(Device* dev);
explicit AdjustableDPI(Device* dev);
uint8_t getSensorCount();
struct SensorDPIList
{
struct SensorDPIList {
std::vector<uint16_t> dpis;
bool isRange;
uint16_t dpiStep;
};
SensorDPIList getSensorDPIList(uint8_t sensor);
uint16_t getDefaultSensorDPI(uint8_t sensor);
uint16_t getSensorDPI(uint8_t sensor);
void setSensorDPI(uint8_t sensor, uint16_t dpi);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_ADJUSTABLEDPI_H

View File

@ -16,16 +16,13 @@
*
*/
#include "ChangeHost.h"
#include "../Error.h"
using namespace logid::backend::hidpp20;
ChangeHost::ChangeHost(Device *dev) : Feature(dev, ID), _host_count (0)
{
ChangeHost::ChangeHost(Device* dev) : Feature(dev, ID), _host_count(0) {
}
ChangeHost::HostInfo ChangeHost::getHostInfo()
{
ChangeHost::HostInfo ChangeHost::getHostInfo() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetHostInfo, params);
@ -34,23 +31,22 @@ ChangeHost::HostInfo ChangeHost::getHostInfo()
info.currentHost = response[1];
info.enhancedHostSwitch = response[2] & 1;
if(!_host_count)
if (!_host_count)
_host_count = info.hostCount;
return info;
}
void ChangeHost::setHost(uint8_t host)
{
void ChangeHost::setHost(uint8_t host) {
/* Expect connection to be severed here, send without response
*
* Since there is no response, we have to emulate any kind of
* error that may be returned (i.e. InvalidArgument as per the docs)
*/
if(!_host_count)
if (!_host_count)
getHostInfo();
if(host >= _host_count)
if (host >= _host_count)
throw hidpp20::Error(hidpp20::Error::InvalidArgument);
std::vector<uint8_t> params = {host};
@ -58,9 +54,9 @@ void ChangeHost::setHost(uint8_t host)
callFunctionNoResponse(SetCurrentHost, params);
}
std::vector<uint8_t> ChangeHost::getCookies()
{
if(!_host_count)
[[maybe_unused]]
std::vector<uint8_t> ChangeHost::getCookies() {
if (!_host_count)
getHostInfo();
std::vector<uint8_t> params(0);
@ -71,8 +67,8 @@ std::vector<uint8_t> ChangeHost::getCookies()
return response;
}
void ChangeHost::setCookie(uint8_t host, uint8_t cookie)
{
[[maybe_unused]]
void ChangeHost::setCookie(uint8_t host, uint8_t cookie) {
std::vector<uint8_t> params = {host, cookie};
callFunction(SetCookie, params);
}

View File

@ -21,17 +21,14 @@
#include "../feature_defs.h"
#include "../Feature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class ChangeHost : public Feature
{
namespace logid::backend::hidpp20 {
class ChangeHost : public Feature {
public:
static const uint16_t ID = FeatureID::CHANGE_HOST;
virtual uint16_t getID() { return ID; }
ChangeHost(Device* dev);
[[nodiscard]] uint16_t getID() final { return ID; }
explicit ChangeHost(Device* dev);
enum Function {
GetHostInfo = 0,
@ -40,22 +37,23 @@ namespace hidpp20
SetCookie = 3
};
struct HostInfo
{
struct HostInfo {
uint8_t hostCount;
uint8_t currentHost;
bool enhancedHostSwitch;
[[maybe_unused]] bool enhancedHostSwitch;
};
HostInfo getHostInfo();
void setHost(uint8_t host);
std::vector<uint8_t> getCookies();
void setCookie(uint8_t host, uint8_t cookie);
[[maybe_unused]] [[maybe_unused]] std::vector<uint8_t> getCookies();
[[maybe_unused]] [[maybe_unused]] void setCookie(uint8_t host, uint8_t cookie);
private:
uint8_t _host_count;
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_CHANGEHOST_H

View File

@ -16,61 +16,39 @@
*
*/
#include <cmath>
#include "DeviceName.h"
using namespace logid::backend;
using namespace logid::backend::hidpp20;
DeviceName::DeviceName(Device* dev) : Feature(dev, ID)
{
}
namespace {
std::string _getName(uint8_t length,
const std::function<std::vector<uint8_t>(std::vector<uint8_t>)>& fcall) {
uint8_t function_calls = length / hidpp::LongParamLength;
if (length % hidpp::LongParamLength)
function_calls++;
std::vector<uint8_t> params(1);
std::string name;
uint8_t DeviceName::getNameLength()
{
std::vector<uint8_t> params(0);
auto response = this->callFunction(Function::GetLength, params);
return response[0];
}
std::string _getName(uint8_t length,
const std::function<std::vector<uint8_t>(std::vector<uint8_t>)>& fcall)
{
uint8_t function_calls = length/hidpp::LongParamLength;
if(length % hidpp::LongParamLength)
function_calls++;
std::vector<uint8_t> params(1);
std::string name;
for(uint8_t i = 0; i < function_calls; i++) {
params[0] = i*hidpp::LongParamLength;
auto name_section = fcall(params);
for(std::size_t j = 0; j < hidpp::LongParamLength; j++) {
if(params[0] + j >= length)
return name;
name += name_section[j];
for (uint8_t i = 0; i < function_calls; i++) {
params[0] = i * hidpp::LongParamLength;
auto name_section = fcall(params);
for (std::size_t j = 0; j < hidpp::LongParamLength; j++) {
if (params[0] + j >= length)
return name;
name += (char) name_section[j];
}
}
return name;
}
return name;
}
std::string DeviceName::getName()
{
return _getName(getNameLength(), [this]
(std::vector<uint8_t> params)->std::vector<uint8_t> {
return this->callFunction(Function::GetDeviceName, params);
});
DeviceName::DeviceName(hidpp::Device* dev) :
EssentialFeature(dev, ID) {
}
EssentialDeviceName::EssentialDeviceName(hidpp::Device* dev) :
EssentialFeature(dev, ID)
{
}
uint8_t EssentialDeviceName::getNameLength()
{
uint8_t DeviceName::getNameLength() {
std::vector<uint8_t> params(0);
auto response = this->callFunction(DeviceName::Function::GetLength, params);
@ -78,10 +56,9 @@ uint8_t EssentialDeviceName::getNameLength()
return response[0];
}
std::string EssentialDeviceName::getName()
{
std::string DeviceName::getName() {
return _getName(getNameLength(), [this]
(std::vector<uint8_t> params)->std::vector<uint8_t> {
(std::vector<uint8_t> params) -> std::vector<uint8_t> {
return this->callFunction(DeviceName::Function::GetDeviceName, params);
});
}

View File

@ -23,39 +23,24 @@
#include "../feature_defs.h"
#include "../EssentialFeature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class DeviceName : public Feature
{
namespace logid::backend::hidpp20 {
class DeviceName : public EssentialFeature {
public:
static const uint16_t ID = FeatureID::DEVICE_NAME;
virtual uint16_t getID() { return ID; }
enum Function : uint8_t
{
enum Function : uint8_t {
GetLength = 0,
GetDeviceName = 1
};
explicit DeviceName(Device* device);
[[nodiscard]] uint16_t getID() final { return ID; }
uint8_t getNameLength();
std::string getName();
explicit DeviceName(hidpp::Device* device);
[[nodiscard]] uint8_t getNameLength();
[[nodiscard]] std::string getName();
};
class EssentialDeviceName : public EssentialFeature
{
public:
static const uint16_t ID = FeatureID::DEVICE_NAME;
virtual uint16_t getID() { return ID; }
explicit EssentialDeviceName(hidpp::Device* device);
uint8_t getNameLength();
std::string getName();
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H

View File

@ -19,19 +19,17 @@
using namespace logid::backend::hidpp20;
FeatureSet::FeatureSet(Device *device) : Feature(device, ID)
{
[[maybe_unused]]
FeatureSet::FeatureSet(Device* device) : Feature(device, ID) {
}
uint8_t FeatureSet::getFeatureCount()
{
uint8_t FeatureSet::getFeatureCount() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetFeatureCount, params);
return response[0];
}
uint16_t FeatureSet::getFeature(uint8_t feature_index)
{
uint16_t FeatureSet::getFeature(uint8_t feature_index) {
std::vector<uint8_t> params(1);
params[0] = feature_index;
auto response = callFunction(GetFeature, params);
@ -41,11 +39,11 @@ uint16_t FeatureSet::getFeature(uint8_t feature_index)
return feature_id;
}
std::map<uint8_t, uint16_t> FeatureSet::getFeatures()
{
[[maybe_unused]]
std::map<uint8_t, uint16_t> FeatureSet::getFeatures() {
uint8_t feature_count = getFeatureCount();
std::map<uint8_t, uint16_t> features;
for(uint8_t i = 0; i < feature_count; i++)
for (uint8_t i = 0; i < feature_count; i++)
features[i] = getFeature(i);
return features;
}

View File

@ -21,28 +21,28 @@
#include "../Feature.h"
#include "../feature_defs.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class FeatureSet : public Feature
{
namespace logid::backend::hidpp20 {
class FeatureSet : public Feature {
public:
static const uint16_t ID = FeatureID::FEATURE_SET;
virtual uint16_t getID() { return ID; }
enum Function : uint8_t
{
[[nodiscard]] uint16_t getID() final { return ID; }
enum Function : uint8_t {
GetFeatureCount = 0,
GetFeature = 1
};
[[maybe_unused]] [[maybe_unused]]
explicit FeatureSet(Device* device);
uint8_t getFeatureCount();
uint16_t getFeature(uint8_t feature_index);
std::map<uint8_t, uint16_t> getFeatures();
[[nodiscard]] uint8_t getFeatureCount();
[[nodiscard]] uint16_t getFeature(uint8_t feature_index);
[[maybe_unused]]
[[nodiscard]] std::map<uint8_t, uint16_t> getFeatures();
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_FEATURESET_H

View File

@ -20,12 +20,10 @@
using namespace logid::backend::hidpp20;
HiresScroll::HiresScroll(Device *device) : Feature(device, ID)
{
HiresScroll::HiresScroll(Device* device) : Feature(device, ID) {
}
HiresScroll::Capabilities HiresScroll::getCapabilities()
{
HiresScroll::Capabilities HiresScroll::getCapabilities() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetCapabilities, params);
@ -35,41 +33,35 @@ HiresScroll::Capabilities HiresScroll::getCapabilities()
return capabilities;
}
uint8_t HiresScroll::getMode()
{
uint8_t HiresScroll::getMode() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetMode, params);
return response[0];
}
void HiresScroll::setMode(uint8_t mode)
{
void HiresScroll::setMode(uint8_t mode) {
std::vector<uint8_t> params(1);
params[0] = mode;
callFunction(SetMode, params);
}
bool HiresScroll::getRatchetState()
{
[[maybe_unused]] bool HiresScroll::getRatchetState() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetRatchetState, params);
return params[0];
}
HiresScroll::WheelStatus HiresScroll::wheelMovementEvent(const hidpp::Report
&report)
{
HiresScroll::WheelStatus HiresScroll::wheelMovementEvent(const hidpp::Report& report) {
assert(report.function() == WheelMovement);
WheelStatus status{};
status.hiRes = report.paramBegin()[0] & 1<<4;
status.hiRes = report.paramBegin()[0] & 1 << 4;
status.periods = report.paramBegin()[0] & 0x0F;
status.deltaV = report.paramBegin()[1] << 8 | report.paramBegin()[2];
status.deltaV = (int16_t) (report.paramBegin()[1] << 8 | report.paramBegin()[2]);
return status;
}
HiresScroll::RatchetState HiresScroll::ratchetSwitchEvent(const hidpp::Report
&report)
{
[[maybe_unused]]
HiresScroll::RatchetState HiresScroll::ratchetSwitchEvent(const hidpp::Report& report) {
assert(report.function() == RatchetSwitch);
// Possible bad cast
return static_cast<RatchetState>(report.paramBegin()[0]);

View File

@ -21,58 +21,48 @@
#include "../Feature.h"
#include "../feature_defs.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class HiresScroll : public Feature
{
namespace logid::backend::hidpp20 {
class HiresScroll : public Feature {
public:
///TODO: Hires scroll V1?
static const uint16_t ID = FeatureID::HIRES_SCROLLING_V2;
virtual uint16_t getID() { return ID; }
enum Function : uint8_t
{
uint16_t getID() final { return ID; }
enum Function : uint8_t {
GetCapabilities = 0,
GetMode = 1,
SetMode = 2,
GetRatchetState = 3
};
enum Event : uint8_t
{
enum Event : uint8_t {
WheelMovement = 0,
RatchetSwitch = 1,
};
enum Capability : uint8_t
{
Invertable = 1<<3,
HasRatchet = 1<<2
enum Capability : uint8_t {
Invertible = 1 << 3,
HasRatchet = 1 << 2
};
enum Mode : uint8_t
{
Inverted = 1<<2,
HiRes = 1<<1,
enum Mode : uint8_t {
Inverted = 1 << 2,
HiRes = 1 << 1,
Target = 1
};
enum RatchetState : uint8_t
{
enum RatchetState : uint8_t {
FreeWheel = 0,
Ratchet = 1
};
struct Capabilities
{
struct Capabilities {
uint8_t multiplier;
uint8_t flags;
};
struct WheelStatus
{
struct WheelStatus {
bool hiRes;
uint8_t periods;
int16_t deltaV;
@ -81,13 +71,19 @@ namespace hidpp20
explicit HiresScroll(Device* device);
Capabilities getCapabilities();
uint8_t getMode();
void setMode(uint8_t mode);
[[maybe_unused]]
bool getRatchetState();
static WheelStatus wheelMovementEvent(const hidpp::Report& report);
[[maybe_unused]]
static RatchetState ratchetSwitchEvent(const hidpp::Report& report);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_HIRESSCROLL_H

View File

@ -21,47 +21,51 @@
using namespace logid::backend::hidpp20;
#define DEFINE_REPROG(x, base) \
x::x(Device* dev) : base(dev, ID) \
{ \
} \
x::x(Device* dev, uint16_t _id) : base(dev, _id) \
{ \
}
// Define all the ReprogControls versions
#define DEFINE_REPROG(T, Base) \
T::T(Device* dev, uint16_t _id) : Base(dev, _id) { } \
T::T(Device* dev) : T(dev, ID) { }
#define MAKE_REPROG(x, dev) \
try { \
return std::make_shared<x>(dev); \
} catch(UnsupportedFeature &e) {\
}
// Define all of the ReprogControls versions
DEFINE_REPROG(ReprogControls, Feature)
DEFINE_REPROG(ReprogControlsV2, ReprogControls)
DEFINE_REPROG(ReprogControlsV2_2, ReprogControlsV2)
DEFINE_REPROG(ReprogControlsV3, ReprogControlsV2_2)
DEFINE_REPROG(ReprogControlsV4, ReprogControlsV3)
std::shared_ptr<ReprogControls> ReprogControls::autoVersion(Device *dev)
{
MAKE_REPROG(ReprogControlsV4, dev)
MAKE_REPROG(ReprogControlsV3, dev)
MAKE_REPROG(ReprogControlsV2_2, dev)
MAKE_REPROG(ReprogControlsV2, dev)
template<typename T>
std::shared_ptr<T> make_reprog(Device* dev) {
try {
return std::make_shared<T>(dev);
} catch (UnsupportedFeature& e) {
return {};
}
}
std::shared_ptr<ReprogControls> ReprogControls::autoVersion(Device* dev) {
if (auto v4 = make_reprog<ReprogControlsV4>(dev)) {
return v4;
} else if (auto v3 = make_reprog<ReprogControlsV3>(dev)) {
return v3;
} else if (auto v2_2 = make_reprog<ReprogControlsV2_2>(dev)) {
return v2_2;
} else if (auto v2 = make_reprog<ReprogControlsV2>(dev)) {
return v2;
}
// If base version cannot be made, throw error
return std::make_shared<ReprogControls>(dev);
}
uint8_t ReprogControls::getControlCount()
{
uint8_t ReprogControls::getControlCount() {
std::vector<uint8_t> params(0);
auto response = callFunction(GetControlCount, params);
return response[0];
}
ReprogControls::ControlInfo ReprogControls::getControlInfo(uint8_t index)
{
ReprogControls::ControlInfo ReprogControls::getControlInfo(uint8_t index) {
std::vector<uint8_t> params(1);
ControlInfo info{};
params[0] = index;
@ -79,13 +83,12 @@ ReprogControls::ControlInfo ReprogControls::getControlInfo(uint8_t index)
return info;
}
void ReprogControls::initCidMap()
{
void ReprogControls::initCidMap() {
std::unique_lock<std::mutex> lock(_cids_populating);
if(_cids_initialized)
if (_cids_initialized)
return;
uint8_t controls = getControlCount();
for(uint8_t i = 0; i < controls; i++) {
for (uint8_t i = 0; i < controls; i++) {
auto info = getControlInfo(i);
_cids.emplace(info.controlID, info);
}
@ -93,57 +96,53 @@ void ReprogControls::initCidMap()
}
const std::map<uint16_t, ReprogControls::ControlInfo>&
ReprogControls::getControls() const
{
ReprogControls::getControls() const {
return _cids;
}
ReprogControls::ControlInfo ReprogControls::getControlIdInfo(uint16_t cid)
{
if(!_cids_initialized)
ReprogControls::ControlInfo ReprogControls::getControlIdInfo(uint16_t cid) {
if (!_cids_initialized)
initCidMap();
auto it = _cids.find(cid);
if(it == _cids.end())
if (it == _cids.end())
throw Error(Error::InvalidArgument);
else
return it->second;
}
ReprogControls::ControlInfo ReprogControls::getControlReporting(uint16_t cid)
{
[[maybe_unused]] ReprogControls::ControlInfo ReprogControls::getControlReporting(uint16_t cid) {
// Emulate this function, only Reprog controls v4 supports this
auto info = getControlIdInfo(cid);
ControlInfo report{};
report.controlID = cid;
report.flags = 0;
if(info.flags & TemporaryDivertable)
if (info.flags & TemporaryDivertable)
report.flags |= TemporaryDiverted;
if(info.flags & PersisentlyDivertable)
if (info.flags & PersistentlyDivertable)
report.flags |= PersistentlyDiverted;
if(info.additionalFlags & RawXY)
if (info.additionalFlags & RawXY)
report.flags |= RawXYDiverted;
return report;
}
void ReprogControls::setControlReporting(uint8_t cid, ControlInfo info)
{
void ReprogControls::setControlReporting(uint8_t cid, ControlInfo info) {
// This function does not exist pre-v4 and cannot be emulated, ignore.
(void)cid; (void)info; // Suppress unused warnings
(void) cid;
(void) info; // Suppress unused warnings
}
std::set<uint16_t> ReprogControls::divertedButtonEvent(
const hidpp::Report& report)
{
const hidpp::Report& report) {
assert(report.function() == DivertedButtonEvent);
std::set<uint16_t> buttons;
uint8_t cids = std::distance(report.paramBegin(), report.paramEnd())/2;
for(uint8_t i = 0; i < cids; i++) {
uint16_t cid = report.paramBegin()[2*i + 1];
cid |= report.paramBegin()[2*i] << 8;
if(cid)
uint8_t cids = std::distance(report.paramBegin(), report.paramEnd()) / 2;
for (uint8_t i = 0; i < cids; i++) {
uint16_t cid = report.paramBegin()[2 * i + 1];
cid |= report.paramBegin()[2 * i] << 8;
if (cid)
buttons.insert(cid);
else
break;
@ -152,19 +151,15 @@ std::set<uint16_t> ReprogControls::divertedButtonEvent(
}
ReprogControls::Move ReprogControls::divertedRawXYEvent(const hidpp::Report
&report)
{
& report) {
assert(report.function() == DivertedRawXYEvent);
Move move{};
move.x = report.paramBegin()[1];
move.x |= report.paramBegin()[0] << 8;
move.y = report.paramBegin()[3];
move.y |= report.paramBegin()[2] << 8;
move.x = (int16_t) ((report.paramBegin()[0] << 8) | report.paramBegin()[1]);
move.y = (int16_t) ((report.paramBegin()[2] << 8) | report.paramBegin()[3]);
return move;
}
ReprogControls::ControlInfo ReprogControlsV4::getControlReporting(uint16_t cid)
{
ReprogControls::ControlInfo ReprogControlsV4::getControlReporting(uint16_t cid) {
std::vector<uint8_t> params(2);
ControlInfo info{};
params[0] = (cid >> 8) & 0xff;
@ -177,8 +172,7 @@ ReprogControls::ControlInfo ReprogControlsV4::getControlReporting(uint16_t cid)
return info;
}
void ReprogControlsV4::setControlReporting(uint8_t cid, ControlInfo info)
{
void ReprogControlsV4::setControlReporting(uint8_t cid, ControlInfo info) {
std::vector<uint8_t> params(5);
params[0] = (cid >> 8) & 0xff;
params[1] = cid & 0xff;

View File

@ -23,12 +23,8 @@
#include "../feature_defs.h"
#include "../Feature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class ReprogControls : public Feature
{
namespace logid::backend::hidpp20 {
class ReprogControls : public Feature {
public:
enum Function {
GetControlCount = 0,
@ -41,8 +37,7 @@ namespace hidpp20
DivertedRawXYEvent = 1
};
struct ControlInfo
{
struct ControlInfo {
uint16_t controlID;
uint16_t taskID;
uint8_t flags;
@ -52,121 +47,127 @@ namespace hidpp20
uint8_t additionalFlags;
};
enum ControlInfoFlags: uint8_t
{
enum ControlInfoFlags : uint8_t {
MouseButton = 1, //Mouse button
FKey = 1<<1, //Fx key
Hotkey = 1<<2,
FnToggle = 1<<3,
ReprogHint = 1<<4,
TemporaryDivertable = 1<<5,
PersisentlyDivertable = 1<<6,
Virtual = 1<<7
FKey = 1 << 1, //Fx key
Hotkey = 1 << 2,
FnToggle = 1 << 3,
ReprogHint = 1 << 4,
TemporaryDivertable = 1 << 5,
PersistentlyDivertable = 1 << 6,
Virtual = 1 << 7
};
enum ControlInfoAdditionalFlags: uint8_t {
RawXY = 1<<0
enum ControlInfoAdditionalFlags : uint8_t {
RawXY = 1 << 0
};
enum ControlReportingFlags: uint8_t {
TemporaryDiverted = 1<<0,
ChangeTemporaryDivert = 1<<1,
PersistentlyDiverted = 1<<2,
ChangePersistentDivert = 1<<3,
RawXYDiverted = 1<<4,
ChangeRawXYDivert = 1<<5
enum ControlReportingFlags : uint8_t {
TemporaryDiverted = 1 << 0,
ChangeTemporaryDivert = 1 << 1,
PersistentlyDiverted = 1 << 2,
ChangePersistentDivert [[maybe_unused]] = 1 << 3,
RawXYDiverted = 1 << 4,
ChangeRawXYDivert = 1 << 5
};
struct Move
{
struct Move {
int16_t x;
int16_t y;
};
static const uint16_t ID = FeatureID::REPROG_CONTROLS;
virtual uint16_t getID() { return ID; }
virtual bool supportsRawXY() { return false; }
[[nodiscard]] uint16_t getID() override { return ID; }
[[nodiscard]] virtual bool supportsRawXY() { return false; }
explicit ReprogControls(Device* dev);
virtual uint8_t getControlCount();
[[nodiscard]] virtual uint8_t getControlCount();
virtual ControlInfo getControlInfo(uint8_t cid);
[[nodiscard]] virtual ControlInfo getControlInfo(uint8_t cid);
virtual ControlInfo getControlIdInfo(uint16_t cid);
[[nodiscard]] virtual ControlInfo getControlIdInfo(uint16_t cid);
virtual void initCidMap();
const std::map<uint16_t, ControlInfo>& getControls() const;
[[nodiscard]] const std::map<uint16_t, ControlInfo>& getControls() const;
// Onlu controlId and flags will be set
virtual ControlInfo getControlReporting(uint16_t cid);
// Only controlId and flags will be set
[[maybe_unused]]
[[nodiscard]] virtual ControlInfo getControlReporting(uint16_t cid);
// Only controlId (for remap) and flags will be read
virtual void setControlReporting(uint8_t cid, ControlInfo info);
static std::set<uint16_t> divertedButtonEvent(const hidpp::Report&
report);
[[nodiscard]] static std::set<uint16_t> divertedButtonEvent(const hidpp::Report& report);
static Move divertedRawXYEvent(const hidpp::Report& report);
[[nodiscard]] static Move divertedRawXYEvent(const hidpp::Report& report);
[[nodiscard]] static std::shared_ptr<ReprogControls> autoVersion(Device* dev);
static std::shared_ptr<ReprogControls> autoVersion(Device *dev);
protected:
ReprogControls(Device* dev, uint16_t _id);
std::map<uint16_t, ControlInfo> _cids;
bool _cids_initialized = false;
std::mutex _cids_populating;
};
class ReprogControlsV2 : public ReprogControls
{
class ReprogControlsV2 : public ReprogControls {
public:
static const uint16_t ID = FeatureID::REPROG_CONTROLS_V2;
virtual uint16_t getID() override { return ID; }
[[nodiscard]] uint16_t getID() override { return ID; }
explicit ReprogControlsV2(Device* dev);
protected:
ReprogControlsV2(Device* dev, uint16_t _id);
};
class ReprogControlsV2_2 : public ReprogControlsV2
{
class ReprogControlsV2_2 : public ReprogControlsV2 {
public:
static const uint16_t ID = FeatureID::REPROG_CONTROLS_V2_2;
virtual uint16_t getID() override { return ID; }
[[nodiscard]] uint16_t getID() override { return ID; }
explicit ReprogControlsV2_2(Device* dev);
protected:
ReprogControlsV2_2(Device* dev, uint16_t _id);
};
class ReprogControlsV3 : public ReprogControlsV2_2
{
class ReprogControlsV3 : public ReprogControlsV2_2 {
public:
static const uint16_t ID = FeatureID::REPROG_CONTROLS_V3;
virtual uint16_t getID() override { return ID; }
[[nodiscard]] uint16_t getID() override { return ID; }
explicit ReprogControlsV3(Device* dev);
protected:
ReprogControlsV3(Device* dev, uint16_t _id);
};
class ReprogControlsV4 : public ReprogControlsV3
{
class ReprogControlsV4 : public ReprogControlsV3 {
public:
static const uint16_t ID = FeatureID::REPROG_CONTROLS_V4;
virtual uint16_t getID() override { return ID; }
bool supportsRawXY() override { return true; }
[[nodiscard]] uint16_t getID() final { return ID; }
ControlInfo getControlReporting(uint16_t cid) override;
[[nodiscard]] bool supportsRawXY() override { return true; }
[[nodiscard]] ControlInfo getControlReporting(uint16_t cid) override;
void setControlReporting(uint8_t cid, ControlInfo info) override;
explicit ReprogControlsV4(Device* dev);
protected:
[[maybe_unused]]
ReprogControlsV4(Device* dev, uint16_t _id);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_REPROGCONTROLS_H

View File

@ -19,12 +19,10 @@
using namespace logid::backend::hidpp20;
Reset::Reset(Device *device) : Feature(device, ID)
{
Reset::Reset(Device* device) : Feature(device, ID) {
}
uint16_t Reset::getProfile()
{
uint16_t Reset::getProfile() {
std::vector<uint8_t> params(0);
auto results = callFunction(GetProfile, params);
@ -33,8 +31,7 @@ uint16_t Reset::getProfile()
return profile;
}
void Reset::reset(uint16_t profile)
{
void Reset::reset(uint16_t profile) {
std::vector<uint8_t> params(2);
params[0] = (profile >> 8) & 0xff;
params[1] = profile & 0xff;

View File

@ -21,27 +21,24 @@
#include "../Feature.h"
#include "../feature_defs.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class Reset : public Feature
{
namespace logid::backend::hidpp20 {
class Reset : public Feature {
public:
static const uint16_t ID = FeatureID::RESET;
virtual uint16_t getID() { return ID; }
enum Function : uint8_t
{
GetProfile = 0,
ResetToProfile = 1
[[nodiscard]] uint16_t getID() final { return ID; }
enum Function : uint8_t {
GetProfile = 0,
ResetToProfile = 1
};
explicit Reset(Device* device);
uint16_t getProfile();
void reset(uint16_t profile = 0);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_RESET_H

View File

@ -17,82 +17,53 @@
*/
#include "Root.h"
#include "../Error.h"
using namespace logid::backend::hidpp20;
Root::Root(Device* dev) : Feature(dev, ID)
{
namespace {
std::vector<uint8_t> _genGetFeatureParams(uint16_t feature_id) {
std::vector<uint8_t> params(2);
params[0] = feature_id & 0xff;
params[1] = (feature_id >> 8) & 0xff;
return params;
}
feature_info _genGetFeatureInfo(uint16_t feature_id,
std::vector<uint8_t> response) {
feature_info info{};
info.feature_id = response[0];
if (!info.feature_id)
throw UnsupportedFeature(feature_id);
info.hidden = response[1] & Root::FeatureFlag::Hidden;
info.obsolete = response[1] & Root::FeatureFlag::Obsolete;
info.internal = response[1] & Root::FeatureFlag::Internal;
return info;
}
}
std::vector<uint8_t> _genGetFeatureParams(uint16_t feature_id)
{
std::vector<uint8_t> params(2);
params[0] = feature_id & 0xff;
params[1] = (feature_id >> 8) & 0xff;
return params;
Root::Root(hidpp::Device* dev) : EssentialFeature(dev, ID) {
}
feature_info _genGetFeatureInfo(uint16_t feature_id,
std::vector<uint8_t> response)
{
feature_info info{};
info.feature_id = response[0];
if(!info.feature_id)
throw UnsupportedFeature(feature_id);
info.hidden = response[1] & Root::FeatureFlag::Hidden;
info.obsolete = response[1] & Root::FeatureFlag::Obsolete;
info.internal = response[1] & Root::FeatureFlag::Internal;
return info;
}
feature_info Root::getFeature(uint16_t feature_id)
{
feature_info Root::getFeature(uint16_t feature_id) {
auto params = _genGetFeatureParams(feature_id);
try {
auto response = this->callFunction(Root::Function::GetFeature, params);
return _genGetFeatureInfo(feature_id, response);
} catch(Error& e) {
if(e.code() == Error::InvalidFeatureIndex)
} catch (Error& e) {
if (e.code() == Error::InvalidFeatureIndex)
throw UnsupportedFeature(feature_id);
throw e;
}
}
std::tuple<uint8_t, uint8_t> Root::getVersion()
{
std::vector<uint8_t> params(0);
auto response = this->callFunction(Function::Ping, params);
return std::make_tuple(response[0], response[1]);
}
EssentialRoot::EssentialRoot(hidpp::Device* dev) : EssentialFeature(dev, ID)
{
}
feature_info EssentialRoot::getFeature(uint16_t feature_id)
{
auto params = _genGetFeatureParams(feature_id);
try {
auto response = this->callFunction(Root::Function::GetFeature, params);
return _genGetFeatureInfo(feature_id, response);
} catch(Error& e) {
if(e.code() == Error::InvalidFeatureIndex)
throw UnsupportedFeature(feature_id);
throw e;
}
}
std::tuple<uint8_t, uint8_t> EssentialRoot::getVersion()
{
std::tuple<uint8_t, uint8_t> Root::getVersion() {
std::vector<uint8_t> params(0);
auto response = this->callFunction(Root::Function::Ping, params);
if(response[0] == 0x11)
if (response[0] == 0x11)
return std::make_tuple(1, 0);
return std::make_tuple(response[0], response[1]);

View File

@ -23,46 +23,31 @@
#include "../EssentialFeature.h"
#include "../feature_defs.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class Root : public Feature
{
namespace logid::backend::hidpp20 {
class Root : public EssentialFeature {
public:
static const uint16_t ID = FeatureID::ROOT;
virtual uint16_t getID() { return ID; }
enum Function : uint8_t
{
uint16_t getID() final { return ID; }
explicit Root(hidpp::Device* device);
enum Function : uint8_t {
GetFeature = 0,
Ping = 1
};
explicit Root(Device* device);
feature_info getFeature(uint16_t feature_id);
feature_info getFeature (uint16_t feature_id);
std::tuple<uint8_t, uint8_t> getVersion();
enum FeatureFlag : uint8_t
{
Obsolete = 1<<7,
Hidden = 1<<6,
Internal = 1<<5
enum FeatureFlag : uint8_t {
Obsolete = 1 << 7,
Hidden = 1 << 6,
Internal = 1 << 5
};
};
class EssentialRoot : public EssentialFeature
{
public:
static const uint16_t ID = FeatureID::ROOT;
virtual uint16_t getID() { return ID; }
explicit EssentialRoot(hidpp::Device* device);
feature_info getFeature(uint16_t feature_id);
std::tuple<uint8_t, uint8_t> getVersion();
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H

View File

@ -19,29 +19,26 @@
using namespace logid::backend::hidpp20;
SmartShift::SmartShift(Device* dev) : Feature(dev, ID)
{
SmartShift::SmartShift(Device* dev) : Feature(dev, ID) {
}
SmartShift::SmartshiftStatus SmartShift::getStatus()
{
SmartShift::SmartshiftStatus SmartShift::getStatus() {
std::vector<uint8_t> params(0);
SmartshiftStatus status{};
auto response = callFunction(GetStatus, params);
status.active = response[0]-1;
status.active = response[0] - 1;
status.autoDisengage = response[1];
status.defaultAutoDisengage = response[2];
return status;
}
void SmartShift::setStatus(SmartshiftStatus status)
{
void SmartShift::setStatus(SmartshiftStatus status) {
std::vector<uint8_t> params(3);
if(status.setActive)
if (status.setActive)
params[0] = status.active + 1;
if(status.setAutoDisengage)
if (status.setAutoDisengage)
params[1] = status.autoDisengage;
if(status.setDefaultAutoDisengage)
if (status.setDefaultAutoDisengage)
params[2] = status.defaultAutoDisengage;
callFunction(SetStatus, params);
}

View File

@ -21,15 +21,12 @@
#include "../feature_defs.h"
#include "../Feature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class SmartShift : public Feature
{
namespace logid::backend::hidpp20 {
class SmartShift : public Feature {
public:
static const uint16_t ID = FeatureID::SMART_SHIFT;
virtual uint16_t getID() { return ID; }
uint16_t getID() final { return ID; }
enum Function {
GetStatus = 0,
@ -38,8 +35,7 @@ namespace hidpp20
explicit SmartShift(Device* dev);
struct SmartshiftStatus
{
struct SmartshiftStatus {
bool active;
uint8_t autoDisengage;
uint8_t defaultAutoDisengage;
@ -47,8 +43,9 @@ namespace hidpp20
};
SmartshiftStatus getStatus();
void setStatus(SmartshiftStatus status);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_SMARTSHIFT_H

View File

@ -21,12 +21,10 @@
using namespace logid::backend::hidpp20;
ThumbWheel::ThumbWheel(Device *dev) : Feature(dev, ID)
{
ThumbWheel::ThumbWheel(Device* dev) : Feature(dev, ID) {
}
ThumbWheel::ThumbwheelInfo ThumbWheel::getInfo()
{
ThumbWheel::ThumbwheelInfo ThumbWheel::getInfo() {
std::vector<uint8_t> params(0), response;
ThumbwheelInfo info{};
response = callFunction(GetInfo, params);
@ -43,20 +41,20 @@ ThumbWheel::ThumbwheelInfo ThumbWheel::getInfo()
return info;
}
ThumbWheel::ThumbwheelStatus ThumbWheel::getStatus()
{
ThumbWheel::ThumbwheelStatus ThumbWheel::getStatus() {
std::vector<uint8_t> params(0), response;
ThumbwheelStatus status{};
response = callFunction(GetStatus, params);
status.diverted = response[0];
status.inverted = response[1] & 1;
status.touch = response[1] & (1 << 1);
status.proxy = response[1] & (1 << 2);
return status;
}
ThumbWheel::ThumbwheelStatus ThumbWheel::setStatus(bool divert, bool invert)
{
ThumbWheel::ThumbwheelStatus ThumbWheel::setStatus(bool divert, bool invert) {
std::vector<uint8_t> params(2), response;
ThumbwheelStatus status{};
params[0] = divert;
@ -69,13 +67,10 @@ ThumbWheel::ThumbwheelStatus ThumbWheel::setStatus(bool divert, bool invert)
return status;
}
ThumbWheel::ThumbwheelEvent ThumbWheel::thumbwheelEvent(
const hidpp::Report& report)
{
ThumbWheel::ThumbwheelEvent ThumbWheel::thumbwheelEvent(const hidpp::Report& report) {
assert(report.function() == Event);
ThumbwheelEvent event{};
event.rotation = report.paramBegin()[1];
event.rotation |= report.paramBegin()[0] << 8;
event.rotation = (int16_t) ((report.paramBegin()[0] << 8) | report.paramBegin()[1]);
event.timestamp = report.paramBegin()[3];
event.timestamp |= report.paramBegin()[2] << 8;
event.rotationStatus = static_cast<RotationStatus>(report.paramBegin()[4]);

View File

@ -21,15 +21,12 @@
#include "../feature_defs.h"
#include "../Feature.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class ThumbWheel : public Feature
{
namespace logid::backend::hidpp20 {
class ThumbWheel : public Feature {
public:
static const uint16_t ID = FeatureID::THUMB_WHEEL;
virtual uint16_t getID() { return ID; }
uint16_t getID() final { return ID; }
enum Function {
GetInfo = 0,
@ -43,12 +40,11 @@ namespace hidpp20
explicit ThumbWheel(Device* dev);
enum Capabilities : uint8_t
{
enum Capabilities : uint8_t {
Timestamp = 1,
Touch = 1<<1,
Proxy = 1<<2,
SingleTap = 1<<3
Touch = 1 << 1,
Proxy = 1 << 2,
SingleTap = 1 << 3
};
struct ThumbwheelInfo {
@ -66,8 +62,7 @@ namespace hidpp20
bool proxy;
};
enum RotationStatus : uint8_t
{
enum RotationStatus : uint8_t {
Inactive = 0,
Start = 1,
Active = 2,
@ -81,14 +76,14 @@ namespace hidpp20
uint8_t flags;
};
ThumbwheelInfo getInfo();
ThumbwheelStatus getStatus();
[[nodiscard]] ThumbwheelInfo getInfo();
[[nodiscard]] ThumbwheelStatus getStatus();
ThumbwheelStatus setStatus(bool divert, bool invert);
[[nodiscard]] ThumbwheelEvent thumbwheelEvent(
const hidpp::Report& report);
[[nodiscard]] static ThumbwheelEvent thumbwheelEvent(const hidpp::Report& report);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_THUMBWHEEL_H

View File

@ -20,13 +20,11 @@
using namespace logid::backend::hidpp20;
WirelessDeviceStatus::WirelessDeviceStatus(Device* dev) : Feature(dev, ID)
{
WirelessDeviceStatus::WirelessDeviceStatus(Device* dev) : Feature(dev, ID) {
}
WirelessDeviceStatus::Status WirelessDeviceStatus::statusBroadcastEvent(
const hidpp::Report &report)
{
const hidpp::Report& report) {
assert(report.function() == StatusBroadcast);
Status status = {};
auto params = report.paramBegin();

View File

@ -21,32 +21,27 @@
#include "../Feature.h"
#include "../feature_defs.h"
namespace logid {
namespace backend {
namespace hidpp20
{
class WirelessDeviceStatus : public Feature
{
namespace logid::backend::hidpp20 {
class WirelessDeviceStatus : public Feature {
public:
static constexpr uint16_t ID = FeatureID::WIRELESS_DEVICE_STATUS;
virtual uint16_t getID() { return ID; }
WirelessDeviceStatus(Device* dev);
[[nodiscard]] uint16_t getID() final { return ID; }
enum Event : uint8_t
{
explicit WirelessDeviceStatus(Device* dev);
enum Event : uint8_t {
StatusBroadcast = 0
};
struct Status
{
struct Status {
bool reconnection;
bool reconfNeeded;
bool powerSwitch;
};
static Status statusBroadcastEvent(const hidpp::Report &report);
static Status statusBroadcastEvent(const hidpp::Report& report);
};
}}}
}
#endif //LOGID_BACKEND_HIDPP20_FEATURE_WIRELESSDEVICESTATUS_H

View File

@ -26,35 +26,33 @@
extern "C"
{
#include <unistd.h>
#include <libudev.h>
}
using namespace logid;
using namespace logid::backend::raw;
DeviceMonitor::DeviceMonitor() : _io_monitor (std::make_shared<IOMonitor>()),
_ready (false)
{
DeviceMonitor::DeviceMonitor() : _io_monitor(std::make_shared<IOMonitor>()),
_ready(false) {
int ret;
_udev_context = udev_new();
if(!_udev_context)
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)
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)
if (0 != ret) {
if (_udev_monitor)
udev_monitor_unref(_udev_monitor);
if(_udev_context)
if (_udev_context)
udev_unref(_udev_context);
throw std::system_error(
-ret, std::system_category(),
@ -62,10 +60,10 @@ DeviceMonitor::DeviceMonitor() : _io_monitor (std::make_shared<IOMonitor>()),
}
ret = udev_monitor_enable_receiving(_udev_monitor);
if(0 != ret) {
if(_udev_monitor)
if (0 != ret) {
if (_udev_monitor)
udev_monitor_unref(_udev_monitor);
if(_udev_context)
if (_udev_context)
udev_unref(_udev_context);
throw std::system_error(-ret, std::system_category(),
"udev_monitor_enable_receiving");
@ -74,34 +72,32 @@ DeviceMonitor::DeviceMonitor() : _io_monitor (std::make_shared<IOMonitor>()),
_fd = udev_monitor_get_fd(_udev_monitor);
}
DeviceMonitor::~DeviceMonitor()
{
if(_ready)
DeviceMonitor::~DeviceMonitor() {
if (_ready)
_io_monitor->remove(_fd);
if(_udev_monitor)
if (_udev_monitor)
udev_monitor_unref(_udev_monitor);
if(_udev_context)
if (_udev_context)
udev_unref(_udev_context);
}
void DeviceMonitor::ready()
{
if(_ready)
void DeviceMonitor::ready() {
if (_ready)
return;
_ready = true;
_io_monitor->add(_fd, {
[this]() {
struct udev_device *device = udev_monitor_receive_device(
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);
std::string dev_node = udev_device_get_devnode(device);
if (action == "add")
spawn_task([this, devnode]() { _addHandler(devnode); });
spawn_task([this, dev_node]() { _addHandler(dev_node); });
else if (action == "remove")
spawn_task([this, devnode]() { _removeHandler(devnode); });
spawn_task([this, dev_node]() { _removeHandler(dev_node); });
udev_device_unref(device);
},
@ -114,66 +110,62 @@ void DeviceMonitor::ready()
});
}
void DeviceMonitor::enumerate()
{
void DeviceMonitor::enumerate() {
int ret;
struct udev_enumerate* udev_enum = udev_enumerate_new(_udev_context);
ret = udev_enumerate_add_match_subsystem(udev_enum, "hidraw");
if(0 != ret)
if (0 != ret)
throw std::system_error(-ret, std::system_category(),
"udev_enumerate_add_match_subsystem");
"udev_enumerate_add_match_subsystem");
ret = udev_enumerate_scan_devices(udev_enum);
if(0 != ret)
if (0 != ret)
throw std::system_error(-ret, std::system_category(),
"udev_enumerate_scan_devices");
struct udev_list_entry* udev_enum_entry;
udev_list_entry_foreach(udev_enum_entry,
udev_enumerate_get_list_entry(udev_enum)) {
udev_enumerate_get_list_entry(udev_enum)) {
const char* name = udev_list_entry_get_name(udev_enum_entry);
struct udev_device* device = udev_device_new_from_syspath(_udev_context,
name);
if(!device)
name);
if (!device)
throw std::runtime_error("udev_device_new_from_syspath failed");
std::string devnode = udev_device_get_devnode(device);
std::string dev_node = udev_device_get_devnode(device);
udev_device_unref(device);
_addHandler(devnode);
_addHandler(dev_node);
}
udev_enumerate_unref(udev_enum);
}
void DeviceMonitor::_addHandler(const std::string& device)
{
void DeviceMonitor::_addHandler(const std::string& device) {
try {
auto supported_reports = backend::hidpp::getSupportedReports(
RawDevice::getReportDescriptor(device));
if(supported_reports)
if (supported_reports)
this->addDevice(device);
else
logPrintf(DEBUG, "Unsupported device %s ignored",
device.c_str());
} catch(std::exception& e) {
} catch (std::exception& e) {
logPrintf(WARN, "Error adding device %s: %s",
device.c_str(), e.what());
}
}
void DeviceMonitor::_removeHandler(const std::string& device)
{
void DeviceMonitor::_removeHandler(const std::string& device) {
try {
this->removeDevice(device);
} catch(std::exception& e) {
} catch (std::exception& e) {
logPrintf(WARN, "Error removing device %s: %s",
device.c_str(), e.what());
}
}
std::shared_ptr<IOMonitor> DeviceMonitor::ioMonitor() const
{
std::shared_ptr<IOMonitor> DeviceMonitor::ioMonitor() const {
return _io_monitor;
}

View File

@ -27,28 +27,32 @@
extern "C"
{
struct udev;
struct udev_monitor;
struct udev;
struct udev_monitor;
}
namespace logid::backend::raw
{
class DeviceMonitor
{
namespace logid::backend::raw {
class DeviceMonitor {
public:
virtual ~DeviceMonitor();
void enumerate();
[[nodiscard]] std::shared_ptr<IOMonitor> ioMonitor() const;
protected:
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<IOMonitor> _io_monitor;

View File

@ -23,21 +23,16 @@
#include <cstdint>
#include <vector>
namespace logid {
namespace backend {
namespace raw
{
struct RawEventHandler
{
namespace logid::backend::raw {
struct RawEventHandler {
std::function<bool(const std::vector<uint8_t>&)> condition;
std::function<void(const std::vector<uint8_t>&)> callback;
RawEventHandler(std::function<bool(const std::vector<uint8_t>&)> cond,
std::function<void(const std::vector<uint8_t>&)> call) :
condition (std::move(cond)), callback (std::move(call))
{
condition(std::move(cond)), callback(std::move(call)) {
}
};
}}}
}
#endif //LOGID_BACKEND_RAW_DEFS_H

View File

@ -30,24 +30,21 @@ using namespace logid::backend::raw;
IOHandler::IOHandler(std::function<void()> r,
std::function<void()> hup,
std::function<void()> err) :
read (std::move(r)),
hangup (std::move(hup)),
error (std::move(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)
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);
if (_event_fd < 0) {
close(_epoll_fd);
throw std::runtime_error("failed to create event fd");
}
@ -55,84 +52,80 @@ IOMonitor::IOMonitor() : _epoll_fd (epoll_create1(0)),
event.events = EPOLLIN;
event.data.fd = _event_fd;
if(::epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _event_fd, &event)) {
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");
}));
_fds.emplace(std::piecewise_construct, std::forward_as_tuple(_event_fd),
std::forward_as_tuple([]() {}, []() {
throw std::runtime_error("event_fd hangup");
}, []() {
throw std::runtime_error("event_fd error");
}));
_io_thread = std::make_unique<std::thread>([this](){
_io_thread = std::make_unique<std::thread>([this]() {
_listen();
});
}
IOMonitor::~IOMonitor() noexcept
{
IOMonitor::~IOMonitor() noexcept {
std::lock_guard<std::mutex> ctl_lock(_ctl_lock);
_stop();
if(_event_fd >= 0)
if (_event_fd >= 0)
close(_event_fd);
if(_epoll_fd >= 0)
if (_epoll_fd >= 0)
close(_epoll_fd);
}
void IOMonitor::_listen()
{
void IOMonitor::_listen() {
std::lock_guard<std::mutex> run_lock(_run_lock);
std::vector<struct epoll_event> events;
_is_running = true;
while(_is_running) {
while (_is_running) {
{
std::unique_lock<std::mutex> lock(_interrupt_lock);
_interrupt_cv.wait(lock, [this](){
return !(bool)_interrupting;
_interrupt_cv.wait(lock, [this]() {
return !(bool) _interrupting;
});
if(!_is_running)
if (!_is_running)
break;
}
std::lock_guard<std::mutex> io_lock(_io_lock);
if(events.size() != _fds.size())
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) {
int ev_count = ::epoll_wait(_epoll_fd, events.data(), (int) events.size(), -1);
for (int i = 0; i < ev_count; ++i) {
const auto& handler = _fds.at(events[i].data.fd);
if(events[i].events & EPOLLIN)
if (events[i].events & EPOLLIN)
handler.read();
if(events[i].events & EPOLLHUP)
if (events[i].events & EPOLLHUP)
handler.hangup();
if(events[i].events & EPOLLERR)
if (events[i].events & EPOLLERR)
handler.error();
}
}
}
void IOMonitor::_stop() noexcept
{
void IOMonitor::_stop() noexcept {
_interrupt();
_is_running = false;
_continue();
_io_thread->join();
}
bool IOMonitor::_running() const
{
[[maybe_unused]]
bool IOMonitor::_running() const {
std::unique_lock<std::mutex> run_lock(_run_lock, std::try_to_lock);
return !run_lock.owns_lock() || _is_running;
}
void IOMonitor::add(int fd, IOHandler handler)
{
void IOMonitor::add(int fd, IOHandler handler) {
std::lock_guard<std::mutex> lock(_ctl_lock);
_interrupt();
@ -141,12 +134,12 @@ void IOMonitor::add(int fd, IOHandler handler)
event.data.fd = fd;
// TODO: EPOLL_CTL_MOD
if(_fds.contains(fd)) {
if (_fds.contains(fd)) {
_continue();
throw std::runtime_error("duplicate io fd");
}
if(::epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &event)) {
if (::epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &event)) {
_continue();
throw std::system_error(errno, std::generic_category());
}
@ -155,8 +148,7 @@ void IOMonitor::add(int fd, IOHandler handler)
_continue();
}
void IOMonitor::remove(int fd) noexcept
{
void IOMonitor::remove(int fd) noexcept {
std::lock_guard<std::mutex> lock(_ctl_lock);
_interrupt();
std::lock_guard<std::mutex> io_lock(_io_lock);
@ -167,8 +159,7 @@ void IOMonitor::remove(int fd) noexcept
_continue();
}
void IOMonitor::_interrupt() noexcept
{
void IOMonitor::_interrupt() noexcept {
std::unique_lock<std::mutex> run_lock(_run_lock, std::try_to_lock);
_interrupting = true;
@ -182,8 +173,7 @@ void IOMonitor::_interrupt() noexcept
}
void IOMonitor::_continue() noexcept
{
void IOMonitor::_continue() noexcept {
std::unique_lock<std::mutex> run_lock(_run_lock, std::try_to_lock);
uint64_t counter;
@ -191,7 +181,7 @@ void IOMonitor::_continue() noexcept
assert(ret != -1);
if(counter == 1) {
if (counter == 1) {
_interrupting = false;
_interrupt_cv.notify_all();
}

View File

@ -35,21 +35,25 @@ namespace logid::backend::raw {
std::function<void()> err);
};
class IOMonitor
{
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;
[[maybe_unused]]
[[nodiscard]] bool _running() const;
void _interrupt() noexcept;
void _continue() noexcept;
std::unique_ptr<std::thread> _io_thread;

View File

@ -19,7 +19,6 @@
#include "RawDevice.h"
#include "DeviceMonitor.h"
#include "IOMonitor.h"
#include "../Error.h"
#include "../../util/log.h"
#include <string>
@ -39,31 +38,28 @@ using namespace logid::backend::raw;
using namespace logid::backend;
using namespace std::chrono;
int get_fd(const std::string& path)
{
int get_fd(const std::string& path) {
int fd = ::open(path.c_str(), O_RDWR | O_NONBLOCK);
if(fd == -1)
if (fd == -1)
throw std::system_error(errno, std::system_category(),
"RawDevice open failed");
return fd;
}
RawDevice::dev_info get_devinfo(int fd)
{
hidraw_devinfo devinfo{};
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo)) {
RawDevice::dev_info get_dev_info(int fd) {
hidraw_devinfo dev_info{};
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &dev_info)) {
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(),
"RawDevice HIDIOCGRAWINFO failed");
}
return {devinfo.vendor, devinfo.product};
return {dev_info.vendor, dev_info.product};
}
std::string get_name(int fd)
{
std::string get_name(int fd) {
ssize_t len;
char name_buf[256];
if (-1 == (len = ::ioctl(fd, HIDIOCGRAWNAME(sizeof(name_buf)), name_buf))) {
@ -75,128 +71,111 @@ std::string get_name(int fd)
return {name_buf, static_cast<size_t>(len)};
}
RawDevice::RawDevice(std::string path,
std::shared_ptr<DeviceMonitor> 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())
{
RawDevice::RawDevice(std::string path, const std::shared_ptr<DeviceMonitor>& monitor) :
_valid(true), _path(std::move(path)), _fd(get_fd(_path)),
_dev_info(get_dev_info(_fd)), _name(get_name(_fd)),
_report_desc(getReportDescriptor(_fd)), _io_monitor(monitor->ioMonitor()) {
_io_monitor->add(_fd, {
[this]() { _readReports(); },
[this]() { _valid = false; },
[this]() { _valid = false; }
[this]() { _readReports(); },
[this]() { _valid = false; },
[this]() { _valid = false; }
});
}
RawDevice::~RawDevice() noexcept
{
RawDevice::~RawDevice() noexcept {
_io_monitor->remove(_fd);
::close(_fd);
}
const std::string& RawDevice::rawPath() const
{
const std::string& RawDevice::rawPath() const {
return _path;
}
const std::string& RawDevice::name() const
{
const std::string& RawDevice::name() const {
return _name;
}
int16_t RawDevice::vendorId() const
{
return _devinfo.vid;
[[maybe_unused]]
int16_t RawDevice::vendorId() const {
return _dev_info.vid;
}
int16_t RawDevice::productId() const
{
return _devinfo.pid;
int16_t RawDevice::productId() const {
return _dev_info.pid;
}
std::vector<uint8_t> RawDevice::getReportDescriptor(std::string path)
{
std::vector<uint8_t> RawDevice::getReportDescriptor(const std::string& path) {
int fd = ::open(path.c_str(), O_RDWR | O_NONBLOCK);
if (fd == -1)
throw std::system_error(errno, std::system_category(),
"open failed");
auto rdesc = getReportDescriptor(fd);
auto report_desc = getReportDescriptor(fd);
::close(fd);
return rdesc;
return report_desc;
}
std::vector<uint8_t> RawDevice::getReportDescriptor(int fd)
{
hidraw_report_descriptor rdesc{};
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &rdesc.size)) {
std::vector<uint8_t> RawDevice::getReportDescriptor(int fd) {
hidraw_report_descriptor report_desc{};
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &report_desc.size)) {
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(),
"RawDevice HIDIOCGRDESCSIZE failed");
}
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &rdesc)) {
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &report_desc)) {
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(),
"RawDevice HIDIOCGRDESC failed");
}
return std::vector<uint8_t>(rdesc.value, rdesc.value + rdesc.size);
return {report_desc.value, report_desc.value + report_desc.size};
}
const std::vector<uint8_t>& RawDevice::reportDescriptor() const
{
return _rdesc;
const std::vector<uint8_t>& RawDevice::reportDescriptor() const {
return _report_desc;
}
void RawDevice::sendReport(const std::vector<uint8_t>& report)
{
if(!_valid) {
void RawDevice::sendReport(const std::vector<uint8_t>& report) {
if (!_valid) {
// We could throw an error here, but this will likely be closed soon.
return;
}
if(logid::global_loglevel <= LogLevel::RAWREPORT) {
if (logid::global_loglevel <= LogLevel::RAWREPORT) {
printf("[RAWREPORT] %s OUT: ", _path.c_str());
for(auto &i : report)
for (auto& i: report)
printf("%02x ", i);
printf("\n");
}
if(write(_fd, report.data(), report.size()) == -1)
if (write(_fd, report.data(), report.size()) == -1)
throw std::system_error(errno, std::system_category(),
"sendReport write failed");
}
RawDevice::EvHandlerId RawDevice::addEventHandler(RawEventHandler handler)
{
RawDevice::EvHandlerId RawDevice::addEventHandler(RawEventHandler handler) {
std::lock_guard<std::mutex> lock(_event_handler_lock);
_event_handlers.emplace_front(std::move(handler));
return _event_handlers.cbegin();
}
void RawDevice::removeEventHandler(RawDevice::EvHandlerId id)
{
void RawDevice::removeEventHandler(RawDevice::EvHandlerId id) {
std::lock_guard<std::mutex> lock(_event_handler_lock);
_event_handlers.erase(id);
}
void RawDevice::_readReports()
{
void RawDevice::_readReports() {
uint8_t buf[max_data_length];
ssize_t len;
while(-1 != (len = ::read(_fd, buf, max_data_length))) {
while (-1 != (len = ::read(_fd, buf, max_data_length))) {
assert(len <= max_data_length);
std::vector<uint8_t> report(buf, buf + len);
if(logid::global_loglevel <= LogLevel::RAWREPORT) {
if (logid::global_loglevel <= LogLevel::RAWREPORT) {
printf("[RAWREPORT] %s IN: ", _path.c_str());
for(auto &i : report)
for (auto& i: report)
printf("%02x ", i);
printf("\n");
}
@ -205,10 +184,9 @@ void RawDevice::_readReports()
}
}
void RawDevice::_handleEvent(const std::vector<uint8_t>& report)
{
void RawDevice::_handleEvent(const std::vector<uint8_t>& report) {
std::unique_lock<std::mutex> lock(_event_handler_lock);
for(auto& handler : _event_handlers)
if(handler.condition(report))
for (auto& handler: _event_handlers)
if (handler.condition(report))
handler.callback(report);
}

View File

@ -28,15 +28,14 @@
#include <set>
#include <list>
#include "defs.h"
#include "EventHandler.h"
namespace logid::backend::raw
{
namespace logid::backend::raw {
class DeviceMonitor;
class IOMonitor;
class RawDevice
{
class RawDevice {
public:
static constexpr int max_data_length = 32;
typedef std::list<RawEventHandler>::const_iterator EvHandlerId;
@ -47,22 +46,29 @@ namespace logid::backend::raw
};
RawDevice(std::string path,
std::shared_ptr<DeviceMonitor> monitor);
const std::shared_ptr<DeviceMonitor>& monitor);
~RawDevice() noexcept;
[[nodiscard]] const std::string& rawPath() const;
[[nodiscard]] const std::string& name() const;
[[maybe_unused]]
[[nodiscard]] int16_t vendorId() const;
[[nodiscard]] int16_t productId() const;
static std::vector<uint8_t> getReportDescriptor(std::string path);
static std::vector<uint8_t> getReportDescriptor(const std::string& path);
static std::vector<uint8_t> getReportDescriptor(int fd);
[[nodiscard]] const std::vector<uint8_t>& reportDescriptor() const;
void sendReport(const std::vector<uint8_t>& report);
EvHandlerId addEventHandler(RawEventHandler handler);
void removeEventHandler(EvHandlerId id);
private:
@ -72,14 +78,15 @@ namespace logid::backend::raw
const std::string _path;
const int _fd;
const dev_info _devinfo;
const dev_info _dev_info;
const std::string _name;
const std::vector<uint8_t> _rdesc;
const std::vector<uint8_t> _report_desc;
std::shared_ptr<IOMonitor> _io_monitor;
std::list<RawEventHandler> _event_handlers;
std::mutex _event_handler_lock;
void _handleEvent(const std::vector<uint8_t>& report);
};
}

Some files were not shown because too many files have changed in this diff Show More