Skip to content

feat(Hardware Support): Razer Tartarus Pro#518

Open
dripsnek wants to merge 1 commit into
ShadowBlip:mainfrom
dripsnek:razer_tartarus_pro
Open

feat(Hardware Support): Razer Tartarus Pro#518
dripsnek wants to merge 1 commit into
ShadowBlip:mainfrom
dripsnek:razer_tartarus_pro

Conversation

@dripsnek
Copy link
Copy Markdown

@dripsnek dripsnek commented Feb 11, 2026

This PR implements support for the Razer Tartarus Pro gaming keypad. To date I've not found anything which allows usage of the analog mode specific to this model under Linux. This aims to bridge that gap.

The need for a driver exists because analog mode generates vendor defined HID reports that contain the positional value of each key instead of events. These must be processed and mapped to input events and this seemed like a natural fit for InputPlumber to handle.

I think this device is the first of its kind for InputPlumber and assuming the project wishes to extend support to these peripherals, how to represent them from a profile perspective in my mind is the major piece of work to go.

The driver has two modes, basic and analog. Basic mode simply uses the Tartarus Pro in its power-up configuration as a regular keyboard/mouse hybrid and is configured as any other device. Analog mode requires commanding the Tartarus Pro. This can occur manually before starting InputPlumber or if using OpenRazer >=3.12.2 you can use driver_mode = True in your config file to the same effect. False will leave the device in basic mode.

This implementation takes full control of the hidraw (x3) and evdev nodes (x4) but passes through the last endpoint allowing lighting control software e.g. OpenRGB or Polychromatic to manage the RGB functions whilst InputPlumber is running.

The analog event handler is implemented using simple linear regressions on a small buffer* to drive a per-key state machine and supports the following:

  • User defined actuation points between 1.5mm** and 3.6mm depths
  • Dual-function keys
  • Retrigger*** with shared or separate upward and downward thresholds
  • Wooting-style continuous retrigger***

* The buffer depth of 5 was based on protocol analysis of fast key transitions from the device
** Quantization and implementation quirks label the minimum at 1.4mm but the Tartarus Pro marketing spec stands.
*** AKA Rapid Trigger from other vendors

Analog mode usage:

Analog mode parameters currently reside at 50-razer_tartarus_pro.yaml in the analogkeys mapping. There are 5 arrays of 20 values, each value left-to-right represents the numbered key on the Tartarus Pro in order, putting aside 0 indexing. All 20 keys have individual analog settings and these will apply to any loaded key binding profiles. Values are sanitised with a specific exception in place for zeroes. Analog parameters cannot be changed at runtime, a restart of InputPlumber is required to take effect.

Config Definition Limits Notes
primary_actuation Absolute depth value for actuation of first key bind 1.4 to 3.6mm in 0.1mm steps Cannot be disabled. A value of 0 will map to effectively 1.4mm. Key bindings are per basic mode, can be rebound using a profile
secondary_actuation Set to enable dual-function. Absolute depth value for actuation of second key bind 1.4 to 3.6mm in 0.1mm steps Default is disabled. Must be greater than primary_actuation to enable. Can be explicitly disabled by setting to 0, otherwise any invalid setting will be interpreted as disabled. Prevents usage of retrigger though a similar effect exists for the second actuation point due to how events are processed. Secondary bindings are mapped to fixed "phantom" keys which can be further customized via profile, see secondary_rebind.yaml
retrigger_reset_threshold Set to enable retrigger logic. Value reflects travel distance in mm to reset a key 0 to 2.1mm in 0.1mm steps Default is disabled. Automatically disabled when secondary_actuation is active. Can be explicitly disabled by setting to 0mm.
retrigger_trigger_threshold Complements retrigger_reset_threshold. Travel distance in mm to trigger a key after being reset 0 to 2.1mm in 0.1mm steps If this value is 0 then retrigger_reset_threshold will be used for this purpose. This variable exists in case separate reset and trigger thresholds are desired
continuous_retrigger Complements retrigger_reset_threshold. During retrigger ignore the primary_actuation value, continue until key reaches the top of travel String (Y/N) Default is N. Has no effect if retrigger_reset_threshold is disabled.

Limits to this PR:

  • No plans to include other types of analog events to this driver considering the recent issues surrounding Snap Tap.
  • No Hypershift or equivalent mode, I think that's more of a wider InputPlumber capability rather than something specific to a device driver.
  • The profile LEDs on the side of the Tartarus should eventually be supported by OpenRazer and changing their state is better managed by a profile front-end application rather than InputPlumber directly.
  • RGB support is already implemented by Polychromatic and OpenRGB.

Other topics influencing implementation, not necessarily impacting the path out of WIP:

  • Device details:
    Like a lot of products in this class it is possible to acquire the serial number, firmware revision and other such data from the device registers. This could be used to uniquely assign profiles to a specific device or implement quirks for a given firmware. Should this be incorporated?
  • Multi-instance support:
    The Tartarus Pro is a left-handed device but someone, somewhere will somehow find a way to use 2 of them. Should we embrace this or defend against it?

