device: Add PRO X 2 Superstrike mouse support with HITS tuning settings (#3132)

* feat: PRO X 2 Superstrike support with click haptics, actuation point and rapid trigger config support

* feat: PRO X 2 Superstrike docs

* docs: document PRO X 2 Superstrike features, device entry, and capabilities

* fix: code review points

# Conflicts:
#	lib/logitech_receiver/hidpp20_constants.py

* Fix the write_key_value for dpi_extended

I was playing with the branch from the MR and I wanted to fix the cli stuff, it now properly sets when I use:

solaar config 1 dpi_extended X 400

Should be enough

Signed-off-by: Shane Fagan <mail@shanefagan.com>

* Fix ruff style check

---------

Signed-off-by: Shane Fagan <mail@shanefagan.com>
Co-authored-by: Shane Fagan <mail@shanefagan.com>
This commit is contained in:
Caio Quirino da Silva 2026-04-12 15:53:47 +02:00 committed by GitHub
parent 99a403c554
commit 5478224cfa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 644 additions and 0 deletions

View File

@ -0,0 +1,374 @@
# Logitech PRO X 2 Superstrike - Solaar CLI Reference
This document describes all available settings for the Logitech PRO X 2 Superstrike mouse via the Solaar CLI.
## Device Identification
| Property | Value |
|----------|-------|
| Name | PRO X 2 Superstrike |
| WPID | 40BD |
| Protocol | HID++ 4.2 |
| Kind | mouse |
## General CLI Syntax
```bash
# List all settings for device
solaar config <device>
# Read a specific setting
solaar config <device> <setting-name>
# Write a specific setting
solaar config <device> <setting-name> <value>
```
The `<device>` can be:
- Device number (e.g., `1`)
- Device name (e.g., `"PRO X 2 Superstrike"`)
- Serial number (e.g., `A1C55DB2`)
---
## Available Settings
### 1. Onboard Profiles
Controls whether the device uses its onboard profile or host-controlled settings.
| Property | Value |
|----------|-------|
| Setting Name | `onboard_profiles` |
| Type | Choice |
| Possible Values | `Disabled`, `Profile 1` |
**Commands:**
```bash
# Read current value
solaar config 1 onboard_profiles
# Set to disabled (allows host control of DPI, report rate, etc.)
solaar config 1 onboard_profiles Disabled
# Set to Profile 1 (use onboard profile)
solaar config 1 onboard_profiles "Profile 1"
```
**Note:** Many settings require `onboard_profiles` to be set to `Disabled` to be effective.
---
### 2. Report Rate
Controls the frequency of device movement reports.
| Property | Value |
|----------|-------|
| Setting Name | `report_rate_extended` |
| Type | Choice |
| Possible Values | `8ms`, `4ms`, `2ms`, `1ms`, `500us`, `250us`, `125us` |
**Commands:**
```bash
# Read current value
solaar config 1 report_rate_extended
# Set to 1ms (1000Hz)
solaar config 1 report_rate_extended 1ms
# Set to 500us (2000Hz)
solaar config 1 report_rate_extended 500us
# Set to 125us (8000Hz)
solaar config 1 report_rate_extended 125us
```
**Polling Rate Reference:**
| Value | Polling Rate |
|-------|--------------|
| `8ms` | 125 Hz |
| `4ms` | 250 Hz |
| `2ms` | 500 Hz |
| `1ms` | 1000 Hz |
| `500us` | 2000 Hz |
| `250us` | 4000 Hz |
| `125us` | 8000 Hz |
---
### 3. Sensitivity (DPI)
Controls mouse movement sensitivity.
| Property | Value |
|----------|-------|
| Setting Name | `dpi_extended` |
| Type | Complex (X, Y, LOD) |
| DPI Range | 100 - 32000 |
| LOD Values | `LOW`, `HIGH` |
**Commands:**
```bash
# Read current value
solaar config 1 dpi_extended
# Set DPI (format: {X:<value>, Y:<value>, LOD:<value>})
solaar config 1 dpi_extended "{X:800, Y:800, LOD:HIGH}"
# Set to 1600 DPI
solaar config 1 dpi_extended "{X:1600, Y:1600, LOD:HIGH}"
# Set different X and Y sensitivity
solaar config 1 dpi_extended "{X:800, Y:1600, LOD:LOW}"
```
---
## HITS Tuning Settings (Hall-Effect Inductive Trigger Switch)
These settings control the advanced click behavior of the PRO X 2 Superstrike's hall-effect switches.
### 4. Actuation Point
Controls how deep the button must be pressed to register a click.
| Property | Value |
|----------|-------|
| Setting Name (Left) | `superstrike-tuning_actuation-0` |
| Setting Name (Right) | `superstrike-tuning_actuation-1` |
| Type | Range |
| Range | 1 - 10 |
| Default | 5 |
**Value Interpretation:**
- `1` = Shallowest (hair trigger, minimal press)
- `10` = Deepest (full press required)
**Commands:**
```bash
# Read left button actuation
solaar config 1 superstrike-tuning_actuation-0
# Read right button actuation
solaar config 1 superstrike-tuning_actuation-1
# Set left button to shallow actuation (hair trigger)
solaar config 1 superstrike-tuning_actuation-0 1
# Set left button to deep actuation
solaar config 1 superstrike-tuning_actuation-0 10
# Set right button to medium actuation
solaar config 1 superstrike-tuning_actuation-1 5
```
---
### 5. Rapid Trigger Level
Controls the rapid trigger sensitivity, which allows the button to re-actuate quickly after partial release.
| Property | Value |
|----------|-------|
| Setting Name (Left) | `superstrike-tuning_rapid-trigger-level-0` |
| Setting Name (Right) | `superstrike-tuning_rapid-trigger-level-1` |
| Type | Range |
| Range | 1 - 5 |
| Default | 3 |
**Value Interpretation:**
- `1` = Fastest (most sensitive, smallest movement to re-trigger)
- `5` = Slowest (least sensitive, larger movement needed)
**Note:** Rapid trigger cannot be disabled on this device. The minimum level is 1.
**Commands:**
```bash
# Read left button rapid trigger level
solaar config 1 superstrike-tuning_rapid-trigger-level-0
# Read right button rapid trigger level
solaar config 1 superstrike-tuning_rapid-trigger-level-1
# Set left button to fastest rapid trigger
solaar config 1 superstrike-tuning_rapid-trigger-level-0 1
# Set left button to slowest rapid trigger
solaar config 1 superstrike-tuning_rapid-trigger-level-0 5
# Set right button to medium rapid trigger
solaar config 1 superstrike-tuning_rapid-trigger-level-1 3
```
---
### 6. Click Haptics
Controls the intensity of the haptic feedback when clicking.
| Property | Value |
|----------|-------|
| Setting Name (Left) | `superstrike-tuning_haptics-0` |
| Setting Name (Right) | `superstrike-tuning_haptics-1` |
| Type | Range |
| Range | 0 - 5 |
| Default | 3 |
**Value Interpretation:**
- `0` = Off (no haptic feedback)
- `1` = Minimal
- `2` = Light
- `3` = Medium
- `4` = Strong
- `5` = Strongest (maximum haptic feedback)
**Commands:**
```bash
# Read left button haptics level
solaar config 1 superstrike-tuning_haptics-0
# Read right button haptics level
solaar config 1 superstrike-tuning_haptics-1
# Disable haptics on left button
solaar config 1 superstrike-tuning_haptics-0 0
# Set left button to maximum haptics
solaar config 1 superstrike-tuning_haptics-0 5
# Set right button to medium haptics
solaar config 1 superstrike-tuning_haptics-1 3
```
---
## Complete Settings Summary
| Setting | CLI Name | Type | Range/Values | Button-Specific |
|---------|----------|------|--------------|-----------------|
| Onboard Profiles | `onboard_profiles` | Choice | `Disabled`, `Profile 1` | No |
| Report Rate | `report_rate_extended` | Choice | `8ms` to `125us` | No |
| Sensitivity | `dpi_extended` | Complex | 100-32000 DPI | No |
| Actuation Point | `superstrike-tuning_actuation-{0,1}` | Range | 1-10 | Yes |
| Rapid Trigger | `superstrike-tuning_rapid-trigger-level-{0,1}` | Range | 1-5 | Yes |
| Click Haptics | `superstrike-tuning_haptics-{0,1}` | Range | 0-5 | Yes |
---
## Batch Configuration Examples
### Gaming Profile (Fast Response)
```bash
#!/bin/bash
# Gaming profile: fast actuation, sensitive rapid trigger, medium haptics
solaar config 1 onboard_profiles Disabled
solaar config 1 report_rate_extended 125us
solaar config 1 dpi_extended "{X:800, Y:800, LOD:HIGH}"
# Left button - hair trigger
solaar config 1 superstrike-tuning_actuation-0 1
solaar config 1 superstrike-tuning_rapid-trigger-level-0 1
solaar config 1 superstrike-tuning_haptics-0 3
# Right button - hair trigger
solaar config 1 superstrike-tuning_actuation-1 1
solaar config 1 superstrike-tuning_rapid-trigger-level-1 1
solaar config 1 superstrike-tuning_haptics-1 3
```
### Productivity Profile (Comfortable)
```bash
#!/bin/bash
# Productivity profile: deeper actuation, slower rapid trigger, strong haptics
solaar config 1 onboard_profiles Disabled
solaar config 1 report_rate_extended 1ms
solaar config 1 dpi_extended "{X:1600, Y:1600, LOD:HIGH}"
# Left button - comfortable click
solaar config 1 superstrike-tuning_actuation-0 7
solaar config 1 superstrike-tuning_rapid-trigger-level-0 4
solaar config 1 superstrike-tuning_haptics-0 5
# Right button - comfortable click
solaar config 1 superstrike-tuning_actuation-1 7
solaar config 1 superstrike-tuning_rapid-trigger-level-1 4
solaar config 1 superstrike-tuning_haptics-1 5
```
### Silent Profile (No Haptics)
```bash
#!/bin/bash
# Silent profile: no haptic feedback
solaar config 1 superstrike-tuning_haptics-0 0
solaar config 1 superstrike-tuning_haptics-1 0
```
---
## Programmatic Usage
### Reading All Settings (JSON-like parsing)
```bash
# Get all settings as output
solaar config 1 2>/dev/null | grep "^[a-z]" | while read line; do
setting=$(echo "$line" | cut -d'=' -f1 | tr -d ' ')
value=$(echo "$line" | cut -d'=' -f2 | tr -d ' ')
echo "{\"setting\": \"$setting\", \"value\": \"$value\"}"
done
```
### Reading a Single Setting Value
```bash
# Extract just the value
solaar config 1 superstrike-tuning_actuation-0 2>/dev/null | grep "^superstrike" | cut -d'=' -f2 | tr -d ' '
```
### Error Handling
```bash
# Check if command succeeded
if solaar config 1 superstrike-tuning_actuation-0 5 2>/dev/null; then
echo "Setting applied successfully"
else
echo "Failed to apply setting"
fi
```
---
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Error (device not found, invalid setting, invalid value) |
---
## Notes
1. **Device Discovery**: Use `solaar show` to list all connected devices and their indices.
2. **Persistence**: Settings are saved to `~/.config/solaar/config.yaml` and automatically reapplied when the device reconnects.
3. **Onboard Profiles**: When `onboard_profiles` is set to `Profile 1`, some settings (DPI, report rate) are controlled by the device's onboard memory and cannot be changed via Solaar.
4. **HITS Settings**: The actuation, rapid trigger, and haptics settings are stored in the device and persist across reconnections, regardless of the onboard profile setting.
5. **Button Index**: `0` = Left button, `1` = Right button.

View File

@ -188,6 +188,42 @@ Solaar uses the standard US keyboard layout. This currently only matters for th
This is an experimental feature and may be modified or even eliminated. This is an experimental feature and may be modified or even eliminated.
### HITS Tuning (Hall-Effect Inductive Trigger Switch)
Some gaming mice (such as the PRO X 2 Superstrike) feature hall-effect magnetic switches on their primary buttons instead of traditional mechanical switches. These switches expose tunable parameters via the `SUPERSTRIKE_TUNING` HID++ feature (`0x1B0C`).
Solaar supports three per-button settings for each primary button (left = 0, right = 1):
- **Actuation Point** (`superstrike-tuning_actuation-{0,1}`): How deep the button must be pressed to register a click. Range 110, where 1 is the shallowest (hair trigger) and 10 is the deepest (full press). Default is 5.
- **Rapid Trigger Level** (`superstrike-tuning_rapid-trigger-level-{0,1}`): Sensitivity of rapid re-actuation after partial release. Range 15, where 1 is the most sensitive and 5 is the least. This cannot be fully disabled.
- **Click Haptics** (`superstrike-tuning_haptics-{0,1}`): Intensity of haptic feedback on click. Range 05, where 0 disables haptics and 5 is maximum intensity.
These settings are written directly to the device and persist across reconnections regardless of the onboard profile state.
### Extended DPI
Some gaming mice (such as the PRO X 2 Superstrike) support the `EXTENDED_ADJUSTABLE_DPI` feature (`0x2202`) which allows independent X and Y axis DPI configuration as well as lift-off distance (LOD) control. This is exposed via the `dpi_extended` setting:
```bash
solaar config <device> dpi_extended "{X:1600, Y:1600, LOD:HIGH}"
```
LOD values are `LOW` and `HIGH`. DPI range depends on the device sensor (up to 32000 DPI on the PRO X 2 Superstrike).
### Extended Report Rate
Some gaming mice (such as the PRO X 2 Superstrike) support the `EXTENDED_ADJUSTABLE_REPORT_RATE` feature (`0x8061`) which enables sub-millisecond polling rates beyond the standard 1 ms (1000 Hz). This is exposed via the `report_rate_extended` setting:
| Value | Polling Rate |
|---------|-------------|
| `8ms` | 125 Hz |
| `4ms` | 250 Hz |
| `2ms` | 500 Hz |
| `1ms` | 1000 Hz |
| `500us` | 2000 Hz |
| `250us` | 4000 Hz |
| `125us` | 8000 Hz |
### Onboard Profiles ### Onboard Profiles
Some mice store one or more profiles onboard. An onboard profile controls certain aspects of the behavior of the mouse, including the rate at which the mouse reports movement, the resolution of the the movement reports, what the mouse buttons do, LED effects, and maybe more. Solaar has a setting that switches between profiles or disables all profiles. Some mice store one or more profiles onboard. An onboard profile controls certain aspects of the behavior of the mouse, including the rate at which the mouse reports movement, the resolution of the the movement reports, what the mouse buttons do, LED effects, and maybe more. Solaar has a setting that switches between profiles or disables all profiles.

View File

@ -211,6 +211,7 @@ so what is important for support is the USB WPID or Bluetooth model ID.
|------------------------------|------|-------| |------------------------------|------|-------|
| G604 Wireless Gaming Mouse | 4085 | 4.2 | | G604 Wireless Gaming Mouse | 4085 | 4.2 |
| PRO X Superlight Wireless | 4093 | 4.2 | | PRO X Superlight Wireless | 4093 | 4.2 |
| PRO X 2 Superstrike | 40BD | 4.2 |
### Trackballs (Unifying) ### Trackballs (Unifying)

View File

@ -0,0 +1,100 @@
Solaar version 1.1.19
1: PRO X 2 Superstrike
Device path : None
WPID : 40BD
Codename : PRO X 2 Superstrike
Kind : mouse
Protocol : HID++ 4.2
Report Rate : 1ms
Serial number:
Model ID: 40BDC0A80000
Unit ID:
Bootloader: BL2 73.00.B0011
Firmware: MPM 42.00.B0011
The power switch is located on the base.
Supports 36 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: DEVICE FW VERSION {0003} V7
Firmware: Bootloader BL2 73.00.B0011
Firmware: Firmware MPM 42.00.B0011
Unit ID: Model ID: 40BDC0A80000 Transport IDs: {'wpid': '40BD', 'usbid': 'C0A8'}
3: DEVICE NAME {0005} V5
Name: PRO X2 SUPERSTRIKE
Kind: mouse
4: WIRELESS DEVICE STATUS {1D4B} V0
5: CONFIG CHANGE {0020} V0
6: UNIFIED BATTERY {1004} V5
7: XY STATS {2250} V1
8: WHEEL STATS {2251} V0
9: EXTENDED ADJUSTABLE DPI {2202} V0
Sensitivity (DPI): {X:800, Y:800, LOD:HIGH}
10: MODE STATUS {8090} V3
11: unknown:80E0 {80E0} V0
12: SUPERSTRIKE TUNING {1B0C} V0
Left Button Actuation Point: 5
Left Button Rapid Trigger Level: 3
Left Button Click Haptics: 3
Right Button Actuation Point: 5
Right Button Rapid Trigger Level: 3
Right Button Click Haptics: 3
13: EXTENDED ADJUSTABLE REPORT RATE {8061} V0
Report Rate: 1ms
14: ONBOARD PROFILES {8100} V0
Device Mode: On-Board
Onboard Profiles: Profile 1
15: MOUSE BUTTON SPY {8110} V0
16: FORCE PAIRING {1500} V0
17: unknown:1801 {1801} V0 internal, hidden
18: DEVICE RESET {1802} V0
19: unknown:1803 {1803} V0 internal, hidden
20: CONFIG DEVICE PROPS {1806} V8
21: unknown:1817 {1817} V0 internal, hidden
22: OOBSTATE {1805} V0
23: unknown:1830 {1830} V0 internal, hidden
24: unknown:1877 {1877} V0 internal, hidden
25: unknown:9403 {9403} V0 internal, hidden
26: unknown:1861 {1861} V0 internal, hidden
27: unknown:1890 {1890} V0 internal, hidden
28: unknown:18A1 {18A1} V0 internal, hidden
29: unknown:1E00 {1E00} V0 hidden
30: unknown:1E02 {1E02} V0 internal, hidden
31: unknown:1E22 {1E22} V0 internal, hidden
32: unknown:1E30 {1E30} V0 internal, hidden
33: unknown:1602 {1602} V0
34: unknown:1EB0 {1EB0} V0 internal, hidden
35: unknown:18B1 {18B1} V0 internal, hidden
Battery: discharging.
SUPERSTRIKE TUNING Feature (0x1B0C)
-----------------------------------
This feature controls the HITS (Hall-Effect Inductive Trigger Switch) settings
for the left and right mouse buttons.
Capabilities (function 0x00):
Byte 0: Flags
Byte 1: Button count (3, but only 0 and 1 are accessible)
Byte 2: Max actuation value (40)
Byte 3: Max rapid trigger value (20)
Byte 4: Max haptics value (20)
Read button settings (function 0x20, param: button_index):
Response: [button_index, actuation, rapid_trigger, haptics, ...]
- actuation: 4-40 (quantized to multiples of 4)
- rapid_trigger: 1-20 (cannot be set to 0)
- haptics: 0-20 (quantized to multiples of 4: 0, 4, 8, 12, 16, 20)
Write button settings (function 0x10):
Params: [button_index, actuation, rapid_trigger, haptics]
Solaar Settings:
- superstrike-tuning_actuation-{0,1}: Range 1-10 (maps to device 4-40)
- superstrike-tuning_rapid-trigger-level-{0,1}: Range 1-5 (maps to device 1-20)
- superstrike-tuning_haptics-{0,1}: Range 0-5 (maps to device 0-20)
Note: Feature 0x80E0 (unknown:80E0) appears to be a non-functional stub for haptics.
Haptics are actually controlled via byte 3 of the SUPERSTRIKE TUNING feature.
Note: Feature 0x9403 (unknown:9403) appears to be a hidden BHOP (bunny hop) feature
that is not accessible via HID++.

View File

@ -33,6 +33,7 @@ Feature | ID | Status | Notes
`UNIFIED_BATTERY` | `0x1004` | Supported | `get_battery`, read only `UNIFIED_BATTERY` | `0x1004` | Supported | `get_battery`, read only
`CHARGING_CONTROL` | `0x1010` | Unsupported | `CHARGING_CONTROL` | `0x1010` | Unsupported |
`LED_CONTROL` | `0x1300` | Unsupported | `LED_CONTROL` | `0x1300` | Unsupported |
`FORCE_PAIRING` | `0x1500` | Unsupported |
`GENERIC_TEST` | `0x1800` | Unsupported | `GENERIC_TEST` | `0x1800` | Unsupported |
`DEVICE_RESET` | `0x1802` | Unsupported | `DEVICE_RESET` | `0x1802` | Unsupported |
`OOBSTATE` | `0x1805` | Unsupported | `OOBSTATE` | `0x1805` | Unsupported |
@ -49,6 +50,7 @@ Feature | ID | Status | Notes
`REPROG_CONTROLS_V2_2` | `0x1B02` | Unsupported | `REPROG_CONTROLS_V2_2` | `0x1B02` | Unsupported |
`REPROG_CONTROLS_V3` | `0x1B03` | Unsupported | `REPROG_CONTROLS_V3` | `0x1B03` | Unsupported |
`REPROG_CONTROLS_V4` | `0x1B04` | Partial Support | `ReprogrammableKeys`, `DivertKeys`, `MouseGesture`, `get_keys` `REPROG_CONTROLS_V4` | `0x1B04` | Partial Support | `ReprogrammableKeys`, `DivertKeys`, `MouseGesture`, `get_keys`
`SUPERSTRIKE_TUNING` | `0x1B0C` | Supported | `SuperstrikeTuning` (actuation point, rapid trigger, click haptics)
`REPORT_HID_USAGE` | `0x1BC0` | Unsupported | `REPORT_HID_USAGE` | `0x1BC0` | Unsupported |
`PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | Supported | `PersistentRemappableAction` `PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | Supported | `PersistentRemappableAction`
`WIRELESS_DEVICE_STATUS` | `0x1D4B` | Read only | status reporting from device `WIRELESS_DEVICE_STATUS` | `0x1D4B` | Read only | status reporting from device
@ -67,9 +69,12 @@ Feature | ID | Status | Notes
`THUMB_WHEEL` | `0x2150` | Supported | `ThumbMode`, `ThumbInvert` `THUMB_WHEEL` | `0x2150` | Supported | `ThumbMode`, `ThumbInvert`
`MOUSE_POINTER` | `0x2200` | Supported | `get_mouse_pointer_info`, read only `MOUSE_POINTER` | `0x2200` | Supported | `get_mouse_pointer_info`, read only
`ADJUSTABLE_DPI` | `0x2201` | Supported | `AdjustableDpi`, `DpiSliding` `ADJUSTABLE_DPI` | `0x2201` | Supported | `AdjustableDpi`, `DpiSliding`
`EXTENDED_ADJUSTABLE_DPI` | `0x2202` | Supported | `ExtendedAdjustableDpi` (X/Y DPI + lift-off distance)
`POINTER_SPEED` | `0x2205` | Supported | `PointerSpeed`, `SpeedChange`, `get_pointer_speed_info` `POINTER_SPEED` | `0x2205` | Supported | `PointerSpeed`, `SpeedChange`, `get_pointer_speed_info`
`ANGLE_SNAPPING` | `0x2230` | Unsupported | `ANGLE_SNAPPING` | `0x2230` | Unsupported |
`SURFACE_TUNING` | `0x2240` | Unsupported | `SURFACE_TUNING` | `0x2240` | Unsupported |
`XY_STATS` | `0x2250` | Unsupported |
`WHEEL_STATS` | `0x2251` | Unsupported |
`HYBRID_TRACKING` | `0x2400` | Unsupported | `HYBRID_TRACKING` | `0x2400` | Unsupported |
`FN_INVERSION` | `0x40A0` | Supported | `FnSwap` `FN_INVERSION` | `0x40A0` | Supported | `FnSwap`
`NEW_FN_INVERSION` | `0x40A2` | Supported | `NewFnSwap`, `get_new_fn_inversion `NEW_FN_INVERSION` | `0x40A2` | Supported | `NewFnSwap`, `get_new_fn_inversion
@ -101,6 +106,7 @@ Feature | ID | Status | Notes
`MR` | `0x8030` | Supported | `MRKeyLED` `MR` | `0x8030` | Supported | `MRKeyLED`
`BRIGHTNESS_CONTROL` | `0x8040` | Supported | `BrightnessControl` `BRIGHTNESS_CONTROL` | `0x8040` | Supported | `BrightnessControl`
`REPORT_RATE` | `0x8060` | Supported | `ReportRate` `REPORT_RATE` | `0x8060` | Supported | `ReportRate`
`EXTENDED_ADJUSTABLE_REPORT_RATE` | `0x8061` | Supported | `report_rate_extended` (sub-millisecond polling up to 8000 Hz)
`COLOR_LED_EFFECTS` | `0x8070` | Supported | `LEDControl`, `LEDZoneSetting` `COLOR_LED_EFFECTS` | `0x8070` | Supported | `LEDControl`, `LEDZoneSetting`
`RGB_EFFECTS` | `0X8071` | Supported | `RGBControl`, `RGBEffectSetting` `RGB_EFFECTS` | `0X8071` | Supported | `RGBControl`, `RGBEffectSetting`
`PER_KEY_LIGHTING` | `0x8080` | Unsupported | `PER_KEY_LIGHTING` | `0x8080` | Unsupported |

View File

@ -76,6 +76,7 @@ class SupportedFeature(IntEnum):
REPROG_CONTROLS_V2_2 = 0x1B02 # LogiOptions 2.10.73 features.xml REPROG_CONTROLS_V2_2 = 0x1B02 # LogiOptions 2.10.73 features.xml
REPROG_CONTROLS_V3 = 0x1B03 REPROG_CONTROLS_V3 = 0x1B03
REPROG_CONTROLS_V4 = 0x1B04 REPROG_CONTROLS_V4 = 0x1B04
ANALOG_BUTTONS = 0x1B0C # Analog button tuning (actuation point, rapid trigger, haptics)
FULL_KEY_CUSTOMIZATION = 0x1B05 FULL_KEY_CUSTOMIZATION = 0x1B05
CONTROL_LIST = 0x1B10 CONTROL_LIST = 0x1B10
SWITCH_SWAPABILITY = 0x1B20 SWITCH_SWAPABILITY = 0x1B20

View File

@ -1055,10 +1055,15 @@ class ExtendedAdjustableDpi(settings.Setting):
keys = common.NamedInts(X=0, Y=1, LOD=2) keys = common.NamedInts(X=0, Y=1, LOD=2)
def write_key_value(self, key, value, save=True): def write_key_value(self, key, value, save=True):
# Force a read to populate the full X/Y/LOD dictionary if it's missing (fixes CLI)
if not isinstance(self._value, dict):
self.read()
if isinstance(self._value, dict): if isinstance(self._value, dict):
self._value[key] = value self._value[key] = value
else: else:
self._value = {key: value} self._value = {key: value}
result = self.write(self._value, save) result = self.write(self._value, save)
return result[key] if isinstance(result, dict) else result return result[key] if isinstance(result, dict) else result
@ -1809,6 +1814,126 @@ class ForceSensing(settings_new.Settings):
return setting return setting
# Analog button tuning settings (actuation point, rapid trigger, haptics)
class _AnalogButtonActuationRW(settings.FeatureRW):
"""RW for analog button actuation point per button."""
def __init__(self, feature, button_index):
super().__init__(feature, read_fnid=0x20, write_fnid=0x10)
self.button_index = button_index
def read(self, device, data_bytes=b""):
res = device.feature_request(self.feature, 0x20, self.button_index)
if not res:
return b"\x14" # default mid-point
return bytes([res[1]])
def write(self, device, data_bytes):
current = device.feature_request(self.feature, 0x20, self.button_index)
if not current:
return None
return device.feature_request(self.feature, 0x10, self.button_index, data_bytes[0], current[2], current[3])
class _AnalogButtonRapidTriggerRW(settings.FeatureRW):
"""RW for analog button rapid trigger sensitivity per button."""
def __init__(self, feature, button_index):
super().__init__(feature, read_fnid=0x20, write_fnid=0x10)
self.button_index = button_index
def read(self, device, data_bytes=b""):
res = device.feature_request(self.feature, 0x20, self.button_index)
if not res:
return b"\x0a" # default mid-point
return bytes([res[2]])
def write(self, device, data_bytes):
current = device.feature_request(self.feature, 0x20, self.button_index)
if not current:
return None
return device.feature_request(self.feature, 0x10, self.button_index, current[1], data_bytes[0], current[3])
class _AnalogButtonHapticsRW(settings.FeatureRW):
"""RW for analog button click haptics per button."""
def __init__(self, feature, button_index):
super().__init__(feature, read_fnid=0x20, write_fnid=0x10)
self.button_index = button_index
def read(self, device, data_bytes=b""):
res = device.feature_request(self.feature, 0x20, self.button_index)
if not res:
return b"\x0a" # default mid-point
return bytes([res[3]])
def write(self, device, data_bytes):
current = device.feature_request(self.feature, 0x20, self.button_index)
if not current:
return None
return device.feature_request(self.feature, 0x10, self.button_index, current[1], current[2], data_bytes[0])
class AnalogButtonTuning(settings.Setting):
"""Analog button tuning: actuation point, rapid trigger, and haptics configuration."""
name = "analog-button-tuning"
label = _("Analog Button Tuning")
description = _("Configure analog button settings including actuation point, rapid trigger, and haptics.")
feature = _F.ANALOG_BUTTONS
@classmethod
def build(cls, device):
if cls.feature not in device.features:
return None
# Get capabilities: [flags, button_count, max_actuation, max_rt, max_haptics, ...]
caps = device.feature_request(cls.feature, 0x00)
if not caps or len(caps) < 5:
return None
button_count = min(caps[1], 2) # Byte 1 is button count, limit to 2 (left/right)
max_actuation = caps[2] if caps[2] > 0 else 40 # Byte 2 is max actuation
max_rt_level = caps[3] if caps[3] > 0 else 20 # Byte 3 is max RT level
max_haptics = caps[4] if caps[4] > 0 else 20 # Byte 4 is max haptics
if button_count == 0:
return None
button_names = [_("Left Button"), _("Right Button")]
all_settings = []
for i in range(button_count):
btn_name = button_names[i] if i < len(button_names) else f"Button {i}"
rw_act = _AnalogButtonActuationRW(cls.feature, i)
val_act = settings_validator.RangeValidator(min_value=1, max_value=max_actuation)
s_act = settings.Setting(device, rw_act, val_act)
s_act.name = f"analog-button-tuning_actuation-{i}"
s_act.label = f"{btn_name} Actuation Point"
s_act.description = _("Actuation point depth (raw device value).")
all_settings.append(s_act)
rw_rt = _AnalogButtonRapidTriggerRW(cls.feature, i)
val_rt = settings_validator.RangeValidator(min_value=1, max_value=max_rt_level)
s_rt = settings.Setting(device, rw_rt, val_rt)
s_rt.name = f"analog-button-tuning_rapid-trigger-{i}"
s_rt.label = f"{btn_name} Rapid Trigger"
s_rt.description = _("Rapid trigger sensitivity (raw device value).")
all_settings.append(s_rt)
rw_haptics = _AnalogButtonHapticsRW(cls.feature, i)
val_haptics = settings_validator.RangeValidator(min_value=0, max_value=max_haptics)
s_haptics = settings.Setting(device, rw_haptics, val_haptics)
s_haptics.name = f"analog-button-tuning_haptics-{i}"
s_haptics.label = f"{btn_name} Click Haptics"
s_haptics.description = _("Click haptic feedback intensity (raw device value, 0=off).")
all_settings.append(s_haptics)
return all_settings if all_settings else None
class HapticLevel(settings.Setting): class HapticLevel(settings.Setting):
name = "haptic-level" name = "haptic-level"
label = _("Haptic Feedback Level") label = _("Haptic Feedback Level")
@ -1932,6 +2057,7 @@ SETTINGS: list[settings.Setting] = [
Gesture2Gestures, # working Gesture2Gestures, # working
Gesture2Divert, Gesture2Divert,
Gesture2Params, # working Gesture2Params, # working
AnalogButtonTuning,
HapticLevel, HapticLevel,
PlayHapticWaveForm, PlayHapticWaveForm,
Sidetone, Sidetone,