Use events instead of continous pinging
This commit is contained in:
parent
684f502b2e
commit
b95cc60fd1
|
@ -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: (
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
@ -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();
|
void ButtonHandler::handleEvent (const HIDPP::Report &event)
|
||||||
listener_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::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;
|
||||||
}
|
}
|
|
@ -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,15 +34,30 @@ 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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DeviceConfig* config;
|
||||||
|
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
|
class EventHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual const HIDPP20::FeatureInterface *feature() const = 0;
|
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;
|
virtual void handleEvent (const HIDPP::Report &event) = 0;
|
||||||
};
|
};
|
||||||
class ButtonHandler : public EventHandler
|
class ButtonHandler : public EventHandler
|
||||||
|
@ -55,6 +75,21 @@ public:
|
||||||
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
|
||||||
|
{
|
||||||
|
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
|
class EventListener
|
||||||
{
|
{
|
||||||
|
@ -93,16 +128,4 @@ public:
|
||||||
virtual bool event (EventHandler* handler, const HIDPP::Report &report);
|
virtual bool event (EventHandler* handler, const HIDPP::Report &report);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
#endif //DEVICE_H
|
||||||
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_dpi(int dpi, bool scanning=false);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //LOGIOPS_DEVICE_H
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue
Block a user