Problem
The thumbwheel on Logitech MX Master 3S only responds to right scrolling. Left scrolling produces no output.
Environment
- Device: Logitech MX Master 3S
- OS: Linux Mint
- logiops version: latest from main branch
Configuration
thumbwheel: {
divert: true;
invert: false;
right: { mode: "Axis"; axis: "REL_HWHEEL"; axis_multiplier: 1.0; };
left: { mode: "Axis"; axis: "REL_HWHEEL"; axis_multiplier: 1.0; };
};
Root Cause
The issue stems from three problems in the code:
1. ThumbWheel.cpp - Line 203: Resetting accumulator
// BEFORE:
if (scroll_action) {
scroll_action->press(false); // ← Resets _axis to 0
scroll_action->move(event.rotation);
}
// AFTER:
if (scroll_action) {
scroll_action->move(event.rotation);
}
Why: press(false) was resetting the accumulator to 0 before each move, preventing negative values from accumulating.
2. ThumbWheel.cpp - Lines 187-192: Asymmetric threshold initialization
// REMOVE this entire block:
if (event.rotationStatus == hidpp20::ThumbWheel::Start) {
if (_right_gesture)
_right_gesture->press(true); // Sets _axis = +50
if (_left_gesture)
_left_gesture->press(true); // Sets _axis = +50
}
Why: press(true) set _axis = +50 for both gestures, creating asymmetric behavior:
- ✅ Right (+2):
50 + 2 = 52 > 50 → Works immediately
- ❌ Left (-2):
50 - 2 = 48 < 50 → Requires ~51 clicks to reach -51
3. AxisGesture.cpp - Missing negative value support
// BEFORE (Line 86):
if (new_axis > threshold) {
// AFTER:
if (std::abs(new_axis) > threshold) {
// BEFORE (Lines 88-94):
if (_axis < threshold)
move = new_axis - threshold;
// AFTER:
if (std::abs(_axis) < threshold) {
if (new_axis > 0)
move = new_axis - threshold;
else
move = new_axis + threshold;
}
// BEFORE (Lines 96-106): Complex negative_multiplier logic
bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0;
if (negative_multiplier)
move *= -_config.axis_multiplier.value_or(1);
else
move *= _config.axis_multiplier.value_or(1);
// ... later ...
if (negative_multiplier)
move_floor = -move_floor;
// AFTER: Simplified
move *= _config.axis_multiplier.value_or(1);
Why: Original code didn't handle negative input values and had flawed sign-flipping logic.
Solution - Complete Patch
diff --git a/src/logid/features/ThumbWheel.cpp b/src/logid/features/ThumbWheel.cpp
--- a/src/logid/features/ThumbWheel.cpp
+++ b/src/logid/features/ThumbWheel.cpp
@@ -184,12 +184,6 @@
// Make right positive unless inverted
event.rotation *= _wheel_info.defaultDirection;
- if (event.rotationStatus == hidpp20::ThumbWheel::Start) {
- if (_right_gesture)
- _right_gesture->press(true);
- if (_left_gesture)
- _left_gesture->press(true);
- }
if (event.rotation) {
std::shared_ptr<actions::Gesture> scroll_action;
@@ -200,7 +194,6 @@
scroll_action = _left_gesture;
if (scroll_action) {
- scroll_action->press(false);
scroll_action->move(event.rotation);
}
}
diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp
--- a/src/logid/actions/gesture/AxisGesture.cpp
+++ b/src/logid/actions/gesture/AxisGesture.cpp
@@ -82,10 +82,16 @@
int low_res_axis = InputDevice::getLowResAxis(axis);
int hires_remainder = _hires_remainder;
- if (new_axis > threshold) {
+ if (std::abs(new_axis) > threshold) {
double move = axis;
- if (_axis < threshold)
- move = new_axis - threshold;
+ if (std::abs(_axis) < threshold) {
+ if (new_axis > 0)
+ move = new_axis - threshold;
+ else
+ move = new_axis + threshold;
+ }
+
- bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0;
- if (negative_multiplier)
- move *= -_config.axis_multiplier.value_or(1);
- else
- move *= _config.axis_multiplier.value_or(1);
+ move *= _config.axis_multiplier.value_or(1);
// Handle hi-res multiplier
move *= _multiplier;
@@ -107,9 +103,6 @@
_axis_remainder -= int_remainder;
}
- if (negative_multiplier)
- move_floor = -move_floor;
-
if (low_res_axis != -1) {
Testing
After applying the patch:
- ✅ Both directions respond immediately
- ✅
axis_multiplier can be positive or negative to control direction
- ✅ No threshold delay
- ✅ Symmetric behavior in both directions
Tested and confirmed working on MX Master 3S.
Happy to provide more details or create a PR if this approach is acceptable!
Problem
The thumbwheel on Logitech MX Master 3S only responds to right scrolling. Left scrolling produces no output.
Environment
Configuration
thumbwheel: { divert: true; invert: false; right: { mode: "Axis"; axis: "REL_HWHEEL"; axis_multiplier: 1.0; }; left: { mode: "Axis"; axis: "REL_HWHEEL"; axis_multiplier: 1.0; }; };Root Cause
The issue stems from three problems in the code:
1. ThumbWheel.cpp - Line 203: Resetting accumulator
Why: press(false) was resetting the accumulator to 0 before each move, preventing negative values from accumulating.
2. ThumbWheel.cpp - Lines 187-192: Asymmetric threshold initialization
Why: press(true) set
_axis = +50for both gestures, creating asymmetric behavior:50 + 2 = 52 > 50→ Works immediately50 - 2 = 48 < 50→ Requires ~51 clicks to reach -513. AxisGesture.cpp - Missing negative value support
Why: Original code didn't handle negative input values and had flawed sign-flipping logic.
Solution - Complete Patch
Testing
After applying the patch:
axis_multipliercan be positive or negative to control directionTested and confirmed working on MX Master 3S.
Happy to provide more details or create a PR if this approach is acceptable!