Use events instead of continous pinging
This commit is contained in:
parent
684f502b2e
commit
b95cc60fd1
|
@ -6,7 +6,12 @@ devices: (
|
|||
on: true;
|
||||
threshold: 30;
|
||||
};
|
||||
hiresscroll: true;
|
||||
hiresscroll:
|
||||
{
|
||||
hires: true;
|
||||
invert: false;
|
||||
target: false;
|
||||
};
|
||||
dpi: 1000;
|
||||
|
||||
buttons: (
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "util.h"
|
||||
#include "Actions.h"
|
||||
|
||||
void log_printf(LogLevel level, const char* format, ...)
|
||||
{
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue
Block a user