diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 32746d4..de51a75 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(logid actions/ToggleHiresScroll.cpp actions/ToggleSmartShift.cpp actions/CycleDPI.cpp + actions/ChangeDPI.cpp actions/GestureAction.cpp actions/gesture/Gesture.cpp actions/gesture/ReleaseGesture.cpp diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index 41cf325..307f5df 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -25,6 +25,7 @@ #include "GestureAction.h" #include "NullAction.h" #include "CycleDPI.h" +#include "ChangeDPI.h" using namespace logid; using namespace logid::actions; @@ -60,6 +61,8 @@ std::shared_ptr Action::makeAction(Device *device, libconfig::Setting return std::make_shared(device, setting); else if(type == "cycledpi") return std::make_shared(device, setting); + else if(type == "changedpi") + return std::make_shared(device, setting); else if(type == "none") return std::make_shared(device); else diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp new file mode 100644 index 0000000..faab6b9 --- /dev/null +++ b/src/logid/actions/ChangeDPI.cpp @@ -0,0 +1,109 @@ +/* + * 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 "ChangeDPI.h" +#include "../Device.h" +#include "../util/task.h" +#include "../util/log.h" +#include "../backend/hidpp20/Error.h" +#include "../backend/hidpp20/features/ReprogControls.h" + +using namespace logid::actions; + +ChangeDPI::ChangeDPI(Device *device, libconfig::Setting &setting) : + Action(device), _config(device, setting) +{ + _dpi = _device->getFeature("dpi"); + if(!_dpi) + logPrintf(WARN, "%s:%d: DPI feature not found, cannot use " + "ChangeDPI action.", + _device->hidpp20().devicePath().c_str(), + _device->hidpp20().deviceIndex()); +} + +void ChangeDPI::press() +{ + _pressed = true; + if(_dpi) { + task::spawn([this]{ + try { + uint16_t last_dpi = _dpi->getDPI(_config.sensor()); + _dpi->setDPI(last_dpi + _config.interval(), _config.sensor()); + } catch (backend::hidpp20::Error& e) { + if(e.code() == backend::hidpp20::Error::InvalidArgument) + logPrintf(WARN, "%s:%d: Could not get/set DPI for sensor " + "%d", + _device->hidpp20().devicePath().c_str(), + _device->hidpp20().deviceIndex(), + _config.sensor()); + else + throw e; + } + }); + } +} + +void ChangeDPI::release() +{ + _pressed = false; +} + +uint8_t ChangeDPI::reprogFlags() const +{ + return backend::hidpp20::ReprogControls::TemporaryDiverted; +} + +ChangeDPI::Config::Config(Device *device, libconfig::Setting &config) : + Action::Config(device), _interval (0), _sensor (0) +{ + if(!config.isGroup()) { + logPrintf(WARN, "Line %d: action must be an object, skipping.", + config.getSourceLine()); + return; + } + + try { + auto& inc = config.lookup("inc"); + if(inc.getType() != libconfig::Setting::TypeInt) + logPrintf(WARN, "Line %d: inc must be an integer", + inc.getSourceLine()); + _interval = (int)inc; + } catch(libconfig::SettingNotFoundException& e) { + logPrintf(WARN, "Line %d: inc is a required field, skipping.", + config.getSourceLine()); + } + + try { + auto& sensor = config.lookup("sensor"); + if(sensor.getType() != libconfig::Setting::TypeInt) + logPrintf(WARN, "Line %d: sensor must be an integer", + sensor.getSourceLine()); + _sensor = (int)sensor; + } catch(libconfig::SettingNotFoundException& e) { + // Ignore + } +} + +uint16_t ChangeDPI::Config::interval() const +{ + return _interval; +} + +uint8_t ChangeDPI::Config::sensor() const +{ + return _sensor; +} \ No newline at end of file diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h new file mode 100644 index 0000000..4d9e04f --- /dev/null +++ b/src/logid/actions/ChangeDPI.h @@ -0,0 +1,54 @@ +/* + * 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_ACTION_CHANGEDPI_H +#define LOGID_ACTION_CHANGEDPI_H + +#include +#include "Action.h" +#include "../features/DPI.h" + +namespace logid { + namespace actions { + class ChangeDPI : public Action + { + public: + explicit ChangeDPI(Device* device, libconfig::Setting& setting); + + virtual void press(); + virtual void release(); + + virtual uint8_t reprogFlags() const; + + class Config : public Action::Config + { + public: + Config(Device* device, libconfig::Setting& setting); + uint16_t interval() const; + uint8_t sensor() const; + private: + uint16_t _interval; + uint8_t _sensor; + }; + + protected: + Config _config; + std::shared_ptr _dpi; + }; + }} + +#endif //LOGID_ACTION_CHANGEDPI_H \ No newline at end of file diff --git a/src/logid/features/DPI.cpp b/src/logid/features/DPI.cpp index ffc5482..435cdb8 100644 --- a/src/logid/features/DPI.cpp +++ b/src/logid/features/DPI.cpp @@ -66,12 +66,20 @@ DPI::DPI(Device* device) : DeviceFeature(device), _config (device), void DPI::configure() { const uint8_t sensors = _adjustable_dpi.getSensorCount(); - for(uint8_t i = 0; i < _config.getSensorCount() && i < sensors; i++) { - auto dpi = _config.getDPI(i); - if(dpi) { - auto dpi_list = _adjustable_dpi.getSensorDPIList(i); - _adjustable_dpi.setSensorDPI(i, getClosestDPI(dpi_list, - dpi)); + for(uint8_t i = 0; i < _config.getSensorCount(); i++) { + hidpp20::AdjustableDPI::SensorDPIList dpi_list; + if(_dpi_lists.size() <= i) { + dpi_list = _adjustable_dpi.getSensorDPIList(i); + _dpi_lists.push_back(dpi_list); + } else { + dpi_list = _dpi_lists[i]; + } + if(i < sensors) { + auto dpi = _config.getDPI(i); + if(dpi) { + _adjustable_dpi.setSensorDPI(i, getClosestDPI(dpi_list, + dpi)); + } } } } @@ -87,7 +95,15 @@ uint16_t DPI::getDPI(uint8_t sensor) void DPI::setDPI(uint16_t dpi, uint8_t sensor) { - _adjustable_dpi.setSensorDPI(sensor, dpi); + hidpp20::AdjustableDPI::SensorDPIList dpi_list; + if(_dpi_lists.size() <= sensor) { + dpi_list = _adjustable_dpi.getSensorDPIList(sensor); + for(std::size_t i = _dpi_lists.size()-1; i <= sensor; i++) { + _dpi_lists.push_back(_adjustable_dpi.getSensorDPIList(i)); + } + } + dpi_list = _dpi_lists[sensor]; + _adjustable_dpi.setSensorDPI(sensor, getClosestDPI(dpi_list, dpi)); } /* Some devices have multiple sensors, but an older config format diff --git a/src/logid/features/DPI.h b/src/logid/features/DPI.h index 78f102f..8bc2468 100644 --- a/src/logid/features/DPI.h +++ b/src/logid/features/DPI.h @@ -46,6 +46,7 @@ namespace features private: Config _config; backend::hidpp20::AdjustableDPI _adjustable_dpi; + std::vector _dpi_lists; }; }}