Skip to content

Commit

Permalink
Added --output option
Browse files Browse the repository at this point in the history
Ability to output in JSON, YAML, ENV

* Deprecated short output (was also not really consistent and has a weird format)
* Simplified adding a device in device_registry.c
* Added a test device with --test-device
* Reworked main.c:
    * Print device table as markdown using --readme-helper
    * When a device is connected, help now only shows commands for this device
    * Added --help-all
    * Removed all output from main.c
    * Reworked logic for calling device features
  • Loading branch information
Sapd committed Feb 20, 2024
1 parent 464a12a commit 3ba8f0d
Show file tree
Hide file tree
Showing 15 changed files with 1,589 additions and 330 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
build/
src/version.h

.idea/
cmake-build-debug/
.codechecker/

.vscode/*
*.code-workspace
Expand Down
19 changes: 18 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# ------------------------------------------------------------------------------
# Git version
# ------------------------------------------------------------------------------

execute_process(
COMMAND git describe --tags --dirty=-modified
OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Configure a header file to pass the version number to the source code
configure_file(
"${PROJECT_SOURCE_DIR}/src/version.h.in"
"${PROJECT_SOURCE_DIR}/src/version.h"
@ONLY
)

# ------------------------------------------------------------------------------
# Clang format
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -143,7 +160,7 @@ include (CTest)
## Simple test wether we can run the application (should basic hidapi functions, like enumerate, work)
enable_testing()
add_test(run_test headsetcontrol)
set_tests_properties(run_test PROPERTIES PASS_REGULAR_EXPRESSION "No supported headset found")
set_tests_properties(run_test PROPERTIES PASS_REGULAR_EXPRESSION "No supported device found;Found")
# use make check to compile+test
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
DEPENDS headsetcontrol)
150 changes: 62 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,31 @@ talking. This differs from a simple loopback via PulseAudio as you won't have an

## Supported Headsets

- HyperX Cloud Alpha Wireless
- Battery, Inactive time, Sidetone, Voice Prompts (only tested on Linux)
- HyperX Cloud Flight Wireless
- Battery only (only tested on Linux)
- Corsair **Void** (Most void-versions*)
- Sidetone, Battery (for Wireless), LED on/off, Notification Sound
- Logitech G430
- No support in current version (Last working on macOS in commit 41be99379f)
- Logitech G432
- Sidetone (only tested on Linux)
- Logitech G433
- Sidetone (only tested on Linux)
- Logitech G533
- Sidetone, Battery (for Wireless)
- Logitech G535
- Sidetone, Battery, Inactive time (only tested on Linux)
- Logitech G633 / G635 / G733 / G933 / G935
- Sidetone, Battery (for Wireless), LED on/off
- Logitech G930
- Sidetone, Battery
- SteelSeries Arctis 1, Arctis 1 for XBox
- Sidetone, Battery, Inactive time
- SteelSeries Arctis Nova 3
- Sidetone, Equalizer Presets, Equalizer, Microphone Mute LED Brightness, Microphone Volume
- SteelSeries Arctis (7 and Pro)
- Sidetone, Battery, Inactive time, Chat-Mix level, LED on/off (allows to turn off the blinking LED on the base-station)
- SteelSeries Arctis 7+
- Sidetone, Battery, Chat-Mix level, Inactive time, Equalizer Presets, Equalizer
- SteelSeries Arctis Nova 7
- Sidetone, Battery, Chat-Mix level, Inactive time, Equalizer Presets, Equalizer
- SteelSeries Arctis 9
- Sidetone, Battery, Inactive time, Chat-Mix level
- SteelSeries Arctis Pro Wireless
- Sidetone, Battery, Inactive time
- SteelSeries Arctis Nova Pro Wireless
- Sidetone, Battery, Inactive time
- Logitech G PRO
- Sidetone, Battery, Inactive time
- Logitech G PRO X 2
- Sidetone, Inactive time
- Logitech Zone Wired/Zone 750
- Sidetone, Voice prompts, Rotate to mute
- Roccat Elo 7.1 Air
- LED on/off, Inactive time (Note for Linux: Sidetone is handled by sound driver => use AlsaMixer)
| Device | sidetone | battery | notification sound | lights | inactive time | chatmix | voice prompts | rotate to mute | equalizer preset | equalizer | microphone mute led brightness | microphone volume |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Corsair Headset Device | x | x | x | x | | | | | | | | |
| HyperX Cloud Alpha Wireless | x | x | | | x | | x | | | | | |
| HyperX Cloud Flight Wireless | | x | | | | | | | | | | |
| Logitech G430 | x | | | | | | | | | | | |
| Logitech G432/G433 | x | | | | | | | | | | | |
| Logitech G533 | x | x | | | x | | | | | | | |
| Logitech G535 | x | x | | | x | | | | | | | |
| Logitech G930 | x | x | | | | | | | | | | |
| Logitech G633/G635/G733/G933/G935 | x | x | | x | | | | | | | | |
| Logitech G PRO Series | x | x | | | x | | | | | | | |
| Logitech G PRO X 2 | x | | | | x | | | | | | | |
| Logitech Zone Wired/Zone 750 | x | | | | | | x | x | | | | |
| SteelSeries Arctis (1/7X) Wireless | x | x | | | x | | | | | | | |
| SteelSeries Arctis (7/Pro) | x | x | | x | x | x | | | | | | |
| SteelSeries Arctis 9 | x | x | | | x | x | | | | | | |
| SteelSeries Arctis Pro Wireless | x | x | | | x | | | | | | | |
| ROCCAT Elo 7.1 Air | | | | x | x | | | | | | | |
| ROCCAT Elo 7.1 USB | | | | x | | | | | | | | |
| SteelSeries Arctis Nova 3 | x | | | | | | | | x | x | x | x |
| SteelSeries Arctis Nova 7 | x | x | | | x | x | | | x | x | | |
| SteelSeries Arctis 7+ | x | x | | | x | x | | | x | x | | |
| SteelSeries Arctis Nova Pro Wireless | x | x | | x | x | | | | x | x | | |
| HeadsetControl Test device | x | x | x | x | x | x | x | x | x | x | x | x |

For non-supported headsets on Linux: There is a chance that you can set the sidetone via AlsaMixer

Expand All @@ -66,16 +47,17 @@ Some headsets expose sidetone as audio-channel volume and as such can be changed

### Prerequisites

You will need hidapi, c compilers and cmake. All usually installable via package managers.
Before building, ensure you have the necessary dependencies installed, including HIDAPI, C compilers, and CMake. These dependencies can usually be installed via your system's package manager.

#### Debian / Ubuntu

`apt-get install build-essential git cmake libhidapi-dev`

#### CentOS / RHEL (RedHat based)

RHEL and CentOS also require the epel-repository: `yum install epel-release`. Please inform yourself about the consequences of activating the epel-repository.
RHEL and CentOS also require the epel-repository.

`yum install epel-release`
`yum groupinstall "Development tools"`
`yum install git cmake hidapi-devel`

Expand Down Expand Up @@ -106,18 +88,19 @@ RHEL and CentOS also require the epel-repository: `yum install epel-release`. Pl

#### Mac OS X

I recommend using [Homebrew](https://brew.sh).
Recommendation: Use [Homebrew](https://brew.sh).

You can automatically compile and install the latest version of the software, by using
`brew install sapd/headsetcontrol/headsetcontrol --HEAD`.
* To automatically compile and install the latest version:
`brew install sapd/headsetcontrol/headsetcontrol --HEAD`
* To manually compile, first install the dependencies:
`brew install hidapi cmake`

If you wish to compile it manually, you can install the dependencies with `brew install hidapi cmake`.

Also you have to download Xcode via the Mac App Store for the compilers.
Note: Xcode must be downloaded via the Mac App Store for the compilers.

#### Windows

Windows support is a bit experimental and might not work in all cases. You can find binaries in the [releases](https://github.com/Sapd/HeadsetControl/releases) page, or compile instructions via MSYS2/MinGW in the [wiki](https://github.com/Sapd/HeadsetControl/wiki/Development#windows).
* Binaries are available on the [releases](https://github.com/Sapd/HeadsetControl/releases) page.
* For compilation instructions using MSYS2/MinGW refer to the [wiki](https://github.com/Sapd/HeadsetControl/wiki/Development#windows).

### Compiling

Expand All @@ -128,58 +111,49 @@ cmake ..
make
```

If you want to be able to call HeadsetControl from every folder type:
To make `headsetcontrol` accessible globally, run:

```bash
make install
sudo make install
```

This will copy the binary to a folder globally accessible via path.

### Access without root

Also in Linux, you need udev rules if you don't want to start the application with root. Those rules are generated via `headsetcontrol -u`. Typing `make install` on Linux generates and writes them automatically to /etc/udev/rules.d/.

You can reload udev configuration without reboot via `sudo udevadm control --reload-rules && sudo udevadm trigger`

## Usage

Type `headsetcontrol -h` to get all available options.\
(Don't forget to prefix it with `./` when the application resides in the current folder)

Type `headsetcontrol -?` to get a list of supported capabilities for the currently detected headset.

`headsetcontrol -s 128` sets the sidetone to 128 (REAL loud). You can silence it with `0`. I recommend a loudness of 16.

The following options don't work on all devices yet:

`headsetcontrol -b` check battery level. Returns a value from 0 to 100 or loading.
This command installs the binary in a location that is globally accessible via your system's PATH.

`headsetcontrol -n 0|1` sends a notification sound, made by the headset. 0 or 1 are currently supported as values.
### Access Without Root (Linux only)

`headsetcontrol -l 0|1` switches LED off/on (off almost doubles battery lifetime!).
To use the application without root privileges on Linux, udev rules are required. These can be generated with:

`headsetcontrol --short-output` cut unnecessary output, for reading by other scripts or applications.
```bash
headsetcontrol -u
```

`headsetcontrol -i 0-90` sets inactive time in minutes, time must be between 0 and 90, 0 disables the feature.
Running `sudo make install` will automatically generate and write these rules to /etc/udev/rules.d/. To apply the changes without rebooting, reload udev configuration:

`headsetcontrol -m` retrieves the current chat-mix-dial level setting between 0 and 128. Below 64 is the game side and above is the chat side.
```bash
sudo udevadm control --reload-rules && sudo udevadm trigger
```

`headsetcontrol -v 0|1` turn voice prompts on or off.
## Usage

`headsetcontrol -r 0|1` turn rotate to mute feature on or off.
To view available options for your device, use:

`headsetcontrol -u` Generates and outputs udev-rules for Linux.
```bash
headsetcontrol -h
```

`headsetcontrol --dev` Advanced menu for developers, to send and/or receive custom data
For a complete list of all options, run:

`headsetcontrol -p 0-3` sets equalizer preset, must be between 0 and 3, 0 is the default preset.
```bash
headsetcontrol --help-all
```

`headsetcontrol -e string` sets equalizer to specified curve, string must contain band values specific to the device (hex or decimal) delimited by spaces, or commas, or new-lines e.g "0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18".
To use headsetcontrol in scripts or other applications, explore:

##### Modifiers
```bash
headsetcontrol --output
```

`--timeout 5000` Specifies a timeout for read-operations in milliseconds. Default is 5 seconds, 0 disables timeout.
Note: When running the application from the current directory, prefix commands with `./`

### Third Party

Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ set(SOURCE_FILES ${SOURCE_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/device_registry.h
${CMAKE_CURRENT_SOURCE_DIR}/hid_utility.c
${CMAKE_CURRENT_SOURCE_DIR}/hid_utility.h
${CMAKE_CURRENT_SOURCE_DIR}/output.c
${CMAKE_CURRENT_SOURCE_DIR}/output.h
${CMAKE_CURRENT_SOURCE_DIR}/utility.c
${CMAKE_CURRENT_SOURCE_DIR}/utility.h
PARENT_SCOPE)
18 changes: 17 additions & 1 deletion src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const char* const capabilities_str[NUM_CAPABILITIES]
= {
[CAP_SIDETONE] = "sidetone",
[CAP_BATTERY_STATUS] = "battery status",
[CAP_BATTERY_STATUS] = "battery",
[CAP_NOTIFICATION_SOUND] = "notification sound",
[CAP_LIGHTS] = "lights",
[CAP_INACTIVE_TIME] = "inactive time",
Expand All @@ -16,6 +16,22 @@ const char* const capabilities_str[NUM_CAPABILITIES]
[CAP_MICROPHONE_VOLUME] = "microphone volume"
};

const char* const capabilities_str_enum[NUM_CAPABILITIES]
= {
[CAP_SIDETONE] = "CAP_SIDETONE",
[CAP_BATTERY_STATUS] = "CAP_BATTERY_STATUS",
[CAP_NOTIFICATION_SOUND] = "CAP_NOTIFICATION_SOUND",
[CAP_LIGHTS] = "CAP_LIGHTS",
[CAP_INACTIVE_TIME] = "CAP_INACTIVE_TIME",
[CAP_CHATMIX_STATUS] = "CAP_CHATMIX_STATUS",
[CAP_VOICE_PROMPTS] = "CAP_VOICE_PROMPTS",
[CAP_ROTATE_TO_MUTE] = "CAP_ROTATE_TO_MUTE",
[CAP_EQUALIZER_PRESET] = "CAP_EQUALIZER_PRESET",
[CAP_EQUALIZER] = "CAP_EQUALIZER",
[CAP_MICROPHONE_MUTE_LED_BRIGHTNESS] = "CAP_MICROPHONE_MUTE_LED_BRIGHTNESS",
[CAP_MICROPHONE_VOLUME] = "CAP_MICROPHONE_VOLUME"
};

const char capabilities_str_short[NUM_CAPABILITIES]
= {
[CAP_SIDETONE] = 's',
Expand Down
49 changes: 47 additions & 2 deletions src/device.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
#pragma once

#include <hidapi.h>
#include <stdbool.h>
#include <stdint.h>

#define VENDOR_CORSAIR 0x1b1c
#define VENDOR_LOGITECH 0x046d
#define VENDOR_STEELSERIES 0x1038
#define VENDOR_ROCCAT 0x1e7d

#define VENDOR_TESTDEVICE 0xF00B
#define PRODUCT_TESTDEVICE 0xA00C

/// Convert given number to bitmask
#define B(X) (1 << X)

Expand Down Expand Up @@ -35,10 +39,22 @@ enum capabilities {
NUM_CAPABILITIES
};

enum capabilitytype {
CAPABILITYTYPE_ACTION,
CAPABILITYTYPE_INFO
};

/// Long name of every capability
extern const char* const capabilities_str[NUM_CAPABILITIES];
/// Short name of every capability
/// Short name of every capability (deprecated)
extern const char capabilities_str_short[NUM_CAPABILITIES];
/// Enum name of every capability
extern const char* const capabilities_str_enum[NUM_CAPABILITIES];

static inline bool has_capability(int device_capabilities, enum capabilities cap)
{
return (device_capabilities & B(cap)) == B(cap);
}

struct capability_detail {
// Usage page, only used when usageid is not 0; HID Protocol specific
Expand All @@ -53,7 +69,8 @@ struct capability_detail {
*/
enum battery_status {
BATTERY_UNAVAILABLE = 65534,
BATTERY_CHARGING = 65535
BATTERY_CHARGING = 65535,
BATTERY_AVAILABLE = 65500,
};

