Repository navigation
Conversation
mmaher88
requested changes
Nov 9, 2026
mmaher88
left a comment
Owner
There was a problem hiding this comment.
Thanks for digging into this. The original MX Master isn't supported on master today, and your Gesture 2 analysis lines up with Solaar (fn 2/4 offset-mask writes, gesture 46 = THUMBWHEEL). The branch is 15 commits behind and DeviceSession has been reworked since (#174, #176), so it needs a rebase either way. To get this merged, could you split it in two?
- A descriptor-only PR:
- List all three hardware revisions (
0xb012/0x4041,0xb017/0x4060,0xb01e/0x4071). Bluetooth devices are only picked up if their PID is in the descriptor. - Set
thumbWheel: falseand drop the thumb-wheel control and hotspots for now; the wheel keeps its native horizontal scroll. - Either point
imagesat../mx-master-2s/or use downscaled copies, rather than adding another 15 MB of identical PNGs.
- List all three hardware revisions (
- A follow-up for the thumb wheel, written as a ThumbWheel capability variant table (0x2150 and 0x6501) chosen from the device's feature table, rather than a new descriptor flag. The current flag isn't in
schema.json, which descriptors are validated against. Please also find the gesture and diversion indices by walking the 0x6501 field table, the way Solaar'sGesturesclass does, instead of hardcoding 1/0, and fix the comment that says the index is 3.
The README "Gestures" predicate fix is a good catch, but please send it as its own small PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feature(device): MX Master (1st gen)
I added the original MX Master descriptor and the C++ plumbing it needs for thumb wheel.
Tested on CachyOS (6.18.24-1-cachyos-lts kernel) over Bluetooth (PID 0xb01e)
with the standard pacman build flow.
hotspot coordinates are nearly identical between the two generations.
and Easy-Switch all work via the existing capability paths.
make testfailures on my host are pre-existing test-infra brittleness unrelated to
this PR (see "Test status" section).
C++ implementation — thumb wheel via Gesture 2 diversion
The 1st-gen MX Master is the only MX Master generation that does not
expose HID++ feature
0x2150 (ThumbWheel). Verified two ways:solaar showoutput has no entry for0x2150.feature 2150 -> index 0(= not in thedevice's feature table).
Instead the thumb wheel rides on
0x6501 (Gesture 2)— when a gesture isdiverted, rotation events arrive as long-form HID++ notifications. Captured
event for one tick right:
To make this work end-to-end Logitune needs to:
0x02, gesture index 1 onthis device — second entry in the gesture table after
NATURAL_SCROLLINGid 45).
0x04, diversion index 0 — the onlydivertible gesture).
thumbWheelRotation(delta)so theexisting
ButtonActionDispatcherroutes through volume / scroll / zoomper
thumbWheelMode.scrollreleasesthe wheel back to native HID horizontal scroll).
What was added
src/core/hidpp/features/GestureV2.{h,cpp}— extended withparseDivertedGestureEvent,buildSetDiverted(offset/mask requestbuilder shared with
setEnabled), function-ID constantskFnSetEnabled = 0x02andkFnSetDiverted = 0x04, and akThumbWheelEventMarker = 0x03constant.
src/core/hidpp/capabilities/GestureV2Capability.{h,cpp}— new varianttable following the same pattern as Battery / SmartShift / ReprogControls.
src/core/CMakeLists.txt— added the new capability source.What was touched in non-MX-Master code
Every behavioral change is gated on the new descriptor flag
thumbWheelGestureV2, which only the original MX Master sets. For everyother descriptor the flag defaults to
falseand the new code paths areunreachable.
interfaces/IDevice.hbool thumbWheelGestureV2 = false;toFeatureSupportdevices/JsonDevice.cppdevices/schema.json(×2)DeviceSession::enumerateAndSetupDeviceSession::handleNotificationDeviceSession::setThumbWheelModeelsebranch after the existingif (hasFeature(ThumbWheel)) { …; return; }app/models/DeviceModel::thumbWheelSupportedf.thumbWheel→f.thumbWheel || f.thumbWheelGestureV2scripts/generate-readme-devices.pyfeatures.thumbWheelto scanningcontrols[]fordefaultActionType == "gesture-trigger"The
Gesturespredicate change is technically a non-MX-Master edit but itfixes a predicate that worked by coincidence on every other device (every
HID++ 0x2150 device also has a gesture button, so reading
thumbWheelhappened to give the right answer). The new predicate is semantically
correct, and the regenerated README is byte-identical for every row except
this one.
Known limitations
passes invert into the firmware; 0x6501 has no equivalent. A one-line
fix in
ButtonActionDispatcher::onThumbWheelRotation(multiplynormalizedby-1whensession->thumbWheelInvert()is true) wouldhonor it in software for every device, but that's a behavior change
outside this PR's scope. Left as-is.
index 0 — derived from Solaar's runtime gesture-table dump on this
device. A more thorough implementation would enumerate the table at
startup via
getCount(function0x00) +getGestureInfo(function0x10) and find the THUMBWHEEL entry (gesture id46) dynamically.Left out for size; the indices are stable across firmware revisions on
this generation.
— gesture button (CID 0xC3) works; verified by hand on the device.
Test status
make testshows 14 failures on my host. They are all pre-existingtest-infrastructure brittleness, none caused by this branch:
DeviceRegistry.ReloadByPathRefreshesSingleDevicedoesqputenv("XDG_DATA_HOME", tmp)thenqunsetenv("XDG_DATA_HOME")at theend without restoring. Subsequent registry constructions then fall back
to whatever
~/.local/share/logitune/devicesand/usr/share/logitune/deviceshappen to hold on the host.logitunepackage installed,/usr/share/logitune/deviceslacks bothmx-masterandmx-master-3→ 12 of the 14 failures, plus
MxVerticalForBusinessRegisteredandIdentifyDirectDeviceflake when the env mutation prevents the rightdescriptors loading.
Both isolated subsets are green:
CI / a fresh devcontainer should be unaffected — there's no
/usr/share/logitune/devicesshadowing the fork's owndevices/folder.Sources for thumb-wheel implementation
for diverted Gesture 2 events on the 1st-gen MX Master (note: the issue
describes byte 2 as the "diversion index", but on this device it's a
static
0x03marker — the dynamic diversion index lives in the bitmapwritten by function
0x40).lib/logitech_receiver/hidpp20.py— function-ID layoutfor
setEnabled(0x20),setDiverted(0x40) and the offset/maskpayload format.