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; on: true;
threshold: 30; threshold: 30;
}; };
hiresscroll: true; hiresscroll:
{
hires: true;
invert: false;
target: false;
};
dpi: 1000; dpi: 1000;
buttons: ( buttons: (

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include <libevdev/libevdev.h> #include <libevdev/libevdev.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <hidpp20/IHiresScroll.h>
#include "Configuration.h" #include "Configuration.h"
#include "util.h" #include "util.h"
@ -77,12 +78,50 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
log_printf(WARN, "Line %d: DPI must me an integer; not setting.", root["dpi"].getSourceLine()); log_printf(WARN, "Line %d: DPI must me an integer; not setting.", root["dpi"].getSourceLine());
} }
try
{
const Setting& hr = root["hiresscroll"];
uint8_t hss = 0;
try try
{ {
bool b; bool b;
if(!root.lookupValue("hiresscroll", b)) if(!hr.lookupValue("hires", b))
throw SettingTypeException(root["hiresscroll"]); throw SettingTypeException(root["hires"]);
hiresscroll = new bool(b); 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) catch(const SettingNotFoundException &e)
{ {
@ -90,18 +129,18 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
} }
catch(const SettingTypeException &e) 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 try
{ {
const Setting& ss = root["smartshift"]; const Setting& ss = root["smartshift"];
smartshift = new smartshift_options; smartshift = new HIDPP20::ISmartShift::SmartshiftStatus {};
bool on; bool on;
int threshold; int threshold;
try 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()); else log_printf(WARN, "Line %d: on field must be a boolean", ss["on"].getSourceLine());
} }
catch(const SettingNotFoundException &e) { } catch(const SettingNotFoundException &e) { }
@ -113,26 +152,24 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root)
if(threshold < 0) if(threshold < 0)
{ {
threshold = 1; 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) if(threshold >= 100)
{ {
threshold = 99; threshold = 99;
log_printf(INFO, "Smartshift threshold must be > 0 or < 100, setting to 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()); else log_printf(WARN, "Line %d: threshold must be an integer", ss["threshold"].getSourceLine());
} }
catch(const SettingNotFoundException &e) 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) 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; Setting* buttons;

View File

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

View File

@ -6,21 +6,23 @@
#include <hidpp20/IFeatureSet.h> #include <hidpp20/IFeatureSet.h>
#include <hidpp20/Error.h> #include <hidpp20/Error.h>
#include <hidpp20/IReprogControls.h> #include <hidpp20/IReprogControls.h>
#include <hidpp20/ISmartShift.h>
#include <hidpp20/Device.h> #include <hidpp20/Device.h>
#include <hidpp10/Error.h> #include <hidpp10/Error.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <utility>
#include <hidpp20/UnsupportedFeature.h> #include <hidpp20/UnsupportedFeature.h>
#include <hidpp20/IHiresScroll.h>
#include "Device.h" #include "Device.h"
#include "Actions.h"
#include "Configuration.h"
#include "util.h" #include "util.h"
#include "EvdevDevice.h" #include "EvdevDevice.h"
using namespace std::chrono_literals; 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 // Initialise variables
DeviceRemoved = false; DeviceRemoved = false;
@ -74,39 +76,42 @@ void Device::divert_buttons(bool scanning)
} }
catch(HIDPP20::UnsupportedFeature &e) 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; try
parameters.push_back(ops.on == nullptr ? 0 : (*ops.on)? 2 : 1);
if(ops.threshold != nullptr)
{ {
parameters.push_back(*ops.threshold); HIDPP20::ISmartShift ss(hidpp_dev);
parameters.push_back(*ops.threshold); ss.setStatus(ops);
} }
catch (HIDPP20::UnsupportedFeature &e)
if(features.find(0x2110) == features.end())
{ {
log_printf(DEBUG, "Error toggling smart shift, feature is non-existent."); log_printf(ERROR, "Device does not support SmartShift");
return;
} }
const uint8_t f_index = features.find(0x2110)->second;
try { hidpp_dev->callFunction(f_index, 0x01, parameters); }
catch (HIDPP20::Error &e) catch (HIDPP20::Error &e)
{ {
if(scanning) log_printf(ERROR, "Error setting SmartShift options, code %d: %s\n", e.errorCode(), e.what());
throw e;
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) void Device::set_dpi(int dpi, bool scanning)
@ -128,49 +133,11 @@ void Device::start()
auto *d = new HIDPP::SimpleDispatcher(path.c_str()); auto *d = new HIDPP::SimpleDispatcher(path.c_str());
listener = new SimpleListener(d, index); listener = new SimpleListener(d, index);
listener->addEventHandler( std::make_unique<ButtonHandler>(hidpp_dev, this) ); listener->addEventHandler( std::make_unique<ButtonHandler>(hidpp_dev, this) );
auto listener_thread = std::thread { [=]() { listener->start(); } }; listener->addEventHandler( std::make_unique<ReceiverHandler>(this) );
listener_thread.detach(); listener->start();
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();
} }
void Device::ButtonHandler::handleEvent (const HIDPP::Report &event) void ButtonHandler::handleEvent (const HIDPP::Report &event)
{ {
switch (event.function()) 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>::iterator it;
std::vector<uint16_t> cids(states.size() + new_states.size()); 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()); 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) for (uint16_t i : cids)
{ {
if (std::find(new_states.begin(), new_states.end(), i) != new_states.end()) 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(); std::thread{[=]() { dev->move_diverted(i, raw_xy); }}.detach();
break; 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) for (const auto &p: iterators)
dispatcher->unregisterEventHandler(p.second); dispatcher->unregisterEventHandler(p.second);
@ -219,35 +230,37 @@ void Device::EventListener::removeEventHandlers ()
iterators.clear(); iterators.clear();
} }
Device::EventListener::~EventListener() EventListener::~EventListener()
{ {
removeEventHandlers(); 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(); EventHandler *ptr = handler.get();
for(uint8_t feature : handler->featureIndices())
{
handlers.emplace(feature, std::move(handler)); handlers.emplace(feature, std::move(handler));
dispatcher->registerEventHandler(index, feature, [ptr](const HIDPP::Report &report) dispatcher->registerEventHandler(index, feature, [=](const HIDPP::Report &report)
{ {
ptr->handleEvent(report); ptr->handleEvent(report);
return true; return true;
}); });
}
} }
void Device::SimpleListener::start() void SimpleListener::start()
{ {
try { dispatcher->listen(); } try { dispatcher->listen(); }
catch(std::system_error &e) { } catch(std::system_error &e) { }
} }
void Device::SimpleListener::stop() void SimpleListener::stop()
{ {
dispatcher->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); handler->handleEvent (report);
return true; return true;
@ -255,7 +268,7 @@ bool Device::SimpleListener::event (EventHandler *handler, const HIDPP::Report &
void Device::stop() void Device::stop()
{ {
DeviceRemoved = true; listener->stop();
} }
void Device::press_button(uint16_t cid) 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; std::map<uint16_t, uint8_t> features;
HIDPP20::IFeatureSet ifs (hidpp_dev); HIDPP20::IFeatureSet ifs (hidpp_dev);
unsigned int feature_count = ifs.getCount(); 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; return features;
} }

