mirror of
https://github.com/PixlOne/logiops.git
synced 2025-07-14 05:12:34 +08:00
Code cleanup and reformatting
This commit is contained in:
parent
9af666f863
commit
9efd121387
@ -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 ()
|
||||
|
@ -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}}
|
||||
}, {}, {})
|
||||
{
|
||||
}, {}, {}) {
|
||||
}
|
@ -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:
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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{};
|
||||
};
|
||||
|
@ -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", {}, {}, {}) {
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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
|
@ -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> ¶ms)
|
||||
{
|
||||
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());
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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> ¶ms)
|
||||
{
|
||||
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 {
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user