From 3129cda5812d0d91b1f3d0e6e23bca03a08156ef Mon Sep 17 00:00:00 2001 From: pixl Date: Thu, 2 Jul 2020 16:57:38 -0400 Subject: [PATCH] Add hidpp20 ReprogControls support --- src/logid/CMakeLists.txt | 1 + .../hidpp20/features/ReprogControls.cpp | 133 +++++++++++++++ .../backend/hidpp20/features/ReprogControls.h | 158 ++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 src/logid/backend/hidpp20/features/ReprogControls.cpp create mode 100644 src/logid/backend/hidpp20/features/ReprogControls.h diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index aa9570d..a1904c3 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -37,6 +37,7 @@ add_executable(logid backend/hidpp20/features/Reset.cpp backend/hidpp20/features/AdjustableDPI.cpp backend/hidpp20/features/SmartShift.cpp + backend/hidpp20/features/ReprogControls.cpp backend/dj/Report.cpp util/mutex_queue.h util/thread.cpp diff --git a/src/logid/backend/hidpp20/features/ReprogControls.cpp b/src/logid/backend/hidpp20/features/ReprogControls.cpp new file mode 100644 index 0000000..d9835bd --- /dev/null +++ b/src/logid/backend/hidpp20/features/ReprogControls.cpp @@ -0,0 +1,133 @@ +/* + * Copyright 2019-2020 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include +#include "ReprogControls.h" + +using namespace logid::backend::hidpp20; + +#define DEFINE_REPROG(x, base) \ +x::x(Device* dev) : base(dev, ID) \ +{ \ +} \ +x::x(Device* dev, uint16_t _id) : base(dev, _id) \ +{ \ +} + +#define MAKE_REPROG(x, dev) \ +try { \ + return x(dev); \ +} catch(UnsupportedFeature &e) {\ +} + +// Define all of the ReprogControls versions +DEFINE_REPROG(ReprogControls, Feature); +DEFINE_REPROG(ReprogControlsV2, ReprogControls); +DEFINE_REPROG(ReprogControlsV2_2, ReprogControlsV2); +DEFINE_REPROG(ReprogControlsV3, ReprogControlsV2_2); +DEFINE_REPROG(ReprogControlsV4, ReprogControlsV3); + +ReprogControls ReprogControls::autoVersion(Device *dev) +{ + MAKE_REPROG(ReprogControlsV4, dev); + MAKE_REPROG(ReprogControlsV3, dev); + MAKE_REPROG(ReprogControlsV2_2, dev); + MAKE_REPROG(ReprogControlsV2, dev); + + // If base version cannot be made, throw error + return ReprogControls(dev); +} + +uint8_t ReprogControls::getControlCount() +{ + std::vector params(0); + auto response = callFunction(GetControlCount, params); + return response[0]; +} + +ReprogControls::ControlInfo ReprogControls::getControlInfo(uint8_t index) +{ + std::vector params(1); + ControlInfo info{}; + params[0] = index; + auto response = callFunction(GetControlInfo, params); + + info.controlID = response[1]; + info.controlID |= response[0] << 8; + info.taskID = response[3]; + info.taskID |= response[2] << 8; + info.flags = response[4]; + info.position = response[5]; + info.group = response[6]; + info.groupMask = response[7]; + info.additionalFlags = response[8]; + return info; +} + +ReprogControls::ControlInfo ReprogControls::getControlReporting(uint16_t cid) +{ + std::vector params(2); + ControlInfo info{}; + params[0] = (cid >> 8) & 0xff; + params[1] = cid & 0xff; + auto response = callFunction(GetControlReporting, params); + + info.controlID = response[1]; + info.controlID |= response[0] << 8; + info.flags = response[2]; + return info; +} + +void ReprogControls::setControlReporting(uint8_t cid, ControlInfo info) +{ + std::vector params(5); + params[0] = (cid >> 8) & 0xff; + params[1] = cid & 0xff; + params[2] = info.flags; + params[3] = (info.controlID >> 8) & 0xff; + params[4] = info.controlID & 0xff; + callFunction(SetControlReporting, params); +} + +std::set ReprogControls::divertedButtonEvent( + const hidpp::Report& report) +{ + assert(report.function() == DivertedButtonEvent); + std::set buttons; + uint8_t cids = std::distance(report.paramBegin(), report.paramEnd())/2; + for(uint8_t i = 0; i < cids; i++) { + uint16_t cid = report.paramBegin()[2*i + 1]; + cid |= report.paramBegin()[2*i] << 8; + if(cid) + buttons.insert(cid); + else + break; + } + return buttons; +} + +ReprogControls::Move ReprogControls::divertedRawXYEvent(const hidpp::Report + &report) +{ + assert(report.function() == DivertedRawXYEvent); + Move move{}; + move.x = report.paramBegin()[1]; + move.x |= report.paramBegin()[0] << 8; + move.y = report.paramBegin()[3]; + move.y |= report.paramBegin()[2] << 8; + return move; +} diff --git a/src/logid/backend/hidpp20/features/ReprogControls.h b/src/logid/backend/hidpp20/features/ReprogControls.h new file mode 100644 index 0000000..3197040 --- /dev/null +++ b/src/logid/backend/hidpp20/features/ReprogControls.h @@ -0,0 +1,158 @@ +/* + * Copyright 2019-2020 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_BACKEND_HIDPP20_FEATURE_REPROGCONTROLS_H +#define LOGID_BACKEND_HIDPP20_FEATURE_REPROGCONTROLS_H + +#include "../feature_defs.h" +#include "../Feature.h" + +namespace logid { +namespace backend { +namespace hidpp20 +{ + class ReprogControls : public Feature + { + public: + static const uint16_t ID = FeatureID::REPROG_CONTROLS; + virtual uint16_t getID() { return ID; } + + virtual bool supportsRawXY() { return false; } + + enum Function { + GetControlCount = 0, + GetControlInfo = 1, + GetControlReporting = 2, + SetControlReporting = 3 + }; + + enum Event { + DivertedButtonEvent = 0, + DivertedRawXYEvent = 1 + }; + + explicit ReprogControls(Device* dev); + + virtual uint8_t getControlCount(); + + struct ControlInfo + { + uint16_t controlID; + uint16_t taskID; + uint8_t flags; + uint8_t position; // F key position, 0 if not an Fx key + uint8_t group; + uint8_t groupMask; + uint8_t additionalFlags; + }; + + enum ControlInfoFlags: uint8_t + { + MouseButton = 1, //Mouse button + FKey = 1<<1, //Fx key + Hotkey = 1<<2, + FnToggle = 1<<3, + ReprogHint = 1<<4, + TemporaryDivertable = 1<<5, + PerisentlyDiverable = 1<<6, + Virtual = 1<<7 + }; + enum ControlInfoAdditionalFlags: uint8_t { + RawXY = 1<<0 + }; + + virtual ControlInfo getControlInfo(uint8_t index); + + enum ControlReportingFlags: uint8_t { + TemporaryDiverted = 1<<0, + ChangeTemporaryDivert = 1<<1, + PersistentDiverted = 1<<2, + ChangePersistentDivert = 1<<3, + RawXYDiverted = 1<<4, + ChangeRawXYDivert = 1<<5 + }; + + // Onlu controlId and flags will be set + virtual ControlInfo getControlReporting(uint16_t cid); + + // Only controlId (for remap) and flags will be read + virtual void setControlReporting(uint8_t cid, ControlInfo info); + + static std::set divertedButtonEvent(const hidpp::Report& + report); + + struct Move + { + int16_t x; + int16_t y; + }; + + static Move divertedRawXYEvent(const hidpp::Report& report); + + static ReprogControls autoVersion(Device *dev); + protected: + ReprogControls(Device* dev, uint16_t _id); + }; + + class ReprogControlsV2 : public ReprogControls + { + public: + static const uint16_t ID = FeatureID::REPROG_CONTROLS_V2; + uint16_t getID() override { return ID; } + + explicit ReprogControlsV2(Device* dev); + protected: + ReprogControlsV2(Device* dev, uint16_t _id); + }; + + class ReprogControlsV2_2 : public ReprogControlsV2 + { + public: + static const uint16_t ID = FeatureID::REPROG_CONTROLS_V2_2; + uint16_t getID() override { return ID; } + + explicit ReprogControlsV2_2(Device* dev); + protected: + ReprogControlsV2_2(Device* dev, uint16_t _id); + }; + + class ReprogControlsV3 : public ReprogControlsV2_2 + { + public: + static const uint16_t ID = FeatureID::REPROG_CONTROLS_V3; + uint16_t getID() override { return ID; } + + explicit ReprogControlsV3(Device* dev); + protected: + ReprogControlsV3(Device* dev, uint16_t _id); + }; + + class ReprogControlsV4 : public ReprogControlsV3 + { + public: + static const uint16_t ID = FeatureID::REPROG_CONTROLS_V4; + uint16_t getID() override { return ID; } + + bool supportsRawXY() override { return true; } + + explicit ReprogControlsV4(Device* dev); + protected: + ReprogControlsV4(Device* dev, uint16_t _id); + }; +}}} + +#endif //LOGID_BACKEND_HIDPP20_FEATURE_REPROGCONTROLS_H