View File

@ -1,13 +1,18 @@
#ifndef LOGIOPS_DEVICE_H #ifndef DEVICE_H
#define LOGIOPS_DEVICE_H #define DEVICE_H
#include "Actions.h"
#include "DeviceFinder.h"
#include "Configuration.h"
#include <map> #include <map>
#include <memory> #include <memory>
#include <hidpp/Dispatcher.h> #include <hidpp/Dispatcher.h>
#include <hidpp/SimpleDispatcher.h> #include <hidpp/SimpleDispatcher.h>
#include <hidpp10/IReceiver.h>
#include "Actions.h" class EventListener;
#include "Configuration.h" class DeviceConfig;
class Device class Device
{ {
@ -29,40 +34,70 @@ public:
std::map<uint16_t, uint8_t> features; std::map<uint16_t, uint8_t> features;
std::string path; const std::string path;
const HIDPP::DeviceIndex index; const HIDPP::DeviceIndex index;
HIDPP::Dispatcher* dispatcher; HIDPP::Dispatcher* dispatcher;
HIDPP20::Device* hidpp_dev; HIDPP20::Device* hidpp_dev;
class EventHandler protected:
{ DeviceConfig* config;
public: bool DeviceRemoved;
EventListener* listener;
void divert_buttons(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 HIDPP20::FeatureInterface *feature() const = 0;
virtual void handleEvent (const HIDPP::Report &event) = 0; virtual const std::vector<uint8_t> featureIndices() const
};
class ButtonHandler : public EventHandler
{ {
public: 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) { } ButtonHandler (HIDPP20::Device *hidppdev, Device *d) : _irc (HIDPP20::IReprogControls::auto_version(hidppdev)), dev (d) { }
const HIDPP20::FeatureInterface *feature () const const HIDPP20::FeatureInterface *feature () const
{ {
return &_irc; return &_irc;
} }
void handleEvent (const HIDPP::Report &event); void handleEvent (const HIDPP::Report &event);
protected: protected:
HIDPP20::IReprogControls _irc; HIDPP20::IReprogControls _irc;
Device* dev; Device* dev;
std::vector<uint16_t> states; std::vector<uint16_t> states;
std::vector<uint16_t> new_states; std::vector<uint16_t> new_states;
}; };
class ReceiverHandler : public EventHandler
class EventListener {
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;
};
class EventListener
{
HIDPP::Dispatcher *dispatcher; HIDPP::Dispatcher *dispatcher;
HIDPP::DeviceIndex index; HIDPP::DeviceIndex index;
std::map<uint8_t, std::unique_ptr<EventHandler>> handlers; std::map<uint8_t, std::unique_ptr<EventHandler>> handlers;
std::map<uint8_t, HIDPP::Dispatcher::listener_iterator> iterators; std::map<uint8_t, HIDPP::Dispatcher::listener_iterator> iterators;
public: public:
EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): dispatcher (dispatcher), index (index) {} EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): dispatcher (dispatcher), index (index) {}
virtual void removeEventHandlers (); virtual void removeEventHandlers ();
@ -72,14 +107,14 @@ public:
virtual void start () = 0; virtual void start () = 0;
virtual void stop () = 0; virtual void stop () = 0;
protected: protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report) = 0; virtual bool event (EventHandler* handler, const HIDPP::Report &report) = 0;
}; };
class SimpleListener : public EventListener class SimpleListener : public EventListener
{ {
HIDPP::SimpleDispatcher *dispatcher; HIDPP::SimpleDispatcher *dispatcher;
public: public:
SimpleListener (HIDPP::SimpleDispatcher* dispatcher, HIDPP::DeviceIndex index): SimpleListener (HIDPP::SimpleDispatcher* dispatcher, HIDPP::DeviceIndex index):
EventListener (dispatcher, index), EventListener (dispatcher, index),
dispatcher (dispatcher) dispatcher (dispatcher)
@ -89,20 +124,8 @@ public:
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
protected:
virtual bool event (EventHandler* handler, const HIDPP::Report &report);
};
protected: protected:
DeviceConfig* config; virtual bool event (EventHandler* handler, const HIDPP::Report &report);
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_dpi(int dpi, bool scanning=false);
}; };
#endif //DEVICE_H
#endif //LOGIOPS_DEVICE_H

