mirror of
https://github.com/PixlOne/logiops.git
synced 2025-09-14 13:56:50 +08:00
Merge pull request #292 from PixlOne/config_rework
Rework config interface
This commit is contained in:
commit
6614702929
@ -1 +1 @@
|
|||||||
Subproject commit ac4cd8f52eb6d632e885c2b1ed3eb4b310897800
|
Subproject commit 22559236d8c6e30aac640f79b8d4983467ba5cc8
|
@ -1,7 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(logid)
|
project(logid)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
# C++20 is only needed for string literal template parameters
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake")
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake")
|
||||||
|
|
||||||
|
@ -25,154 +25,41 @@
|
|||||||
|
|
||||||
using namespace logid;
|
using namespace logid;
|
||||||
using namespace libconfig;
|
using namespace libconfig;
|
||||||
using namespace std::chrono;
|
using namespace logid::config;
|
||||||
|
|
||||||
Configuration::Configuration(const std::string& config_file)
|
Configuration::Configuration(const std::string& config_file) :
|
||||||
|
_config_file (config_file)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_config.readFile(config_file.c_str());
|
_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(),
|
logPrintf(ERROR, "I/O Error while reading %s: %s", _config_file.c_str(),
|
||||||
e.what());
|
e.what());
|
||||||
throw e;
|
throw;
|
||||||
} catch(const ParseException &e) {
|
} catch(const ParseException &e) {
|
||||||
logPrintf(ERROR, "Parse error in %s, line %d: %s", e.getFile(),
|
logPrintf(ERROR, "Parse error in %s, line %d: %s", e.getFile(),
|
||||||
e.getLine(), e.getError());
|
e.getLine(), e.getError());
|
||||||
throw e;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Setting &root = _config.getRoot();
|
Config::operator=(get<Config>(_config.getRoot()));
|
||||||
|
|
||||||
|
if(!devices.has_value())
|
||||||
|
devices = decltype(config::Config::devices)();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configuration::save()
|
||||||
|
{
|
||||||
|
config::set(_config.getRoot(), *this);
|
||||||
try {
|
try {
|
||||||
auto& worker_count = root["workers"];
|
_config.writeFile(_config_file);
|
||||||
if(worker_count.getType() == Setting::TypeInt) {
|
} catch(const FileIOException &e) {
|
||||||
_worker_threads = worker_count;
|
logPrintf(ERROR, "I/O Error while writing %s: %s",
|
||||||
if(_worker_threads < 0)
|
_config_file.c_str(), e.what());
|
||||||
logPrintf(WARN, "Line %d: workers cannot be negative.",
|
throw;
|
||||||
worker_count.getSourceLine());
|
} catch(const std::exception& e) {
|
||||||
} else {
|
logPrintf(ERROR, "Error while writing %s: %s",
|
||||||
logPrintf(WARN, "Line %d: workers must be an integer.",
|
_config_file.c_str(), e.what());
|
||||||
worker_count.getSourceLine());
|
throw;
|
||||||
}
|
|
||||||
} catch(const SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
try {
|
|
||||||
auto& timeout = root["io_timeout"];
|
|
||||||
if(timeout.isNumber()) {
|
|
||||||
if(timeout.getType() == Setting::TypeFloat)
|
|
||||||
_io_timeout = duration_cast<milliseconds>(
|
|
||||||
duration<double, std::milli>(timeout));
|
|
||||||
else
|
|
||||||
_io_timeout = milliseconds((int)timeout);
|
|
||||||
} else
|
|
||||||
logPrintf(WARN, "Line %d: io_timeout must be a number.",
|
|
||||||
timeout.getSourceLine());
|
|
||||||
} catch(const SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& devices = root["devices"];
|
|
||||||
|
|
||||||
for(int i = 0; i < devices.getLength(); i++) {
|
|
||||||
const Setting& device = devices[i];
|
|
||||||
std::string name;
|
|
||||||
try {
|
|
||||||
if(!device.lookupValue("name", name)) {
|
|
||||||
logPrintf(WARN, "Line %d: 'name' must be a string, skipping"
|
|
||||||
" device.", device["name"].getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch(SettingNotFoundException &e) {
|
|
||||||
logPrintf(WARN, "Line %d: Missing name field, skipping device."
|
|
||||||
, device.getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_device_paths.insert({name, device.getPath()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(const SettingNotFoundException &e) {
|
|
||||||
logPrintf(WARN, "No devices listed in config file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& ignore = root.lookup("ignore");
|
|
||||||
if(ignore.getType() == libconfig::Setting::TypeInt) {
|
|
||||||
_ignore_list.insert((int)ignore);
|
|
||||||
} else if(ignore.isList() || ignore.isArray()) {
|
|
||||||
int ignore_count = ignore.getLength();
|
|
||||||
for(int i = 0; i < ignore_count; i++) {
|
|
||||||
if(ignore[i].getType() != libconfig::Setting::TypeInt) {
|
|
||||||
logPrintf(WARN, "Line %d: ignore must refer to device PIDs",
|
|
||||||
ignore[i].getSourceLine());
|
|
||||||
if(ignore.isArray())
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
_ignore_list.insert((int)ignore[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(const SettingNotFoundException& e) {
|
|
||||||
// May be called blacklist
|
|
||||||
try {
|
|
||||||
auto& ignore = root.lookup("blacklist");
|
|
||||||
if(ignore.getType() == libconfig::Setting::TypeInt) {
|
|
||||||
_ignore_list.insert((int)ignore);
|
|
||||||
} else if(ignore.isList() || ignore.isArray()) {
|
|
||||||
int ignore_count = ignore.getLength();
|
|
||||||
for(int i = 0; i < ignore_count; i++) {
|
|
||||||
if(ignore[i].getType() != libconfig::Setting::TypeInt) {
|
|
||||||
logPrintf(WARN, "Line %d: blacklist must refer to "
|
|
||||||
"device PIDs",
|
|
||||||
ignore[i].getSourceLine());
|
|
||||||
if(ignore.isArray())
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
_ignore_list.insert((int)ignore[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(const SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libconfig::Setting& Configuration::getSetting(const std::string& path)
|
|
||||||
{
|
|
||||||
return _config.lookup(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Configuration::getDevice(const std::string& name)
|
|
||||||
{
|
|
||||||
auto it = _device_paths.find(name);
|
|
||||||
if(it == _device_paths.end())
|
|
||||||
throw DeviceNotFound(name);
|
|
||||||
else
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Configuration::isIgnored(uint16_t pid) const
|
|
||||||
{
|
|
||||||
return _ignore_list.find(pid) != _ignore_list.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
Configuration::DeviceNotFound::DeviceNotFound(std::string name) :
|
|
||||||
_name (std::move(name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * Configuration::DeviceNotFound::what() const noexcept
|
|
||||||
{
|
|
||||||
return _name.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Configuration::workerCount() const
|
|
||||||
{
|
|
||||||
return _worker_threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::milliseconds Configuration::ioTimeout() const
|
|
||||||
{
|
|
||||||
return _io_timeout;
|
|
||||||
}
|
|
@ -25,36 +25,27 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#define LOGID_DEFAULT_IO_TIMEOUT std::chrono::milliseconds(400)
|
#include "config/schema.h"
|
||||||
#define LOGID_DEFAULT_WORKER_COUNT 4
|
|
||||||
|
|
||||||
namespace logid
|
namespace logid
|
||||||
{
|
{
|
||||||
class Configuration
|
namespace defaults {
|
||||||
|
static constexpr double io_timeout = 500;
|
||||||
|
static constexpr int gesture_threshold = 50;
|
||||||
|
static constexpr int worker_count = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Configuration : public config::Config
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Configuration(const std::string& config_file);
|
explicit Configuration(const std::string& config_file);
|
||||||
Configuration() = default;
|
Configuration() = default;
|
||||||
libconfig::Setting& getSetting(const std::string& path);
|
|
||||||
std::string getDevice(const std::string& name);
|
|
||||||
bool isIgnored(uint16_t pid) const;
|
|
||||||
|
|
||||||
class DeviceNotFound : public std::exception
|
// Reloading is not safe, references will be invalidated
|
||||||
{
|
//void reload();
|
||||||
public:
|
void save();
|
||||||
explicit DeviceNotFound(std::string name);
|
|
||||||
const char* what() const noexcept override;
|
|
||||||
private:
|
|
||||||
std::string _name;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::chrono::milliseconds ioTimeout() const;
|
|
||||||
int workerCount() const;
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, std::string> _device_paths;
|
std::string _config_file;
|
||||||
std::set<uint16_t> _ignore_list;
|
|
||||||
std::chrono::milliseconds _io_timeout = LOGID_DEFAULT_IO_TIMEOUT;
|
|
||||||
int _worker_threads = LOGID_DEFAULT_WORKER_COUNT;
|
|
||||||
libconfig::Config _config;
|
libconfig::Config _config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,9 +98,10 @@ std::shared_ptr<Device> Device::make(
|
|||||||
Device::Device(std::string path, backend::hidpp::DeviceIndex index,
|
Device::Device(std::string path, backend::hidpp::DeviceIndex index,
|
||||||
std::shared_ptr<DeviceManager> manager) :
|
std::shared_ptr<DeviceManager> manager) :
|
||||||
_hidpp20 (path, index,
|
_hidpp20 (path, index,
|
||||||
manager->config()->ioTimeout(), manager->workQueue()),
|
manager->config()->io_timeout.value_or(defaults::io_timeout),
|
||||||
|
manager->workQueue()),
|
||||||
_path (std::move(path)), _index (index),
|
_path (std::move(path)), _index (index),
|
||||||
_config (manager->config(), this),
|
_config (_getConfig(manager, _hidpp20.name())),
|
||||||
_receiver (nullptr),
|
_receiver (nullptr),
|
||||||
_manager (manager),
|
_manager (manager),
|
||||||
_nickname (manager),
|
_nickname (manager),
|
||||||
@ -115,7 +116,7 @@ Device::Device(std::shared_ptr<backend::raw::RawDevice> raw_device,
|
|||||||
std::shared_ptr<DeviceManager> manager) :
|
std::shared_ptr<DeviceManager> manager) :
|
||||||
_hidpp20(raw_device, index),
|
_hidpp20(raw_device, index),
|
||||||
_path (raw_device->hidrawPath()), _index (index),
|
_path (raw_device->hidrawPath()), _index (index),
|
||||||
_config (manager->config(), this),
|
_config (_getConfig(manager, _hidpp20.name())),
|
||||||
_receiver (nullptr),
|
_receiver (nullptr),
|
||||||
_manager (manager),
|
_manager (manager),
|
||||||
_nickname (manager),
|
_nickname (manager),
|
||||||
@ -129,7 +130,7 @@ Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
|
|||||||
std::shared_ptr<DeviceManager> manager) :
|
std::shared_ptr<DeviceManager> manager) :
|
||||||
_hidpp20 (receiver->rawReceiver(), index),
|
_hidpp20 (receiver->rawReceiver(), index),
|
||||||
_path (receiver->path()), _index (index),
|
_path (receiver->path()), _index (index),
|
||||||
_config (manager->config(), this),
|
_config (_getConfig(manager, _hidpp20.name())),
|
||||||
_receiver (receiver),
|
_receiver (receiver),
|
||||||
_manager (manager),
|
_manager (manager),
|
||||||
_nickname (manager),
|
_nickname (manager),
|
||||||
@ -144,6 +145,10 @@ void Device::_init()
|
|||||||
logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(),
|
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())
|
||||||
|
_profile = _config.profiles.insert({_config.default_profile, {}}).first;
|
||||||
|
|
||||||
_addFeature<features::DPI>("dpi");
|
_addFeature<features::DPI>("dpi");
|
||||||
_addFeature<features::SmartShift>("smartshift");
|
_addFeature<features::SmartShift>("smartshift");
|
||||||
_addFeature<features::HiresScroll>("hiresscroll");
|
_addFeature<features::HiresScroll>("hiresscroll");
|
||||||
@ -239,9 +244,18 @@ std::shared_ptr<ipcgull::node> Device::ipcNode() const
|
|||||||
return _ipc_node;
|
return _ipc_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Config& Device::config()
|
/*config::Device& Device::config()
|
||||||
{
|
{
|
||||||
return _config;
|
return _config;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
config::Profile& Device::activeProfile()
|
||||||
|
{
|
||||||
|
return _profile->second;
|
||||||
|
}
|
||||||
|
const config::Profile& Device::activeProfile() const
|
||||||
|
{
|
||||||
|
return _profile->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
hidpp20::Device& Device::hidpp20()
|
hidpp20::Device& Device::hidpp20()
|
||||||
@ -285,118 +299,28 @@ void Device::DeviceIPC::notifyStatus() const
|
|||||||
emit_signal("StatusChanged", (bool)(_device._awake));
|
emit_signal("StatusChanged", (bool)(_device._awake));
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Config::Config(const std::shared_ptr<Configuration>& config, Device*
|
config::Device& Device::_getConfig(
|
||||||
device) : _device (device), _config (config)
|
const std::shared_ptr<DeviceManager>& manager,
|
||||||
|
const std::string& name)
|
||||||
{
|
{
|
||||||
try {
|
static std::mutex config_mutex;
|
||||||
_root_setting = config->getDevice(device->name());
|
std::lock_guard<std::mutex> lock(config_mutex);
|
||||||
} catch(Configuration::DeviceNotFound& e) {
|
auto& devices = manager->config()->devices;
|
||||||
logPrintf(INFO, "Device %s not configured, using default config.",
|
if(!devices.has_value())
|
||||||
device->name().c_str());
|
devices = decltype(config::Config::devices)();
|
||||||
return;
|
auto& device = devices.value()[name];
|
||||||
|
if(std::holds_alternative<config::Profile>(device)) {
|
||||||
|
config::Device d;
|
||||||
|
d.profiles["default"] = std::get<config::Profile>(device);
|
||||||
|
d.default_profile = "default";
|
||||||
|
device = std::move(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
auto& conf = std::get<config::Device>(device);
|
||||||
auto& profiles = _config->getSetting(_root_setting + "/profiles");
|
if(conf.profiles.empty()) {
|
||||||
int profile_index = 0;
|
conf.profiles["default"] = std::get<config::Profile>(device);
|
||||||
if(!profiles.isList()) {
|
conf.default_profile = "default";
|
||||||
logPrintf(WARN, "Line %d: profiles must be a list, defaulting to"
|
|
||||||
"old-style config", profiles.getSourceLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& default_profile = _config->getSetting(_root_setting +
|
|
||||||
"/default_profile");
|
|
||||||
if(default_profile.getType() == libconfig::Setting::TypeString) {
|
|
||||||
_profile_name = (const char*)default_profile;
|
|
||||||
} else if(default_profile.isNumber()) {
|
|
||||||
profile_index = default_profile;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: default_profile must be a string or"
|
|
||||||
" integer, defaulting to first profile",
|
|
||||||
default_profile.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(INFO, "Line %d: default_profile missing, defaulting to "
|
|
||||||
"first profile", profiles.getSourceLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(profiles.getLength() <= profile_index) {
|
|
||||||
if(profiles.getLength() == 0) {
|
|
||||||
logPrintf(WARN, "Line %d: No profiles defined",
|
|
||||||
profiles.getSourceLine());
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: default_profile does not exist, "
|
|
||||||
"defaulting to first",
|
|
||||||
profiles.getSourceLine());
|
|
||||||
profile_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < profiles.getLength(); i++) {
|
|
||||||
const auto& profile = profiles[i];
|
|
||||||
std::string name;
|
|
||||||
if(!profile.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: Profile must be a group, "
|
|
||||||
"skipping", profile.getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const auto& name_setting = profile.lookup("name");
|
|
||||||
if(name_setting.getType() !=
|
|
||||||
libconfig::Setting::TypeString) {
|
|
||||||
logPrintf(WARN, "Line %d: Profile names must be "
|
|
||||||
"strings, using name \"%d\"",
|
|
||||||
name_setting.getSourceLine(), i);
|
|
||||||
name = std::to_string(i);
|
|
||||||
} else {
|
|
||||||
name = (const char *) name_setting;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_profiles.find(name) != _profiles.end()) {
|
|
||||||
logPrintf(WARN, "Line %d: Profile with the same name "
|
|
||||||
"already exists, skipping.",
|
|
||||||
name_setting.getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(INFO, "Line %d: Profile is unnamed, using name "
|
|
||||||
"\"%d\"", profile.getSourceLine(), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(i == profile_index && _profile_name.empty())
|
|
||||||
_profile_root = profile.getPath();
|
|
||||||
_profiles[name] = profile.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_profiles.empty()) {
|
|
||||||
_profile_name = "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_profile_root.empty())
|
|
||||||
_profile_root = _profiles[_profile_name];
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// No profiles, default to root
|
|
||||||
_profile_root = _root_setting;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
libconfig::Setting& Device::Config::getSetting(const std::string& path)
|
return conf;
|
||||||
{
|
|
||||||
if(_profile_root.empty())
|
|
||||||
throw libconfig::SettingNotFoundException((_root_setting + '/' +
|
|
||||||
path).c_str());
|
|
||||||
return _config->getSetting(_profile_root + '/' + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<std::string, std::string> & Device::Config::getProfiles() const
|
|
||||||
{
|
|
||||||
return _profiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::Config::setProfile(const std::string &name)
|
|
||||||
{
|
|
||||||
_profile_name = name;
|
|
||||||
_profile_root = _profiles[name];
|
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,9 @@ namespace logid
|
|||||||
std::string name();
|
std::string name();
|
||||||
uint16_t pid();
|
uint16_t pid();
|
||||||
|
|
||||||
Config& config();
|
//config::Device& config();
|
||||||
|
config::Profile& activeProfile();
|
||||||
|
const config::Profile& activeProfile() const;
|
||||||
backend::hidpp20::Device& hidpp20();
|
backend::hidpp20::Device& hidpp20();
|
||||||
|
|
||||||
static std::shared_ptr<Device> make(
|
static std::shared_ptr<Device> make(
|
||||||
@ -108,6 +110,10 @@ namespace logid
|
|||||||
Device(Receiver* receiver, backend::hidpp::DeviceIndex index,
|
Device(Receiver* receiver, backend::hidpp::DeviceIndex index,
|
||||||
std::shared_ptr<DeviceManager> manager);
|
std::shared_ptr<DeviceManager> manager);
|
||||||
|
|
||||||
|
static config::Device& _getConfig(
|
||||||
|
const std::shared_ptr<DeviceManager>& manager,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
void _init();
|
void _init();
|
||||||
|
|
||||||
/* Adds a feature without calling an error if unsupported */
|
/* Adds a feature without calling an error if unsupported */
|
||||||
@ -120,29 +126,13 @@ namespace logid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(const std::shared_ptr<Configuration>& config, Device*
|
|
||||||
device);
|
|
||||||
libconfig::Setting& getSetting(const std::string& path);
|
|
||||||
const std::map<std::string, std::string>& getProfiles() const;
|
|
||||||
void setProfile(const std::string& name);
|
|
||||||
private:
|
|
||||||
Device* _device;
|
|
||||||
std::string _root_setting;
|
|
||||||
std::string _profile_root;
|
|
||||||
std::string _profile_name;
|
|
||||||
std::map<std::string, std::string> _profiles;
|
|
||||||
std::shared_ptr<Configuration> _config;
|
|
||||||
};
|
|
||||||
|
|
||||||
backend::hidpp20::Device _hidpp20;
|
backend::hidpp20::Device _hidpp20;
|
||||||
std::string _path;
|
std::string _path;
|
||||||
backend::hidpp::DeviceIndex _index;
|
backend::hidpp::DeviceIndex _index;
|
||||||
std::map<std::string, std::shared_ptr<features::DeviceFeature>>
|
std::map<std::string, std::shared_ptr<features::DeviceFeature>>
|
||||||
_features;
|
_features;
|
||||||
Config _config;
|
config::Device& _config;
|
||||||
|
std::map<std::string, config::Profile>::iterator _profile;
|
||||||
|
|
||||||
Receiver* _receiver;
|
Receiver* _receiver;
|
||||||
const std::weak_ptr<DeviceManager> _manager;
|
const std::weak_ptr<DeviceManager> _manager;
|
||||||
|
@ -44,7 +44,7 @@ namespace logid {
|
|||||||
DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
|
DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
|
||||||
std::shared_ptr<InputDevice> virtual_input,
|
std::shared_ptr<InputDevice> virtual_input,
|
||||||
std::shared_ptr<ipcgull::server> server) :
|
std::shared_ptr<ipcgull::server> server) :
|
||||||
backend::raw::DeviceMonitor(config->workerCount()),
|
backend::raw::DeviceMonitor(config->workers.value_or(defaults::worker_count)),
|
||||||
_server (std::move(server)), _config (std::move(config)),
|
_server (std::move(server)), _config (std::move(config)),
|
||||||
_virtual_input (std::move(virtual_input)),
|
_virtual_input (std::move(virtual_input)),
|
||||||
_root_node (ipcgull::node::make_root("")),
|
_root_node (ipcgull::node::make_root("")),
|
||||||
@ -95,8 +95,11 @@ void DeviceManager::addDevice(std::string path)
|
|||||||
|
|
||||||
// Check if device is ignored before continuing
|
// Check if device is ignored before continuing
|
||||||
{
|
{
|
||||||
raw::RawDevice raw_dev(path, config()->ioTimeout(), workQueue());
|
raw::RawDevice raw_dev(
|
||||||
if(config()->isIgnored(raw_dev.productId())) {
|
path,config()->io_timeout.value_or(defaults::io_timeout),
|
||||||
|
workQueue());
|
||||||
|
if(config()->ignore.has_value() &&
|
||||||
|
config()->ignore.value().contains(raw_dev.productId())) {
|
||||||
logPrintf(DEBUG, "%s: Device 0x%04x ignored.",
|
logPrintf(DEBUG, "%s: Device 0x%04x ignored.",
|
||||||
path.c_str(), raw_dev.productId());
|
path.c_str(), raw_dev.productId());
|
||||||
return;
|
return;
|
||||||
@ -104,8 +107,10 @@ void DeviceManager::addDevice(std::string path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
hidpp::Device device(path, hidpp::DefaultDevice,
|
hidpp::Device device(
|
||||||
config()->ioTimeout(), workQueue());
|
path, hidpp::DefaultDevice,
|
||||||
|
config()->io_timeout.value_or(defaults::io_timeout),
|
||||||
|
workQueue());
|
||||||
isReceiver = device.version() == std::make_tuple(1, 0);
|
isReceiver = device.version() == std::make_tuple(1, 0);
|
||||||
} catch(hidpp10::Error &e) {
|
} catch(hidpp10::Error &e) {
|
||||||
if(e.code() != hidpp10::Error::UnknownDevice)
|
if(e.code() != hidpp10::Error::UnknownDevice)
|
||||||
|
@ -65,7 +65,8 @@ std::shared_ptr<Receiver> Receiver::make(
|
|||||||
Receiver::Receiver(const std::string& path,
|
Receiver::Receiver(const std::string& path,
|
||||||
const std::shared_ptr<DeviceManager>& manager) :
|
const std::shared_ptr<DeviceManager>& manager) :
|
||||||
dj::ReceiverMonitor(path,
|
dj::ReceiverMonitor(path,
|
||||||
manager->config()->ioTimeout(),
|
manager->config()->io_timeout.value_or(
|
||||||
|
defaults::io_timeout),
|
||||||
manager->workQueue()),
|
manager->workQueue()),
|
||||||
_path (path), _manager (manager), _nickname (manager),
|
_path (path), _manager (manager), _nickname (manager),
|
||||||
_ipc_node (manager->receiversNode()->make_child(_nickname)),
|
_ipc_node (manager->receiversNode()->make_child(_nickname)),
|
||||||
@ -99,7 +100,8 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if device is ignored before continuing
|
// Check if device is ignored before continuing
|
||||||
if(manager->config()->isIgnored(event.pid)) {
|
if(manager->config()->ignore.value_or(
|
||||||
|
std::set<uint16_t>()).contains(event.pid)) {
|
||||||
logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.",
|
logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.",
|
||||||
_path.c_str(), event.index, event.pid);
|
_path.c_str(), event.index, event.pid);
|
||||||
return;
|
return;
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "../util/log.h"
|
|
||||||
#include "KeypressAction.h"
|
#include "KeypressAction.h"
|
||||||
#include "ToggleSmartShift.h"
|
#include "ToggleSmartShift.h"
|
||||||
#include "ToggleHiresScroll.h"
|
#include "ToggleHiresScroll.h"
|
||||||
@ -31,49 +30,39 @@
|
|||||||
using namespace logid;
|
using namespace logid;
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
std::shared_ptr<Action> Action::makeAction(Device *device, libconfig::Setting
|
template <typename T>
|
||||||
&setting)
|
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<T&> : action_type<T> { };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<Action> _makeAction(Device* device,
|
||||||
|
T action) {
|
||||||
|
return std::make_shared<typename action_type<T>::type>(device, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Action> Action::makeAction(Device *device,
|
||||||
|
config::BasicAction& action)
|
||||||
{
|
{
|
||||||
if(!setting.isGroup()) {
|
std::shared_ptr<Action> ret;
|
||||||
logPrintf(WARN, "Line %d: Action is not a group, ignoring.",
|
std::visit([&device, &ret](auto&& x) {
|
||||||
setting.getSourceLine());
|
ret = _makeAction(device, x);
|
||||||
throw InvalidAction();
|
}, action);
|
||||||
}
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
std::shared_ptr<Action> Action::makeAction(Device *device,
|
||||||
auto& action_type = setting.lookup("type");
|
config::Action& action)
|
||||||
|
{
|
||||||
if(action_type.getType() != libconfig::Setting::TypeString) {
|
std::shared_ptr<Action> ret;
|
||||||
logPrintf(WARN, "Line %d: Action type must be a string",
|
std::visit([&device, &ret](auto&& x) {
|
||||||
action_type.getSourceLine());
|
ret = _makeAction(device, x);
|
||||||
throw InvalidAction();
|
}, action);
|
||||||
}
|
return ret;
|
||||||
|
}
|
||||||
std::string type = action_type;
|
|
||||||
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
|
|
||||||
|
|
||||||
if(type == "keypress")
|
|
||||||
return std::make_shared<KeypressAction>(device, setting);
|
|
||||||
else if(type == "togglesmartshift")
|
|
||||||
return std::make_shared<ToggleSmartShift>(device);
|
|
||||||
else if(type == "togglehiresscroll")
|
|
||||||
return std::make_shared<ToggleHiresScroll>(device);
|
|
||||||
else if(type == "gestures")
|
|
||||||
return std::make_shared<GestureAction>(device, setting);
|
|
||||||
else if(type == "cycledpi")
|
|
||||||
return std::make_shared<CycleDPI>(device, setting);
|
|
||||||
else if(type == "changedpi")
|
|
||||||
return std::make_shared<ChangeDPI>(device, setting);
|
|
||||||
else if(type == "none")
|
|
||||||
return std::make_shared<NullAction>(device);
|
|
||||||
else if(type == "changehost")
|
|
||||||
return std::make_shared<ChangeHostAction>(device, setting);
|
|
||||||
else
|
|
||||||
throw InvalidAction(type);
|
|
||||||
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Action type is missing, ignoring.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
throw InvalidAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <libconfig.h++>
|
#include <libconfig.h++>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "../config/schema.h"
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
class Device;
|
class Device;
|
||||||
@ -46,7 +47,10 @@ namespace actions {
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Action> makeAction(Device* device,
|
static std::shared_ptr<Action> makeAction(Device* device,
|
||||||
libconfig::Setting& setting);
|
config::BasicAction& action);
|
||||||
|
|
||||||
|
static std::shared_ptr<Action> makeAction(Device* device,
|
||||||
|
config::Action& action);
|
||||||
|
|
||||||
virtual void press() = 0;
|
virtual void press() = 0;
|
||||||
virtual void release() = 0;
|
virtual void release() = 0;
|
||||||
@ -65,14 +69,6 @@ namespace actions {
|
|||||||
|
|
||||||
virtual ~Action() = default;
|
virtual ~Action() = default;
|
||||||
|
|
||||||
class Config
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
explicit Config(Device* device) : _device (device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Device* _device;
|
|
||||||
};
|
|
||||||
protected:
|
protected:
|
||||||
explicit Action(Device* device) : _device (device), _pressed (false)
|
explicit Action(Device* device) : _device (device), _pressed (false)
|
||||||
{
|
{
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
ChangeDPI::ChangeDPI(Device *device, libconfig::Setting &setting) :
|
ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) :
|
||||||
Action(device), _config(device, setting)
|
Action(device), _config (config)
|
||||||
{
|
{
|
||||||
_dpi = _device->getFeature<features::DPI>("dpi");
|
_dpi = _device->getFeature<features::DPI>("dpi");
|
||||||
if(!_dpi)
|
if(!_dpi)
|
||||||
@ -42,15 +42,16 @@ void ChangeDPI::press()
|
|||||||
task::spawn(_device->workQueue(),
|
task::spawn(_device->workQueue(),
|
||||||
[this]{
|
[this]{
|
||||||
try {
|
try {
|
||||||
uint16_t last_dpi = _dpi->getDPI(_config.sensor());
|
uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0));
|
||||||
_dpi->setDPI(last_dpi + _config.interval(), _config.sensor());
|
_dpi->setDPI(last_dpi + _config.inc,
|
||||||
|
_config.sensor.value_or(0));
|
||||||
} catch (backend::hidpp20::Error& e) {
|
} 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 get/set DPI for sensor "
|
logPrintf(WARN, "%s:%d: Could not get/set DPI for sensor "
|
||||||
"%d",
|
"%d",
|
||||||
_device->hidpp20().devicePath().c_str(),
|
_device->hidpp20().devicePath().c_str(),
|
||||||
_device->hidpp20().deviceIndex(),
|
_device->hidpp20().deviceIndex(),
|
||||||
_config.sensor());
|
_config.sensor.value_or(0));
|
||||||
else
|
else
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -67,44 +68,3 @@ uint8_t ChangeDPI::reprogFlags() const
|
|||||||
{
|
{
|
||||||
return backend::hidpp20::ReprogControls::TemporaryDiverted;
|
return backend::hidpp20::ReprogControls::TemporaryDiverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeDPI::Config::Config(Device *device, libconfig::Setting &config) :
|
|
||||||
Action::Config(device), _interval (0), _sensor (0)
|
|
||||||
{
|
|
||||||
if(!config.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: action must be an object, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& inc = config.lookup("inc");
|
|
||||||
if(inc.getType() != libconfig::Setting::TypeInt)
|
|
||||||
logPrintf(WARN, "Line %d: inc must be an integer",
|
|
||||||
inc.getSourceLine());
|
|
||||||
_interval = (int)inc;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: inc is a required field, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& sensor = config.lookup("sensor");
|
|
||||||
if(sensor.getType() != libconfig::Setting::TypeInt)
|
|
||||||
logPrintf(WARN, "Line %d: sensor must be an integer",
|
|
||||||
sensor.getSourceLine());
|
|
||||||
_sensor = (int)sensor;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ChangeDPI::Config::interval() const
|
|
||||||
{
|
|
||||||
return _interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ChangeDPI::Config::sensor() const
|
|
||||||
{
|
|
||||||
return _sensor;
|
|
||||||
}
|
|
@ -27,26 +27,15 @@ namespace logid {
|
|||||||
class ChangeDPI : public Action
|
class ChangeDPI : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ChangeDPI(Device* device, libconfig::Setting& setting);
|
explicit ChangeDPI(Device* device, config::ChangeDPI& setting);
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
|
||||||
virtual uint8_t reprogFlags() const;
|
virtual uint8_t reprogFlags() const;
|
||||||
|
|
||||||
class Config : public Action::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& setting);
|
|
||||||
uint16_t interval() const;
|
|
||||||
uint8_t sensor() const;
|
|
||||||
private:
|
|
||||||
uint16_t _interval;
|
|
||||||
uint8_t _sensor;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Config _config;
|
config::ChangeDPI& _config;
|
||||||
std::shared_ptr<features::DPI> _dpi;
|
std::shared_ptr<features::DPI> _dpi;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
@ -24,9 +24,14 @@
|
|||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
|
|
||||||
ChangeHostAction::ChangeHostAction(Device *device, libconfig::Setting&
|
ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config)
|
||||||
config) : Action(device), _config (device, config)
|
: Action(device), _config (config)
|
||||||
{
|
{
|
||||||
|
if(std::holds_alternative<std::string>(_config.host)) {
|
||||||
|
auto& host = std::get<std::string>(_config.host);
|
||||||
|
std::transform(host.begin(), host.end(),
|
||||||
|
host.begin(), ::tolower);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
_change_host = std::make_shared<hidpp20::ChangeHost>(&device->hidpp20());
|
_change_host = std::make_shared<hidpp20::ChangeHost>(&device->hidpp20());
|
||||||
} catch (hidpp20::UnsupportedFeature& e) {
|
} catch (hidpp20::UnsupportedFeature& e) {
|
||||||
@ -47,9 +52,21 @@ void ChangeHostAction::release()
|
|||||||
task::spawn(_device->workQueue(),
|
task::spawn(_device->workQueue(),
|
||||||
[this] {
|
[this] {
|
||||||
auto host_info = _change_host->getHostInfo();
|
auto host_info = _change_host->getHostInfo();
|
||||||
auto next_host = _config.nextHost(host_info);
|
int next_host;
|
||||||
|
if(std::holds_alternative<std::string>(_config.host)) {
|
||||||
|
const auto& host = std::get<std::string>(_config.host);
|
||||||
|
if(host == "next")
|
||||||
|
next_host = host_info.currentHost + 1;
|
||||||
|
else if(host == "prev" || host == "previous")
|
||||||
|
next_host = host_info.currentHost - 1;
|
||||||
|
else
|
||||||
|
next_host = host_info.currentHost;
|
||||||
|
} else {
|
||||||
|
next_host = std::get<int>(_config.host)-1;
|
||||||
|
}
|
||||||
|
next_host %= host_info.hostCount;
|
||||||
if(next_host != host_info.currentHost)
|
if(next_host != host_info.currentHost)
|
||||||
_change_host->setHost(next_host);
|
_change_host->setHost(next_host-1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,63 +75,3 @@ uint8_t ChangeHostAction::reprogFlags() const
|
|||||||
{
|
{
|
||||||
return hidpp20::ReprogControls::TemporaryDiverted;
|
return hidpp20::ReprogControls::TemporaryDiverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeHostAction::Config::Config(Device *device, libconfig::Setting& config)
|
|
||||||
: Action::Config(device)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& host = config.lookup("host");
|
|
||||||
if(host.getType() == libconfig::Setting::TypeInt) {
|
|
||||||
_offset = false;
|
|
||||||
_host = host;
|
|
||||||
_host--; // hosts are one-indexed in config
|
|
||||||
|
|
||||||
if(_host < 0) {
|
|
||||||
logPrintf(WARN, "Line %d: host must be positive.",
|
|
||||||
host.getSourceLine());
|
|
||||||
_offset = true;
|
|
||||||
_host = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(host.getType() == libconfig::Setting::TypeString) {
|
|
||||||
_offset = true;
|
|
||||||
std::string hostmode = host;
|
|
||||||
std::transform(hostmode.begin(), hostmode.end(),
|
|
||||||
hostmode.begin(), ::tolower);
|
|
||||||
|
|
||||||
if(hostmode == "next")
|
|
||||||
_host = 1;
|
|
||||||
else if(hostmode == "prev" || hostmode == "previous")
|
|
||||||
_host = -1;
|
|
||||||
else {
|
|
||||||
logPrintf(WARN, "Line %d: host must equal an integer, 'next',"
|
|
||||||
"or 'prev'.", host.getSourceLine());
|
|
||||||
_host = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: host must equal an integer, 'next',"
|
|
||||||
"or 'prev'.", host.getSourceLine());
|
|
||||||
_offset = true;
|
|
||||||
_host = 0;
|
|
||||||
}
|
|
||||||
} catch (libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: host is a required field, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
_offset = true;
|
|
||||||
_host = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ChangeHostAction::Config::nextHost(hidpp20::ChangeHost::HostInfo info)
|
|
||||||
{
|
|
||||||
if(_offset) {
|
|
||||||
return (info.currentHost + _host) % info.hostCount;
|
|
||||||
} else {
|
|
||||||
if(_host >= info.hostCount || _host < 0) {
|
|
||||||
logPrintf(WARN, "No such host %d, defaulting to current.",
|
|
||||||
_host+1);
|
|
||||||
return info.currentHost;
|
|
||||||
} else
|
|
||||||
return _host;
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,26 +28,16 @@ namespace actions
|
|||||||
class ChangeHostAction : public Action
|
class ChangeHostAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChangeHostAction(Device* device, libconfig::Setting& config);
|
ChangeHostAction(Device* device, config::ChangeHost& config);
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
|
||||||
virtual uint8_t reprogFlags() const;
|
virtual uint8_t reprogFlags() const;
|
||||||
|
|
||||||
class Config : public Action::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& setting);
|
|
||||||
uint8_t nextHost(backend::hidpp20::ChangeHost::HostInfo info);
|
|
||||||
private:
|
|
||||||
bool _offset;
|
|
||||||
int _host;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<backend::hidpp20::ChangeHost> _change_host;
|
std::shared_ptr<backend::hidpp20::ChangeHost> _change_host;
|
||||||
Config _config;
|
config::ChangeHost& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
using namespace libconfig;
|
using namespace libconfig;
|
||||||
|
|
||||||
CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) :
|
CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) :
|
||||||
Action (device), _config (device, setting)
|
Action (device), _config (config), _current_dpi (_config.dpis.begin())
|
||||||
{
|
{
|
||||||
_dpi = _device->getFeature<features::DPI>("dpi");
|
_dpi = _device->getFeature<features::DPI>("dpi");
|
||||||
if(!_dpi)
|
if(!_dpi)
|
||||||
@ -39,18 +39,21 @@ CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) :
|
|||||||
void CycleDPI::press()
|
void CycleDPI::press()
|
||||||
{
|
{
|
||||||
_pressed = true;
|
_pressed = true;
|
||||||
if(_dpi && !_config.empty()) {
|
if(_dpi && !_config.dpis.empty()) {
|
||||||
task::spawn(_device->workQueue(),
|
task::spawn(_device->workQueue(),
|
||||||
[this](){
|
[this](){
|
||||||
uint16_t dpi = _config.nextDPI();
|
std::lock_guard<std::mutex> lock(_dpi_lock);
|
||||||
|
++_current_dpi;
|
||||||
|
if(_current_dpi == _config.dpis.end())
|
||||||
|
_current_dpi = _config.dpis.begin();
|
||||||
try {
|
try {
|
||||||
_dpi->setDPI(dpi, _config.sensor());
|
_dpi->setDPI(*_current_dpi, _config.sensor.value_or(0));
|
||||||
} catch (backend::hidpp20::Error& e) {
|
} 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 "
|
logPrintf(WARN, "%s:%d: Could not set DPI to %d for "
|
||||||
"sensor %d", _device->hidpp20().devicePath().c_str(),
|
"sensor %d", _device->hidpp20().devicePath().c_str(),
|
||||||
_device->hidpp20().deviceIndex(), dpi,
|
_device->hidpp20().deviceIndex(), *_current_dpi,
|
||||||
_config.sensor());
|
_config.sensor.value_or(0));
|
||||||
else
|
else
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -67,68 +70,3 @@ uint8_t CycleDPI::reprogFlags() const
|
|||||||
{
|
{
|
||||||
return backend::hidpp20::ReprogControls::TemporaryDiverted;
|
return backend::hidpp20::ReprogControls::TemporaryDiverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
CycleDPI::Config::Config(Device *device, libconfig::Setting &config) :
|
|
||||||
Action::Config(device), _current_index (0), _sensor (0)
|
|
||||||
{
|
|
||||||
if(!config.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: action must be an object, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& sensor = config.lookup("sensor");
|
|
||||||
if(sensor.getType() != Setting::TypeInt)
|
|
||||||
logPrintf(WARN, "Line %d: sensor must be an integer",
|
|
||||||
sensor.getSourceLine());
|
|
||||||
_sensor = (int)sensor;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& dpis = config.lookup("dpis");
|
|
||||||
if(!dpis.isList() && !dpis.isArray()) {
|
|
||||||
logPrintf(WARN, "Line %d: dpis must be a list or array, skipping.",
|
|
||||||
dpis.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dpi_count = dpis.getLength();
|
|
||||||
for(int i = 0; i < dpi_count; i++) {
|
|
||||||
if(dpis[i].getType() != Setting::TypeInt) {
|
|
||||||
logPrintf(WARN, "Line %d: dpis must be integers, skipping.",
|
|
||||||
dpis[i].getSourceLine());
|
|
||||||
if(dpis.isList())
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_dpis.push_back((int)(dpis[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: dpis is a required field, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t CycleDPI::Config::nextDPI()
|
|
||||||
{
|
|
||||||
uint16_t dpi = _dpis[_current_index++];
|
|
||||||
if(_current_index >= _dpis.size())
|
|
||||||
_current_index = 0;
|
|
||||||
return dpi;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CycleDPI::Config::empty() const
|
|
||||||
{
|
|
||||||
return _dpis.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t CycleDPI::Config::sensor() const
|
|
||||||
{
|
|
||||||
return _sensor;
|
|
||||||
}
|
|
@ -27,29 +27,18 @@ namespace actions {
|
|||||||
class CycleDPI : public Action
|
class CycleDPI : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CycleDPI(Device* device, libconfig::Setting& setting);
|
explicit CycleDPI(Device* device, config::CycleDPI& setting);
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
|
||||||
virtual uint8_t reprogFlags() const;
|
virtual uint8_t reprogFlags() const;
|
||||||
|
|
||||||
class Config : public Action::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& setting);
|
|
||||||
uint16_t nextDPI();
|
|
||||||
bool empty() const;
|
|
||||||
uint8_t sensor() const;
|
|
||||||
private:
|
|
||||||
std::size_t _current_index;
|
|
||||||
std::vector<uint16_t> _dpis;
|
|
||||||
uint8_t _sensor;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Config _config;
|
std::mutex _dpi_lock;
|
||||||
|
config::CycleDPI& _config;
|
||||||
std::shared_ptr<features::DPI> _dpi;
|
std::shared_ptr<features::DPI> _dpi;
|
||||||
|
std::list<int>::const_iterator _current_dpi;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -54,16 +54,28 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y)
|
|||||||
return x <= -y ? Up : Right;
|
return x <= -y ? Up : Right;
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction::GestureAction(Device* dev, libconfig::Setting& config) :
|
GestureAction::GestureAction(Device* dev, config::GestureAction& config) :
|
||||||
Action (dev), _config (dev, config)
|
Action (dev), _config (config)
|
||||||
{
|
{
|
||||||
|
if(_config.gestures.has_value()) {
|
||||||
|
auto& gestures = _config.gestures.value();
|
||||||
|
for(auto& x : gestures) {
|
||||||
|
try {
|
||||||
|
auto direction = toDirection(x.first);
|
||||||
|
_gestures.emplace(direction,
|
||||||
|
Gesture::makeGesture(dev, x.second));
|
||||||
|
} catch(std::invalid_argument& e) {
|
||||||
|
logPrintf(WARN, "%s is not a direction", x.first.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GestureAction::press()
|
void GestureAction::press()
|
||||||
{
|
{
|
||||||
_pressed = true;
|
_pressed = true;
|
||||||
_x = 0, _y = 0;
|
_x = 0, _y = 0;
|
||||||
for(auto& gesture : _config.gestures())
|
for(auto& gesture : _gestures)
|
||||||
gesture.second->press();
|
gesture.second->press();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,13 +85,13 @@ void GestureAction::release()
|
|||||||
bool threshold_met = false;
|
bool threshold_met = false;
|
||||||
|
|
||||||
auto d = toDirection(_x, _y);
|
auto d = toDirection(_x, _y);
|
||||||
auto primary_gesture = _config.gestures().find(d);
|
auto primary_gesture = _gestures.find(d);
|
||||||
if(primary_gesture != _config.gestures().end()) {
|
if(primary_gesture != _gestures.end()) {
|
||||||
threshold_met = primary_gesture->second->metThreshold();
|
threshold_met = primary_gesture->second->metThreshold();
|
||||||
primary_gesture->second->release(true);
|
primary_gesture->second->release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& gesture : _config.gestures()) {
|
for(auto& gesture : _gestures) {
|
||||||
if(gesture.first == d)
|
if(gesture.first == d)
|
||||||
continue;
|
continue;
|
||||||
if(!threshold_met) {
|
if(!threshold_met) {
|
||||||
@ -96,10 +108,13 @@ void GestureAction::release()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!threshold_met) {
|
if(!threshold_met) {
|
||||||
if(_config.noneAction()) {
|
try {
|
||||||
_config.noneAction()->press();
|
auto none = _gestures.at(None);
|
||||||
_config.noneAction()->release();
|
if(none) {
|
||||||
}
|
none->press();
|
||||||
|
none->release();
|
||||||
|
}
|
||||||
|
} catch(std::out_of_range& e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,60 +124,60 @@ void GestureAction::move(int16_t x, int16_t y)
|
|||||||
|
|
||||||
if(abs(x) > 0) {
|
if(abs(x) > 0) {
|
||||||
if(_x < 0 && new_x >= 0) { // Left -> Origin/Right
|
if(_x < 0 && new_x >= 0) { // Left -> Origin/Right
|
||||||
auto left = _config.gestures().find(Left);
|
auto left = _gestures.find(Left);
|
||||||
if(left != _config.gestures().end())
|
if(left != _gestures.end() && left->second)
|
||||||
left->second->move(_x);
|
left->second->move(_x);
|
||||||
if(new_x) { // Ignore to origin
|
if(new_x) { // Ignore to origin
|
||||||
auto right = _config.gestures().find(Right);
|
auto right = _gestures.find(Right);
|
||||||
if(right != _config.gestures().end())
|
if(right != _gestures.end() && right->second)
|
||||||
right->second->move(new_x);
|
right->second->move(new_x);
|
||||||
}
|
}
|
||||||
} else if(_x > 0 && new_x <= 0) { // Right -> Origin/Left
|
} else if(_x > 0 && new_x <= 0) { // Right -> Origin/Left
|
||||||
auto right = _config.gestures().find(Right);
|
auto right = _gestures.find(Right);
|
||||||
if(right != _config.gestures().end())
|
if(right != _gestures.end() && right->second)
|
||||||
right->second->move(-_x);
|
right->second->move(-_x);
|
||||||
if(new_x) { // Ignore to origin
|
if(new_x) { // Ignore to origin
|
||||||
auto left = _config.gestures().find(Left);
|
auto left = _gestures.find(Left);
|
||||||
if(left != _config.gestures().end())
|
if(left != _gestures.end() && left->second)
|
||||||
left->second->move(-new_x);
|
left->second->move(-new_x);
|
||||||
}
|
}
|
||||||
} else if(new_x < 0) { // Origin/Left to Left
|
} else if(new_x < 0) { // Origin/Left to Left
|
||||||
auto left = _config.gestures().find(Left);
|
auto left = _gestures.find(Left);
|
||||||
if(left != _config.gestures().end())
|
if(left != _gestures.end() && left->second)
|
||||||
left->second->move(-x);
|
left->second->move(-x);
|
||||||
} else if(new_x > 0) { // Origin/Right to Right
|
} else if(new_x > 0) { // Origin/Right to Right
|
||||||
auto right = _config.gestures().find(Right);
|
auto right = _gestures.find(Right);
|
||||||
if(right != _config.gestures().end())
|
if(right != _gestures.end() && right->second)
|
||||||
right->second->move(x);
|
right->second->move(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(abs(y) > 0) {
|
if(abs(y) > 0) {
|
||||||
if(_y > 0 && new_y <= 0) { // Up -> Origin/Down
|
if(_y > 0 && new_y <= 0) { // Up -> Origin/Down
|
||||||
auto up = _config.gestures().find(Up);
|
auto up = _gestures.find(Up);
|
||||||
if(up != _config.gestures().end())
|
if(up != _gestures.end() && up->second)
|
||||||
up->second->move(_y);
|
up->second->move(_y);
|
||||||
if(new_y) { // Ignore to origin
|
if(new_y) { // Ignore to origin
|
||||||
auto down = _config.gestures().find(Down);
|
auto down = _gestures.find(Down);
|
||||||
if(down != _config.gestures().end())
|
if(down != _gestures.end() && down->second)
|
||||||
down->second->move(new_y);
|
down->second->move(new_y);
|
||||||
}
|
}
|
||||||
} else if(_y < 0 && new_y >= 0) { // Down -> Origin/Up
|
} else if(_y < 0 && new_y >= 0) { // Down -> Origin/Up
|
||||||
auto down = _config.gestures().find(Down);
|
auto down = _gestures.find(Down);
|
||||||
if(down != _config.gestures().end())
|
if(down != _gestures.end() && down->second)
|
||||||
down->second->move(-_y);
|
down->second->move(-_y);
|
||||||
if(new_y) { // Ignore to origin
|
if(new_y) { // Ignore to origin
|
||||||
auto up = _config.gestures().find(Up);
|
auto up = _gestures.find(Up);
|
||||||
if(up != _config.gestures().end())
|
if(up != _gestures.end() && up->second)
|
||||||
up->second->move(-new_y);
|
up->second->move(-new_y);
|
||||||
}
|
}
|
||||||
} else if(new_y < 0) { // Origin/Up to Up
|
} else if(new_y < 0) { // Origin/Up to Up
|
||||||
auto up = _config.gestures().find(Up);
|
auto up = _gestures.find(Up);
|
||||||
if(up != _config.gestures().end())
|
if(up != _gestures.end() && up->second)
|
||||||
up->second->move(-y);
|
up->second->move(-y);
|
||||||
} else if(new_y > 0) {// Origin/Down to Down
|
} else if(new_y > 0) {// Origin/Down to Down
|
||||||
auto down = _config.gestures().find(Down);
|
auto down = _gestures.find(Down);
|
||||||
if(down != _config.gestures().end())
|
if(down != _gestures.end() && down->second)
|
||||||
down->second->move(y);
|
down->second->move(y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,117 +190,3 @@ uint8_t GestureAction::reprogFlags() const
|
|||||||
return (hidpp20::ReprogControls::TemporaryDiverted |
|
return (hidpp20::ReprogControls::TemporaryDiverted |
|
||||||
hidpp20::ReprogControls::RawXYDiverted);
|
hidpp20::ReprogControls::RawXYDiverted);
|
||||||
}
|
}
|
||||||
|
|
||||||
GestureAction::Config::Config(Device* device, libconfig::Setting &root) :
|
|
||||||
Action::Config(device)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& gestures = root.lookup("gestures");
|
|
||||||
|
|
||||||
if(!gestures.isList()) {
|
|
||||||
logPrintf(WARN, "Line %d: gestures must be a list, ignoring.",
|
|
||||||
gestures.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gesture_count = gestures.getLength();
|
|
||||||
|
|
||||||
for(int i = 0; i < gesture_count; i++) {
|
|
||||||
if(!gestures[i].isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: gesture must be a group, skipping.",
|
|
||||||
gestures[i].getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Direction d;
|
|
||||||
try {
|
|
||||||
auto& direction = gestures[i].lookup("direction");
|
|
||||||
if(direction.getType() != libconfig::Setting::TypeString) {
|
|
||||||
logPrintf(WARN, "Line %d: direction must be a string, "
|
|
||||||
"skipping.", direction.getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
d = toDirection(direction);
|
|
||||||
} catch(std::invalid_argument& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid direction %s",
|
|
||||||
direction.getSourceLine(), (const char*)direction);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: direction is a required field, "
|
|
||||||
"skipping.", gestures[i].getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_gestures.find(d) != _gestures.end() || (d == None && _none_action)) {
|
|
||||||
logPrintf(WARN, "Line %d: Gesture is already defined for "
|
|
||||||
"this direction, duplicate ignored.",
|
|
||||||
gestures[i].getSourceLine());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(d == None) {
|
|
||||||
try {
|
|
||||||
auto& mode = gestures[i].lookup("mode");
|
|
||||||
if(mode.getType() == libconfig::Setting::TypeString) {
|
|
||||||
std::string mode_str = mode;
|
|
||||||
std::transform(mode_str.begin(), mode_str.end(),
|
|
||||||
mode_str.begin(), ::tolower);
|
|
||||||
if(mode_str == "nopress") // No action
|
|
||||||
continue;
|
|
||||||
else if(mode_str != "onrelease")
|
|
||||||
logPrintf(WARN, "Line %d: Only NoPress and "
|
|
||||||
"OnRelease are supported for the "
|
|
||||||
"None direction, defaulting to "
|
|
||||||
"OnRelease.", mode.getSourceLine());
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: mode must be a string, "
|
|
||||||
"defaulting to OnRelease",
|
|
||||||
mode.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// Default to OnRelease
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
_none_action = Action::makeAction(_device,
|
|
||||||
gestures[i].lookup("action"));
|
|
||||||
} catch (InvalidAction& e) {
|
|
||||||
logPrintf(WARN, "Line %d: %s is not a valid action, "
|
|
||||||
"skipping.", gestures[i].lookup("action")
|
|
||||||
.getSourceLine(), e.what());
|
|
||||||
} catch (libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: action is a required field, "
|
|
||||||
"skipping.", gestures[i].getSourceLine(),
|
|
||||||
e.what());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
_gestures.emplace(d, Gesture::makeGesture(_device,
|
|
||||||
gestures[i]));
|
|
||||||
} catch(InvalidGesture& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid gesture: %s",
|
|
||||||
gestures[i].getSourceLine(), e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: gestures is a required field, ignoring.",
|
|
||||||
root.getSourceLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<GestureAction::Direction, std::shared_ptr<Gesture>>&
|
|
||||||
GestureAction::Config::gestures()
|
|
||||||
{
|
|
||||||
return _gestures;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Action> GestureAction::Config::noneAction()
|
|
||||||
{
|
|
||||||
return _none_action;
|
|
||||||
}
|
|
@ -39,7 +39,7 @@ namespace actions {
|
|||||||
static Direction toDirection(std::string direction);
|
static Direction toDirection(std::string direction);
|
||||||
static Direction toDirection(int16_t x, int16_t y);
|
static Direction toDirection(int16_t x, int16_t y);
|
||||||
|
|
||||||
GestureAction(Device* dev, libconfig::Setting& config);
|
GestureAction(Device* dev, config::GestureAction& config);
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
@ -47,20 +47,10 @@ namespace actions {
|
|||||||
|
|
||||||
virtual uint8_t reprogFlags() const;
|
virtual uint8_t reprogFlags() const;
|
||||||
|
|
||||||
class Config : public Action::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& root);
|
|
||||||
std::map<Direction, std::shared_ptr<Gesture>>& gestures();
|
|
||||||
std::shared_ptr<Action> noneAction();
|
|
||||||
protected:
|
|
||||||
std::map<Direction, std::shared_ptr<Gesture>> _gestures;
|
|
||||||
std::shared_ptr<Action> _none_action;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int16_t _x, _y;
|
int16_t _x, _y;
|
||||||
Config _config;
|
std::map<Direction, std::shared_ptr<Gesture>> _gestures;
|
||||||
|
config::GestureAction& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -24,22 +24,57 @@
|
|||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
|
|
||||||
KeypressAction::KeypressAction(Device *device, libconfig::Setting& config) :
|
KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) :
|
||||||
Action(device), _config (device, config)
|
Action(device), _config (config)
|
||||||
{
|
{
|
||||||
|
if(std::holds_alternative<std::string>(_config.keys)) {
|
||||||
|
const auto& key = std::get<std::string>(_config.keys);
|
||||||
|
try {
|
||||||
|
auto code = _device->virtualInput()->toKeyCode(key);
|
||||||
|
_device->virtualInput()->registerKey(code);
|
||||||
|
_keys.emplace_back(code);
|
||||||
|
} catch(InputDevice::InvalidEventCode& e) {
|
||||||
|
logPrintf(WARN, "Invalid keycode %s, skipping.", key.c_str());
|
||||||
|
}
|
||||||
|
} else if(std::holds_alternative<uint>(_config.keys)) {
|
||||||
|
const auto& key = std::get<uint>(_config.keys);
|
||||||
|
_device->virtualInput()->registerKey(key);
|
||||||
|
_keys.emplace_back(key);
|
||||||
|
} else if(std::holds_alternative<std::list<std::variant<uint, std::string
|
||||||
|
>>>(_config.keys)) {
|
||||||
|
const auto& keys = std::get<std::list<std::variant<uint, std::string>>>(
|
||||||
|
_config.keys);
|
||||||
|
for(const auto& key : keys) {
|
||||||
|
if(std::holds_alternative<std::string>(_config.keys)) {
|
||||||
|
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) {
|
||||||
|
logPrintf(WARN, "Invalid keycode %s, skipping.",
|
||||||
|
key_str.c_str());
|
||||||
|
}
|
||||||
|
} else if(std::holds_alternative<uint>(_config.keys)) {
|
||||||
|
auto& code = std::get<uint>(_config.keys);
|
||||||
|
_device->virtualInput()->registerKey(code);
|
||||||
|
_keys.emplace_back(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeypressAction::press()
|
void KeypressAction::press()
|
||||||
{
|
{
|
||||||
_pressed = true;
|
_pressed = true;
|
||||||
for(auto& key : _config.keys())
|
for(auto& key : _keys)
|
||||||
_device->virtualInput()->pressKey(key);
|
_device->virtualInput()->pressKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeypressAction::release()
|
void KeypressAction::release()
|
||||||
{
|
{
|
||||||
_pressed = false;
|
_pressed = false;
|
||||||
for(auto& key : _config.keys())
|
for(auto& key : _keys)
|
||||||
_device->virtualInput()->releaseKey(key);
|
_device->virtualInput()->releaseKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,48 +82,3 @@ uint8_t KeypressAction::reprogFlags() const
|
|||||||
{
|
{
|
||||||
return hidpp20::ReprogControls::TemporaryDiverted;
|
return hidpp20::ReprogControls::TemporaryDiverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeypressAction::Config::Config(Device* device, libconfig::Setting& config) :
|
|
||||||
Action::Config(device)
|
|
||||||
{
|
|
||||||
if(!config.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: action must be an object, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto &keys = config.lookup("keys");
|
|
||||||
if(keys.isArray() || keys.isList()) {
|
|
||||||
int key_count = keys.getLength();
|
|
||||||
for(int i = 0; i < key_count; i++) {
|
|
||||||
auto& key = keys[i];
|
|
||||||
if(key.isNumber()) {
|
|
||||||
_keys.push_back(key);
|
|
||||||
_device->virtualInput()->registerKey(key);
|
|
||||||
} else if(key.getType() == libconfig::Setting::TypeString) {
|
|
||||||
try {
|
|
||||||
_keys.push_back(
|
|
||||||
_device->virtualInput()->toKeyCode(key));
|
|
||||||
_device->virtualInput()->registerKey(
|
|
||||||
_device->virtualInput()->toKeyCode(key));
|
|
||||||
} catch(InputDevice::InvalidEventCode& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid keycode %s, skipping."
|
|
||||||
, key.getSourceLine(), key.c_str());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: keycode must be string or int",
|
|
||||||
key.getSourceLine(), key.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: keys is a required field, skipping.",
|
|
||||||
config.getSourceLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint>& KeypressAction::Config::keys()
|
|
||||||
{
|
|
||||||
return _keys;
|
|
||||||
}
|
|
@ -27,23 +27,15 @@ namespace actions {
|
|||||||
class KeypressAction : public Action
|
class KeypressAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KeypressAction(Device* dev, libconfig::Setting& config);
|
KeypressAction(Device* dev, config::KeypressAction& config);
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
|
||||||
virtual uint8_t reprogFlags() const;
|
virtual uint8_t reprogFlags() const;
|
||||||
|
|
||||||
class Config : public Action::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* device, libconfig::Setting& root);
|
|
||||||
std::vector<uint>& keys();
|
|
||||||
protected:
|
|
||||||
std::vector<uint> _keys;
|
|
||||||
};
|
|
||||||
protected:
|
protected:
|
||||||
Config _config;
|
config::KeypressAction& _config;
|
||||||
|
std::list<uint> _keys;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ namespace actions
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NullAction(Device* device);
|
explicit NullAction(Device* device);
|
||||||
|
NullAction(Device* device, [[maybe_unused]] config::NoAction& config) :
|
||||||
|
NullAction(device) { }
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
@ -28,6 +28,9 @@ namespace actions
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ToggleHiresScroll(Device* dev);
|
explicit ToggleHiresScroll(Device* dev);
|
||||||
|
ToggleHiresScroll(Device* device,
|
||||||
|
[[maybe_unused]] config::ToggleHiresScroll& action) :
|
||||||
|
ToggleHiresScroll(device) { }
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
@ -28,6 +28,9 @@ namespace actions {
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ToggleSmartShift(Device* dev);
|
explicit ToggleSmartShift(Device* dev);
|
||||||
|
ToggleSmartShift(Device* device,
|
||||||
|
[[maybe_unused]] config::ToggleSmartShift& action) :
|
||||||
|
ToggleSmartShift(device) { }
|
||||||
|
|
||||||
virtual void press();
|
virtual void press();
|
||||||
virtual void release();
|
virtual void release();
|
||||||
|
@ -23,14 +23,28 @@
|
|||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
AxisGesture::AxisGesture(Device *device, libconfig::Setting &root) :
|
AxisGesture::AxisGesture(Device *device, config::AxisGesture& config) :
|
||||||
Gesture (device), _config (device, root)
|
Gesture (device), _multiplier (1), _config (config)
|
||||||
{
|
{
|
||||||
|
if(std::holds_alternative<uint>(_config.axis)) {
|
||||||
|
_input_axis = std::get<uint>(_config.axis);
|
||||||
|
} else {
|
||||||
|
const auto& axis = std::get<std::string>(_config.axis);
|
||||||
|
try {
|
||||||
|
_axis = _device->virtualInput()->toAxisCode(axis);
|
||||||
|
_device->virtualInput()->registerAxis(_axis);
|
||||||
|
} catch(InputDevice::InvalidEventCode& e) {
|
||||||
|
logPrintf(WARN, "Invalid axis %s.");
|
||||||
|
throw InvalidGesture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_device->virtualInput()->registerAxis(_input_axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AxisGesture::press(bool init_threshold)
|
void AxisGesture::press(bool init_threshold)
|
||||||
{
|
{
|
||||||
_axis = init_threshold ? _config.threshold() : 0;
|
_axis = init_threshold ?
|
||||||
|
_config.threshold.value_or(defaults::gesture_threshold) : 0;
|
||||||
_axis_remainder = 0;
|
_axis_remainder = 0;
|
||||||
_hires_remainder = 0;
|
_hires_remainder = 0;
|
||||||
}
|
}
|
||||||
@ -43,19 +57,23 @@ void AxisGesture::release(bool primary)
|
|||||||
|
|
||||||
void AxisGesture::move(int16_t axis)
|
void AxisGesture::move(int16_t axis)
|
||||||
{
|
{
|
||||||
|
const auto threshold = _config.threshold.value_or(
|
||||||
|
defaults::gesture_threshold);
|
||||||
int16_t new_axis = _axis+axis;
|
int16_t new_axis = _axis+axis;
|
||||||
int low_res_axis = InputDevice::getLowResAxis(_config.axis());
|
int low_res_axis = InputDevice::getLowResAxis(axis);
|
||||||
int hires_remainder = _hires_remainder;
|
int hires_remainder = _hires_remainder;
|
||||||
|
|
||||||
if(new_axis > _config.threshold()) {
|
if(new_axis > threshold) {
|
||||||
double move = axis;
|
double move = axis;
|
||||||
if(_axis < _config.threshold())
|
if(_axis < threshold)
|
||||||
move = new_axis - _config.threshold();
|
move = new_axis - threshold;
|
||||||
bool negative_multiplier = _config.multiplier() < 0;
|
bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0;
|
||||||
if(negative_multiplier)
|
if(negative_multiplier)
|
||||||
move *= -_config.multiplier();
|
move *= -_config.axis_multiplier.value_or(1);
|
||||||
else
|
else
|
||||||
move *= _config.multiplier();
|
move *= _config.axis_multiplier.value_or(1);
|
||||||
|
// Handle hi-res multiplier
|
||||||
|
move *= _multiplier;
|
||||||
|
|
||||||
double move_floor = floor(move);
|
double move_floor = floor(move);
|
||||||
_axis_remainder = move - move_floor;
|
_axis_remainder = move - move_floor;
|
||||||
@ -70,7 +88,7 @@ void AxisGesture::move(int16_t axis)
|
|||||||
|
|
||||||
if(low_res_axis != -1) {
|
if(low_res_axis != -1) {
|
||||||
int lowres_movement = 0, hires_movement = move_floor;
|
int lowres_movement = 0, hires_movement = move_floor;
|
||||||
_device->virtualInput()->moveAxis(_config.axis(), hires_movement);
|
_device->virtualInput()->moveAxis(_input_axis, hires_movement);
|
||||||
hires_remainder += hires_movement;
|
hires_remainder += hires_movement;
|
||||||
if(abs(hires_remainder) >= 60) {
|
if(abs(hires_remainder) >= 60) {
|
||||||
lowres_movement = hires_remainder/120;
|
lowres_movement = hires_remainder/120;
|
||||||
@ -82,7 +100,7 @@ void AxisGesture::move(int16_t axis)
|
|||||||
|
|
||||||
_hires_remainder = hires_remainder;
|
_hires_remainder = hires_remainder;
|
||||||
} else {
|
} else {
|
||||||
_device->virtualInput()->moveAxis(_config.axis(), move_floor);
|
_device->virtualInput()->moveAxis(_input_axis, move_floor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_axis = new_axis;
|
_axis = new_axis;
|
||||||
@ -90,72 +108,7 @@ void AxisGesture::move(int16_t axis)
|
|||||||
|
|
||||||
bool AxisGesture::metThreshold() const
|
bool AxisGesture::metThreshold() const
|
||||||
{
|
{
|
||||||
return _axis >= _config.threshold();
|
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
|
||||||
}
|
|
||||||
|
|
||||||
void AxisGesture::setHiresMultiplier(double multiplier)
|
|
||||||
{
|
|
||||||
_config.setHiresMultiplier(multiplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) :
|
|
||||||
Gesture::Config(device, setting, false)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& axis = setting.lookup("axis");
|
|
||||||
if(axis.isNumber()) {
|
|
||||||
_axis = axis;
|
|
||||||
_device->virtualInput()->registerAxis(_axis);
|
|
||||||
} else if(axis.getType() == libconfig::Setting::TypeString) {
|
|
||||||
try {
|
|
||||||
_axis = _device->virtualInput()->toAxisCode(axis);
|
|
||||||
_device->virtualInput()->registerAxis(_axis);
|
|
||||||
} catch(InputDevice::InvalidEventCode& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid axis %s, skipping."
|
|
||||||
, axis.getSourceLine(), axis.c_str());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: axis must be string or int, skipping.",
|
|
||||||
axis.getSourceLine(), axis.c_str());
|
|
||||||
throw InvalidGesture();
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: axis is a required field, skippimg.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
throw InvalidGesture();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& multiplier = setting.lookup("axis_multiplier");
|
|
||||||
if(multiplier.isNumber()) {
|
|
||||||
if(multiplier.getType() == libconfig::Setting::TypeFloat)
|
|
||||||
_multiplier = multiplier;
|
|
||||||
else
|
|
||||||
_multiplier = (int)multiplier;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: axis_multiplier must be a number, "
|
|
||||||
"setting to default (1).",
|
|
||||||
multiplier.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
int low_res_axis = InputDevice::getLowResAxis(_axis);
|
|
||||||
if(low_res_axis != -1) {
|
|
||||||
_multiplier *= 120;
|
|
||||||
_device->virtualInput()->registerAxis(low_res_axis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int AxisGesture::Config::axis() const
|
|
||||||
{
|
|
||||||
return _axis;
|
|
||||||
}
|
|
||||||
|
|
||||||
double AxisGesture::Config::multiplier() const
|
|
||||||
{
|
|
||||||
return _multiplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AxisGesture::wheelCompatibility() const
|
bool AxisGesture::wheelCompatibility() const
|
||||||
@ -163,15 +116,9 @@ bool AxisGesture::wheelCompatibility() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AxisGesture::Config::setHiresMultiplier(double multiplier)
|
void AxisGesture::setHiresMultiplier(double multiplier)
|
||||||
{
|
{
|
||||||
if(_hires_multiplier == multiplier || multiplier == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(InputDevice::getLowResAxis(_axis) != -1) {
|
if(InputDevice::getLowResAxis(_axis) != -1) {
|
||||||
_multiplier *= _hires_multiplier;
|
_multiplier = multiplier;
|
||||||
_multiplier /= multiplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_hires_multiplier = multiplier;
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace logid {
|
|||||||
class AxisGesture : public Gesture
|
class AxisGesture : public Gesture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AxisGesture(Device* device, libconfig::Setting& root);
|
AxisGesture(Device* device, config::AxisGesture& config);
|
||||||
|
|
||||||
virtual void press(bool init_threshold=false);
|
virtual void press(bool init_threshold=false);
|
||||||
virtual void release(bool primary=false);
|
virtual void release(bool primary=false);
|
||||||
@ -37,24 +37,13 @@ namespace logid {
|
|||||||
|
|
||||||
void setHiresMultiplier(double multiplier);
|
void setHiresMultiplier(double multiplier);
|
||||||
|
|
||||||
class Config : public Gesture::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& setting);
|
|
||||||
unsigned int axis() const;
|
|
||||||
double multiplier() const;
|
|
||||||
void setHiresMultiplier(double multiplier);
|
|
||||||
private:
|
|
||||||
unsigned int _axis;
|
|
||||||
double _multiplier = 1;
|
|
||||||
double _hires_multiplier = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int16_t _axis;
|
int16_t _axis;
|
||||||
double _axis_remainder;
|
double _axis_remainder;
|
||||||
int _hires_remainder;
|
int _hires_remainder;
|
||||||
Config _config;
|
uint _input_axis;
|
||||||
|
double _multiplier;
|
||||||
|
config::AxisGesture& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -18,104 +18,42 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "Gesture.h"
|
#include "Gesture.h"
|
||||||
#include "../../util/log.h"
|
|
||||||
#include "ReleaseGesture.h"
|
#include "ReleaseGesture.h"
|
||||||
#include "ThresholdGesture.h"
|
#include "ThresholdGesture.h"
|
||||||
#include "../../backend/hidpp20/features/ReprogControls.h"
|
|
||||||
#include "IntervalGesture.h"
|
#include "IntervalGesture.h"
|
||||||
#include "AxisGesture.h"
|
#include "AxisGesture.h"
|
||||||
#include "NullGesture.h"
|
#include "NullGesture.h"
|
||||||
|
|
||||||
|
using namespace logid;
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
Gesture::Gesture(Device *device) : _device (device)
|
Gesture::Gesture(Device *device) : _device (device)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Gesture::Config::Config(Device* device, libconfig::Setting& root,
|
template <typename T>
|
||||||
bool action_required) : _device (device)
|
struct gesture_type {
|
||||||
{
|
typedef typename T::gesture type;
|
||||||
if(action_required) {
|
};
|
||||||
try {
|
|
||||||
_action = Action::makeAction(_device,
|
|
||||||
root.lookup("action"));
|
|
||||||
} catch (libconfig::SettingNotFoundException &e) {
|
|
||||||
throw InvalidGesture("action is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_action->reprogFlags() & backend::hidpp20::ReprogControls::RawXYDiverted)
|
template <typename T>
|
||||||
throw InvalidGesture("gesture cannot require RawXY");
|
struct gesture_type<const T> : gesture_type<T> { };
|
||||||
}
|
|
||||||
|
|
||||||
_threshold = LOGID_GESTURE_DEFAULT_THRESHOLD;
|
template <typename T>
|
||||||
try {
|
struct gesture_type<T&> : gesture_type<T> { };
|
||||||
auto& threshold = root.lookup("threshold");
|
|
||||||
if(threshold.getType() == libconfig::Setting::TypeInt) {
|
template <typename T>
|
||||||
_threshold = (int)threshold;
|
std::shared_ptr<Gesture> _makeGesture(Device* device,
|
||||||
if(_threshold <= 0) {
|
T gesture) {
|
||||||
_threshold = LOGID_GESTURE_DEFAULT_THRESHOLD;
|
return std::make_shared<typename gesture_type<T>::type>(device, gesture);
|
||||||
logPrintf(WARN, "Line %d: threshold must be positive, setting "
|
|
||||||
"to default (%d)", threshold.getSourceLine(),
|
|
||||||
_threshold);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
logPrintf(WARN, "Line %d: threshold must be an integer, setting "
|
|
||||||
"to default (%d).", threshold.getSourceLine());
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Gesture> Gesture::makeGesture(Device *device,
|
std::shared_ptr<Gesture> Gesture::makeGesture(Device *device,
|
||||||
libconfig::Setting &setting)
|
config::Gesture& gesture)
|
||||||
{
|
{
|
||||||
if(!setting.isGroup()) {
|
std::shared_ptr<Gesture> ret;
|
||||||
logPrintf(WARN, "Line %d: Gesture is not a group, ignoring.",
|
std::visit([&device, &ret](auto&& x) {
|
||||||
setting.getSourceLine());
|
ret = _makeGesture(device, x);
|
||||||
throw InvalidGesture();
|
}, gesture);
|
||||||
}
|
return ret;
|
||||||
|
|
||||||
try {
|
|
||||||
auto& gesture_mode = setting.lookup("mode");
|
|
||||||
|
|
||||||
if(gesture_mode.getType() != libconfig::Setting::TypeString) {
|
|
||||||
logPrintf(WARN, "Line %d: Gesture mode must be a string,"
|
|
||||||
"defaulting to OnRelease.",
|
|
||||||
gesture_mode.getSourceLine());
|
|
||||||
return std::make_shared<ReleaseGesture>(device, setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string type = gesture_mode;
|
|
||||||
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
|
|
||||||
|
|
||||||
if(type == "onrelease")
|
|
||||||
return std::make_shared<ReleaseGesture>(device, setting);
|
|
||||||
else if(type == "onthreshold")
|
|
||||||
return std::make_shared<ThresholdGesture>(device, setting);
|
|
||||||
else if(type == "oninterval" || type == "onfewpixels")
|
|
||||||
return std::make_shared<IntervalGesture>(device, setting);
|
|
||||||
else if(type == "axis")
|
|
||||||
return std::make_shared<AxisGesture>(device, setting);
|
|
||||||
else if(type == "nopress")
|
|
||||||
return std::make_shared<NullGesture>(device, setting);
|
|
||||||
else {
|
|
||||||
logPrintf(WARN, "Line %d: Unknown gesture mode %s, defaulting to "
|
|
||||||
"OnRelease.", gesture_mode.getSourceLine(),
|
|
||||||
(const char*)gesture_mode);
|
|
||||||
return std::make_shared<ReleaseGesture>(device, setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
return std::make_shared<ReleaseGesture>(device, setting);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t Gesture::Config::threshold() const
|
|
||||||
{
|
|
||||||
return _threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Action> Gesture::Config::action()
|
|
||||||
{
|
|
||||||
return _action;
|
|
||||||
}
|
|
@ -51,21 +51,8 @@ namespace actions
|
|||||||
|
|
||||||
virtual ~Gesture() = default;
|
virtual ~Gesture() = default;
|
||||||
|
|
||||||
class Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& root,
|
|
||||||
bool action_required=true);
|
|
||||||
virtual int16_t threshold() const;
|
|
||||||
virtual std::shared_ptr<Action> action();
|
|
||||||
protected:
|
|
||||||
Device* _device;
|
|
||||||
std::shared_ptr<Action> _action;
|
|
||||||
int16_t _threshold;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::shared_ptr<Gesture> makeGesture(Device* device,
|
static std::shared_ptr<Gesture> makeGesture(Device* device,
|
||||||
libconfig::Setting& setting);
|
config::Gesture& gesture);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Gesture(Device* device);
|
explicit Gesture(Device* device);
|
||||||
|
@ -17,17 +17,26 @@
|
|||||||
*/
|
*/
|
||||||
#include "IntervalGesture.h"
|
#include "IntervalGesture.h"
|
||||||
#include "../../util/log.h"
|
#include "../../util/log.h"
|
||||||
|
#include "../../Configuration.h"
|
||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
IntervalGesture::IntervalGesture(Device *device, libconfig::Setting &root) :
|
IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config) :
|
||||||
Gesture (device), _config (device, root)
|
Gesture (device), _config (config)
|
||||||
{
|
{
|
||||||
|
if(config.action) {
|
||||||
|
try {
|
||||||
|
_action = Action::makeAction(device, config.action.value());
|
||||||
|
} catch(InvalidAction& e) {
|
||||||
|
logPrintf(WARN, "Mapping gesture to invalid action");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntervalGesture::press(bool init_threshold)
|
void IntervalGesture::press(bool init_threshold)
|
||||||
{
|
{
|
||||||
_axis = init_threshold ? _config.threshold() : 0;
|
_axis = init_threshold ?
|
||||||
|
_config.threshold.value_or(defaults::gesture_threshold) : 0;
|
||||||
_interval_pass_count = 0;
|
_interval_pass_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,15 +48,19 @@ void IntervalGesture::release(bool primary)
|
|||||||
|
|
||||||
void IntervalGesture::move(int16_t axis)
|
void IntervalGesture::move(int16_t axis)
|
||||||
{
|
{
|
||||||
|
const auto threshold =
|
||||||
|
_config.threshold.value_or(defaults::gesture_threshold);
|
||||||
_axis += axis;
|
_axis += axis;
|
||||||
if(_axis < _config.threshold())
|
if(_axis < threshold)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int16_t new_interval_count = (_axis - _config.threshold())/
|
int16_t new_interval_count = (_axis - threshold)/
|
||||||
_config.interval();
|
_config.interval;
|
||||||
if(new_interval_count > _interval_pass_count) {
|
if(new_interval_count > _interval_pass_count) {
|
||||||
_config.action()->press();
|
if(_action) {
|
||||||
_config.action()->release();
|
_action->press();
|
||||||
|
_action->release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_interval_pass_count = new_interval_count;
|
_interval_pass_count = new_interval_count;
|
||||||
}
|
}
|
||||||
@ -59,38 +72,5 @@ bool IntervalGesture::wheelCompatibility() const
|
|||||||
|
|
||||||
bool IntervalGesture::metThreshold() const
|
bool IntervalGesture::metThreshold() const
|
||||||
{
|
{
|
||||||
return _axis >= _config.threshold();
|
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntervalGesture::Config::Config(Device *device, libconfig::Setting &setting) :
|
|
||||||
Gesture::Config(device, setting)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& interval = setting.lookup("interval");
|
|
||||||
if(interval.getType() != libconfig::Setting::TypeInt) {
|
|
||||||
logPrintf(WARN, "Line %d: interval must be an integer, skipping.",
|
|
||||||
interval.getSourceLine());
|
|
||||||
throw InvalidGesture();
|
|
||||||
}
|
|
||||||
_interval = (int)interval;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
try {
|
|
||||||
// pixels is an alias for interval
|
|
||||||
auto& interval = setting.lookup("pixels");
|
|
||||||
if(interval.getType() != libconfig::Setting::TypeInt) {
|
|
||||||
logPrintf(WARN, "Line %d: pixels must be an integer, skipping.",
|
|
||||||
interval.getSourceLine());
|
|
||||||
throw InvalidGesture();
|
|
||||||
}
|
|
||||||
_interval = (int)interval;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: interval is a required field, skipping.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t IntervalGesture::Config::interval() const
|
|
||||||
{
|
|
||||||
return _interval;
|
|
||||||
}
|
|
@ -26,7 +26,7 @@ namespace actions
|
|||||||
class IntervalGesture : public Gesture
|
class IntervalGesture : public Gesture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IntervalGesture(Device* device, libconfig::Setting& root);
|
IntervalGesture(Device* device, config::IntervalGesture& config);
|
||||||
|
|
||||||
virtual void press(bool init_threshold=false);
|
virtual void press(bool init_threshold=false);
|
||||||
virtual void release(bool primary=false);
|
virtual void release(bool primary=false);
|
||||||
@ -35,19 +35,11 @@ namespace actions
|
|||||||
virtual bool wheelCompatibility() const;
|
virtual bool wheelCompatibility() const;
|
||||||
virtual bool metThreshold() const;
|
virtual bool metThreshold() const;
|
||||||
|
|
||||||
class Config : public Gesture::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Config(Device* device, libconfig::Setting& setting);
|
|
||||||
int16_t interval() const;
|
|
||||||
private:
|
|
||||||
int16_t _interval;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int16_t _axis;
|
int16_t _axis;
|
||||||
int16_t _interval_pass_count;
|
int16_t _interval_pass_count;
|
||||||
Config _config;
|
std::shared_ptr<Action> _action;
|
||||||
|
config::IntervalGesture& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -16,17 +16,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "NullGesture.h"
|
#include "NullGesture.h"
|
||||||
|
#include "../../Configuration.h"
|
||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
NullGesture::NullGesture(Device *device, libconfig::Setting& setting) :
|
NullGesture::NullGesture(Device *device,
|
||||||
Gesture (device), _config (device, setting, false)
|
config::NoGesture& config) :
|
||||||
|
Gesture (device), _config (config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NullGesture::press(bool init_threshold)
|
void NullGesture::press(bool init_threshold)
|
||||||
{
|
{
|
||||||
_axis = init_threshold ? _config.threshold() : 0;
|
_axis = init_threshold ? _config.threshold.value_or(
|
||||||
|
defaults::gesture_threshold) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NullGesture::release(bool primary)
|
void NullGesture::release(bool primary)
|
||||||
@ -47,5 +50,5 @@ bool NullGesture::wheelCompatibility() const
|
|||||||
|
|
||||||
bool NullGesture::metThreshold() const
|
bool NullGesture::metThreshold() const
|
||||||
{
|
{
|
||||||
return _axis > _config.threshold();
|
return _axis > _config.threshold.value_or(defaults::gesture_threshold);
|
||||||
}
|
}
|
@ -26,7 +26,8 @@ namespace actions
|
|||||||
class NullGesture : public Gesture
|
class NullGesture : public Gesture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NullGesture(Device* device, libconfig::Setting& setting);
|
NullGesture(Device* device,
|
||||||
|
config::NoGesture& config);
|
||||||
|
|
||||||
virtual void press(bool init_threshold=false);
|
virtual void press(bool init_threshold=false);
|
||||||
virtual void release(bool primary=false);
|
virtual void release(bool primary=false);
|
||||||
@ -36,7 +37,7 @@ namespace actions
|
|||||||
virtual bool metThreshold() const;
|
virtual bool metThreshold() const;
|
||||||
protected:
|
protected:
|
||||||
int16_t _axis;
|
int16_t _axis;
|
||||||
Gesture::Config _config;
|
config::NoGesture& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -16,24 +16,30 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "ReleaseGesture.h"
|
#include "ReleaseGesture.h"
|
||||||
|
#include "../../Configuration.h"
|
||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
ReleaseGesture::ReleaseGesture(Device *device, libconfig::Setting &root) :
|
ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config) :
|
||||||
Gesture (device), _config (device, root)
|
Gesture (device), _config (config)
|
||||||
{
|
{
|
||||||
|
if(_config.action.has_value())
|
||||||
|
_action = Action::makeAction(device, _config.action.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseGesture::press(bool init_threshold)
|
void ReleaseGesture::press(bool init_threshold)
|
||||||
{
|
{
|
||||||
_axis = init_threshold ? _config.threshold() : 0;
|
_axis = init_threshold ? _config.threshold.value_or(
|
||||||
|
defaults::gesture_threshold) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseGesture::release(bool primary)
|
void ReleaseGesture::release(bool primary)
|
||||||
{
|
{
|
||||||
if(metThreshold() && primary) {
|
if(metThreshold() && primary) {
|
||||||
_config.action()->press();
|
if(_action) {
|
||||||
_config.action()->release();
|
_action->press();
|
||||||
|
_action->release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,5 +55,5 @@ bool ReleaseGesture::wheelCompatibility() const
|
|||||||
|
|
||||||
bool ReleaseGesture::metThreshold() const
|
bool ReleaseGesture::metThreshold() const
|
||||||
{
|
{
|
||||||
return _axis >= _config.threshold();
|
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ namespace actions
|
|||||||
class ReleaseGesture : public Gesture
|
class ReleaseGesture : public Gesture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReleaseGesture(Device* device, libconfig::Setting& root);
|
ReleaseGesture(Device* device, config::ReleaseGesture& config);
|
||||||
|
|
||||||
virtual void press(bool init_threshold=false);
|
virtual void press(bool init_threshold=false);
|
||||||
virtual void release(bool primary=false);
|
virtual void release(bool primary=false);
|
||||||
@ -37,7 +37,8 @@ namespace actions
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
int16_t _axis;
|
int16_t _axis;
|
||||||
Gesture::Config _config;
|
std::shared_ptr<Action> _action;
|
||||||
|
config::ReleaseGesture& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -16,17 +16,27 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "ThresholdGesture.h"
|
#include "ThresholdGesture.h"
|
||||||
|
#include "../../Configuration.h"
|
||||||
|
|
||||||
using namespace logid::actions;
|
using namespace logid::actions;
|
||||||
|
|
||||||
ThresholdGesture::ThresholdGesture(Device *device, libconfig::Setting &root) :
|
ThresholdGesture::ThresholdGesture(Device *device,
|
||||||
Gesture (device), _config (device, root)
|
config::ThresholdGesture& config) :
|
||||||
|
Gesture (device), _config (config)
|
||||||
{
|
{
|
||||||
|
if(config.action) {
|
||||||
|
try {
|
||||||
|
_action = Action::makeAction(device, config.action.value());
|
||||||
|
} catch(InvalidAction& e) {
|
||||||
|
logPrintf(WARN, "Mapping gesture to invalid action");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThresholdGesture::press(bool init_threshold)
|
void ThresholdGesture::press(bool init_threshold)
|
||||||
{
|
{
|
||||||
_axis = init_threshold ? _config.threshold() : 0;
|
_axis = init_threshold ?
|
||||||
|
_config.threshold.value_or(defaults::gesture_threshold) : 0;
|
||||||
this->_executed = false;
|
this->_executed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,15 +52,17 @@ void ThresholdGesture::move(int16_t axis)
|
|||||||
_axis += axis;
|
_axis += axis;
|
||||||
|
|
||||||
if(!this->_executed && metThreshold()) {
|
if(!this->_executed && metThreshold()) {
|
||||||
_config.action()->press();
|
if(_action) {
|
||||||
_config.action()->release();
|
_action->press();
|
||||||
|
_action->release();
|
||||||
|
}
|
||||||
this->_executed = true;
|
this->_executed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThresholdGesture::metThreshold() const
|
bool ThresholdGesture::metThreshold() const
|
||||||
{
|
{
|
||||||
return _axis >= _config.threshold();
|
return _axis >= _config.threshold.value_or(defaults::gesture_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThresholdGesture::wheelCompatibility() const
|
bool ThresholdGesture::wheelCompatibility() const
|
||||||
|
@ -26,7 +26,7 @@ namespace actions
|
|||||||
class ThresholdGesture : public Gesture
|
class ThresholdGesture : public Gesture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ThresholdGesture(Device* device, libconfig::Setting& root);
|
ThresholdGesture(Device* device, config::ThresholdGesture& config);
|
||||||
|
|
||||||
virtual void press(bool init_threshold=false);
|
virtual void press(bool init_threshold=false);
|
||||||
virtual void release(bool primary=false);
|
virtual void release(bool primary=false);
|
||||||
@ -38,7 +38,8 @@ namespace actions
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
int16_t _axis;
|
int16_t _axis;
|
||||||
Gesture::Config _config;
|
std::shared_ptr<actions::Action> _action;
|
||||||
|
config::ThresholdGesture& _config;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _executed = false;
|
bool _executed = false;
|
||||||
|
@ -45,7 +45,7 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
Receiver::Receiver(std::string path,
|
Receiver::Receiver(std::string path,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq) :
|
const std::shared_ptr<workqueue>& wq) :
|
||||||
_raw_device (std::make_shared<raw::RawDevice>(
|
_raw_device (std::make_shared<raw::RawDevice>(
|
||||||
std::move(path), io_timeout, wq)),
|
std::move(path), io_timeout, wq)),
|
||||||
|
@ -53,7 +53,7 @@ namespace dj
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Receiver(std::string path,
|
Receiver(std::string path,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq);
|
const std::shared_ptr<workqueue>& wq);
|
||||||
|
|
||||||
enum DjEvents : uint8_t
|
enum DjEvents : uint8_t
|
||||||
|
@ -27,7 +27,7 @@ using namespace logid::backend::dj;
|
|||||||
|
|
||||||
ReceiverMonitor::ReceiverMonitor(
|
ReceiverMonitor::ReceiverMonitor(
|
||||||
std::string path,
|
std::string path,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq) :
|
const std::shared_ptr<workqueue>& wq) :
|
||||||
_workqueue (wq),
|
_workqueue (wq),
|
||||||
_receiver (std::make_shared<Receiver>(std::move(path), io_timeout, wq))
|
_receiver (std::make_shared<Receiver>(std::move(path), io_timeout, wq))
|
||||||
|
@ -33,7 +33,7 @@ namespace dj
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReceiverMonitor(std::string path,
|
ReceiverMonitor(std::string path,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq);
|
const std::shared_ptr<workqueue>& wq);
|
||||||
virtual ~ReceiverMonitor();
|
virtual ~ReceiverMonitor();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(const std::string& path, DeviceIndex index,
|
Device::Device(const std::string& path, DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq):
|
const std::shared_ptr<workqueue>& wq):
|
||||||
_raw_device (std::make_shared<raw::RawDevice>(path, io_timeout, wq)),
|
_raw_device (std::make_shared<raw::RawDevice>(path, io_timeout, wq)),
|
||||||
_receiver (nullptr), _path (path), _index (index)
|
_receiver (nullptr), _path (path), _index (index)
|
||||||
|
@ -62,7 +62,7 @@ namespace hidpp
|
|||||||
};
|
};
|
||||||
|
|
||||||
Device(const std::string& path, DeviceIndex index,
|
Device(const std::string& path, DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq);
|
const std::shared_ptr<workqueue>& wq);
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_device,
|
Device(std::shared_ptr<raw::RawDevice> raw_device,
|
||||||
DeviceIndex index);
|
DeviceIndex index);
|
||||||
|
@ -25,7 +25,7 @@ using namespace logid::backend;
|
|||||||
using namespace logid::backend::hidpp10;
|
using namespace logid::backend::hidpp10;
|
||||||
|
|
||||||
Device::Device(const std::string &path, hidpp::DeviceIndex index,
|
Device::Device(const std::string &path, hidpp::DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq) :
|
const std::shared_ptr<workqueue>& wq) :
|
||||||
hidpp::Device(path, index, io_timeout, wq)
|
hidpp::Device(path, index, io_timeout, wq)
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,7 @@ namespace hidpp10
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Device(const std::string& path, hidpp::DeviceIndex index,
|
Device(const std::string& path, hidpp::DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq);
|
const std::shared_ptr<workqueue>& wq);
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
||||||
hidpp::DeviceIndex index);
|
hidpp::DeviceIndex index);
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
using namespace logid::backend::hidpp20;
|
using namespace logid::backend::hidpp20;
|
||||||
|
|
||||||
Device::Device(std::string path, hidpp::DeviceIndex index,
|
Device::Device(std::string path, hidpp::DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout, const std::shared_ptr<workqueue>& wq) :
|
||||||
const std::shared_ptr<workqueue>& wq) :
|
|
||||||
hidpp::Device(path, index, io_timeout, wq)
|
hidpp::Device(path, index, io_timeout, wq)
|
||||||
{
|
{
|
||||||
assert(std::get<0>(version()) >= 2);
|
assert(std::get<0>(version()) >= 2);
|
||||||
|
@ -29,8 +29,7 @@ namespace hidpp20 {
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Device(std::string path, hidpp::DeviceIndex index,
|
Device(std::string path, hidpp::DeviceIndex index,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout, const std::shared_ptr<workqueue>& wq);
|
||||||
const std::shared_ptr<workqueue>& wq);
|
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index);
|
Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index);
|
||||||
Device(std::shared_ptr<dj::Receiver> receiver, hidpp::DeviceIndex
|
Device(std::shared_ptr<dj::Receiver> receiver, hidpp::DeviceIndex
|
||||||
index);
|
index);
|
||||||
|
@ -65,11 +65,12 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
RawDevice::RawDevice(std::string path,
|
RawDevice::RawDevice(std::string path,
|
||||||
const milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq) :
|
const std::shared_ptr<workqueue>& wq) :
|
||||||
_path (std::move(path)),
|
_path (std::move(path)),
|
||||||
_continue_listen (false), _continue_respond (false),
|
_continue_listen (false), _continue_respond (false),
|
||||||
_io_timeout (io_timeout),
|
_io_timeout (duration_cast<milliseconds>(
|
||||||
|
duration<double, std::milli>(io_timeout))),
|
||||||
_workqueue (wq)
|
_workqueue (wq)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -42,7 +42,7 @@ namespace raw
|
|||||||
static bool supportedReport(uint8_t id, uint8_t length);
|
static bool supportedReport(uint8_t id, uint8_t length);
|
||||||
|
|
||||||
explicit RawDevice(std::string path,
|
explicit RawDevice(std::string path,
|
||||||
const std::chrono::milliseconds& io_timeout,
|
double io_timeout,
|
||||||
const std::shared_ptr<workqueue>& wq);
|
const std::shared_ptr<workqueue>& wq);
|
||||||
~RawDevice();
|
~RawDevice();
|
||||||
std::string hidrawPath() const;
|
std::string hidrawPath() const;
|
||||||
|
206
src/logid/config/group.h
Normal file
206
src/logid/config/group.h
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 PixlOne
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LOGID_CONFIG_GROUP_H
|
||||||
|
#define LOGID_CONFIG_GROUP_H
|
||||||
|
|
||||||
|
#include <libconfig.h++>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
#include "../util/log.h"
|
||||||
|
|
||||||
|
namespace logid::config {
|
||||||
|
template <typename T>
|
||||||
|
void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const T& t);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set(libconfig::Setting& parent, const T& t);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get(const libconfig::Setting& parent, const std::string& name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void append(libconfig::Setting& list, const T& t);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename T, typename... M>
|
||||||
|
struct group_io { };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct group_io<T> {
|
||||||
|
static void get(
|
||||||
|
[[maybe_unused]] const libconfig::Setting& s,
|
||||||
|
[[maybe_unused]] T* t,
|
||||||
|
[[maybe_unused]] const std::vector<std::string>& names,
|
||||||
|
[[maybe_unused]] const std::size_t index) { }
|
||||||
|
static void set(
|
||||||
|
[[maybe_unused]] libconfig::Setting& s,
|
||||||
|
[[maybe_unused]] const T* t,
|
||||||
|
[[maybe_unused]] const std::vector<std::string>& names,
|
||||||
|
[[maybe_unused]] const std::size_t index) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename A, typename... M>
|
||||||
|
struct group_io<T, A, M...> {
|
||||||
|
static void get(
|
||||||
|
const libconfig::Setting& s, T* t,
|
||||||
|
const std::vector<std::string>& names,
|
||||||
|
const std::size_t index, A T::* arg, M T::*... rest) {
|
||||||
|
auto& x = t->*(arg);
|
||||||
|
A old {x};
|
||||||
|
try {
|
||||||
|
x = config::get<A>(s, names[index]);
|
||||||
|
group_io<T, M...>::get(s, t, names, index+1, rest...);
|
||||||
|
} catch(libconfig::SettingTypeException& e) {
|
||||||
|
x = old;
|
||||||
|
throw;
|
||||||
|
} catch(libconfig::SettingException& e) {
|
||||||
|
x = old;
|
||||||
|
throw libconfig::SettingTypeException(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(
|
||||||
|
libconfig::Setting& s, const T* t,
|
||||||
|
const std::vector<std::string>& names,
|
||||||
|
const std::size_t index, A T::* arg, M T::*... rest) {
|
||||||
|
config::set(s, names[index], t->*(arg));
|
||||||
|
group_io<T, M...>::set(s, t, names, index+1, rest...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Sign>
|
||||||
|
struct signed_group;
|
||||||
|
|
||||||
|
struct group {
|
||||||
|
private:
|
||||||
|
const std::vector<std::string> _names;
|
||||||
|
const std::function<void(const libconfig::Setting&, group*,
|
||||||
|
const std::vector<std::string>&)> _getter;
|
||||||
|
const std::function<void(libconfig::Setting&, const group*,
|
||||||
|
const std::vector<std::string>&)> _setter;
|
||||||
|
|
||||||
|
template <typename Sign>
|
||||||
|
friend struct signed_group;
|
||||||
|
protected:
|
||||||
|
template <typename T, typename... M>
|
||||||
|
group(const std::array<std::string, sizeof...(M)>& names,
|
||||||
|
M T::*... args) :
|
||||||
|
_names (names.begin(), names.end()),
|
||||||
|
_getter ([args...](const libconfig::Setting& s, group* g,
|
||||||
|
const std::vector<std::string>& names) {
|
||||||
|
T* t = dynamic_cast<T*>(g);
|
||||||
|
group_io<T, M...>::get(s, t, names, 0, args...);
|
||||||
|
}),
|
||||||
|
_setter ([args...](libconfig::Setting& s, const group* g,
|
||||||
|
const std::vector<std::string>& names) {
|
||||||
|
const T* t = dynamic_cast<const T*>(g);;
|
||||||
|
group_io<T, M...>::set(s, t, names, 0, args...);
|
||||||
|
}) {
|
||||||
|
static_assert(std::is_base_of<group, T>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
group() : _getter ([](const libconfig::Setting&, group*,
|
||||||
|
const std::vector<std::string>&) { }),
|
||||||
|
_setter ([](libconfig::Setting&, const group*,
|
||||||
|
const std::vector<std::string>&) { }) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
group(const group& o) = default;
|
||||||
|
group(group&& o) noexcept = default;
|
||||||
|
group& operator=(const group&) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
group& operator=(group&&) noexcept {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~group() = default;
|
||||||
|
|
||||||
|
virtual void _save(libconfig::Setting& setting) const {
|
||||||
|
_setter(setting, this, _names);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void _load(const libconfig::Setting& setting) {
|
||||||
|
_getter(setting, this, _names);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename T>
|
||||||
|
struct normalize_signature {
|
||||||
|
static const T& make(const T& ret) { return ret; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct normalize_signature<std::string> {
|
||||||
|
static std::string make(const std::string& data) {
|
||||||
|
std::string ret = data;
|
||||||
|
std::transform(ret.begin(), ret.end(),
|
||||||
|
ret.begin(), ::tolower);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Sign>
|
||||||
|
struct signed_group : public group {
|
||||||
|
private:
|
||||||
|
const std::string _sig_field;
|
||||||
|
const Sign _signature;
|
||||||
|
protected:
|
||||||
|
signed_group(std::string sign_name, const Sign& sign_data) :
|
||||||
|
group(), _sig_field (std::move(sign_name)),
|
||||||
|
_signature (normalize_signature<Sign>::make(sign_data)) { }
|
||||||
|
|
||||||
|
template <typename T, typename... M>
|
||||||
|
signed_group(
|
||||||
|
std::string sign_name, const Sign& sign_data,
|
||||||
|
const std::array<std::string, sizeof...(M)>& names,
|
||||||
|
M T::*... args) : group(names, args...),
|
||||||
|
_sig_field (std::move(sign_name)),
|
||||||
|
_signature (normalize_signature<Sign>::make(sign_data)) { }
|
||||||
|
public:
|
||||||
|
signed_group(const signed_group& o) = default;
|
||||||
|
signed_group(signed_group&& o) noexcept = default;
|
||||||
|
signed_group& operator=(const signed_group&) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
signed_group& operator=(signed_group&&) noexcept {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _save(libconfig::Setting& setting) const override {
|
||||||
|
set(setting, _signature, _sig_field);
|
||||||
|
_setter(setting, this, _names);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _load(const libconfig::Setting& setting) override {
|
||||||
|
if(normalize_signature<Sign>::make(get<Sign>(setting, _sig_field))
|
||||||
|
!= _signature)
|
||||||
|
throw libconfig::SettingTypeException(setting);
|
||||||
|
_getter(setting, this, _names);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LOGID_CONFIG_GROUP_H
|
46
src/logid/config/map.h
Normal file
46
src/logid/config/map.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 PixlOne
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LOGID_CONFIG_MAP_H
|
||||||
|
#define LOGID_CONFIG_MAP_H
|
||||||
|
|
||||||
|
#include "group.h"
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace logid::config {
|
||||||
|
template<size_t N>
|
||||||
|
struct string_literal {
|
||||||
|
constexpr string_literal(const char (&str)[N]) {
|
||||||
|
std::copy_n(str, N, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
char value[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Warning: map must be a variant of groups or a group
|
||||||
|
template <typename K, typename V, string_literal KeyName>
|
||||||
|
class map : public std::map<K, V> {
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
map(Args... args) :
|
||||||
|
std::map<K, V>(std::forward<Args>(args)...) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LOGID_CONFIG_MAP_H
|
288
src/logid/config/schema.h
Normal file
288
src/logid/config/schema.h
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 PixlOne
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LOGID_CONFIG_SCHEMA_H
|
||||||
|
#define LOGID_CONFIG_SCHEMA_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace logid::actions {
|
||||||
|
class ChangeDPI;
|
||||||
|
class ChangeHostAction;
|
||||||
|
class CycleDPI;
|
||||||
|
class GestureAction;
|
||||||
|
class KeypressAction;
|
||||||
|
class NullAction;
|
||||||
|
class ToggleHiresScroll;
|
||||||
|
class ToggleSmartShift;
|
||||||
|
|
||||||
|
class AxisGesture;
|
||||||
|
class IntervalGesture;
|
||||||
|
class NullGesture;
|
||||||
|
class ReleaseGesture;
|
||||||
|
class ThresholdGesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace logid::config {
|
||||||
|
|
||||||
|
struct NoAction : public signed_group<std::string> {
|
||||||
|
typedef actions::NullAction action;
|
||||||
|
NoAction() : signed_group<std::string>("type", "None") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeypressAction : public signed_group<std::string> {
|
||||||
|
typedef actions::KeypressAction action;
|
||||||
|
std::variant<std::string, uint,
|
||||||
|
std::list<std::variant<uint, std::string>>> keys;
|
||||||
|
KeypressAction() : signed_group<std::string>(
|
||||||
|
"type", "Keypress",
|
||||||
|
{"keys"}, &KeypressAction::keys) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ToggleSmartShift : public signed_group<std::string> {
|
||||||
|
typedef actions::ToggleSmartShift action;
|
||||||
|
ToggleSmartShift() :
|
||||||
|
signed_group<std::string>("type", "ToggleSmartShift") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ToggleHiresScroll : public signed_group<std::string> {
|
||||||
|
typedef actions::ToggleHiresScroll action;
|
||||||
|
ToggleHiresScroll() :
|
||||||
|
signed_group<std::string>("type", "ToggleHiresScroll") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CycleDPI : public signed_group<std::string> {
|
||||||
|
typedef actions::CycleDPI action;
|
||||||
|
std::list<int> dpis;
|
||||||
|
std::optional<int> sensor;
|
||||||
|
CycleDPI() : signed_group<std::string>(
|
||||||
|
"type", "CycleDPI",
|
||||||
|
{"dpis", "sensor"},
|
||||||
|
&CycleDPI::dpis,
|
||||||
|
&CycleDPI::sensor) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChangeDPI : public signed_group<std::string> {
|
||||||
|
typedef actions::ChangeDPI action;
|
||||||
|
int inc;
|
||||||
|
std::optional<int> sensor;
|
||||||
|
ChangeDPI() : signed_group<std::string>(
|
||||||
|
"type", "ChangeDPI",
|
||||||
|
{"inc", "sensor"},
|
||||||
|
&ChangeDPI::inc,
|
||||||
|
&ChangeDPI::sensor) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChangeHost : public signed_group<std::string> {
|
||||||
|
typedef actions::ChangeHostAction action;
|
||||||
|
std::variant<int, std::string> host;
|
||||||
|
ChangeHost() : signed_group<std::string>(
|
||||||
|
"type", "ChangeHost",
|
||||||
|
{"host"}, &ChangeHost::host) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<
|
||||||
|
NoAction,
|
||||||
|
KeypressAction,
|
||||||
|
ToggleSmartShift,
|
||||||
|
ToggleHiresScroll,
|
||||||
|
CycleDPI,
|
||||||
|
ChangeDPI,
|
||||||
|
ChangeHost
|
||||||
|
> BasicAction;
|
||||||
|
|
||||||
|
struct AxisGesture : public signed_group<std::string> {
|
||||||
|
typedef actions::AxisGesture gesture;
|
||||||
|
std::optional<int> threshold;
|
||||||
|
std::variant<std::string, uint> axis;
|
||||||
|
std::optional<double> axis_multiplier;
|
||||||
|
|
||||||
|
AxisGesture() : signed_group("mode", "Axis",
|
||||||
|
{"threshold", "axis", "axis_multiplier"},
|
||||||
|
&AxisGesture::threshold,
|
||||||
|
&AxisGesture::axis,
|
||||||
|
&AxisGesture::axis_multiplier) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntervalGesture : public signed_group<std::string> {
|
||||||
|
typedef actions::IntervalGesture gesture;
|
||||||
|
std::optional<int> threshold;
|
||||||
|
std::optional<BasicAction> action;
|
||||||
|
int interval;
|
||||||
|
protected:
|
||||||
|
IntervalGesture(const std::string& name) : signed_group(
|
||||||
|
"mode", name,
|
||||||
|
{"threshold", "action", "interval"},
|
||||||
|
&IntervalGesture::threshold,
|
||||||
|
&IntervalGesture::action,
|
||||||
|
&IntervalGesture::interval) { }
|
||||||
|
public:
|
||||||
|
IntervalGesture() : IntervalGesture("OnInterval") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FewPixelsGesture : public IntervalGesture {
|
||||||
|
FewPixelsGesture() : IntervalGesture("OnFewPixels") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReleaseGesture : public signed_group<std::string> {
|
||||||
|
typedef actions::ReleaseGesture gesture;
|
||||||
|
std::optional<int> threshold;
|
||||||
|
std::optional<BasicAction> action;
|
||||||
|
|
||||||
|
ReleaseGesture() : signed_group("mode", "OnRelease",
|
||||||
|
{"threshold", "action"},
|
||||||
|
&ReleaseGesture::threshold,
|
||||||
|
&ReleaseGesture::action) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThresholdGesture : public signed_group<std::string> {
|
||||||
|
typedef actions::ThresholdGesture gesture;
|
||||||
|
std::optional<int> threshold;
|
||||||
|
std::optional<BasicAction> action;
|
||||||
|
|
||||||
|
ThresholdGesture() : signed_group("mode", "OnThreshold",
|
||||||
|
{"threshold", "action"},
|
||||||
|
&ThresholdGesture::threshold,
|
||||||
|
&ThresholdGesture::action) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NoGesture : public signed_group<std::string> {
|
||||||
|
typedef actions::NullGesture gesture;
|
||||||
|
std::optional<int> threshold;
|
||||||
|
NoGesture() : signed_group("mode", "NoPress",
|
||||||
|
{"threshold"},
|
||||||
|
&NoGesture::threshold) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<
|
||||||
|
NoGesture,
|
||||||
|
AxisGesture,
|
||||||
|
IntervalGesture,
|
||||||
|
FewPixelsGesture,
|
||||||
|
ReleaseGesture,
|
||||||
|
ThresholdGesture
|
||||||
|
> Gesture;
|
||||||
|
|
||||||
|
|
||||||
|
struct GestureAction : public signed_group<std::string> {
|
||||||
|
typedef actions::GestureAction action;
|
||||||
|
std::optional<map<std::string, Gesture, "direction">> gestures;
|
||||||
|
|
||||||
|
GestureAction() : signed_group<std::string>(
|
||||||
|
"type", "Gestures",
|
||||||
|
{"gestures"},
|
||||||
|
&GestureAction::gestures) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<
|
||||||
|
NoAction,
|
||||||
|
KeypressAction,
|
||||||
|
ToggleSmartShift,
|
||||||
|
ToggleHiresScroll,
|
||||||
|
CycleDPI,
|
||||||
|
ChangeDPI,
|
||||||
|
ChangeHost,
|
||||||
|
GestureAction
|
||||||
|
> Action;
|
||||||
|
|
||||||
|
struct Button : public group {
|
||||||
|
std::optional<Action> action;
|
||||||
|
Button() : group({"action"},
|
||||||
|
&Button::action) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SmartShift : public group {
|
||||||
|
std::optional<bool> on;
|
||||||
|
std::optional<unsigned int> threshold;
|
||||||
|
SmartShift() : group({"on", "threshold"},
|
||||||
|
&SmartShift::on, &SmartShift::threshold) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct HiresScroll : public group {
|
||||||
|
std::optional<bool> hires;
|
||||||
|
std::optional<bool> invert;
|
||||||
|
std::optional<bool> target;
|
||||||
|
std::optional<Gesture> up;
|
||||||
|
std::optional<Gesture> down;
|
||||||
|
HiresScroll() : group({"hires", "invert", "target", "up", "down"},
|
||||||
|
&HiresScroll::hires,
|
||||||
|
&HiresScroll::invert,
|
||||||
|
&HiresScroll::target,
|
||||||
|
&HiresScroll::up,
|
||||||
|
&HiresScroll::down) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<int, std::list<int>> DPI;
|
||||||
|
|
||||||
|
struct ThumbWheel : public group {
|
||||||
|
std::optional<bool> divert;
|
||||||
|
std::optional<bool> invert;
|
||||||
|
std::optional<Gesture> left;
|
||||||
|
std::optional<Gesture> right;
|
||||||
|
std::optional<BasicAction> proxy;
|
||||||
|
std::optional<BasicAction> touch;
|
||||||
|
std::optional<BasicAction> tap;
|
||||||
|
|
||||||
|
ThumbWheel() : group({"divert", "invert", "left", "right",
|
||||||
|
"proxy", "touch", "tap" },
|
||||||
|
&ThumbWheel::divert, &ThumbWheel::invert,
|
||||||
|
&ThumbWheel::left, &ThumbWheel::right,
|
||||||
|
&ThumbWheel::proxy, &ThumbWheel::touch,
|
||||||
|
&ThumbWheel::tap) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef map<uint16_t, Button, "cid"> RemapButton;
|
||||||
|
|
||||||
|
struct Profile : public group {
|
||||||
|
std::optional<DPI> dpi;
|
||||||
|
std::optional<SmartShift> smartshift;
|
||||||
|
std::optional<std::variant<bool, HiresScroll>> hiresscroll;
|
||||||
|
std::optional<ThumbWheel> thumbwheel;
|
||||||
|
std::optional<RemapButton> buttons;
|
||||||
|
|
||||||
|
Profile() : group({"dpi", "smartshift", "hiresscroll",
|
||||||
|
"buttons", "thumbwheel"},
|
||||||
|
&Profile::dpi, &Profile::smartshift,
|
||||||
|
&Profile::hiresscroll, &Profile::buttons,
|
||||||
|
&Profile::thumbwheel) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Device : public group {
|
||||||
|
std::string default_profile;
|
||||||
|
map<std::string, Profile, "name"> profiles;
|
||||||
|
|
||||||
|
Device() : group({"default_profile", "profiles"},
|
||||||
|
&Device::default_profile,
|
||||||
|
&Device::profiles) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Config : public group {
|
||||||
|
std::optional<map<std::string,
|
||||||
|
std::variant<Device, Profile>, "name">> devices;
|
||||||
|
std::optional<std::set<uint16_t>> ignore;
|
||||||
|
std::optional<double> io_timeout;
|
||||||
|
std::optional<int> workers;
|
||||||
|
Config() : group({"devices", "ignore", "io_timeout", "workers"},
|
||||||
|
&Config::devices,
|
||||||
|
&Config::ignore,
|
||||||
|
&Config::io_timeout,
|
||||||
|
&Config::workers) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LOGID_CONFIG_SCHEMA_H
|
446
src/logid/config/types.h
Normal file
446
src/logid/config/types.h
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 PixlOne
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LOGID_CONFIG_PRIMITIVE_H
|
||||||
|
#define LOGID_CONFIG_PRIMITIVE_H
|
||||||
|
|
||||||
|
#include <libconfig.h++>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <optional>
|
||||||
|
#include <variant>
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include "group.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "../util/log.h"
|
||||||
|
|
||||||
|
/// TODO: A single element failing should not cause the container to be invalid.
|
||||||
|
|
||||||
|
// Containers are chosen specifically so that no iterator is invalidated.
|
||||||
|
|
||||||
|
namespace logid::config {
|
||||||
|
namespace {
|
||||||
|
template <typename T>
|
||||||
|
struct config_io {
|
||||||
|
static_assert(std::is_base_of<group, T>::value);
|
||||||
|
|
||||||
|
static T get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
T t {};
|
||||||
|
t._load(parent.lookup(name));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static T get(const libconfig::Setting& setting) {
|
||||||
|
T t {};
|
||||||
|
t._load(setting);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const T& t) {
|
||||||
|
if(!parent.exists(name)) {
|
||||||
|
parent.add(name, libconfig::Setting::TypeGroup);
|
||||||
|
} else if(parent.lookup(name).getType()
|
||||||
|
!= libconfig::Setting::TypeGroup) {
|
||||||
|
parent.remove(name);
|
||||||
|
parent.add(name, libconfig::Setting::TypeGroup);
|
||||||
|
}
|
||||||
|
t._save(parent.lookup(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting, const T& t) {
|
||||||
|
t._save(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list, const T& t) {
|
||||||
|
auto& x = list.add(libconfig::Setting::TypeGroup);
|
||||||
|
set(x, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, libconfig::Setting::Type TypeEnum>
|
||||||
|
struct primitive_io {
|
||||||
|
static T get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return parent.lookup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T get(const libconfig::Setting& setting) {
|
||||||
|
return setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const T& t) {
|
||||||
|
if(!parent.exists(name)) {
|
||||||
|
parent.add(name, TypeEnum);
|
||||||
|
} else if(parent.lookup(name).getType() != TypeEnum) {
|
||||||
|
parent.remove(name);
|
||||||
|
parent.add(name, TypeEnum);
|
||||||
|
}
|
||||||
|
set(parent.lookup(name), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting, const T& t) {
|
||||||
|
setting = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list, const T& t) {
|
||||||
|
auto& x = list.add(TypeEnum);
|
||||||
|
set(x, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename O, libconfig::Setting::Type TypeEnum>
|
||||||
|
struct reinterpret_io {
|
||||||
|
static T get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return static_cast<T>(primitive_io<O, TypeEnum>::get(parent, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static T get(const libconfig::Setting& setting) {
|
||||||
|
return static_cast<T>(primitive_io<O, TypeEnum>::get(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const T& t) {
|
||||||
|
primitive_io<O, TypeEnum>::set(parent, name,
|
||||||
|
static_cast<O>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting, const T& t) {
|
||||||
|
primitive_io<O, TypeEnum>::set(setting,
|
||||||
|
static_cast<O>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list, const T& t) {
|
||||||
|
primitive_io<O, TypeEnum>::append(list,
|
||||||
|
static_cast<O>(t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct config_io<bool> : public primitive_io<bool,
|
||||||
|
libconfig::Setting::TypeBoolean> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<int8_t> : public reinterpret_io<int8_t, int,
|
||||||
|
libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<uint8_t> : public reinterpret_io<uint8_t, int,
|
||||||
|
libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<short> : public reinterpret_io<short, int,
|
||||||
|
libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<unsigned short> : public reinterpret_io<unsigned short,
|
||||||
|
int, libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<int> : public primitive_io<int,
|
||||||
|
libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<unsigned int> : public reinterpret_io<unsigned int,
|
||||||
|
int, libconfig::Setting::TypeInt> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<long> : public reinterpret_io<long, long long,
|
||||||
|
libconfig::Setting::TypeInt64> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<unsigned long> : public reinterpret_io<unsigned long,
|
||||||
|
long long, libconfig::Setting::TypeInt64> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<long long> : public primitive_io<long long,
|
||||||
|
libconfig::Setting::TypeInt64> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<unsigned long long> :
|
||||||
|
public reinterpret_io<unsigned long long, long long,
|
||||||
|
libconfig::Setting::TypeInt64> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<float> : public primitive_io<float,
|
||||||
|
libconfig::Setting::TypeFloat> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<double> : public primitive_io<double,
|
||||||
|
libconfig::Setting::TypeFloat> { };
|
||||||
|
template <>
|
||||||
|
struct config_io<std::string> : public primitive_io<std::string,
|
||||||
|
libconfig::Setting::TypeString> { };
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
struct config_io<std::variant<T...>> {
|
||||||
|
private:
|
||||||
|
template <typename Singleton>
|
||||||
|
static std::variant<T...> try_each(
|
||||||
|
const libconfig::Setting& setting) {
|
||||||
|
try {
|
||||||
|
return config_io<Singleton>::get(setting);
|
||||||
|
} catch(libconfig::SettingTypeException& e) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename First, typename Next, typename... Rest>
|
||||||
|
static std::variant<T...> try_each(
|
||||||
|
const libconfig::Setting& setting) {
|
||||||
|
try {
|
||||||
|
return config_io<First>::get(setting);
|
||||||
|
} catch(libconfig::SettingException& e) {
|
||||||
|
return try_each<Next, Rest...>(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static std::variant<T...> get(const libconfig::Setting& setting) {
|
||||||
|
return try_each<T...>(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::variant<T...> get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return get(parent.lookup(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting,
|
||||||
|
const std::variant<T...>& t) {
|
||||||
|
std::visit([&setting](auto&& arg){
|
||||||
|
config::set(setting, arg);
|
||||||
|
}, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const std::variant<T...>& t) {
|
||||||
|
std::visit([&parent, &name](auto&& arg){
|
||||||
|
config::set(parent, name, arg);
|
||||||
|
}, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list,
|
||||||
|
const std::variant<T...>& t) {
|
||||||
|
std::visit([&list](auto&& arg){
|
||||||
|
config::append(list, arg);
|
||||||
|
}, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct config_io<std::list<T>> {
|
||||||
|
static std::list<T> get(const libconfig::Setting& setting) {
|
||||||
|
const auto size = setting.getLength();
|
||||||
|
std::list<T> t {};
|
||||||
|
for(int i = 0; i < size; ++i) {
|
||||||
|
try {
|
||||||
|
t.emplace_back(config_io<T>::get(setting[i]));
|
||||||
|
} catch(libconfig::SettingException& e) { }
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::list<T> get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return get(parent.lookup(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting,
|
||||||
|
const std::list<T>& t) {
|
||||||
|
while(setting.getLength() != 0)
|
||||||
|
setting.remove((int)0);
|
||||||
|
for(auto& x : t) {
|
||||||
|
config_io<T>::append(setting, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const std::list<T>& t) {
|
||||||
|
if (!parent.exists(name)) {
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
} else if(!parent.lookup(name).isList()) {
|
||||||
|
parent.remove(name);
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
}
|
||||||
|
set(parent.lookup(name), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list,
|
||||||
|
const std::list<T>& t) {
|
||||||
|
auto& s = list.add(libconfig::Setting::TypeList);
|
||||||
|
set(s, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct config_io<std::set<T>> {
|
||||||
|
static std::set<T> get(const libconfig::Setting& setting) {
|
||||||
|
const auto size = setting.getLength();
|
||||||
|
std::set<T> t;
|
||||||
|
for(int i = 0; i < size; ++i) {
|
||||||
|
try {
|
||||||
|
t.emplace(config_io<T>::get(setting[i]));
|
||||||
|
} catch(libconfig::SettingException& e) { }
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::set<T> get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return get(parent.lookup(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting,
|
||||||
|
const std::set<T>& t) {
|
||||||
|
while(setting.getLength() != 0)
|
||||||
|
setting.remove((int)0);
|
||||||
|
for(auto& x : t) {
|
||||||
|
auto& s = setting.add(libconfig::Setting::TypeGroup);
|
||||||
|
config_io<T>::set(s, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const std::set<T>& t) {
|
||||||
|
if (!parent.exists(name)) {
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
} else if(!parent.lookup(name).isArray()) {
|
||||||
|
parent.remove(name);
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
}
|
||||||
|
set(parent.lookup(name), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list,
|
||||||
|
const std::set<T>& t) {
|
||||||
|
auto& s = list.add(libconfig::Setting::TypeList);
|
||||||
|
set(s, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, string_literal KeyName>
|
||||||
|
struct config_io<map<K, V, KeyName>> {
|
||||||
|
static map<K, V, KeyName> get(const libconfig::Setting& setting) {
|
||||||
|
const auto size = setting.getLength();
|
||||||
|
map<K, V, KeyName> t;
|
||||||
|
for(int i = 0; i < size; ++i) {
|
||||||
|
auto& s = setting[i];
|
||||||
|
try {
|
||||||
|
t.emplace(config_io<K>::get(s.lookup(KeyName.value)),
|
||||||
|
config_io<V>::get(s));
|
||||||
|
} catch(libconfig::SettingException& e) { }
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static map<K, V, KeyName> get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
return get(parent.lookup(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& setting,
|
||||||
|
const map<K, V, KeyName>& t) {
|
||||||
|
while(setting.getLength() != 0)
|
||||||
|
setting.remove((int)0);
|
||||||
|
for(auto& x : t) {
|
||||||
|
auto& s = setting.add(libconfig::Setting::TypeGroup);
|
||||||
|
config_io<V>::set(s, x.second);
|
||||||
|
config_io<K>::set(s, KeyName.value, x.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const map<K, V, KeyName>& t) {
|
||||||
|
if (!parent.exists(name)) {
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
} else if(!parent.lookup(name).isArray()) {
|
||||||
|
parent.remove(name);
|
||||||
|
parent.add(name, libconfig::Setting::TypeList);
|
||||||
|
}
|
||||||
|
set(parent.lookup(name), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append(libconfig::Setting& list,
|
||||||
|
const map<K, V, KeyName>& t) {
|
||||||
|
auto& s = list.add(libconfig::Setting::TypeList);
|
||||||
|
set(s, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct config_io<std::optional<T>> {
|
||||||
|
static std::optional<T> get(const libconfig::Setting& parent,
|
||||||
|
const std::string& name) {
|
||||||
|
try {
|
||||||
|
return config_io<T>::get(parent.lookup(name));
|
||||||
|
} catch(libconfig::SettingException& e) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const std::optional<T>& t) {
|
||||||
|
if (t.has_value())
|
||||||
|
config_io<T>::set(parent, name, t.value());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optionals may not appear as part of a list or array
|
||||||
|
template <typename T, typename... Rest>
|
||||||
|
struct config_io<std::variant<std::optional<T>, Rest...>> {
|
||||||
|
static_assert(!sizeof(std::optional<T>), "Invalid type");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct config_io<std::list<std::optional<T>>> {
|
||||||
|
static_assert(!sizeof(std::optional<T>), "Invalid type");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct config_io<std::optional<std::optional<T>>> {
|
||||||
|
static_assert(!sizeof(std::optional<T>), "Invalid type");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set(libconfig::Setting& parent,
|
||||||
|
const std::string& name,
|
||||||
|
const T& t) {
|
||||||
|
config_io<T>::set(parent, name, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set(libconfig::Setting& setting, const T& t) {
|
||||||
|
config_io<T>::set(setting, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void append(libconfig::Setting& list, const T& t) {
|
||||||
|
config_io<T>::set(list, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get(const libconfig::Setting& setting) {
|
||||||
|
return config_io<T>::get(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get(const libconfig::Setting& parent, const std::string& name) {
|
||||||
|
return config_io<T>::get(parent, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LOGID_CONFIG_PRIMITIVE_H
|
@ -19,12 +19,11 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "DPI.h"
|
#include "DPI.h"
|
||||||
#include "../Device.h"
|
#include "../Device.h"
|
||||||
#include "../util/log.h"
|
|
||||||
|
|
||||||
using namespace logid::features;
|
using namespace logid::features;
|
||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
|
|
||||||
uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list,
|
uint16_t getClosestDPI(const hidpp20::AdjustableDPI::SensorDPIList& dpi_list,
|
||||||
uint16_t dpi)
|
uint16_t dpi)
|
||||||
{
|
{
|
||||||
if(dpi_list.isRange) {
|
if(dpi_list.isRange) {
|
||||||
@ -58,7 +57,8 @@ uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPI::DPI(Device* device) : DeviceFeature(device), _config (device)
|
DPI::DPI(Device* device) : DeviceFeature(device),
|
||||||
|
_config (device->activeProfile().dpi)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_adjustable_dpi = std::make_shared<hidpp20::AdjustableDPI>
|
_adjustable_dpi = std::make_shared<hidpp20::AdjustableDPI>
|
||||||
@ -70,20 +70,23 @@ DPI::DPI(Device* device) : DeviceFeature(device), _config (device)
|
|||||||
|
|
||||||
void DPI::configure()
|
void DPI::configure()
|
||||||
{
|
{
|
||||||
const uint8_t sensors = _adjustable_dpi->getSensorCount();
|
if(_config.has_value()) {
|
||||||
for(uint8_t i = 0; i < _config.getSensorCount(); i++) {
|
const auto& config = _config.value();
|
||||||
hidpp20::AdjustableDPI::SensorDPIList dpi_list;
|
if(std::holds_alternative<int>(config)) {
|
||||||
if(_dpi_lists.size() <= i) {
|
const auto& dpi = std::get<int>(config);
|
||||||
dpi_list = _adjustable_dpi->getSensorDPIList(i);
|
_adjustable_dpi->setSensorDPI(
|
||||||
_dpi_lists.push_back(dpi_list);
|
0,
|
||||||
|
getClosestDPI(_adjustable_dpi->getSensorDPIList(0),
|
||||||
|
dpi) );
|
||||||
} else {
|
} else {
|
||||||
dpi_list = _dpi_lists[i];
|
const auto& dpis = std::get<std::list<int>>(config);
|
||||||
}
|
int i = 0;
|
||||||
if(i < sensors) {
|
for(const auto& dpi : dpis) {
|
||||||
auto dpi = _config.getDPI(i);
|
_adjustable_dpi->setSensorDPI(
|
||||||
if(dpi) {
|
i,
|
||||||
_adjustable_dpi->setSensorDPI(i, getClosestDPI(dpi_list,
|
getClosestDPI(_adjustable_dpi->getSensorDPIList(i),
|
||||||
dpi));
|
dpi) );
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,36 +114,3 @@ void DPI::setDPI(uint16_t dpi, uint8_t sensor)
|
|||||||
dpi_list = _dpi_lists[sensor];
|
dpi_list = _dpi_lists[sensor];
|
||||||
_adjustable_dpi->setSensorDPI(sensor, getClosestDPI(dpi_list, dpi));
|
_adjustable_dpi->setSensorDPI(sensor, getClosestDPI(dpi_list, dpi));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Some devices have multiple sensors, but an older config format
|
|
||||||
* only supports a single DPI. The dpi setting can be an array or
|
|
||||||
* an integer.
|
|
||||||
*/
|
|
||||||
DPI::Config::Config(Device *dev) : DeviceFeature::Config(dev)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& config_root = dev->config().getSetting("dpi");
|
|
||||||
if(config_root.isNumber()) {
|
|
||||||
int dpi = config_root;
|
|
||||||
_dpis.push_back(dpi);
|
|
||||||
} else if(config_root.isArray()) {
|
|
||||||
for(int i = 0; i < config_root.getLength(); i++)
|
|
||||||
_dpis.push_back((int)config_root[i]);
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: dpi is improperly formatted",
|
|
||||||
config_root.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// DPI not configured, use default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t DPI::Config::getSensorCount()
|
|
||||||
{
|
|
||||||
return _dpis.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t DPI::Config::getDPI(uint8_t sensor)
|
|
||||||
{
|
|
||||||
return _dpis[sensor];
|
|
||||||
}
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "../backend/hidpp20/features/AdjustableDPI.h"
|
#include "../backend/hidpp20/features/AdjustableDPI.h"
|
||||||
#include "DeviceFeature.h"
|
#include "DeviceFeature.h"
|
||||||
|
#include "../config/schema.h"
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
namespace features
|
namespace features
|
||||||
@ -33,18 +34,8 @@ namespace features
|
|||||||
|
|
||||||
uint16_t getDPI(uint8_t sensor=0);
|
uint16_t getDPI(uint8_t sensor=0);
|
||||||
void setDPI(uint16_t dpi, uint8_t sensor=0);
|
void setDPI(uint16_t dpi, uint8_t sensor=0);
|
||||||
|
|
||||||
class Config : public DeviceFeature::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev);
|
|
||||||
uint16_t getDPI(uint8_t sensor);
|
|
||||||
uint8_t getSensorCount();
|
|
||||||
protected:
|
|
||||||
std::vector<uint16_t> _dpis;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
Config _config;
|
std::optional<config::DPI>& _config;
|
||||||
std::shared_ptr<backend::hidpp20::AdjustableDPI> _adjustable_dpi;
|
std::shared_ptr<backend::hidpp20::AdjustableDPI> _adjustable_dpi;
|
||||||
std::vector<backend::hidpp20::AdjustableDPI::SensorDPIList> _dpi_lists;
|
std::vector<backend::hidpp20::AdjustableDPI::SensorDPIList> _dpi_lists;
|
||||||
};
|
};
|
||||||
|
@ -44,15 +44,6 @@ namespace features
|
|||||||
virtual void configure() = 0;
|
virtual void configure() = 0;
|
||||||
virtual void listen() = 0;
|
virtual void listen() = 0;
|
||||||
virtual ~DeviceFeature() = default;
|
virtual ~DeviceFeature() = default;
|
||||||
class Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev) : _device (dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
Device* _device;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Device* _device;
|
Device* _device;
|
||||||
|
@ -34,7 +34,7 @@ DeviceStatus::DeviceStatus(logid::Device *dev) : DeviceFeature(dev)
|
|||||||
throw UnsupportedFeature();
|
throw UnsupportedFeature();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_wireless_device_status =std::make_shared<
|
_wireless_device_status = std::make_shared<
|
||||||
hidpp20::WirelessDeviceStatus>(&dev->hidpp20());
|
hidpp20::WirelessDeviceStatus>(&dev->hidpp20());
|
||||||
} catch(hidpp20::UnsupportedFeature& e) {
|
} catch(hidpp20::UnsupportedFeature& e) {
|
||||||
throw UnsupportedFeature();
|
throw UnsupportedFeature();
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "HiresScroll.h"
|
#include "HiresScroll.h"
|
||||||
#include "../Device.h"
|
#include "../Device.h"
|
||||||
#include "../InputDevice.h"
|
#include "../InputDevice.h"
|
||||||
#include "../actions/gesture/Gesture.h"
|
|
||||||
#include "../actions/gesture/AxisGesture.h"
|
#include "../actions/gesture/AxisGesture.h"
|
||||||
|
|
||||||
using namespace logid::features;
|
using namespace logid::features;
|
||||||
@ -26,38 +25,45 @@ using namespace logid::backend;
|
|||||||
|
|
||||||
#define MOVE_EVENTHANDLER_NAME "HIRES_SCROLL"
|
#define MOVE_EVENTHANDLER_NAME "HIRES_SCROLL"
|
||||||
|
|
||||||
HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), _config(dev)
|
HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev),
|
||||||
|
_config (dev->activeProfile().hiresscroll), _mode (0), _mask (0)
|
||||||
{
|
{
|
||||||
|
if(_config.has_value()) {
|
||||||
|
if(std::holds_alternative<bool>(_config.value())) {
|
||||||
|
config::HiresScroll conf {};
|
||||||
|
conf.hires = std::get<bool>(_config.value());
|
||||||
|
conf.invert = false;
|
||||||
|
conf.target = false;
|
||||||
|
_mask |= hidpp20::HiresScroll::Mode::HiRes;
|
||||||
|
_config.value() = conf;
|
||||||
|
}
|
||||||
|
auto& conf = std::get<config::HiresScroll>(_config.value());
|
||||||
|
if(conf.hires.has_value()) {
|
||||||
|
_mask |= hidpp20::HiresScroll::Mode::HiRes;
|
||||||
|
if(conf.hires.value())
|
||||||
|
_mode |= hidpp20::HiresScroll::Mode::HiRes;
|
||||||
|
}
|
||||||
|
if(conf.invert.has_value()) {
|
||||||
|
_mask |= hidpp20::HiresScroll::Mode::Inverted;
|
||||||
|
if(conf.invert.value())
|
||||||
|
_mode |= hidpp20::HiresScroll::Mode::Inverted;
|
||||||
|
}
|
||||||
|
if(conf.target.has_value()) {
|
||||||
|
_mask |= hidpp20::HiresScroll::Mode::Target;
|
||||||
|
if(conf.target.value())
|
||||||
|
_mode |= hidpp20::HiresScroll::Mode::Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
_makeAction(_up_action, conf.up);
|
||||||
|
_makeAction(_down_action, conf.down);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_hires_scroll = std::make_shared<hidpp20::HiresScroll>(&dev->hidpp20());
|
_hires_scroll = std::make_shared<hidpp20::HiresScroll>(&dev->hidpp20());
|
||||||
} catch(hidpp20::UnsupportedFeature& e) {
|
} catch(hidpp20::UnsupportedFeature& e) {
|
||||||
throw UnsupportedFeature();
|
throw UnsupportedFeature();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_config.upAction()) {
|
|
||||||
try {
|
|
||||||
auto up_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
|
||||||
_config.upAction());
|
|
||||||
if(up_axis)
|
|
||||||
up_axis->setHiresMultiplier(
|
|
||||||
_hires_scroll->getCapabilities().multiplier);
|
|
||||||
} catch(std::bad_cast& e) { }
|
|
||||||
|
|
||||||
_config.upAction()->press(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_config.downAction()) {
|
|
||||||
try {
|
|
||||||
auto down_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
|
||||||
_config.downAction());
|
|
||||||
if(down_axis)
|
|
||||||
down_axis->setHiresMultiplier(
|
|
||||||
_hires_scroll->getCapabilities().multiplier);
|
|
||||||
} catch(std::bad_cast& e) { }
|
|
||||||
|
|
||||||
_config.downAction()->press(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_last_scroll = std::chrono::system_clock::now();
|
_last_scroll = std::chrono::system_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,8 +75,8 @@ HiresScroll::~HiresScroll()
|
|||||||
void HiresScroll::configure()
|
void HiresScroll::configure()
|
||||||
{
|
{
|
||||||
auto mode = _hires_scroll->getMode();
|
auto mode = _hires_scroll->getMode();
|
||||||
mode &= ~_config.getMask();
|
mode &= ~_mask;
|
||||||
mode |= (_config.getMode() & _config.getMask());
|
mode |= (_mode & _mask);
|
||||||
_hires_scroll->setMode(mode);
|
_hires_scroll->setMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,18 +109,37 @@ void HiresScroll::setMode(uint8_t mode)
|
|||||||
_hires_scroll->setMode(mode);
|
_hires_scroll->setMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HiresScroll::_makeAction(std::shared_ptr<actions::Gesture> &gesture,
|
||||||
|
std::optional<config::Gesture> &config)
|
||||||
|
{
|
||||||
|
if(config.has_value()) {
|
||||||
|
gesture = actions::Gesture::makeGesture(_device, config.value());
|
||||||
|
try {
|
||||||
|
auto axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
||||||
|
gesture);
|
||||||
|
if(axis)
|
||||||
|
axis->setHiresMultiplier(
|
||||||
|
_hires_scroll->getCapabilities().multiplier);
|
||||||
|
} catch(std::bad_cast& e) { }
|
||||||
|
if(gesture)
|
||||||
|
gesture->press(true);
|
||||||
|
} else {
|
||||||
|
gesture.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event)
|
void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event)
|
||||||
{
|
{
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
if(std::chrono::duration_cast<std::chrono::seconds>(
|
if(std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
now - _last_scroll).count() >= 1) {
|
now - _last_scroll).count() >= 1) {
|
||||||
if(_config.upAction()) {
|
if(_up_action) {
|
||||||
_config.upAction()->release();
|
_up_action->release();
|
||||||
_config.upAction()->press(true);
|
_up_action->press(true);
|
||||||
}
|
}
|
||||||
if(_config.downAction()) {
|
if(_down_action) {
|
||||||
_config.downAction()->release();
|
_down_action->release();
|
||||||
_config.downAction()->press(true);
|
_down_action->press(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_last_direction = 0;
|
_last_direction = 0;
|
||||||
@ -122,140 +147,25 @@ void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event)
|
|||||||
|
|
||||||
if(event.deltaV > 0) {
|
if(event.deltaV > 0) {
|
||||||
if(_last_direction == -1) {
|
if(_last_direction == -1) {
|
||||||
if(_config.downAction()){
|
if(_down_action){
|
||||||
_config.downAction()->release();
|
_down_action->release();
|
||||||
_config.downAction()->press(true);
|
_down_action->press(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_config.upAction())
|
if(_up_action)
|
||||||
_config.upAction()->move(event.deltaV);
|
_up_action->move(event.deltaV);
|
||||||
_last_direction = 1;
|
_last_direction = 1;
|
||||||
} else if(event.deltaV < 0) {
|
} else if(event.deltaV < 0) {
|
||||||
if(_last_direction == 1) {
|
if(_last_direction == 1) {
|
||||||
if(_config.upAction()){
|
if(_up_action){
|
||||||
_config.upAction()->release();
|
_up_action->release();
|
||||||
_config.upAction()->press(true);
|
_up_action->press(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_config.downAction())
|
if(_down_action)
|
||||||
_config.downAction()->move(-event.deltaV);
|
_down_action->move(-event.deltaV);
|
||||||
_last_direction = -1;
|
_last_direction = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_last_scroll = now;
|
_last_scroll = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
HiresScroll::Config::Config(Device *dev) : DeviceFeature::Config(dev)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& config_root = dev->config().getSetting("hiresscroll");
|
|
||||||
if(!config_root.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: hiresscroll must be a group",
|
|
||||||
config_root.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_mode = 0;
|
|
||||||
_mask = 0;
|
|
||||||
try {
|
|
||||||
auto& hires = config_root.lookup("hires");
|
|
||||||
if(hires.getType() == libconfig::Setting::TypeBoolean) {
|
|
||||||
_mask |= hidpp20::HiresScroll::Mode::HiRes;
|
|
||||||
if(hires)
|
|
||||||
_mode |= hidpp20::HiresScroll::Mode::HiRes;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: hires must be a boolean",
|
|
||||||
hires.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& invert = config_root.lookup("invert");
|
|
||||||
if(invert.getType() == libconfig::Setting::TypeBoolean) {
|
|
||||||
_mask |= hidpp20::HiresScroll::Mode::Inverted;
|
|
||||||
if(invert)
|
|
||||||
_mode |= hidpp20::HiresScroll::Mode::Inverted;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.",
|
|
||||||
invert.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& target = config_root.lookup("target");
|
|
||||||
if(target.getType() == libconfig::Setting::TypeBoolean) {
|
|
||||||
_mask |= hidpp20::HiresScroll::Mode::Target;
|
|
||||||
if(target)
|
|
||||||
_mode |= hidpp20::HiresScroll::Mode::Target;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: target must be a boolean, ignoring.",
|
|
||||||
target.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) { }
|
|
||||||
|
|
||||||
if(_mode & hidpp20::HiresScroll::Mode::Target) {
|
|
||||||
try {
|
|
||||||
auto& up = config_root.lookup("up");
|
|
||||||
try {
|
|
||||||
auto g = actions::Gesture::makeGesture(dev, up);
|
|
||||||
if(g->wheelCompatibility()) {
|
|
||||||
_up_action = g;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: This gesture cannot be used"
|
|
||||||
" as a scroll action.",
|
|
||||||
up.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(actions::InvalidGesture& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid scroll action",
|
|
||||||
up.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException&) {
|
|
||||||
logPrintf(WARN, "Line %d: target is true but no up action was"
|
|
||||||
" set", config_root.getSourceLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& down = config_root.lookup("down");
|
|
||||||
try {
|
|
||||||
auto g = actions::Gesture::makeGesture(dev, down);
|
|
||||||
if(g->wheelCompatibility()) {
|
|
||||||
_down_action = g;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: This gesture cannot be used"
|
|
||||||
" as a scroll action.",
|
|
||||||
down.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(actions::InvalidGesture& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid scroll action",
|
|
||||||
down.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException&) {
|
|
||||||
logPrintf(WARN, "Line %d: target is true but no down action was"
|
|
||||||
" set", config_root.getSourceLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// HiresScroll not configured, use default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t HiresScroll::Config::getMode() const
|
|
||||||
{
|
|
||||||
return _mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t HiresScroll::Config::getMask() const
|
|
||||||
{
|
|
||||||
return _mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<logid::actions::Gesture>&
|
|
||||||
HiresScroll::Config::upAction() const
|
|
||||||
{
|
|
||||||
return _up_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<logid::actions::Gesture>&
|
|
||||||
HiresScroll::Config::downAction() const
|
|
||||||
{
|
|
||||||
return _down_action;
|
|
||||||
}
|
|
@ -35,29 +35,22 @@ namespace features
|
|||||||
|
|
||||||
uint8_t getMode();
|
uint8_t getMode();
|
||||||
void setMode(uint8_t mode);
|
void setMode(uint8_t mode);
|
||||||
|
|
||||||
class Config : public DeviceFeature::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev);
|
|
||||||
uint8_t getMode() const;
|
|
||||||
uint8_t getMask() const;
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Gesture>& upAction() const;
|
|
||||||
const std::shared_ptr<actions::Gesture>& downAction() const;
|
|
||||||
protected:
|
|
||||||
uint8_t _mode;
|
|
||||||
uint8_t _mask;
|
|
||||||
|
|
||||||
std::shared_ptr<actions::Gesture> _up_action;
|
|
||||||
std::shared_ptr<actions::Gesture> _down_action;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
|
void _makeAction(std::shared_ptr<actions::Gesture>& gesture,
|
||||||
|
std::optional<config::Gesture>& config);
|
||||||
|
|
||||||
void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event);
|
void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event);
|
||||||
std::shared_ptr<backend::hidpp20::HiresScroll> _hires_scroll;
|
std::shared_ptr<backend::hidpp20::HiresScroll> _hires_scroll;
|
||||||
std::chrono::time_point<std::chrono::system_clock> _last_scroll;
|
std::chrono::time_point<std::chrono::system_clock> _last_scroll;
|
||||||
int16_t _last_direction = 0;
|
int16_t _last_direction = 0;
|
||||||
Config _config;
|
|
||||||
|
std::optional<std::variant<bool, config::HiresScroll>>& _config;
|
||||||
|
|
||||||
|
uint8_t _mode;
|
||||||
|
uint8_t _mask;
|
||||||
|
|
||||||
|
std::shared_ptr<actions::Gesture> _up_action;
|
||||||
|
std::shared_ptr<actions::Gesture> _down_action;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -29,9 +29,26 @@ using namespace logid::actions;
|
|||||||
|
|
||||||
#define EVENTHANDLER_NAME "REMAP_BUTTON"
|
#define EVENTHANDLER_NAME "REMAP_BUTTON"
|
||||||
|
|
||||||
RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev),
|
RemapButton::RemapButton(Device *dev): DeviceFeature(dev),
|
||||||
|
_config (dev->activeProfile().buttons),
|
||||||
_ipc_node (dev->ipcNode()->make_child("buttons"))
|
_ipc_node (dev->ipcNode()->make_child("buttons"))
|
||||||
{
|
{
|
||||||
|
if(_config.has_value()) {
|
||||||
|
for(auto& button : _config.value()) {
|
||||||
|
if(button.second.action.has_value()) {
|
||||||
|
try {
|
||||||
|
_buttons.emplace(
|
||||||
|
button.first,
|
||||||
|
Action::makeAction(
|
||||||
|
dev,button.second.action.value()));
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
logPrintf(WARN, "Error creating button action: %s",
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_reprog_controls = hidpp20::ReprogControls::autoVersion(
|
_reprog_controls = hidpp20::ReprogControls::autoVersion(
|
||||||
&dev->hidpp20());
|
&dev->hidpp20());
|
||||||
@ -42,10 +59,10 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev),
|
|||||||
_reprog_controls->initCidMap();
|
_reprog_controls->initCidMap();
|
||||||
|
|
||||||
if(global_loglevel <= DEBUG) {
|
if(global_loglevel <= DEBUG) {
|
||||||
#define FLAG(x) control.second.flags & hidpp20::ReprogControls::x ? \
|
#define FLAG(x) (control.second.flags & hidpp20::ReprogControls::x ? \
|
||||||
"YES" : ""
|
"YES" : "")
|
||||||
#define ADDITIONAL_FLAG(x) control.second.additionalFlags & \
|
#define ADDITIONAL_FLAG(x) (control.second.additionalFlags & \
|
||||||
hidpp20::ReprogControls::x ? "YES" : ""
|
hidpp20::ReprogControls::x ? "YES" : "")
|
||||||
|
|
||||||
// Print CIDs, originally by zv0n
|
// Print CIDs, originally by zv0n
|
||||||
logPrintf(DEBUG, "%s:%d remappable buttons:",
|
logPrintf(DEBUG, "%s:%d remappable buttons:",
|
||||||
@ -57,6 +74,7 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev),
|
|||||||
logPrintf(DEBUG, "0x%02x | %-7s | %-7s | %-10s | %s",
|
logPrintf(DEBUG, "0x%02x | %-7s | %-7s | %-10s | %s",
|
||||||
control.first, FLAG(TemporaryDivertable), FLAG(FKey),
|
control.first, FLAG(TemporaryDivertable), FLAG(FKey),
|
||||||
FLAG(MouseButton), ADDITIONAL_FLAG(RawXY));
|
FLAG(MouseButton), ADDITIONAL_FLAG(RawXY));
|
||||||
|
#undef ADDITIONAL_FLAG
|
||||||
#undef FLAG
|
#undef FLAG
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +95,7 @@ RemapButton::~RemapButton()
|
|||||||
void RemapButton::configure()
|
void RemapButton::configure()
|
||||||
{
|
{
|
||||||
///TODO: DJ reporting trickery if cannot be remapped
|
///TODO: DJ reporting trickery if cannot be remapped
|
||||||
for(const auto& i : _config.buttons()) {
|
for(const auto& i : _buttons) {
|
||||||
hidpp20::ReprogControls::ControlInfo info{};
|
hidpp20::ReprogControls::ControlInfo info{};
|
||||||
try {
|
try {
|
||||||
info = _reprog_controls->getControlIdInfo(i.first);
|
info = _reprog_controls->getControlIdInfo(i.first);
|
||||||
@ -123,7 +141,7 @@ void RemapButton::listen()
|
|||||||
report));
|
report));
|
||||||
else { // RawXY
|
else { // RawXY
|
||||||
auto divertedXY = _reprog_controls->divertedRawXYEvent(report);
|
auto divertedXY = _reprog_controls->divertedRawXYEvent(report);
|
||||||
for(const auto& button : this->_config.buttons())
|
for(const auto& button : this->_buttons)
|
||||||
if(button.second->pressed())
|
if(button.second->pressed())
|
||||||
button.second->move(divertedXY.x, divertedXY.y);
|
button.second->move(divertedXY.x, divertedXY.y);
|
||||||
}
|
}
|
||||||
@ -144,80 +162,22 @@ void RemapButton::_buttonEvent(const std::set<uint16_t>& new_state)
|
|||||||
if(old_i != _pressed_buttons.end()) {
|
if(old_i != _pressed_buttons.end()) {
|
||||||
_pressed_buttons.erase(old_i);
|
_pressed_buttons.erase(old_i);
|
||||||
} else {
|
} else {
|
||||||
auto action = _config.buttons().find(i);
|
auto action = _buttons.find(i);
|
||||||
if(action != _config.buttons().end())
|
if(action != _buttons.end())
|
||||||
action->second->press();
|
action->second->press();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release all removed buttons
|
// Release all removed buttons
|
||||||
for(auto& i : _pressed_buttons) {
|
for(auto& i : _pressed_buttons) {
|
||||||
auto action = _config.buttons().find(i);
|
auto action = _buttons.find(i);
|
||||||
if(action != _config.buttons().end())
|
if(action != _buttons.end())
|
||||||
action->second->release();
|
action->second->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
_pressed_buttons = new_state;
|
_pressed_buttons = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemapButton::Config::Config(Device *dev) : DeviceFeature::Config(dev)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& config_root = dev->config().getSetting("buttons");
|
|
||||||
if(!config_root.isList()) {
|
|
||||||
logPrintf(WARN, "Line %d: buttons must be a list.",
|
|
||||||
config_root.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int button_count = config_root.getLength();
|
|
||||||
for(int i = 0; i < button_count; i++)
|
|
||||||
_parseButton(config_root[i]);
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// buttons not configured, use default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemapButton::Config::_parseButton(libconfig::Setting &setting)
|
|
||||||
{
|
|
||||||
if(!setting.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: button must be an object, ignoring.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t cid;
|
|
||||||
try {
|
|
||||||
auto& cid_setting = setting.lookup("cid");
|
|
||||||
if(!cid_setting.isNumber()) {
|
|
||||||
logPrintf(WARN, "Line %d: cid must be a number, ignoring.",
|
|
||||||
cid_setting.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cid = (int)cid_setting;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: cid is required, ignoring.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
_buttons.emplace(cid, Action::makeAction(_device,
|
|
||||||
setting.lookup("action")));
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
logPrintf(WARN, "Line %d: action is required, ignoring.",
|
|
||||||
setting.getSourceLine());
|
|
||||||
} catch(InvalidAction& e) {
|
|
||||||
logPrintf(WARN, "Line %d: %s is not a valid action, ignoring.",
|
|
||||||
setting["action"].getSourceLine(), e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<uint8_t, std::shared_ptr<Action>>& RemapButton::Config::buttons()
|
|
||||||
{
|
|
||||||
return _buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RemapButton::ButtonIPC::ButtonIPC(
|
RemapButton::ButtonIPC::ButtonIPC(
|
||||||
RemapButton *parent,
|
RemapButton *parent,
|
||||||
backend::hidpp20::ReprogControls::ControlInfo info) :
|
backend::hidpp20::ReprogControls::ControlInfo info) :
|
||||||
@ -225,9 +185,11 @@ RemapButton::ButtonIPC::ButtonIPC(
|
|||||||
{"ControlID", ipcgull::property<uint16_t>(
|
{"ControlID", ipcgull::property<uint16_t>(
|
||||||
ipcgull::property_readable, info.controlID)},
|
ipcgull::property_readable, info.controlID)},
|
||||||
{"Remappable", ipcgull::property<bool>(
|
{"Remappable", ipcgull::property<bool>(
|
||||||
ipcgull::property_readable, info.flags & hidpp20::ReprogControls::TemporaryDivertable)},
|
ipcgull::property_readable,
|
||||||
|
info.flags & hidpp20::ReprogControls::TemporaryDivertable)},
|
||||||
{"GestureSupport", ipcgull::property<bool>(
|
{"GestureSupport", ipcgull::property<bool>(
|
||||||
ipcgull::property_readable, (info.additionalFlags & hidpp20::ReprogControls::RawXY)
|
ipcgull::property_readable,
|
||||||
|
(info.additionalFlags & hidpp20::ReprogControls::RawXY)
|
||||||
)}
|
)}
|
||||||
}, {})
|
}, {})
|
||||||
{
|
{
|
||||||
|
@ -33,16 +33,6 @@ namespace features
|
|||||||
virtual void configure();
|
virtual void configure();
|
||||||
virtual void listen();
|
virtual void listen();
|
||||||
|
|
||||||
class Config : public DeviceFeature::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev);
|
|
||||||
const std::map<uint8_t, std::shared_ptr<actions::Action>>&
|
|
||||||
buttons();
|
|
||||||
protected:
|
|
||||||
void _parseButton(libconfig::Setting& setting);
|
|
||||||
std::map<uint8_t, std::shared_ptr<actions::Action>> _buttons;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
class ButtonIPC : public ipcgull::interface
|
class ButtonIPC : public ipcgull::interface
|
||||||
{
|
{
|
||||||
@ -52,11 +42,13 @@ namespace features
|
|||||||
};
|
};
|
||||||
|
|
||||||
void _buttonEvent(const std::set<uint16_t>& new_state);
|
void _buttonEvent(const std::set<uint16_t>& new_state);
|
||||||
Config _config;
|
|
||||||
std::shared_ptr<backend::hidpp20::ReprogControls> _reprog_controls;
|
std::shared_ptr<backend::hidpp20::ReprogControls> _reprog_controls;
|
||||||
std::set<uint16_t> _pressed_buttons;
|
std::set<uint16_t> _pressed_buttons;
|
||||||
std::mutex _button_lock;
|
std::mutex _button_lock;
|
||||||
|
|
||||||
|
std::optional<config::RemapButton>& _config;
|
||||||
|
std::map<uint16_t, std::shared_ptr<actions::Action>> _buttons;
|
||||||
|
|
||||||
std::shared_ptr<ipcgull::node> _ipc_node;
|
std::shared_ptr<ipcgull::node> _ipc_node;
|
||||||
typedef std::pair<std::shared_ptr<ipcgull::node>,
|
typedef std::pair<std::shared_ptr<ipcgull::node>,
|
||||||
std::shared_ptr<ButtonIPC>> ButtonIPCPair;
|
std::shared_ptr<ButtonIPC>> ButtonIPCPair;
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
using namespace logid::features;
|
using namespace logid::features;
|
||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
|
|
||||||
SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config
|
SmartShift::SmartShift(Device* device) : DeviceFeature(device),
|
||||||
(device)
|
_config (device->activeProfile().smartshift)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_smartshift = std::make_shared<hidpp20::SmartShift>(&device->hidpp20());
|
_smartshift = std::make_shared<hidpp20::SmartShift>(&device->hidpp20());
|
||||||
@ -34,7 +34,18 @@ SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config
|
|||||||
|
|
||||||
void SmartShift::configure()
|
void SmartShift::configure()
|
||||||
{
|
{
|
||||||
_smartshift->setStatus(_config.getSettings());
|
if(_config.has_value()) {
|
||||||
|
const auto& conf = _config.value();
|
||||||
|
hidpp20::SmartShift::SmartshiftStatus settings {};
|
||||||
|
settings.setActive = conf.on.has_value();
|
||||||
|
if(settings.setActive)
|
||||||
|
settings.active = conf.on.value();
|
||||||
|
settings.setAutoDisengage = conf.threshold.has_value();
|
||||||
|
if(settings.setAutoDisengage)
|
||||||
|
settings.autoDisengage = conf.threshold.value();
|
||||||
|
|
||||||
|
_smartshift->setStatus(settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmartShift::listen()
|
void SmartShift::listen()
|
||||||
@ -51,31 +62,3 @@ void SmartShift::setStatus(backend::hidpp20::SmartShift::SmartshiftStatus
|
|||||||
{
|
{
|
||||||
_smartshift->setStatus(status);
|
_smartshift->setStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartShift::Config::Config(Device *dev) : DeviceFeature::Config(dev), _status()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& config_root = dev->config().getSetting("smartshift");
|
|
||||||
if(!config_root.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: smartshift must be an object",
|
|
||||||
config_root.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_status.setActive = config_root.lookupValue("on", _status.active);
|
|
||||||
int tmp;
|
|
||||||
_status.setAutoDisengage = config_root.lookupValue("threshold", tmp);
|
|
||||||
if(_status.setAutoDisengage)
|
|
||||||
_status.autoDisengage = tmp;
|
|
||||||
_status.setDefaultAutoDisengage = config_root.lookupValue
|
|
||||||
("default_threshold", tmp);
|
|
||||||
if(_status.setDefaultAutoDisengage)
|
|
||||||
_status.defaultAutoDisengage = tmp;
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// SmartShift not configured, use default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hidpp20::SmartShift::SmartshiftStatus SmartShift::Config::getSettings()
|
|
||||||
{
|
|
||||||
return _status;
|
|
||||||
}
|
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "../backend/hidpp20/features/SmartShift.h"
|
#include "../backend/hidpp20/features/SmartShift.h"
|
||||||
#include "DeviceFeature.h"
|
#include "DeviceFeature.h"
|
||||||
|
#include "../config/schema.h"
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
namespace features
|
namespace features
|
||||||
@ -34,16 +35,8 @@ namespace features
|
|||||||
backend::hidpp20::SmartShift::SmartshiftStatus getStatus();
|
backend::hidpp20::SmartShift::SmartshiftStatus getStatus();
|
||||||
void setStatus(backend::hidpp20::SmartShift::SmartshiftStatus status);
|
void setStatus(backend::hidpp20::SmartShift::SmartshiftStatus status);
|
||||||
|
|
||||||
class Config : public DeviceFeature::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev);
|
|
||||||
backend::hidpp20::SmartShift::SmartshiftStatus getSettings();
|
|
||||||
protected:
|
|
||||||
backend::hidpp20::SmartShift::SmartshiftStatus _status;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
Config _config;
|
std::optional<config::SmartShift>& _config;
|
||||||
std::shared_ptr<backend::hidpp20::SmartShift> _smartshift;
|
std::shared_ptr<backend::hidpp20::SmartShift> _smartshift;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
@ -29,9 +29,46 @@ using namespace logid;
|
|||||||
|
|
||||||
#define SCROLL_EVENTHANDLER_NAME "THUMB_WHEEL"
|
#define SCROLL_EVENTHANDLER_NAME "THUMB_WHEEL"
|
||||||
|
|
||||||
ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(),
|
std::shared_ptr<actions::Action> _genAction(
|
||||||
_config(dev)
|
Device* dev, std::optional<config::BasicAction>& conf)
|
||||||
{
|
{
|
||||||
|
if(conf.has_value()) {
|
||||||
|
try {
|
||||||
|
return actions::Action::makeAction(dev, conf.value());
|
||||||
|
} catch(actions::InvalidAction& e) {
|
||||||
|
logPrintf(WARN, "Mapping thumb wheel to invalid action");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<actions::Gesture> _genGesture(
|
||||||
|
Device* dev, std::optional<config::Gesture>& conf)
|
||||||
|
{
|
||||||
|
if(conf.has_value()) {
|
||||||
|
try {
|
||||||
|
return actions::Gesture::makeGesture(dev, conf.value());
|
||||||
|
} catch (actions::InvalidAction &e) {
|
||||||
|
logPrintf(WARN, "Mapping thumb wheel to invalid gesture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(),
|
||||||
|
_config (dev->activeProfile().thumbwheel)
|
||||||
|
{
|
||||||
|
if(_config.has_value()) {
|
||||||
|
auto& conf = _config.value();
|
||||||
|
_left_action = _genGesture(dev, conf.left);
|
||||||
|
_right_action = _genGesture(dev, conf.right);
|
||||||
|
_touch_action = _genAction(dev, conf.touch);
|
||||||
|
_tap_action = _genAction(dev, conf.tap);
|
||||||
|
_proxy_action = _genAction(dev, conf.proxy);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_thumb_wheel = std::make_shared<hidpp20::ThumbWheel>(&dev->hidpp20());
|
_thumb_wheel = std::make_shared<hidpp20::ThumbWheel>(&dev->hidpp20());
|
||||||
} catch(hidpp20::UnsupportedFeature& e) {
|
} catch(hidpp20::UnsupportedFeature& e) {
|
||||||
@ -47,33 +84,41 @@ ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(),
|
|||||||
logPrintf(DEBUG, "Thumb wheel resolution: native (%d), diverted (%d)",
|
logPrintf(DEBUG, "Thumb wheel resolution: native (%d), diverted (%d)",
|
||||||
_wheel_info.nativeRes, _wheel_info.divertedRes);
|
_wheel_info.nativeRes, _wheel_info.divertedRes);
|
||||||
|
|
||||||
if(_config.leftAction()) {
|
if(_left_action) {
|
||||||
try {
|
try {
|
||||||
auto left_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
auto left_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
||||||
_config.leftAction());
|
_left_action);
|
||||||
// TODO: How do hires multipliers work on 0x2150 thumbwheels?
|
// TODO: How do hires multipliers work on 0x2150 thumbwheels?
|
||||||
if(left_axis)
|
if(left_axis)
|
||||||
left_axis->setHiresMultiplier(_wheel_info.divertedRes);
|
left_axis->setHiresMultiplier(_wheel_info.divertedRes);
|
||||||
} catch(std::bad_cast& e) { }
|
} catch(std::bad_cast& e) { }
|
||||||
|
|
||||||
_config.leftAction()->press(true);
|
_left_action->press(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_config.rightAction()) {
|
if(_right_action) {
|
||||||
try {
|
try {
|
||||||
auto right_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
auto right_axis = std::dynamic_pointer_cast<actions::AxisGesture>(
|
||||||
_config.rightAction());
|
_right_action);
|
||||||
if(right_axis)
|
if(right_axis)
|
||||||
right_axis->setHiresMultiplier(_wheel_info.divertedRes);
|
right_axis->setHiresMultiplier(_wheel_info.divertedRes);
|
||||||
} catch(std::bad_cast& e) { }
|
} catch(std::bad_cast& e) { }
|
||||||
|
|
||||||
_config.rightAction()->press(true);
|
_right_action->press(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThumbWheel::~ThumbWheel() {
|
||||||
|
_device->hidpp20().removeEventHandler(SCROLL_EVENTHANDLER_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
void ThumbWheel::configure()
|
void ThumbWheel::configure()
|
||||||
{
|
{
|
||||||
_thumb_wheel->setStatus(_config.divert(), _config.invert());
|
if(_config.has_value()) {
|
||||||
|
const auto& config = _config.value();
|
||||||
|
_thumb_wheel->setStatus(config.divert.value_or(false),
|
||||||
|
config.invert.value_or(false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThumbWheel::listen()
|
void ThumbWheel::listen()
|
||||||
@ -98,7 +143,7 @@ void ThumbWheel::listen()
|
|||||||
void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
||||||
{
|
{
|
||||||
if(event.flags & hidpp20::ThumbWheel::SingleTap) {
|
if(event.flags & hidpp20::ThumbWheel::SingleTap) {
|
||||||
auto action = _config.tapAction();
|
auto action = _tap_action;
|
||||||
if(action) {
|
if(action) {
|
||||||
action->press();
|
action->press();
|
||||||
action->release();
|
action->release();
|
||||||
@ -107,23 +152,21 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
|||||||
|
|
||||||
if((bool)(event.flags & hidpp20::ThumbWheel::Proxy) != _last_proxy) {
|
if((bool)(event.flags & hidpp20::ThumbWheel::Proxy) != _last_proxy) {
|
||||||
_last_proxy = !_last_proxy;
|
_last_proxy = !_last_proxy;
|
||||||
auto action = _config.proxyAction();
|
if(_proxy_action) {
|
||||||
if(action) {
|
|
||||||
if(_last_proxy)
|
if(_last_proxy)
|
||||||
action->press();
|
_proxy_action->press();
|
||||||
else
|
else
|
||||||
action->release();
|
_proxy_action->release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((bool)(event.flags & hidpp20::ThumbWheel::Touch) != _last_touch) {
|
if((bool)(event.flags & hidpp20::ThumbWheel::Touch) != _last_touch) {
|
||||||
_last_touch = !_last_touch;
|
_last_touch = !_last_touch;
|
||||||
auto action = _config.touchAction();
|
if(_touch_action) {
|
||||||
if(action) {
|
|
||||||
if(_last_touch)
|
if(_last_touch)
|
||||||
action->press();
|
_touch_action->press();
|
||||||
else
|
else
|
||||||
action->release();
|
_touch_action->release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,10 +175,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
|||||||
event.rotation *= _wheel_info.defaultDirection;
|
event.rotation *= _wheel_info.defaultDirection;
|
||||||
|
|
||||||
if(event.rotationStatus == hidpp20::ThumbWheel::Start) {
|
if(event.rotationStatus == hidpp20::ThumbWheel::Start) {
|
||||||
if(_config.rightAction())
|
if(_right_action)
|
||||||
_config.rightAction()->press(true);
|
_right_action->press(true);
|
||||||
if(_config.leftAction())
|
if(_left_action)
|
||||||
_config.leftAction()->press(true);
|
_left_action->press(true);
|
||||||
_last_direction = 0;
|
_last_direction = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,9 +187,9 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
|||||||
std::shared_ptr<actions::Gesture> scroll_action;
|
std::shared_ptr<actions::Gesture> scroll_action;
|
||||||
|
|
||||||
if(direction > 0)
|
if(direction > 0)
|
||||||
scroll_action = _config.rightAction();
|
scroll_action = _right_action;
|
||||||
else
|
else
|
||||||
scroll_action = _config.leftAction();
|
scroll_action = _left_action;
|
||||||
|
|
||||||
if(scroll_action) {
|
if(scroll_action) {
|
||||||
scroll_action->press(true);
|
scroll_action->press(true);
|
||||||
@ -157,136 +200,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(event.rotationStatus == hidpp20::ThumbWheel::Stop) {
|
if(event.rotationStatus == hidpp20::ThumbWheel::Stop) {
|
||||||
if(_config.rightAction())
|
if(_right_action)
|
||||||
_config.rightAction()->release();
|
_right_action->release();
|
||||||
if(_config.leftAction())
|
if(_left_action)
|
||||||
_config.leftAction()->release();
|
_left_action->release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ThumbWheel::Config::Config(Device* dev) : DeviceFeature::Config(dev)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& config_root = dev->config().getSetting("thumbwheel");
|
|
||||||
if(!config_root.isGroup()) {
|
|
||||||
logPrintf(WARN, "Line %d: thumbwheel must be a group",
|
|
||||||
config_root.getSourceLine());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& divert = config_root.lookup("divert");
|
|
||||||
if(divert.getType() == libconfig::Setting::TypeBoolean) {
|
|
||||||
_divert = divert;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: divert must be a boolean",
|
|
||||||
divert.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto& invert = config_root.lookup("invert");
|
|
||||||
if(invert.getType() == libconfig::Setting::TypeBoolean) {
|
|
||||||
_invert = invert;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.",
|
|
||||||
invert.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) { }
|
|
||||||
|
|
||||||
if(_divert) {
|
|
||||||
_left_action = _genGesture(dev, config_root, "left");
|
|
||||||
if(!_left_action)
|
|
||||||
logPrintf(WARN, "Line %d: divert is true but no left action "
|
|
||||||
"was set", config_root.getSourceLine());
|
|
||||||
|
|
||||||
_right_action = _genGesture(dev, config_root, "right");
|
|
||||||
if(!_right_action)
|
|
||||||
logPrintf(WARN, "Line %d: divert is true but no right action "
|
|
||||||
"was set", config_root.getSourceLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
_proxy_action = _genAction(dev, config_root, "proxy");
|
|
||||||
_tap_action = _genAction(dev, config_root, "tap");
|
|
||||||
_touch_action = _genAction(dev, config_root, "touch");
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
// ThumbWheel not configured, use default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<actions::Action> ThumbWheel::Config::_genAction(Device* dev,
|
|
||||||
libconfig::Setting& config_root, const std::string& name)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& a_group = config_root.lookup(name);
|
|
||||||
try {
|
|
||||||
return actions::Action::makeAction(dev, a_group);
|
|
||||||
} catch(actions::InvalidAction& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid action",
|
|
||||||
a_group.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<actions::Gesture> ThumbWheel::Config::_genGesture(Device* dev,
|
|
||||||
libconfig::Setting& config_root, const std::string& name)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto& g_group = config_root.lookup(name);
|
|
||||||
try {
|
|
||||||
auto g = actions::Gesture::makeGesture(dev, g_group);
|
|
||||||
if(g->wheelCompatibility()) {
|
|
||||||
return g;
|
|
||||||
} else {
|
|
||||||
logPrintf(WARN, "Line %d: This gesture cannot be used"
|
|
||||||
" as a scroll action.",
|
|
||||||
g_group.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(actions::InvalidGesture& e) {
|
|
||||||
logPrintf(WARN, "Line %d: Invalid scroll action",
|
|
||||||
g_group.getSourceLine());
|
|
||||||
}
|
|
||||||
} catch(libconfig::SettingNotFoundException& e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ThumbWheel::Config::divert() const
|
|
||||||
{
|
|
||||||
return _divert;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ThumbWheel::Config::invert() const
|
|
||||||
{
|
|
||||||
return _invert;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Gesture>& ThumbWheel::Config::leftAction() const
|
|
||||||
{
|
|
||||||
return _left_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Gesture>& ThumbWheel::Config::rightAction() const
|
|
||||||
{
|
|
||||||
return _right_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Action>& ThumbWheel::Config::proxyAction() const
|
|
||||||
{
|
|
||||||
return _proxy_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Action>& ThumbWheel::Config::tapAction() const
|
|
||||||
{
|
|
||||||
return _tap_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Action>& ThumbWheel::Config::touchAction() const
|
|
||||||
{
|
|
||||||
return _touch_action;
|
|
||||||
}
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "../backend/hidpp20/features/ThumbWheel.h"
|
#include "../backend/hidpp20/features/ThumbWheel.h"
|
||||||
#include "DeviceFeature.h"
|
#include "DeviceFeature.h"
|
||||||
#include "../actions/gesture/Gesture.h"
|
#include "../actions/gesture/Gesture.h"
|
||||||
|
#include "../config/schema.h"
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
namespace features
|
namespace features
|
||||||
@ -29,45 +30,26 @@ namespace features
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ThumbWheel(Device* dev);
|
explicit ThumbWheel(Device* dev);
|
||||||
|
~ThumbWheel();
|
||||||
virtual void configure();
|
virtual void configure();
|
||||||
virtual void listen();
|
virtual void listen();
|
||||||
|
|
||||||
class Config : public DeviceFeature::Config
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Config(Device* dev);
|
|
||||||
bool divert() const;
|
|
||||||
bool invert() const;
|
|
||||||
|
|
||||||
const std::shared_ptr<actions::Gesture>& leftAction() const;
|
|
||||||
const std::shared_ptr<actions::Gesture>& rightAction() const;
|
|
||||||
const std::shared_ptr<actions::Action>& proxyAction() const;
|
|
||||||
const std::shared_ptr<actions::Action>& tapAction() const;
|
|
||||||
const std::shared_ptr<actions::Action>& touchAction() const;
|
|
||||||
protected:
|
|
||||||
bool _divert = false;
|
|
||||||
bool _invert = false;
|
|
||||||
|
|
||||||
static std::shared_ptr<actions::Gesture> _genGesture(Device* dev,
|
|
||||||
libconfig::Setting& setting, const std::string& name);
|
|
||||||
static std::shared_ptr<actions::Action> _genAction(Device* dev,
|
|
||||||
libconfig::Setting& setting, const std::string& name);
|
|
||||||
|
|
||||||
std::shared_ptr<actions::Gesture> _left_action;
|
|
||||||
std::shared_ptr<actions::Gesture> _right_action;
|
|
||||||
std::shared_ptr<actions::Action> _proxy_action;
|
|
||||||
std::shared_ptr<actions::Action> _tap_action;
|
|
||||||
std::shared_ptr<actions::Action> _touch_action;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event);
|
void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event);
|
||||||
|
|
||||||
std::shared_ptr<backend::hidpp20::ThumbWheel> _thumb_wheel;
|
std::shared_ptr<backend::hidpp20::ThumbWheel> _thumb_wheel;
|
||||||
backend::hidpp20::ThumbWheel::ThumbwheelInfo _wheel_info;
|
backend::hidpp20::ThumbWheel::ThumbwheelInfo _wheel_info;
|
||||||
|
|
||||||
|
std::shared_ptr<actions::Gesture> _left_action;
|
||||||
|
std::shared_ptr<actions::Gesture> _right_action;
|
||||||
|
std::shared_ptr<actions::Action> _proxy_action;
|
||||||
|
std::shared_ptr<actions::Action> _tap_action;
|
||||||
|
std::shared_ptr<actions::Action> _touch_action;
|
||||||
|
|
||||||
int8_t _last_direction = 0;
|
int8_t _last_direction = 0;
|
||||||
bool _last_proxy = false;
|
bool _last_proxy = false;
|
||||||
bool _last_touch = false;
|
bool _last_touch = false;
|
||||||
Config _config;
|
std::optional<config::ThumbWheel>& _config;
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ template<typename data>
|
|||||||
class mutex_queue
|
class mutex_queue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
mutex_queue<data>() = default;
|
mutex_queue() = default;
|
||||||
bool empty()
|
bool empty()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
Loading…
Reference in New Issue
Block a user