mirror of
https://github.com/PixlOne/logiops.git
synced 2025-07-13 21:02:43 +08:00
Merge pull request #261 from leios76/master
support smartshift(0x2111) on mx anywhere3
This commit is contained in:
commit
3fb18a7d5f
@ -5,6 +5,7 @@ devices: (
|
||||
{
|
||||
on: true;
|
||||
threshold: 30;
|
||||
torque: 50;
|
||||
};
|
||||
hiresscroll:
|
||||
{
|
||||
|
@ -74,6 +74,7 @@ namespace logid::backend::hidpp20 {
|
||||
POINTER_AXES_ORIENTATION = 0x2006,
|
||||
VERTICAL_SCROLLING = 0x2100,
|
||||
SMART_SHIFT = 0x2110,
|
||||
SMART_SHIFT_V2 = 0x2111,
|
||||
HIRES_SCROLLING = 0x2120,
|
||||
HIRES_SCROLLING_V2 = 0x2121, // Referred to as Hi-res wheel in cvuchener/hidpp, seems to be V2?
|
||||
LORES_SCROLLING = 0x2130,
|
||||
|
@ -19,26 +19,107 @@
|
||||
|
||||
using namespace logid::backend::hidpp20;
|
||||
|
||||
SmartShift::SmartShift(Device* dev) : Feature(dev, ID) {
|
||||
SmartShift::SmartShift(Device* dev) : SmartShift(dev, ID) {
|
||||
}
|
||||
|
||||
SmartShift::SmartshiftStatus SmartShift::getStatus() {
|
||||
SmartShift::SmartShift(Device* dev, uint16_t feature_id) :
|
||||
Feature(dev, feature_id) {
|
||||
}
|
||||
|
||||
SmartShiftV2::SmartShiftV2(Device* dev) : SmartShift(dev, ID) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<T> make_smartshift(Device* dev) {
|
||||
try {
|
||||
return std::make_shared<T>(dev);
|
||||
} catch (UnsupportedFeature& e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SmartShift> SmartShift::autoVersion(Device* dev) {
|
||||
if (auto v2 = make_smartshift<SmartShiftV2>(dev))
|
||||
return v2;
|
||||
|
||||
return std::make_shared<SmartShift>(dev);
|
||||
}
|
||||
|
||||
SmartShift::Status SmartShift::getStatus() {
|
||||
std::vector<uint8_t> params(0);
|
||||
SmartshiftStatus status{};
|
||||
|
||||
auto response = callFunction(GetStatus, params);
|
||||
status.active = response[0] - 1;
|
||||
status.autoDisengage = response[1];
|
||||
status.defaultAutoDisengage = response[2];
|
||||
return status;
|
||||
|
||||
return {
|
||||
.active = static_cast<bool>(response[0] - 1),
|
||||
.autoDisengage = response[1],
|
||||
.torque = 0,
|
||||
.setActive = false,
|
||||
.setAutoDisengage = false,
|
||||
.setTorque = false
|
||||
};
|
||||
}
|
||||
|
||||
void SmartShift::setStatus(SmartshiftStatus status) {
|
||||
SmartShift::Defaults SmartShift::getDefaults() {
|
||||
std::vector<uint8_t> params(0);
|
||||
|
||||
auto response = callFunction(GetStatus, params);
|
||||
|
||||
return {
|
||||
.autoDisengage = response[2],
|
||||
.torque = 0,
|
||||
.maxForce = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void SmartShift::setStatus(Status status) {
|
||||
std::vector<uint8_t> params(3);
|
||||
if (status.setActive)
|
||||
params[0] = status.active + 1;
|
||||
if (status.setAutoDisengage)
|
||||
params[1] = status.autoDisengage;
|
||||
if (status.setDefaultAutoDisengage)
|
||||
params[2] = status.defaultAutoDisengage;
|
||||
callFunction(SetStatus, params);
|
||||
}
|
||||
|
||||
SmartShift::Defaults SmartShiftV2::getDefaults() {
|
||||
std::vector<uint8_t> params(0);
|
||||
auto response = callFunction(GetCapabilities, params);
|
||||
|
||||
return {
|
||||
.autoDisengage = response[1],
|
||||
.torque = response[2],
|
||||
.maxForce = response[3],
|
||||
};
|
||||
}
|
||||
|
||||
SmartShift::Status SmartShiftV2::getStatus() {
|
||||
std::vector<uint8_t> params(0);
|
||||
auto response = callFunction(GetStatus, params);
|
||||
|
||||
return {
|
||||
.active = static_cast<bool>(response[0] - 1),
|
||||
.autoDisengage = response[1],
|
||||
.torque = response[2],
|
||||
.setActive = false, .setAutoDisengage = false, .setTorque = false,
|
||||
};
|
||||
}
|
||||
|
||||
void SmartShiftV2::setStatus(Status status) {
|
||||
std::vector<uint8_t> params(3);
|
||||
if (status.setActive)
|
||||
params[0] = status.active + 1;
|
||||
if (status.setAutoDisengage)
|
||||
params[1] = status.autoDisengage;
|
||||
if (status.setTorque)
|
||||
params[2] = status.torque;
|
||||
|
||||
callFunction(SetStatus, params);
|
||||
}
|
||||
|
||||
bool SmartShiftV2::supportsTorque() {
|
||||
std::vector<uint8_t> params(0);
|
||||
auto response = callFunction(GetCapabilities, params);
|
||||
|
||||
return static_cast<bool>(response[0] & 1);
|
||||
}
|
||||
|
||||
|
@ -20,13 +20,14 @@
|
||||
|
||||
#include <backend/hidpp20/feature_defs.h>
|
||||
#include <backend/hidpp20/Feature.h>
|
||||
#include <memory>
|
||||
|
||||
namespace logid::backend::hidpp20 {
|
||||
class SmartShift : public Feature {
|
||||
public:
|
||||
static const uint16_t ID = FeatureID::SMART_SHIFT;
|
||||
|
||||
uint16_t getID() final { return ID; }
|
||||
uint16_t getID() override { return ID; }
|
||||
|
||||
enum Function {
|
||||
GetStatus = 0,
|
||||
@ -35,16 +36,54 @@ namespace logid::backend::hidpp20 {
|
||||
|
||||
explicit SmartShift(Device* dev);
|
||||
|
||||
struct SmartshiftStatus {
|
||||
bool active;
|
||||
struct Defaults {
|
||||
uint8_t autoDisengage;
|
||||
uint8_t defaultAutoDisengage;
|
||||
bool setActive, setAutoDisengage, setDefaultAutoDisengage;
|
||||
uint8_t torque;
|
||||
uint8_t maxForce;
|
||||
};
|
||||
|
||||
SmartshiftStatus getStatus();
|
||||
struct Status {
|
||||
bool active;
|
||||
uint8_t autoDisengage;
|
||||
uint8_t torque;
|
||||
bool setActive, setAutoDisengage, setTorque;
|
||||
};
|
||||
|
||||
void setStatus(SmartshiftStatus status);
|
||||
[[nodiscard]] virtual bool supportsTorque() { return false; }
|
||||
|
||||
[[nodiscard]] virtual Defaults getDefaults();
|
||||
|
||||
[[nodiscard]] virtual Status getStatus();
|
||||
|
||||
virtual void setStatus(Status status);
|
||||
|
||||
[[nodiscard]] static std::shared_ptr<SmartShift> autoVersion(Device* dev);
|
||||
|
||||
protected:
|
||||
SmartShift(Device* dev, uint16_t feature_id);
|
||||
};
|
||||
|
||||
class SmartShiftV2 : public SmartShift
|
||||
{
|
||||
public:
|
||||
static const uint16_t ID = FeatureID::SMART_SHIFT_V2;
|
||||
uint16_t getID() final { return ID; }
|
||||
|
||||
enum Function {
|
||||
GetCapabilities = 0,
|
||||
GetStatus = 1,
|
||||
SetStatus = 2
|
||||
};
|
||||
|
||||
explicit SmartShiftV2(Device* dev);
|
||||
|
||||
[[nodiscard]] bool supportsTorque() final;
|
||||
|
||||
[[nodiscard]] Defaults getDefaults() final;
|
||||
|
||||
[[nodiscard]] Status getStatus() final;
|
||||
|
||||
void setStatus(Status status) final;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -249,9 +249,10 @@ namespace logid::config {
|
||||
struct SmartShift : public group {
|
||||
std::optional<bool> on;
|
||||
std::optional<unsigned int> threshold;
|
||||
std::optional<unsigned int> torque;
|
||||
|
||||
SmartShift() : group({"on", "threshold"},
|
||||
&SmartShift::on, &SmartShift::threshold) {}
|
||||
SmartShift() : group({"on", "threshold", "torque"},
|
||||
&SmartShift::on, &SmartShift::threshold, &SmartShift::torque) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,11 +25,35 @@ using namespace logid::backend;
|
||||
SmartShift::SmartShift(Device* device) : DeviceFeature(device),
|
||||
_config(device->activeProfile().smartshift) {
|
||||
try {
|
||||
_smartshift = std::make_shared<hidpp20::SmartShift>(&device->hidpp20());
|
||||
_smartshift = hidpp20::SmartShift::autoVersion(&device->hidpp20());
|
||||
} catch (hidpp20::UnsupportedFeature& e) {
|
||||
throw UnsupportedFeature();
|
||||
}
|
||||
|
||||
_torque_support = _smartshift->supportsTorque();
|
||||
_defaults = _smartshift->getDefaults();
|
||||
|
||||
if (_config.get().has_value()) {
|
||||
auto& config = _config.get().value();
|
||||
|
||||
if (config.threshold.has_value()) {
|
||||
auto& threshold = config.threshold.value();
|
||||
|
||||
/* 0 means no change, clip to 1. */
|
||||
if (threshold == 0)
|
||||
threshold = 1;
|
||||
}
|
||||
|
||||
if (config.torque.has_value()) {
|
||||
auto& torque = config.torque.value();
|
||||
/* torque is a percentage, clip between 1-100 */
|
||||
if (torque == 0)
|
||||
torque = 1;
|
||||
else if (torque > 100)
|
||||
torque = 100;
|
||||
}
|
||||
}
|
||||
|
||||
_ipc_interface = _device->ipcNode()->make_interface<IPC>(this);
|
||||
}
|
||||
|
||||
@ -45,6 +69,9 @@ void SmartShift::configure() {
|
||||
settings.setAutoDisengage = conf.threshold.has_value();
|
||||
if (settings.setAutoDisengage)
|
||||
settings.autoDisengage = conf.threshold.value();
|
||||
settings.setTorque = conf.torque.has_value();
|
||||
if (settings.setTorque)
|
||||
settings.torque = conf.torque.value();
|
||||
|
||||
_smartshift->setStatus(settings);
|
||||
}
|
||||
@ -66,86 +93,108 @@ void SmartShift::setStatus(Status status) {
|
||||
_smartshift->setStatus(status);
|
||||
}
|
||||
|
||||
const hidpp20::SmartShift::Defaults& SmartShift::getDefaults() const {
|
||||
return _defaults;
|
||||
}
|
||||
|
||||
bool SmartShift::supportsTorque() const {
|
||||
return _torque_support;
|
||||
}
|
||||
|
||||
SmartShift::IPC::IPC(SmartShift* parent) :
|
||||
ipcgull::interface(
|
||||
SERVICE_ROOT_NAME ".SmartShift", {
|
||||
{"GetStatus", {this, &IPC::getStatus, {"active", "threshold"}}},
|
||||
{"SetActive", {this, &IPC::setActive, {"active"}}},
|
||||
{"SetThreshold", {this, &IPC::setThreshold, {"threshold"}}},
|
||||
{"GetDefault", {this, &IPC::getDefault, {"setActive", "active", "setThreshold", "threshold"}}},
|
||||
{"ClearDefaultActive", {this, &IPC::clearDefaultActive}},
|
||||
{"SetDefaultActive", {this, &IPC::setDefaultActive, {"active"}}},
|
||||
{"ClearDefaultThreshold", {this, &IPC::clearDefaultThreshold}},
|
||||
{"SetDefaultThreshold", {this, &IPC::setDefaultThreshold, {"threshold"}}}
|
||||
}, {}, {}),
|
||||
{"GetConfig", {this, &IPC::getConfig, {"active", "threshold", "torque"}}},
|
||||
{"SetActive", {this, &IPC::setActive, {"active", "clear"}}},
|
||||
{"SetThreshold", {this, &IPC::setThreshold, {"threshold", "clear"}}},
|
||||
{"SetTorque", {this, &IPC::setTorque, {"torque", "clear"}}},
|
||||
},
|
||||
{
|
||||
{"TorqueSupport", ipcgull::property<bool>(
|
||||
ipcgull::property_readable, parent->supportsTorque())},
|
||||
}, {}),
|
||||
_parent(*parent) {
|
||||
}
|
||||
|
||||
std::tuple<bool, uint8_t> SmartShift::IPC::getStatus() const {
|
||||
auto ret = _parent.getStatus();
|
||||
return std::make_tuple(ret.active, ret.autoDisengage);
|
||||
std::tuple<uint8_t, uint8_t, uint8_t> SmartShift::IPC::getConfig() const {
|
||||
std::shared_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
auto& defaults = _parent.getDefaults();
|
||||
if (config.has_value()) {
|
||||
auto& conf_value = config.value();
|
||||
return {
|
||||
conf_value.on.has_value() ? (conf_value.on.value() ? 2 : 1) : 0,
|
||||
conf_value.threshold.value_or(defaults.autoDisengage),
|
||||
conf_value.torque.value_or(defaults.torque),
|
||||
};
|
||||
} else {
|
||||
return {0, 0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
void SmartShift::IPC::setActive(bool active) {
|
||||
Status status{};
|
||||
status.setActive = true;
|
||||
status.active = active;
|
||||
_parent.setStatus(status);
|
||||
void SmartShift::IPC::setActive(bool active, bool clear) {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
if (clear) {
|
||||
if (config.has_value())
|
||||
config.value().on.reset();
|
||||
} else {
|
||||
if (!config.has_value())
|
||||
config = config::SmartShift{};
|
||||
config.value().on = active;
|
||||
Status status{};
|
||||
status.active = active, status.setActive = true;
|
||||
_parent.setStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
void SmartShift::IPC::setThreshold(uint8_t threshold) {
|
||||
void SmartShift::IPC::setThreshold(uint8_t threshold, bool clear) {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
Status status{};
|
||||
status.setAutoDisengage = true;
|
||||
status.autoDisengage = threshold;
|
||||
|
||||
/* clip threshold */
|
||||
if (threshold == 0)
|
||||
threshold = 1;
|
||||
|
||||
if (clear) {
|
||||
if (config.has_value())
|
||||
config.value().threshold.reset();
|
||||
status.autoDisengage = _parent.getDefaults().autoDisengage;
|
||||
} else {
|
||||
if (!config.has_value())
|
||||
config = config::SmartShift{};
|
||||
config.value().threshold = threshold;
|
||||
status.autoDisengage = threshold;
|
||||
}
|
||||
_parent.setStatus(status);
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool, uint8_t> SmartShift::IPC::getDefault() const {
|
||||
std::shared_lock lock(_parent._config_mutex);
|
||||
|
||||
auto& config = _parent._config.get();
|
||||
|
||||
if (!config.has_value())
|
||||
return {false, false, false, 0};
|
||||
|
||||
std::tuple<bool, bool, bool, uint8_t> ret;
|
||||
std::get<0>(ret) = config.value().on.has_value();
|
||||
if (std::get<0>(ret))
|
||||
std::get<1>(ret) = config.value().on.value();
|
||||
std::get<2>(ret) = config.value().threshold.has_value();
|
||||
if (std::get<2>(ret))
|
||||
std::get<3>(ret) = config.value().threshold.value();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SmartShift::IPC::clearDefaultActive() {
|
||||
void SmartShift::IPC::setTorque(uint8_t torque, bool clear) {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
if (config.has_value())
|
||||
config.value().on.reset();
|
||||
}
|
||||
Status status{};
|
||||
status.setTorque = true;
|
||||
|
||||
void SmartShift::IPC::setDefaultActive(bool active) {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
if (!config.has_value())
|
||||
config = config::SmartShift{};
|
||||
config.value().on = active;
|
||||
}
|
||||
/* clip torque */
|
||||
if (torque == 0)
|
||||
torque = 1;
|
||||
else if (torque > 100)
|
||||
torque = 100;
|
||||
|
||||
if (!_parent.supportsTorque())
|
||||
throw std::invalid_argument("torque unsupported");
|
||||
|
||||
void SmartShift::IPC::clearDefaultThreshold() {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
if (config.has_value())
|
||||
config.value().threshold.reset();
|
||||
}
|
||||
|
||||
void SmartShift::IPC::setDefaultThreshold(uint8_t threshold) {
|
||||
std::unique_lock lock(_parent._config_mutex);
|
||||
auto& config = _parent._config.get();
|
||||
if (!config.has_value())
|
||||
config = config::SmartShift{};
|
||||
config.value().threshold = threshold;
|
||||
if (clear) {
|
||||
if (config.has_value())
|
||||
config.value().torque.reset();
|
||||
status.torque = _parent.getDefaults().torque;
|
||||
} else {
|
||||
if (!config.has_value())
|
||||
config = config::SmartShift{};
|
||||
config.value().torque = torque;
|
||||
status.torque = torque;
|
||||
}
|
||||
_parent.setStatus(status);
|
||||
}
|
||||
|
@ -27,19 +27,22 @@
|
||||
namespace logid::features {
|
||||
class SmartShift : public DeviceFeature {
|
||||
public:
|
||||
|
||||
void configure() final;
|
||||
|
||||
void listen() final;
|
||||
|
||||
void setProfile(config::Profile& profile) final;
|
||||
|
||||
typedef backend::hidpp20::SmartShift::SmartshiftStatus Status;
|
||||
typedef backend::hidpp20::SmartShift::Status Status;
|
||||
|
||||
[[nodiscard]] Status getStatus() const;
|
||||
|
||||
void setStatus(Status status);
|
||||
|
||||
[[nodiscard]] const backend::hidpp20::SmartShift::Defaults& getDefaults() const;
|
||||
|
||||
[[nodiscard]] bool supportsTorque() const;
|
||||
|
||||
protected:
|
||||
explicit SmartShift(Device* dev);
|
||||
|
||||
@ -48,25 +51,20 @@ namespace logid::features {
|
||||
std::reference_wrapper<std::optional<config::SmartShift>> _config;
|
||||
std::shared_ptr<backend::hidpp20::SmartShift> _smartshift;
|
||||
|
||||
backend::hidpp20::SmartShift::Defaults _defaults{};
|
||||
bool _torque_support = false;
|
||||
|
||||
class IPC : public ipcgull::interface {
|
||||
public:
|
||||
explicit IPC(SmartShift* parent);
|
||||
|
||||
[[nodiscard]] std::tuple<bool, uint8_t> getStatus() const;;
|
||||
[[nodiscard]] std::tuple<uint8_t, uint8_t, uint8_t> getConfig() const;
|
||||
|
||||
void setActive(bool active);
|
||||
void setActive(bool active, bool clear);
|
||||
|
||||
void setThreshold(uint8_t threshold);
|
||||
void setThreshold(uint8_t threshold, bool clear);
|
||||
|
||||
[[nodiscard]] std::tuple<bool, bool, bool, uint8_t> getDefault() const;
|
||||
|
||||
void clearDefaultActive();
|
||||
|
||||
void setDefaultActive(bool active);
|
||||
|
||||
void clearDefaultThreshold();
|
||||
|
||||
void setDefaultThreshold(uint8_t threshold);
|
||||
void setTorque(uint8_t torque, bool clear);
|
||||
|
||||
private:
|
||||
SmartShift& _parent;
|
||||
|
Loading…
Reference in New Issue
Block a user