View File

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

View File

@ -1,18 +1,39 @@
#ifndef MASTEROPTIONS_DEVICEFINDER_H #ifndef DEVICEFINDER_H
#define MASTEROPTIONS_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" #include "Device.h"
struct handler_pair; class Device;
class DeviceFinder : public HID::DeviceMonitor 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: protected:
void addDevice(const char* path); void addDevice(const char* path);
void removeDevice(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 #ifndef EVDEVDEVICE_H
#define MASTEROPTIONS_EVDEVDEVICE_H #define EVDEVDEVICE_H
#include <libevdev/libevdev.h> #include <libevdev/libevdev.h>
#include <libevdev/libevdev-uinput.h> #include <libevdev/libevdev-uinput.h>
@ -16,4 +16,4 @@ public:
extern EvdevDevice* global_evdev; extern EvdevDevice* global_evdev;
#endif //MASTEROPTIONS_EVDEVDEVICE_H #endif //EVDEVDEVICE_H

View File

@ -21,6 +21,7 @@
LogLevel global_verbosity = DEBUG; LogLevel global_verbosity = DEBUG;
Configuration* global_config; Configuration* global_config;
EvdevDevice* global_evdev; EvdevDevice* global_evdev;
DeviceFinder* finder;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
@ -36,7 +37,9 @@ int main(int argc, char** argv)
return EXIT_FAILURE; 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; return EXIT_SUCCESS;
} }

View File

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

View File

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