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:
pixl
2020-06-21 05:33:33 -04:00
parent b05e525bbc
commit e40da5f0c0
24 changed files with 689 additions and 181 deletions
+125 -60
View File
@@ -32,47 +32,17 @@ Receiver::Receiver(std::string path) :
{
if(!supportsDjReports(raw_device->reportDescriptor()))
throw InvalidReceiver(InvalidReceiver::NoDJReports);
// Pass all HID++ events on DefaultDevice to handleHidppEvent
RawEventHandler hidppRawEventHandler;
hidppRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
{
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long) &&
(report[hidpp::Offset::DeviceIndex] == hidpp::DefaultDevice);
};
hidppRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
{
hidpp::Report _report(report);
this->handleHidppEvent(_report);
};
// Pass all DJ events with device index to handleHidppEvent
RawEventHandler djRawEventHandler;
djRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
{
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long);
};
djRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
{
Report _report(report);
this->handleDjEvent(_report);
};
raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
raw_device->addEventHandler("RECV_DJ", djRawEventHandler);
}
void Receiver::enumerate()
void Receiver::enumerateDj()
{
sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
}
Receiver::notification_flags Receiver::getHidppNotifications()
{
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {});
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {},
hidpp::ReportType::Short);
notification_flags flags{};
flags.device_battery_status = response[0] & (1 << 4);
@@ -89,17 +59,28 @@ void Receiver::enableHidppNotifications(notification_flags flags)
if(flags.device_battery_status)
request[0] |= (1 << 4);
if(flags.receiver_wireless_notifications)
request[1] |= (1 << 0);
request[1] |= 1;
if(flags.receiver_software_present)
request[1] |= (1 << 3);
_hidpp10_device.setRegister(EnableHidppNotifications, request);
_hidpp10_device.setRegister(EnableHidppNotifications, request,
hidpp::ReportType::Short);
}
void Receiver::enumerateHidpp()
{
/* This isn't in the documentation but this is how solaar does it
* All I know is that when (p0 & 2), devices are enumerated
*/
_hidpp10_device.setRegister(ConnectionState, {2},
hidpp::ReportType::Short);
}
///TODO: Investigate usage
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
{
auto response = _hidpp10_device.setRegister(ConnectionState, {index});
auto response = _hidpp10_device.getRegister(ConnectionState, {index},
hidpp::ReportType::Short);
return response[0];
}
@@ -113,7 +94,8 @@ void Receiver::startPairing(uint8_t timeout)
request[1] = hidpp::DefaultDevice;
request[2] = timeout;
_hidpp10_device.setRegister(DevicePairing, request);
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
}
void Receiver::stopPairing()
@@ -124,7 +106,8 @@ void Receiver::stopPairing()
request[0] = 2;
request[1] = hidpp::DefaultDevice;
_hidpp10_device.setRegister(DevicePairing, request);
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
}
void Receiver::disconnect(hidpp::DeviceIndex index)
@@ -135,12 +118,14 @@ void Receiver::disconnect(hidpp::DeviceIndex index)
request[0] = 3;
request[1] = index;
_hidpp10_device.setRegister(DevicePairing, request);
_hidpp10_device.setRegister(DevicePairing, request,
hidpp::ReportType::Short);
}
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
{
auto response = _hidpp10_device.getRegister(DeviceActivity, {});
auto response = _hidpp10_device.getRegister(DeviceActivity, {},
hidpp::ReportType::Long);
std::map<hidpp::DeviceIndex, uint8_t> device_activity;
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
@@ -156,7 +141,8 @@ struct Receiver::PairingInfo
request[0] = index;
request[0] += 0x19;
auto response = _hidpp10_device.getRegister(PairingInfo, request);
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
struct PairingInfo info{};
info.destinationId = response[0];
@@ -175,7 +161,8 @@ struct Receiver::ExtendedPairingInfo
request[0] = index;
request[0] += 0x29;
auto response = _hidpp10_device.getRegister(PairingInfo, request);
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
ExtendedPairingInfo info{};
@@ -197,7 +184,8 @@ std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
request[0] = index;
request[0] += 0x39;
auto response = _hidpp10_device.getRegister(PairingInfo, request);
auto response = _hidpp10_device.getRegister(PairingInfo, request,
hidpp::ReportType::Long);
uint8_t size = response[0];
assert(size <= 14);
@@ -215,12 +203,12 @@ hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(hidpp::Report& report)
return report.deviceIndex();
}
Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(
hidpp::Report &report)
{
assert(report.subId() == DeviceConnection);
DeviceConnectionEvent event{};
hidpp::DeviceConnectionEvent event{};
event.index = report.deviceIndex();
event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
@@ -240,23 +228,54 @@ Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
void Receiver::handleDjEvent(Report& report)
{
if(report.feature() == DeviceConnection ||
report.feature() == DeviceDisconnection ||
report.feature() == ConnectionStatus)
{
printf("%s DJ IN: ", raw_device->hidrawPath().c_str());
for(auto &i: report.rawData())
printf("%02x ", i);
printf("\n");
}
for(auto& handler : dj_event_handlers)
if(handler.second->condition(report))
handler.second->callback(report);
}
void Receiver::handleHidppEvent(hidpp::Report &report)
{
printf("%s HID++ IN: ", raw_device->hidrawPath().c_str());
for(auto &i: report.rawReport())
printf("%02x ", i);
printf("\n");
for(auto& handler : hidpp_event_handlers)
if(handler.second->condition(report))
handler.second->callback(report);
}
void Receiver::addDjEventHandler(const std::string& nickname,
const std::shared_ptr<EventHandler>& handler)
{
auto it = dj_event_handlers.find(nickname);
assert(it == dj_event_handlers.end());
dj_event_handlers.emplace(nickname, handler);
}
void Receiver::removeDjEventHandler(const std::string &nickname)
{
dj_event_handlers.erase(nickname);
}
const std::map<std::string, std::shared_ptr<EventHandler>>&
Receiver::djEventHandlers()
{
return dj_event_handlers;
}
void Receiver::addHidppEventHandler(const std::string& nickname,
const std::shared_ptr<hidpp::EventHandler>& handler)
{
auto it = hidpp_event_handlers.find(nickname);
assert(it == hidpp_event_handlers.end());
hidpp_event_handlers.emplace(nickname, handler);
}
void Receiver::removeHidppEventHandler(const std::string &nickname)
{
hidpp_event_handlers.erase(nickname);
}
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
Receiver::hidppEventHandlers()
{
return hidpp_event_handlers;
}
void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
@@ -276,10 +295,56 @@ void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
void Receiver::listen()
{
std::thread{[=]() { raw_device->listen(); }}.detach();
if(!raw_device->isListening())
std::thread{[=]() { raw_device->listen(); }}.detach();
if(raw_device->eventHandlers().find("RECV_HIDPP") ==
raw_device->eventHandlers().end()) {
// Pass all HID++ events on DefaultDevice to handleHidppEvent
std::shared_ptr<RawEventHandler> hidppRawEventHandler =
std::make_shared<RawEventHandler>();
hidppRawEventHandler->condition = [](std::vector<uint8_t>& report)->bool
{
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long);
};
hidppRawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
{
hidpp::Report _report(report);
this->handleHidppEvent(_report);
};
raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
}
if(raw_device->eventHandlers().find("RECV_DJ") ==
raw_device->eventHandlers().end()) {
// Pass all DJ events with device index to handleHidppEvent
std::shared_ptr<RawEventHandler> djRawEventHandler =
std::make_shared<RawEventHandler>();
djRawEventHandler->condition = [](std::vector<uint8_t>& report)->bool
{
return (report[Offset::Type] == Report::Type::Short ||
report[Offset::Type] == Report::Type::Long);
};
djRawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
{
Report _report(report);
this->handleDjEvent(_report);
};
raw_device->addEventHandler("RECV_DJ", djRawEventHandler);
}
}
void Receiver::stopListening()
{
raw_device->stopListener();
raw_device->removeEventHandler("RECV_HIDPP");
raw_device->removeEventHandler("RECV_DJ");
if(raw_device->eventHandlers().empty())
raw_device->stopListener();
}
std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const
{
return raw_device;
}