Assuming this type of device can be included, I propose the following to navigate out of WIP:

  • Decide to [keep basic mode] or refactor to only manage analog mode
  • Decide to keep num_enum crate or refactor impacted code (event.rs / driver.rs - handle_basic)
  • If keeping basic mode, feat: add mouse wheel support #514 merged to support scroll wheel remapping
  • Incorporate device profile support and remove hard coded settings
  • Return device to basic mode either on demand or if InputPlumber closes InputPlumber assumes device state is managed externally, no implementation required.
  • Write up device usage .md file at nominated location
  • Wire up analog event handler to the driver event vector
  • Test what happens when two devices are connected
  • Housekeeping prior to merge

Blockers:
#582 - As this impacts external applications managing device state

Copy link
Copy Markdown
Contributor

@pastaq pastaq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking so long to review. Overall I am impressed with the direction this is going. I do have a few concerns about a couple of the approaches, but we can discuss them below in each of the issues I raised.

Comment thread src/drivers/razer_tartarus_pro/driver.rs Outdated
Comment thread src/drivers/razer_tartarus_pro/driver.rs
Comment thread src/drivers/razer_tartarus_pro/driver.rs Outdated
Comment thread src/drivers/razer_tartarus_pro/driver.rs
Comment thread src/drivers/razer_tartarus_pro/driver.rs
Comment thread src/drivers/razer_tartarus_pro/driver.rs Outdated
Comment thread src/drivers/razer_tartarus_pro/driver.rs
Comment thread src/input/source/hidraw/razer_tartarus_pro.rs
Comment thread src/input/source/hidraw/razer_tartarus_pro.rs Outdated
Comment thread src/input/source/hidraw/razer_tartarus_pro.rs
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch from 18a2cee to 7dc77a8 Compare March 21, 2026 06:16
@dripsnek dripsnek requested a review from pastaq March 21, 2026 07:08
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch from 7dc77a8 to dad1e02 Compare April 4, 2026 06:25
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch 4 times, most recently from ec8d9eb to 556b36c Compare April 21, 2026 10:31
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch 2 times, most recently from 2aff43f to d0dc460 Compare May 12, 2026 11:40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file seems odd to me. The mappings are all 1-1. If the device is already populating native events (used for detection) with those values they will route to any target device that supports them. Can you explain what you were trying to accomplish here?

Copy link
Copy Markdown
Author

@dripsnek dripsnek May 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is more of a template to aid users in customizing keys bound to the secondary actuation should they use it as function of analog mode.

How this is intended to work is that during analog mode there are no HID scancodes to speak of, we have to create them in the driver based on what keydepth is seen during sampling and send that to the composite device. As per the analog mode description this driver supports primary and secondary actuation levels. The key associated with primary actuation takes its value from the scancode that is normally emitted from basic mode but we still need a unique value signify a secondary actuation, the Tartarus itself doesn't have much to offer on that front.

Take for example Tartarus key '01'; In basic mode this is mapped to ANSI numeric row 1 and that carries over to the primary actuation. When representing the second actuation, I picked the "unused" 'b' character as that's sequentially the first gap in the USB scancode list that the Tartarus emits, 'a' being mapped to Tartarus key '12' in firmware. Codes that are and aren't emitted from firmware are documented in razer_tartarus_pro/event.rs

Following on, 'b' in effect is used to signal to the composite device that this is "the secondary actuation of key '01'", not a literal 'b'. Though for the purposes of presenting an output having 'b' pulling double duty as the default value suffices. The profile exists to allow remapping as 'b' from the source (the output of the analog mode handler) has a fixed definition to the composite device which is compiled in, but may not be the key the user actually wants emitted when they press it. Changing the target representation provides this customization. This logic extends to the other keys, 'g' for key '02' and so on.

This seemed the most straight forward way to implement this functionality given the existing capability types, albeit with a very convenient amount of characters to map on the Tartarus. The profile being a 1-1 mapping is a consequence of really being a template, if the users are happy with the default mapping they can go without.

pub const VID: u16 = 0x1532;
pub const PID: u16 = 0x0244;

const ENDPOINT_1: i32 = 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be i32 for a specific reason? u8 seems more appropriate at a glance.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It compares against hidapi::DeviceInfo::interface_number which demands i32. Could always cast it but that may be complicating it. Originally in the match (line 203) these were direct values, but naming them makes it easier to read IMO. Happy to alter as required.

@pastaq
Copy link
Copy Markdown
Contributor

pastaq commented May 12, 2026

This it's starting to look pretty close to being ready. I'll take another look at it soon (the comments from today were pending for a while and I didn't realize I hadn't posted them yet)

Prior to moving this from WIP to ready, can you squash the commits into a single commit that follows our semantic versioning format? Something like:

feat (Hardware Support): Add Driver and Configuration Support for Razer Tararus Pro

- explanation of changes...

@dripsnek dripsnek force-pushed the razer_tartarus_pro branch from d0dc460 to 6438ad8 Compare May 13, 2026 10:10
@dripsnek dripsnek marked this pull request as ready for review May 14, 2026 21:44
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch from 6438ad8 to d8c7815 Compare May 16, 2026 02:56
…er Tararus Pro

- Supports analog mode functions: primary/secondary actuation & retrigger
- Configuration via device YAML, refer documentation
- Introduce num_enum 0.7.6 crate
@dripsnek dripsnek force-pushed the razer_tartarus_pro branch from d8c7815 to dc286fb Compare May 16, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants