Use events instead of continous pinging

This commit is contained in:
PixlOne 2019-07-28 02:08:18 -04:00
parent 684f502b2e
commit b95cc60fd1
13 changed files with 366 additions and 291 deletions

View File

@ -6,7 +6,12 @@ devices: (
on: true;
threshold: 30;
};
hiresscroll: true;
hiresscroll:
{
hires: true;
invert: false;
target: false;
};
dpi: 1000;
buttons: (

View File

@ -1,6 +1,8 @@
#include <hidpp20/Error.h>
#include <hidpp/SimpleDispatcher.h>
#include <hidpp20/IAdjustableDPI.h>
#include <hidpp20/ISmartShift.h>
#include <hidpp20/IHiresScroll.h>
#include "Actions.h"
#include "util.h"
@ -55,48 +57,26 @@ void GestureAction::release()
void SmartshiftAction::press()
{
if(device->features.find(0x2110) == device->features.end())
{
log_printf(DEBUG, "Error toggling smart shift, feature is non-existent.");
return;
}
const uint8_t f_index = device->features.find(0x2110)->second;
std::vector<uint8_t> results;
try
{
results = device->hidpp_dev->callFunction(f_index, 0x00);
if(results[0] == 0x02)
results = device->hidpp_dev->callFunction(f_index, 0x01, {0x01});
else if(results[0] == 0x01)
results = device->hidpp_dev->callFunction(f_index, 0x01, {0x02});
else
results = device->hidpp_dev->callFunction(f_index, 0x01, {0x01});
HIDPP20::ISmartShift iss(device->hidpp_dev);
auto s = iss.getStatus();
iss.setStatus({new bool(!*s.Active)});
}
catch(HIDPP20::Error &e)
{
log_printf(ERROR, "Error toggling smart shift, code %d: %s\n", e.errorCode(), e.what());
return;
}
}
void HiresScrollAction::press()
{
if(device->features.find(0x2110) == device->features.end())
{
log_printf(DEBUG, "Error toggling hires scroll, feature is non-existent.");
return;
}
const uint8_t f_index = device->features.find(0x2121)->second;
std::vector<uint8_t> results;
try
{
results = device->hidpp_dev->callFunction(f_index, 0x01);
if(results[0] == 0x02)
results = device->hidpp_dev->callFunction(f_index, 0x02, {0x00});
else
results = device->hidpp_dev->callFunction(f_index, 0x02, {0x02});
HIDPP20::IHiresScroll ihs(device->hidpp_dev);
auto mode = ihs.getMode();
mode ^= HIDPP20::IHiresScroll::Mode::HiRes;
ihs.setMode(mode);
}
catch(HIDPP20::Error &e)
{

View File

@ -1,9 +1,10 @@
#ifndef LOGIOPS_ACTIONS_H
#define LOGIOPS_ACTIONS_H
#ifndef ACTIONS_H
#define ACTIONS_H
#include "Device.h"
#include <map>
#include <vector>
#include <hidpp20/IReprogControls.h>
#include "Device.h"
enum class Action
{
@ -119,4 +120,4 @@ private:
int dpi_inc;
};
#endif //LOGIOPS_ACTIONS_H
#endif //ACTIONS_H

View File

@ -5,6 +5,7 @@
#include <libevdev/libevdev.h>
#include <algorithm>
#include <cstring>
#include <hidpp20/IHiresScroll.h>
#include "Configuration.h"
#include "util.h"
@ -79,10 +80,48 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
try
{
bool b;
if(!root.lookupValue("hiresscroll", b))
throw SettingTypeException(root["hiresscroll"]);
hiresscroll = new bool(b);
const Setting& hr = root["hiresscroll"];
uint8_t hss = 0;
try
{
bool b;
if(!hr.lookupValue("hires", b))
throw SettingTypeException(root["hires"]);
if(b) hss |= HIDPP20::IHiresScroll::HiRes;
}
catch(SettingNotFoundException &e) { }
catch(SettingTypeException &e)
{
log_printf(INFO, "Line %d: hires field must be a boolean", hr["hires"].getSourceLine());
}
try
{
bool b;
if(!hr.lookupValue("invert", b))
throw SettingTypeException(root["invert"]);
if(b) hss |= HIDPP20::IHiresScroll::Inverted;
}
catch(SettingNotFoundException &e) { }
catch(SettingTypeException &e)
{
log_printf(INFO, "Line %d: invert field must be a boolean", hr["invert"].getSourceLine());
}
try
{
bool b;
if(!hr.lookupValue("target", b))
throw SettingTypeException(root["target"]);
if(b) hss |= HIDPP20::IHiresScroll::Target;
}
catch(SettingNotFoundException &e) { }
catch(SettingTypeException &e)
{
log_printf(INFO, "Line %d: target field must be a boolean", hr["target"].getSourceLine());
}
hiresscroll = new uint8_t(hss);
}
catch(const SettingNotFoundException &e)
{
@ -90,18 +129,18 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
}
catch(const SettingTypeException &e)
{
log_printf(WARN, "Line %d: DPI must me an integer; not setting.", root["hiresscroll"].getSourceLine());
log_printf(WARN, "Line %d: hiresscroll should be an object", root["hiresscroll"].getSourceLine());
}
try
{
const Setting& ss = root["smartshift"];
smartshift = new smartshift_options;
smartshift = new HIDPP20::ISmartShift::SmartshiftStatus {};
bool on;
int threshold;
try
{
if (ss.lookupValue("on", on)) smartshift->on = new bool(on);
if (ss.lookupValue("on", on)) smartshift->Active = new bool(on);
else log_printf(WARN, "Line %d: on field must be a boolean", ss["on"].getSourceLine());
}
catch(const SettingNotFoundException &e) { }
@ -113,26 +152,24 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
if(threshold < 0)
{
threshold = 1;
log_printf(INFO, "Smartshift threshold must be > 0 or < 100, setting to 0.");
log_printf(INFO, "Smartshift threshold must be > 0 or < 100, setting to 1.");
}
if(threshold >= 100)
{
threshold = 99;
log_printf(INFO, "Smartshift threshold must be > 0 or < 100, setting to 99.");
}
smartshift->threshold = new uint8_t(threshold);
smartshift->AutoDisengage = new uint8_t(threshold);
smartshift->DefaultAutoDisengage = new uint8_t(threshold);
}
else log_printf(WARN, "Line %d: threshold must be an integer", ss["threshold"].getSourceLine());
}
catch(const SettingNotFoundException &e)
{
log_printf(INFO, "Missing threshold for smartshift, not setting.");
}
catch(const SettingNotFoundException &e) { }
}
catch(const SettingNotFoundException &e) { }
catch(const SettingTypeException &e)
{
log_printf(WARN, "Line %d: smartshift field must be an object", root["hiressscroll"].getSourceLine());
log_printf(WARN, "Line %d: smartshift field must be an object", root["smartshift"].getSourceLine());
}
Setting* buttons;

View File

@ -1,14 +1,10 @@
#ifndef MASTEROPTIONS_CONFIGURATION_H
#define MASTEROPTIONS_CONFIGURATION_H
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
#include <map>
#include <libconfig.h++>
struct smartshift_options
{
bool* on = nullptr;
uint8_t* threshold = nullptr;
};
#include <hidpp20/ISmartShift.h>
#include "Actions.h"
class DeviceConfig;
class ButtonAction;
@ -20,8 +16,8 @@ public:
DeviceConfig();
DeviceConfig(const libconfig::Setting& root);
const int* dpi = nullptr;
struct smartshift_options* smartshift = nullptr;
const bool* hiresscroll = nullptr;
HIDPP20::ISmartShift::SmartshiftStatus* smartshift;
const uint8_t* hiresscroll = nullptr;
std::map<uint16_t, ButtonAction*> actions;
};
@ -38,4 +34,4 @@ ButtonAction* parse_action(Action action, const libconfig::Setting* action_confi
extern Configuration* global_config;
#endif //MASTEROPTIONS_CONFIGURATION_H
#endif //CONFIGURATION_H

View File

@ -6,21 +6,23 @@
#include <hidpp20/IFeatureSet.h>
#include <hidpp20/Error.h>
#include <hidpp20/IReprogControls.h>
#include <hidpp20/ISmartShift.h>
#include <hidpp20/Device.h>
#include <hidpp10/Error.h>
#include <algorithm>
#include <cstring>
#include <utility>
#include <hidpp20/UnsupportedFeature.h>
#include <hidpp20/IHiresScroll.h>
#include "Device.h"
#include "Actions.h"
#include "Configuration.h"
#include "util.h"
#include "EvdevDevice.h"
using namespace std::chrono_literals;
Device::Device(std::string p, const HIDPP::DeviceIndex i) : path(p), index (i)
Device::Device(std::string p, const HIDPP::DeviceIndex i) : path(std::move(p)), index (i)
{
// Initialise variables
DeviceRemoved = false;
@ -74,39 +76,42 @@ void Device::divert_buttons(bool scanning)
}
catch(HIDPP20::UnsupportedFeature &e)
{
log_printf(DEBUG, "%s does not support Reprog controls, not diverting!", name);
log_printf(DEBUG, "%s does not support Reprog controls, not diverting!", name.c_str());
}
}
void Device::set_smartshift(smartshift_options ops, bool scanning)
void Device::set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops, bool scanning)
{
std::vector<uint8_t> parameters;
parameters.push_back(ops.on == nullptr ? 0 : (*ops.on)? 2 : 1);
if(ops.threshold != nullptr)
try
{
parameters.push_back(*ops.threshold);
parameters.push_back(*ops.threshold);
HIDPP20::ISmartShift ss(hidpp_dev);
ss.setStatus(ops);
}
if(features.find(0x2110) == features.end())
catch (HIDPP20::UnsupportedFeature &e)
{
log_printf(DEBUG, "Error toggling smart shift, feature is non-existent.");
return;
log_printf(ERROR, "Device does not support SmartShift");
}
const uint8_t f_index = features.find(0x2110)->second;
try { hidpp_dev->callFunction(f_index, 0x01, parameters); }
catch (HIDPP20::Error &e)
{
if(scanning)
throw e;
log_printf(ERROR, "Error setting smartshift options, code %d: %s\n", e.errorCode(), e.what());
log_printf(ERROR, "Error setting SmartShift options, code %d: %s\n", e.errorCode(), e.what());
}
}
void Device::set_hiresscroll(bool b, bool scanning)
void Device::set_hiresscroll(uint8_t ops, bool scanning)
{
try
{
HIDPP20::IHiresScroll hs(hidpp_dev);
hs.setMode(ops);
}
catch (HIDPP20::UnsupportedFeature &e)
{
log_printf(ERROR, "Device does not support Hires Scrolling");
}
catch (HIDPP20::Error &e)
{
log_printf(ERROR, "Error setting Hires Scrolling options, code %d: %s\n", e.errorCode(), e.what());
}
}
void Device::set_dpi(int dpi, bool scanning)
@ -128,49 +133,11 @@ void Device::start()
auto *d = new HIDPP::SimpleDispatcher(path.c_str());
listener = new SimpleListener(d, index);
listener->addEventHandler( std::make_unique<ButtonHandler>(hidpp_dev, this) );
auto listener_thread = std::thread { [=]() { listener->start(); } };
listener_thread.detach();
while(!DeviceRemoved)
{
std::mutex m;
std::condition_variable cv;
std::vector<uint8_t> results;
std::thread t([&cv, &results, dev=hidpp_dev, removed=&DeviceRemoved]()
{
try { results = dev->callFunction(0x00, 0x00); }
catch(HIDPP10::Error &e) { usleep(500000); }
catch(std::system_error &e)
{
cv.notify_one();
if(*removed) printf("REMOVED!\n");
*removed = true;
}
cv.notify_one();
});
t.detach();
std::unique_lock<std::mutex> l(m);
if(cv.wait_for(l, 500ms) == std::cv_status::timeout)
{
while(!DeviceRemoved)
{
try
{
configure(true);
break;
}
catch(std::exception &e) {} // Retry infinitely on failure
}
}
usleep(200000);
}
listener->stop();
listener_thread.join();
listener->addEventHandler( std::make_unique<ReceiverHandler>(this) );
listener->start();
}
void Device::ButtonHandler::handleEvent (const HIDPP::Report &event)
void ButtonHandler::handleEvent (const HIDPP::Report &event)
{
switch (event.function())
{
@ -187,7 +154,7 @@ void Device::ButtonHandler::handleEvent (const HIDPP::Report &event)
std::vector<uint16_t>::iterator it;
std::vector<uint16_t> cids(states.size() + new_states.size());
it = std::set_union(states.begin(), states.end(), new_states.begin(), new_states.end(), cids.begin());
cids.resize(it - cids.begin());
cids.resize((ulong)(it - cids.begin()));
for (uint16_t i : cids)
{
if (std::find(new_states.begin(), new_states.end(), i) != new_states.end())
@ -208,10 +175,54 @@ void Device::ButtonHandler::handleEvent (const HIDPP::Report &event)
std::thread{[=]() { dev->move_diverted(i, raw_xy); }}.detach();
break;
}
default:
break;
}
}
void Device::EventListener::removeEventHandlers ()
void ReceiverHandler::handleEvent(const HIDPP::Report &event)
{
switch(event.featureIndex())
{
case HIDPP10::IReceiver::DeviceUnpaired:
{
// Find device, stop it, and delete it
auto it = finder->devices.begin();
while (it != finder->devices.end())
{
if(it->first->path == dev->path && it->first->index == event.deviceIndex())
{
log_printf(INFO, "%s (Device %d on %s) unpaired.", it->first->name.c_str(), event.deviceIndex(), dev->path);
it->first->stop();
it->second.join();
finder->devices.erase(it);
}
else it++;
}
break;
}
case HIDPP10::IReceiver::DevicePaired:
{
break;
}
case HIDPP10::IReceiver::ConnectionStatus:
{
auto status = HIDPP10::IReceiver::connectionStatusEvent(event);
if(status == HIDPP10::IReceiver::LinkLoss)
log_printf(INFO, "Link lost to device %d on %s", event.deviceIndex(), dev->path.c_str());
else if (status == HIDPP10::IReceiver::ConnectionEstablished)
{
dev->configure();
log_printf(INFO, "Connection established to device %d on %s", event.deviceIndex(), dev->path.c_str());
}
break;
}
default:
break;
}
}
void EventListener::removeEventHandlers ()
{
for (const auto &p: iterators)
dispatcher->unregisterEventHandler(p.second);
@ -219,35 +230,37 @@ void Device::EventListener::removeEventHandlers ()
iterators.clear();
}
Device::EventListener::~EventListener()
EventListener::~EventListener()
{
removeEventHandlers();
}
void Device::EventListener::addEventHandler(std::unique_ptr<EventHandler> &&handler)
void EventListener::addEventHandler(std::unique_ptr<EventHandler> &&handler)
{
uint8_t feature = handler->feature()->index();
EventHandler *ptr = handler.get();
handlers.emplace(feature, std::move(handler));
dispatcher->registerEventHandler(index, feature, [ptr](const HIDPP::Report &report)
for(uint8_t feature : handler->featureIndices())
{
ptr->handleEvent(report);
return true;
});
handlers.emplace(feature, std::move(handler));
dispatcher->registerEventHandler(index, feature, [=](const HIDPP::Report &report)
{
ptr->handleEvent(report);
return true;
});
}
}
void Device::SimpleListener::start()
void SimpleListener::start()
{
try { dispatcher->listen(); }
catch(std::system_error &e) { }
}
void Device::SimpleListener::stop()
void SimpleListener::stop()
{
dispatcher->stop();
}
bool Device::SimpleListener::event (EventHandler *handler, const HIDPP::Report &report)
bool SimpleListener::event (EventHandler *handler, const HIDPP::Report &report)
{
handler->handleEvent (report);
return true;
@ -255,7 +268,7 @@ bool Device::SimpleListener::event (EventHandler *handler, const HIDPP::Report &
void Device::stop()
{
DeviceRemoved = true;
listener->stop();
}
void Device::press_button(uint16_t cid)
@ -296,11 +309,5 @@ std::map<uint16_t, uint8_t> Device::get_features()
std::map<uint16_t, uint8_t> features;
HIDPP20::IFeatureSet ifs (hidpp_dev);
unsigned int feature_count = ifs.getCount();
for(uint8_t i = 1; i <= feature_count; i++)
{
features.insert({ifs.getFeatureID(i), i});
log_printf(DEBUG, "%s: 0x%02x : 0x%04x", name.c_str(), i, ifs.getFeatureID(i));
}
return features;
}

View File

@ -1,13 +1,18 @@
#ifndef LOGIOPS_DEVICE_H
#define LOGIOPS_DEVICE_H
#ifndef DEVICE_H
#define DEVICE_H
#include "Actions.h"
#include "DeviceFinder.h"
#include "Configuration.h"
#include <map>
#include <memory>
#include <hidpp/Dispatcher.h>
#include <hidpp/SimpleDispatcher.h>
#include <hidpp10/IReceiver.h>
#include "Actions.h"
#include "Configuration.h"
class EventListener;
class DeviceConfig;
class Device
{
@ -29,80 +34,98 @@ public:
std::map<uint16_t, uint8_t> features;
std::string path;
const std::string path;
const HIDPP::DeviceIndex index;
HIDPP::Dispatcher* dispatcher;
HIDPP20::Device* hidpp_dev;
class EventHandler
{
public:
virtual const HIDPP20::FeatureInterface *feature() const = 0;
virtual void handleEvent (const HIDPP::Report &event) = 0;
};
class ButtonHandler : public EventHandler
{
public:
ButtonHandler (HIDPP20::Device *hidppdev, Device *d) : _irc (HIDPP20::IReprogControls::auto_version(hidppdev)), dev (d) { }
const HIDPP20::FeatureInterface *feature () const
{
return &_irc;
}
void handleEvent (const HIDPP::Report &event);
protected:
HIDPP20::IReprogControls _irc;
Device* dev;
std::vector<uint16_t> states;
std::vector<uint16_t> new_states;
};
class EventListener
{
HIDPP::Dispatcher *dispatcher;
HIDPP::DeviceIndex index;
std::map<uint8_t, std::unique_ptr<EventHandler>> handlers;
std::map<uint8_t, HIDPP::Dispatcher::listener_iterator> iterators;
public:
EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): dispatcher (dispatcher), index (index) {}
virtual void removeEventHandlers ();
virtual ~EventListener();
virtual void addEventHandler (std::unique_ptr<EventHandler> &&handler);
virtual void start () = 0;
virtual void stop () = 0;
protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report) = 0;
};
class SimpleListener : public EventListener
{
HIDPP::SimpleDispatcher *dispatcher;
public:
SimpleListener (HIDPP::SimpleDispatcher* dispatcher, HIDPP::DeviceIndex index):
EventListener (dispatcher, index),
dispatcher (dispatcher)
{
}
virtual void start();
virtual void stop();
protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report);
};
protected:
DeviceConfig* config;
bool DeviceRemoved;
EventListener* listener;
void divert_buttons(bool scanning=false);
void set_smartshift(struct smartshift_options ops, bool scanning=false);
void set_hiresscroll(bool b, bool scanning=false);
void set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops, bool scanning=false);
void set_hiresscroll(uint8_t flags, bool scanning=false);
void set_dpi(int dpi, bool scanning=false);
};
class EventHandler
{
public:
virtual const HIDPP20::FeatureInterface *feature() const = 0;
virtual const std::vector<uint8_t> featureIndices() const
{
return {feature()->index()};
};
virtual void handleEvent (const HIDPP::Report &event) = 0;
};
class ButtonHandler : public EventHandler
{
public:
ButtonHandler (HIDPP20::Device *hidppdev, Device *d) : _irc (HIDPP20::IReprogControls::auto_version(hidppdev)), dev (d) { }
const HIDPP20::FeatureInterface *feature () const
{
return &_irc;
}
void handleEvent (const HIDPP::Report &event);
protected:
HIDPP20::IReprogControls _irc;
Device* dev;
std::vector<uint16_t> states;
std::vector<uint16_t> new_states;
};
class ReceiverHandler : public EventHandler
{
public:
ReceiverHandler (Device *d) : dev (d) { }
const HIDPP20::FeatureInterface *feature () const
{
}
virtual const std::vector<uint8_t> featureIndices() const
{
return HIDPP10::IReceiver::Events;
}
void handleEvent (const HIDPP::Report &event);
protected:
Device* dev;
};
#endif //LOGIOPS_DEVICE_H
class EventListener
{
HIDPP::Dispatcher *dispatcher;
HIDPP::DeviceIndex index;
std::map<uint8_t, std::unique_ptr<EventHandler>> handlers;
std::map<uint8_t, HIDPP::Dispatcher::listener_iterator> iterators;
public:
EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): dispatcher (dispatcher), index (index) {}
virtual void removeEventHandlers ();
virtual ~EventListener();
virtual void addEventHandler (std::unique_ptr<EventHandler> &&handler);
virtual void start () = 0;
virtual void stop () = 0;
protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report) = 0;
};
class SimpleListener : public EventListener
{
HIDPP::SimpleDispatcher *dispatcher;
public:
SimpleListener (HIDPP::SimpleDispatcher* dispatcher, HIDPP::DeviceIndex index):
EventListener (dispatcher, index),
dispatcher (dispatcher)
{
}
virtual void start();
virtual void stop();
protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report);
};
#endif //DEVICE_H

