From ea0ced003b3bb2d4fb48092223b247c1adbe0cf8 Mon Sep 17 00:00:00 2001 From: simyrik Date: Fri, 12 Dec 2025 12:02:52 +0700 Subject: [PATCH 1/4] Add support for HyperX Cloud Flight S - Add PRODUCT_ID 0x16EA to Cloud II Wireless device support - Cloud Flight S uses the same protocol as Cloud II Wireless - Update README.md with Cloud Flight S in supported devices list - Add udev rules for Cloud Flight S (idProduct=16ea) - Fix prepare_write() to handle devices that don't support get_input_report - Fix is_none_or compatibility issue for older Rust versions --- 99-HyperHeadset.rules | 13 +++++++++++++ README.md | 11 +++++++---- hyper-headset.desktop | 10 ++++++++++ src/devices/cloud_ii_wireless.rs | 13 ++++++++----- src/devices/mod.rs | 4 ++-- 5 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 99-HyperHeadset.rules create mode 100644 hyper-headset.desktop diff --git a/99-HyperHeadset.rules b/99-HyperHeadset.rules new file mode 100644 index 0000000..cbe4003 --- /dev/null +++ b/99-HyperHeadset.rules @@ -0,0 +1,13 @@ +SUBSYSTEMS=="usb", ATTRS{idProduct}=="018b", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" + +KERNEL=="hidraw*", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="018b", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" diff --git a/README.md b/README.md index 6af7510..c10a7fc 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ A CLI and tray application for monitoring and managing HyperX headsets. This project is not affiliated with, endorsed by, or associated with HyperX or its parent company in any way. All trademarks and brand names belong to their respective owners. ## Compatibility -The CLI application is compatible with both Linux and MacOS operating systems. -However, the tray application is only functional on Linux. +The CLI application is compatible with both Linux and MacOS operating systems. +However, the tray application is only functional on Linux. Although it was only tested on Manjaro and Kubuntu with KDE, it should also work on other distribution and desktop environments. **Supported Headsets**: - HyperX Cloud II Wireless HP vendorID - HyperX Cloud II Wireless HyperX vendorID - HyperX Cloud III Wireless -- HyperX Cloud Stinger 2 Wireless +- HyperX Cloud Stinger 2 Wireless +- HyperX Cloud Flight S It should be possible to add support for other HyperX headsets. @@ -62,12 +63,14 @@ SUBSYSTEMS=="usb", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666 SUBSYSTEMS=="usb", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="018b", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" ``` Once created, replug the wireless dongle. @@ -132,7 +135,7 @@ Options: ``` `hyper_headset` without any arguments will start the tray application with a 3s refresh interval. -Once it's open, hover over the headset icon in the system tray or right-click to view details such as the battery level. +Once it's open, hover over the headset icon in the system tray or right-click to view details such as the battery level. You can also exit via the right-clock menu. ## Contributing / TODOs diff --git a/hyper-headset.desktop b/hyper-headset.desktop new file mode 100644 index 0000000..439c2ed --- /dev/null +++ b/hyper-headset.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=HyperHeadset +Comment=Monitor and manage HyperX headsets +Exec=/usr/local/bin/hyper_headset +Icon=audio-card +Terminal=false +Categories=AudioVideo;Audio; +StartupNotify=false +X-GNOME-Autostart-enabled=true diff --git a/src/devices/cloud_ii_wireless.rs b/src/devices/cloud_ii_wireless.rs index f03ac09..4075b76 100644 --- a/src/devices/cloud_ii_wireless.rs +++ b/src/devices/cloud_ii_wireless.rs @@ -6,8 +6,8 @@ use std::time::Duration; const HYPERX: u16 = 0x0951; pub const VENDOR_IDS: [u16; 1] = [HYPERX]; -// Possible Cloud II Wireless product IDs -pub const PRODUCT_IDS: [u16; 3] = [0x1718, 0x018B, 0x0b92]; +// Possible Cloud II Wireless product IDs (and Cloud Flight S) +pub const PRODUCT_IDS: [u16; 4] = [0x1718, 0x018B, 0x0b92, 0x16EA]; const BASE_PACKET: [u8; 62] = { let mut tmp = [0u8; 62]; @@ -266,12 +266,15 @@ impl Device for CloudIIWireless { } fn prepare_write(&mut self) { + // Attempt to read input report before writing + // This may not work for all devices (e.g., Cloud Flight S), + // so we ignore the error let mut input_report_buffer = [0u8; 64]; input_report_buffer[0] = 6; - self.state + let _ = self + .state .hid_device - .get_input_report(&mut input_report_buffer) - .unwrap(); + .get_input_report(&mut input_report_buffer); } fn allow_passive_refresh(&mut self) -> bool { diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 5ec756d..7a739c4 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -16,7 +16,7 @@ use thistermination::TerminationFull; // Possible vendor IDs [HyperX, HP] const VENDOR_IDS: [u16; 2] = [0x0951, 0x03F0]; // All supported product IDs -const PRODUCT_IDS: [u16; 6] = [0x1718, 0x018B, 0x0D93, 0x0696, 0x0b92, 0x05B7]; +const PRODUCT_IDS: [u16; 7] = [0x1718, 0x018B, 0x0D93, 0x0696, 0x0b92, 0x05B7, 0x16EA]; const RESPONSE_BUFFER_SIZE: usize = 256; const RESPONSE_DELAY: Duration = Duration::from_millis(50); @@ -518,7 +518,7 @@ pub trait Device { } responded = true; } - if !self.get_device_state().connected.is_none_or(|c| c) { + if !matches!(self.get_device_state().connected, Some(true)) { break; } } From 04d92ec44e61d1e2ed797976af0c2b28002cbfec Mon Sep 17 00:00:00 2001 From: Marius Gehrmann Date: Sat, 3 Jan 2026 09:49:09 +0100 Subject: [PATCH 2/4] Add additional product ID for Cloud III Wireless --- README.md | 2 ++ src/devices/cloud_iii_wireless.rs | 2 +- src/devices/mod.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6af7510..e116c49 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,14 @@ SUBSYSTEMS=="usb", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666 SUBSYSTEMS=="usb", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="0c9d", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="018b", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="0c9d", ATTRS{idVendor}=="03f0", MODE="0666" ``` Once created, replug the wireless dongle. diff --git a/src/devices/cloud_iii_wireless.rs b/src/devices/cloud_iii_wireless.rs index b9c1bd2..07629da 100644 --- a/src/devices/cloud_iii_wireless.rs +++ b/src/devices/cloud_iii_wireless.rs @@ -6,7 +6,7 @@ use std::{time::Duration, vec}; const HP: u16 = 0x03F0; pub const VENDOR_IDS: [u16; 1] = [HP]; -pub const PRODUCT_IDS: [u16; 1] = [0x05B7]; +pub const PRODUCT_IDS: [u16; 2] = [0x05B7, 0x0c9d]; // Possible Cloud III Wireless product IDs const BASE_PACKET: [u8; 62] = { let mut packet = [0; 62]; diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 5ec756d..c0214c9 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -16,7 +16,7 @@ use thistermination::TerminationFull; // Possible vendor IDs [HyperX, HP] const VENDOR_IDS: [u16; 2] = [0x0951, 0x03F0]; // All supported product IDs -const PRODUCT_IDS: [u16; 6] = [0x1718, 0x018B, 0x0D93, 0x0696, 0x0b92, 0x05B7]; +const PRODUCT_IDS: [u16; 7] = [0x1718, 0x018B, 0x0D93, 0x0696, 0x0b92, 0x05B7, 0x0c9d]; const RESPONSE_BUFFER_SIZE: usize = 256; const RESPONSE_DELAY: Duration = Duration::from_millis(50); From a62929ce981e237ed466db61804e2f03f9be70d7 Mon Sep 17 00:00:00 2001 From: Matt Smith Date: Tue, 13 Jan 2026 22:22:38 -0500 Subject: [PATCH 3/4] Remove unnecessary clone --- src/status_tray.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/status_tray.rs b/src/status_tray.rs index 0d7de69..4e7e6e0 100644 --- a/src/status_tray.rs +++ b/src/status_tray.rs @@ -58,7 +58,6 @@ impl Tray for StatusTray { fn tool_tip(&self) -> ToolTip { let description = self .message - .clone() .lines() .filter(|l| !l.contains("Unknown")) .collect::>() From 194529528030c5dd7b2e4399bb214465d816e860 Mon Sep 17 00:00:00 2001 From: Lennard Kittner Date: Fri, 16 Jan 2026 17:26:53 +0100 Subject: [PATCH 4/4] Add rule for new USB device 0c9d:03f0 Added new USB device rule for idProduct 0c9d and idVendor 03f0. --- 99-HyperHeadset.rules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/99-HyperHeadset.rules b/99-HyperHeadset.rules index cbe4003..08c889e 100644 --- a/99-HyperHeadset.rules +++ b/99-HyperHeadset.rules @@ -4,6 +4,7 @@ SUBSYSTEMS=="usb", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666 SUBSYSTEMS=="usb", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" SUBSYSTEMS=="usb", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" +SUBSYSTEMS=="usb", ATTRS{idProduct}=="0c9d", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="0d93", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="018b", ATTRS{idVendor}=="03f0", MODE="0666" @@ -11,3 +12,4 @@ KERNEL=="hidraw*", ATTRS{idProduct}=="0696", ATTRS{idVendor}=="03f0", MODE="0666 KERNEL=="hidraw*", ATTRS{idProduct}=="1718", ATTRS{idVendor}=="0951", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="05b7", ATTRS{idVendor}=="03f0", MODE="0666" KERNEL=="hidraw*", ATTRS{idProduct}=="16ea", ATTRS{idVendor}=="0951", MODE="0666" +KERNEL=="hidraw*", ATTRS{idProduct}=="0c9d", ATTRS{idVendor}=="03f0", MODE="0666"