Implement receiver HID++ connect/disconnect events
Many changes were made here but that was the biggest one. There's currently a bug where std::system_error: Broken pipe is thrown after launching the daemon with a receiver connector. A workaround for this bug is to simply shake the mouse while starting the daemon. I will investigate this soon.
This commit is contained in:
@@ -24,8 +24,8 @@ using namespace std::chrono;
|
||||
|
||||
bool RawDevice::supportedReportID(uint8_t id)
|
||||
{
|
||||
return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id) ||
|
||||
(dj::ReportType::Short == id) || (dj::ReportType::Long == id);
|
||||
return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id)
|
||||
|| (dj::ReportType::Short == id) || (dj::ReportType::Long == id);
|
||||
}
|
||||
|
||||
RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||
@@ -34,14 +34,16 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||
|
||||
fd = ::open(path.c_str(), O_RDWR);
|
||||
if (fd == -1)
|
||||
throw std::system_error(errno, std::system_category(), "RawDevice open failed");
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"RawDevice open failed");
|
||||
|
||||
hidraw_devinfo devinfo{};
|
||||
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
|
||||
{
|
||||
int err = errno;
|
||||
::close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWINFO failed");
|
||||
throw std::system_error(err, std::system_category(),
|
||||
"RawDevice HIDIOCGRAWINFO failed");
|
||||
}
|
||||
vid = devinfo.vendor;
|
||||
pid = devinfo.product;
|
||||
@@ -51,22 +53,25 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||
{
|
||||
int err = errno;
|
||||
::close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWNAME failed");
|
||||
throw std::system_error(err, std::system_category(),
|
||||
"RawDevice HIDIOCGRAWNAME failed");
|
||||
}
|
||||
name.assign(name_buf, ret - 1);
|
||||
_name.assign(name_buf, ret - 1);
|
||||
|
||||
hidraw_report_descriptor _rdesc{};
|
||||
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
|
||||
{
|
||||
int err = errno;
|
||||
::close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESCSIZE failed");
|
||||
throw std::system_error(err, std::system_category(),
|
||||
"RawDevice HIDIOCGRDESCSIZE failed");
|
||||
}
|
||||
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
|
||||
{
|
||||
int err = errno;
|
||||
::close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESC failed");
|
||||
throw std::system_error(err, std::system_category(),
|
||||
"RawDevice HIDIOCGRDESC failed");
|
||||
}
|
||||
rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
|
||||
|
||||
@@ -74,7 +79,8 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||
{
|
||||
int err = errno;
|
||||
close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice pipe open failed");
|
||||
throw std::system_error(err, std::system_category(),
|
||||
"RawDevice pipe open failed");
|
||||
}
|
||||
|
||||
continue_listen = false;
|
||||
@@ -92,8 +98,6 @@ RawDevice::~RawDevice()
|
||||
|
||||
std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
|
||||
{
|
||||
assert(supportedReportID(report[0]));
|
||||
|
||||
/* If the listener will stop, handle I/O manually.
|
||||
* Otherwise, push to queue and wait for result. */
|
||||
if(continue_listen)
|
||||
@@ -189,11 +193,6 @@ std::vector<uint8_t> RawDevice::_respondToReport
|
||||
|
||||
int RawDevice::_sendReport(const std::vector<uint8_t>& report)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dev_io);
|
||||
int ret = ::write(fd, report.data(), report.size());
|
||||
if(ret == -1)
|
||||
throw std::system_error(errno, std::system_category(), "_sendReport write failed");
|
||||
|
||||
if(logid::global_verbosity == LogLevel::RAWREPORT) {
|
||||
printf("[RAWREPORT] %s OUT: ", path.c_str());
|
||||
for(auto &i : report)
|
||||
@@ -201,6 +200,14 @@ int RawDevice::_sendReport(const std::vector<uint8_t>& report)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
assert(supportedReportID(report[0]));
|
||||
|
||||
std::lock_guard<std::mutex> lock(dev_io);
|
||||
int ret = ::write(fd, report.data(), report.size());
|
||||
if(ret == -1)
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"_sendReport write failed");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -225,13 +232,15 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
|
||||
} while(ret == -1 && errno == EINTR);
|
||||
|
||||
if(ret == -1)
|
||||
throw std::system_error(errno, std::system_category(), "_readReport select failed");
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"_readReport select failed");
|
||||
|
||||
if(FD_ISSET(fd, &fds))
|
||||
{
|
||||
ret = read(fd, report.data(), report.size());
|
||||
if(ret == -1)
|
||||
throw std::system_error(errno, std::system_category(), "_readReport read failed");
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"_readReport read failed");
|
||||
report.resize(ret);
|
||||
}
|
||||
|
||||
@@ -240,7 +249,8 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
|
||||
char c;
|
||||
ret = read(dev_pipe[0], &c, sizeof(char));
|
||||
if(ret == -1)
|
||||
throw std::system_error(errno, std::system_category(), "_readReport read pipe failed");
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"_readReport read pipe failed");
|
||||
}
|
||||
|
||||
if(0 == ret)
|
||||
@@ -260,7 +270,8 @@ void RawDevice::interruptRead()
|
||||
{
|
||||
char c = 0;
|
||||
if(-1 == write(dev_pipe[1], &c, sizeof(char)))
|
||||
throw std::system_error(errno, std::system_category(), "interruptRead write pipe failed");
|
||||
throw std::system_error(errno, std::system_category(),
|
||||
"interruptRead write pipe failed");
|
||||
|
||||
// Ensure I/O has halted
|
||||
std::lock_guard<std::mutex> lock(dev_io);
|
||||
@@ -302,7 +313,8 @@ void RawDevice::stopListener()
|
||||
interruptRead();
|
||||
}
|
||||
|
||||
void RawDevice::addEventHandler(const std::string& nickname, RawEventHandler& handler)
|
||||
void RawDevice::addEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<RawEventHandler>& handler)
|
||||
{
|
||||
auto it = event_handlers.find(nickname);
|
||||
assert(it == event_handlers.end());
|
||||
@@ -314,11 +326,17 @@ void RawDevice::removeEventHandler(const std::string &nickname)
|
||||
event_handlers.erase(nickname);
|
||||
}
|
||||
|
||||
const std::map<std::string, std::shared_ptr<RawEventHandler>>&
|
||||
RawDevice::eventHandlers()
|
||||
{
|
||||
return event_handlers;
|
||||
}
|
||||
|
||||
void RawDevice::handleEvent(std::vector<uint8_t> &report)
|
||||
{
|
||||
for(auto& handler : event_handlers)
|
||||
if(handler.second.condition(report))
|
||||
handler.second.callback(report);
|
||||
if(handler.second->condition(report))
|
||||
handler.second->callback(report);
|
||||
}
|
||||
|
||||
bool RawDevice::isListening()
|
||||
@@ -328,5 +346,5 @@ bool RawDevice::isListening()
|
||||
if(ret)
|
||||
listening.unlock();
|
||||
|
||||
return ret;
|
||||
return !ret;
|
||||
}
|
||||
|
@@ -23,9 +23,14 @@ namespace raw
|
||||
public:
|
||||
static bool supportedReportID(uint8_t id);
|
||||
|
||||
RawDevice(std::string path);
|
||||
explicit RawDevice(std::string path);
|
||||
~RawDevice();
|
||||
std::string hidrawPath() const { return path; }
|
||||
|
||||
std::string name() const { return _name; }
|
||||
uint16_t vendorId() const { return vid; }
|
||||
uint16_t productId() const { return pid; }
|
||||
|
||||
std::vector<uint8_t> reportDescriptor() const { return rdesc; }
|
||||
|
||||
std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
|
||||
@@ -36,8 +41,11 @@ namespace raw
|
||||
void stopListener();
|
||||
bool isListening();
|
||||
|
||||
void addEventHandler(const std::string& nickname, RawEventHandler& handler);
|
||||
void addEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<backend::RawEventHandler>& handler);
|
||||
void removeEventHandler(const std::string& nickname);
|
||||
const std::map<std::string, std::shared_ptr<backend::RawEventHandler>>&
|
||||
eventHandlers();
|
||||
|
||||
private:
|
||||
std::mutex dev_io, listening;
|
||||
@@ -46,12 +54,13 @@ namespace raw
|
||||
int dev_pipe[2];
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
std::string name;
|
||||
std::string _name;
|
||||
std::vector<uint8_t> rdesc;
|
||||
|
||||
std::atomic<bool> continue_listen;
|
||||
|
||||
std::map<std::string, backend::RawEventHandler> event_handlers;
|
||||
std::map<std::string, std::shared_ptr<backend::RawEventHandler>>
|
||||
event_handlers;
|
||||
void handleEvent(std::vector<uint8_t>& report);
|
||||
|
||||
/* These will only be used internally and processed with a queue */
|
||||
|
Reference in New Issue
Block a user