enum headsetcontrol_errors {
Expand All @@ -62,6 +79,31 @@ enum headsetcontrol_errors {
HSC_OUT_OF_BOUNDS = -102,
};

typedef enum {
FEATURE_SUCCESS,
FEATURE_ERROR,
FEATURE_DEVICE_FAILED_OPEN,
FEATURE_INFO, // For non-error, informational states like "charging"
FEATURE_NOT_PROCESSED
} FeatureStatus;

typedef struct {
FeatureStatus status;
/// Can hold battery level, error codes, or special status codes
int value;
/// For error messages, "Charging", "Unavailable", etc. Should be free()d after use
char* message;
} FeatureResult;

typedef struct {
enum capabilities cap;
enum capabilitytype type;
void* param;
bool should_process;
FeatureResult result;
const char* name;
} FeatureRequest;

/** @brief Defines equalizer custom setings
*/
struct equalizer_settings {
Expand All @@ -88,6 +130,9 @@ struct device {
/// Name of device, used as information for the user
char device_name[64];

wchar_t device_hid_vendorname[64];
wchar_t device_hid_productname[64];

/// Bitmask of currently supported features the software can currently handle
int capabilities;
/// Details of all capabilities (e.g. to which interface to connect)
Expand Down
Loading

0 comments on commit 3ba8f0d

Please sign in to comment.