diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt
index 4032e9f..dddf7cd 100644
--- a/src/logid/CMakeLists.txt
+++ b/src/logid/CMakeLists.txt
@@ -42,6 +42,7 @@ add_executable(logid
backend/hidpp20/features/AdjustableDPI.cpp
backend/hidpp20/features/SmartShift.cpp
backend/hidpp20/features/ReprogControls.cpp
+ backend/hidpp20/features/HiresScroll.cpp
backend/dj/Report.cpp
util/mutex_queue.h
util/thread.cpp
diff --git a/src/logid/backend/hidpp20/features/HiresScroll.cpp b/src/logid/backend/hidpp20/features/HiresScroll.cpp
new file mode 100644
index 0000000..62bc597
--- /dev/null
+++ b/src/logid/backend/hidpp20/features/HiresScroll.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "HiresScroll.h"
+
+using namespace logid::backend::hidpp20;
+
+HiresScroll::HiresScroll(Device *device) : Feature(device, ID)
+{
+}
+
+HiresScroll::Capabilities HiresScroll::getCapabilities()
+{
+ std::vector params(0);
+ auto response = callFunction(GetCapabilities, params);
+
+ Capabilities capabilities{};
+ capabilities.multiplier = response[0];
+ capabilities.flags = response[1];
+ return capabilities;
+}
+
+uint8_t HiresScroll::getMode()
+{
+ std::vector params(0);
+ auto response = callFunction(GetMode, params);
+ return response[0];
+}
+
+void HiresScroll::setMode(uint8_t mode)
+{
+ std::vector params(1);
+ params[0] = mode;
+ callFunction(SetMode, params);
+}
+
+bool HiresScroll::getRatchetState()
+{
+ std::vector params(0);
+ auto response = callFunction(GetRatchetState, params);
+ return params[0];
+}
+
+HiresScroll::WheelStatus HiresScroll::wheelMovementEvent(const hidpp::Report
+ &report)
+{
+ assert(report.function() == WheelMovement);
+ WheelStatus status{};
+ status.hiRes = report.paramBegin()[0] & 1<<4;
+ status.periods = report.paramBegin()[0] & 0x0F;
+ status.deltaV = report.paramBegin()[1] << 8 | report.paramBegin()[2];
+ return status;
+}
+
+HiresScroll::RatchetState HiresScroll::ratchetSwitchEvent(const hidpp::Report
+ &report)
+{
+ assert(report.function() == WheelMovement);
+ // Possible bad cast
+ return static_cast(report.paramBegin()[0]);
+}
\ No newline at end of file
diff --git a/src/logid/backend/hidpp20/features/HiresScroll.h b/src/logid/backend/hidpp20/features/HiresScroll.h
new file mode 100644
index 0000000..f008c64
--- /dev/null
+++ b/src/logid/backend/hidpp20/features/HiresScroll.h
@@ -0,0 +1,94 @@
+/*
+ * 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_HIRESSCROLL_H
+#define LOGID_BACKEND_HIDPP20_FEATURE_HIRESSCROLL_H
+
+#include "../Feature.h"
+#include "../feature_defs.h"
+
+namespace logid {
+namespace backend {
+namespace hidpp20
+{
+ class HiresScroll : public Feature
+ {
+ public:
+ ///TODO: Hires scroll V1?
+ static const uint16_t ID = FeatureID::HIRES_SCROLLING_V2;
+ virtual uint16_t getID() { return ID; }
+
+ enum Function : uint8_t
+ {
+ GetCapabilities = 0,
+ GetMode = 1,
+ SetMode = 2,
+ GetRatchetState = 3
+ };
+
+ enum Event : uint8_t
+ {
+ WheelMovement = 0,
+ RatchetSwitch = 1,
+ };
+
+ enum Capability : uint8_t
+ {
+ Invertable = 1<<3,
+ HasRatchet = 1<<2
+ };
+
+ enum Mode : uint8_t
+ {
+ Inverted = 1<<2,
+ HiRes = 1<<1,
+ Target = 1
+ };
+
+ enum RatchetState : uint8_t
+ {
+ FreeWheel = 0,
+ Ratchet = 1
+ };
+
+ struct Capabilities
+ {
+ uint8_t multiplier;
+ uint8_t flags;
+ };
+
+ struct WheelStatus
+ {
+ bool hiRes;
+ uint8_t periods;
+ uint16_t deltaV;
+ };
+
+ explicit HiresScroll(Device* device);
+
+ Capabilities getCapabilities();
+ uint8_t getMode();
+ void setMode(uint8_t mode);
+ bool getRatchetState();
+
+ ///TODO: Event handlers
+ static WheelStatus wheelMovementEvent(const hidpp::Report& report);
+ static RatchetState ratchetSwitchEvent(const hidpp::Report& report);
+ };
+}}}
+
+#endif //LOGID_BACKEND_HIDPP20_FEATURE_HIRESSCROLL_H