View File

@ -2,10 +2,11 @@
#include <hidpp/SimpleDispatcher.h>
#include <hidpp/Device.h>
#include <hidpp10/Error.h>
#include <hidpp10/IReceiver.h>
#include <hidpp20/Error.h>
#include <cstring>
#include <unistd.h>
#include <future>
#include <thread>
#include <fstream>
#include <sstream>
@ -13,16 +14,10 @@
#include "util.h"
#include "Device.h"
void find_device()
{
auto df = new DeviceFinder();
df->run();
}
constexpr uint16_t DeviceFinder::UnifyingReceivers[];
void DeviceFinder::addDevice(const char *path)
{
const int max_tries = 5;
const int try_delay = 50000;
std::string string_path(path);
// Asynchronously scan device
std::thread{[=]()
@ -50,6 +45,10 @@ void DeviceFinder::addDevice(const char *path)
if(hidraw_info.find("HID_NAME") != hidraw_info.end())
if (hidraw_info.find("HID_NAME")->second.find("Logitech") == std::string::npos) return;
std::vector<Device*> _devs;
const int max_tries = 5;
const int try_delay = 50000;
//Check if device is an HID++ device and handle it accordingly
try
{
@ -61,80 +60,84 @@ void DeviceFinder::addDevice(const char *path)
HIDPP::WirelessDevice3, HIDPP::WirelessDevice4,
HIDPP::WirelessDevice5, HIDPP::WirelessDevice6})
{
/// TODO: CONTINUOUSLY SCAN ALL DEVICES ON RECEIVER
//Skip wireless devices if default device (receiver) has failed
if(!has_receiver_index && index == HIDPP::WirelessDevice1)
break;
for(int i = 0; i < max_tries; i++)
{
try
{
HIDPP::Device d(&dispatcher, index);
auto version = d.protocolVersion();
if(index == HIDPP::DefaultDevice && version == std::make_tuple(1, 0))
has_receiver_index = true;
uint major, minor;
std::tie(major, minor) = d.protocolVersion();
if(major > 1) // HID++ 2.0 devices only
{
auto dev = new Device(string_path, index);
handlers.insert({
dev, std::async(std::launch::async, &Device::start, *dev)
});
log_printf(INFO, "%s detected: device %d on %s", d.name().c_str(), index, string_path.c_str());
}
break;
}
catch(HIDPP10::Error &e)
{
if(e.errorCode() != HIDPP10::Error::UnknownDevice)
{
if(i == max_tries - 1)
log_printf(WARN, "Error while querying %s, wireless device %d: %s", string_path.c_str(), index, e.what());
else usleep(try_delay);
}
}
catch(HIDPP20::Error &e)
{
if(e.errorCode() != HIDPP20::Error::UnknownDevice)
{
if(i == max_tries - 1)
log_printf(WARN, "Error while querying %s, device %d: %s", string_path.c_str(), index, e.what());
else usleep(try_delay);
}
}
catch(HIDPP::Dispatcher::TimeoutError &e)
{
if(i == max_tries - 1)
log_printf(WARN, "Device %s (index %d) timed out.", string_path.c_str(), index);
else usleep(try_delay);
}
catch(std::runtime_error &e)
{
if(i == max_tries - 1)
log_printf(WARN, "Runtime error on device %d on %s: %s", index, string_path.c_str(), e.what());
else usleep(try_delay);
}
}
if(!has_receiver_index && index == HIDPP::WirelessDevice1)
break;
for(int i = 0; i < max_tries; i++)
{
try
{
HIDPP::Device d(&dispatcher, index);
auto version = d.protocolVersion();
uint major, minor;
std::tie(major, minor) = version;
if(index == HIDPP::DefaultDevice && version == std::make_tuple(1, 0))
has_receiver_index = true;
if(major > 1) // HID++ 2.0 devices only
{
auto dev = new Device(string_path, index);
_devs.push_back(dev);
log_printf(INFO, "%s detected: device %d on %s", d.name().c_str(), index, string_path.c_str());
}
break;
}
catch(HIDPP10::Error &e)
{
if(e.errorCode() != HIDPP10::Error::UnknownDevice)
{
if(i == max_tries - 1)
log_printf(ERROR, "Error while querying %s, wireless device %d: %s", string_path.c_str(), index, e.what());
else usleep(try_delay);
}
else break;
}
catch(HIDPP20::Error &e)
{
if(e.errorCode() != HIDPP20::Error::UnknownDevice)
{
if(i == max_tries - 1)
log_printf(ERROR, "Error while querying %s, device %d: %s", string_path.c_str(), index, e.what());
else usleep(try_delay);
}
else break;
}
catch(HIDPP::Dispatcher::TimeoutError &e)
{
if(i == max_tries - 1)
log_printf(ERROR, "Device %s (index %d) timed out.", string_path.c_str(), index);
else usleep(try_delay);
}
catch(std::runtime_error &e)
{
if(i == max_tries - 1)
log_printf(ERROR, "Runtime error on device %d on %s: %s", index, string_path.c_str(), e.what());
else usleep(try_delay);
}
}
}
}
catch(HIDPP::Dispatcher::NoHIDPPReportException &e) {}
catch(std::system_error &e) { log_printf(WARN, "Failed to open %s: %s", string_path.c_str(), e.what()); }
for(auto dev : _devs)
{
devices.insert({dev, std::thread{[dev]() { dev->start(); }}});
devices[dev].detach();
}
}}.detach();
}
void DeviceFinder::removeDevice(const char* path)
{
// Iterate through Devices, stop all in path
auto it = handlers.begin();
while (it != handlers.end())
auto it = devices.begin();
while (it != devices.end())
{
if(it->first->path == path)
{
log_printf(INFO, "%s on %s disconnected.", it->first->name.c_str(), path);
it->first->stop();
it->second.wait();
//handlers.erase(it);
it->second.join();
devices.erase(it);
it++;
}
else

View File

@ -1,18 +1,39 @@
#ifndef MASTEROPTIONS_DEVICEFINDER_H
#define MASTEROPTIONS_DEVICEFINDER_H
#ifndef DEVICEFINDER_H
#define DEVICEFINDER_H
#include <hid/DeviceMonitor.h>
#include <hidpp/SimpleDispatcher.h>
#include <hidpp10/Device.h>
#include <hidpp10/IReceiver.h>
#include <hidpp20/IReprogControls.h>
#include <map>
#include <thread>
#include "Device.h"
struct handler_pair;
class Device;
class DeviceFinder : public HID::DeviceMonitor
{
public:
std::map<Device*, std::thread> devices;
static constexpr uint16_t UnifyingReceivers[] =
{
0xc52b, 0xc532, // Official Unifying receivers
0xc52f, 0xc526, // Nano receivers
0xc52e, 0xc51b,
0xc531, 0xc517,
0xc518, 0xc51a,
0xc521, 0xc525,
0xc534,
0xc539, 0xc53a, // Lightspeed receivers
0xc53f,
0x17ef, // Lenovo nano receivers
};
protected:
void addDevice(const char* path);
void removeDevice(const char* path);
std::map<Device*, std::future<void>> handlers;
};
void find_device();
extern DeviceFinder* finder;
#endif //MASTEROPTIONS_DEVICEFINDER_H
#endif //DEVICEFINDER_H

View File

@ -1,5 +1,5 @@
#ifndef MASTEROPTIONS_EVDEVDEVICE_H
#define MASTEROPTIONS_EVDEVDEVICE_H
#ifndef EVDEVDEVICE_H
#define EVDEVDEVICE_H
#include <libevdev/libevdev.h>
#include <libevdev/libevdev-uinput.h>
@ -16,4 +16,4 @@ public:
extern EvdevDevice* global_evdev;
#endif //MASTEROPTIONS_EVDEVDEVICE_H
#endif //EVDEVDEVICE_H

View File

@ -21,6 +21,7 @@
LogLevel global_verbosity = DEBUG;
Configuration* global_config;
EvdevDevice* global_evdev;
DeviceFinder* finder;
int main(int argc, char** argv)
{
@ -36,7 +37,9 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
find_device(); // Scan devices, create listeners, handlers, etc.
// Scan devices, create listeners, handlers, etc.
finder = new DeviceFinder();
finder->run();
return EXIT_SUCCESS;
}

View File

@ -6,7 +6,6 @@
#include <algorithm>
#include "util.h"
#include "Actions.h"
void log_printf(LogLevel level, const char* format, ...)
{

View File

@ -1,5 +1,5 @@
#ifndef MASTEROPTIONS_LOGGER_H
#define MASTEROPTIONS_LOGGER_H
#ifndef UTIL_H
#define UTIL_H
#include "Actions.h"
@ -22,4 +22,4 @@ Direction string_to_direction(std::string s);
GestureMode string_to_gesturemode(std::string s);
Action string_to_action(std::string s);
#endif //MASTEROPTIONS_LOGGER_H
#endif //UTIL_H