# How the Fastfetch Gamepad Detection Module Works: Cross-Platform Controller Discovery

> Explore how Fastfetch's gamepad detection module works for cross-platform controller discovery. Learn about native APIs, serial numbers, and battery levels.

- Repository: [fastfetch-cli/fastfetch](https://github.com/fastfetch-cli/fastfetch)
- Tags: internals
- Published: 2026-03-30

---

**Fastfetch's gamepad detection module uses platform-specific native APIs to enumerate connected controllers, extracting serial numbers, human-readable names, and battery levels through a two-layer architecture consisting of low-level detection drivers and a high-level presentation formatter.**

The gamepad detection module in fastfetch-cli/fastfetch provides cross-platform controller discovery for Linux, Windows, macOS, and BSD systems. By abstracting OS-specific device enumeration APIs behind a unified `FFGamepadDevice` structure, the module delivers consistent gamepad information including battery status and hardware identifiers. This article examines the implementation details of the detection layer in `src/detection/gamepad/` and the presentation logic in [`src/modules/gamepad/gamepad.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/gamepad/gamepad.c).

## Architecture of the Gamepad Detection Module

The module follows a layered design that separates hardware detection from output formatting.

The **detection layer** consists of platform-specific implementations of `ffDetectGamepad` that populate an `FFlist` with `FFGamepadDevice` structures. Each device record contains three core fields: `serial` (hardware identifier string), `name` (human-readable label), and `battery` (percentage 0-100 or 0 if unknown).

The **presentation layer** in [`src/modules/gamepad/gamepad.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/gamepad/gamepad.c) filters detected devices according to user preferences and formats the final output string, handling battery percentage display types and indexing for multiple controllers.

## Platform-Specific Detection Implementations

### Linux: Sysfs Input Interface

On Linux, the detection logic resides in [`src/detection/gamepad/gamepad_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad_linux.c). The implementation scans `/sys/class/input/` for joystick devices matching the `jsX` pattern.

For each discovered device, the code constructs paths to read the controller name from `device/name` and attempts to locate battery information via `device/power_supply/*/capacity` or `_level` files. The `uniq` attribute provides the serial number.

```c
const char* ffDetectGamepad(FFlist* devices) {
    DIR* dirp = opendir("/sys/class/input/");               // [gamepad_linux.c#L66-L70]
    …
    while ((entry = readdir(dirp)) != NULL) {               // [gamepad_linux.c#L75-L81]
        if (!ffStrStartsWith(entry->d_name, "js")) continue;
        …
        ffStrbufAppendS(&path, entry->d_name);
        ffStrbufAppendS(&path, "/device/name");             // [gamepad_linux.c#L83-L85]
        …
        detectGamepad(devices, &name, &path);               // [gamepad_linux.c#L90-L92]
    }
    return NULL;
}

```

The helper function `detectGamepad` (defined at lines 5-38) handles the actual population of the `FFGamepadDevice` structure, parsing sysfs attributes and power supply subdirectories to complete the device profile.

### Windows: Raw Input and HID APIs

The Windows implementation in [`src/detection/gamepad/gamepad_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad_windows.c) utilizes the Raw Input API to enumerate Human Interface Devices (HID). It filters for devices with usage page 1 and usage values 4 (joystick) or 5 (gamepad).

After opening each candidate device with `CreateFileW`, the code queries HID strings for manufacturer, product name, and serial number. A vendor mapping function `detectKnownDeviceName` translates Nintendo, Sony, and Logitech product IDs into friendly display names. Battery levels are extracted from HID input reports for supported controllers like DualShock and DualSense.

```c
const char* ffDetectGamepad(FFlist* devices) {
    UINT nDevices = 0;
    GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)); // [gamepad_windows.c#L80-L84]
    …
    for (UINT i = 0; i < nDevices; ++i) {
        if (pRawInputDeviceList[i].dwType != RIM_TYPEHID) continue;
        …
        if (rdi.hid.usUsagePage != 1 ||
           (rdi.hid.usUsage != 4 && rdi.hid.usUsage != 5)) continue; // [gamepad_windows.c#L106-L108]
        …
        FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
        …
    }
    return NULL;
}

```

### macOS: IOKit HID Manager

For macOS systems, [`src/detection/gamepad/gamepad_apple.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad_apple.c) leverages the IOKit framework's `IOHIDManager` API. The implementation creates an HID manager instance, configures it to match devices with "Generic Desktop" usage page and "Joystick" or "GamePad" usage types, then copies the matching device set.

The enumeration callback extracts manufacturer, product, and serial properties using `IOHIDDeviceGetProperty`, storing the CFString values in the standard `FFGamepadDevice` structure.

```c
const char* ffDetectGamepad(FFlist* devices) {
    IOHIDManagerRef manager = IOHIDManagerCreate(...);
    …
    CFSetRef set = IOHIDManagerCopyDevices(manager);
    if (set) CFSetApplyFunction(set, (CFSetApplierFunction) &enumSet, devices); // [gamepad_apple.c#L41-L44]
    return NULL;
}

```

### BSD and Other Platforms

BSD systems use a sysfs-style approach similar to Linux in [`src/detection/gamepad/gamepad_bsd.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad_bsd.c), scanning `/dev/input` for controller devices. Haiku platforms implement Haiku-specific HID APIs in [`gamepad_haiku.cpp`](https://github.com/fastfetch-cli/fastfetch/blob/main/gamepad_haiku.cpp). Unsupported platforms compile [`gamepad_nosupport.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/gamepad_nosupport.c), which returns a "Not supported on this platform" error string while maintaining API compatibility.

## The Presentation Layer

The module frontend in [`src/modules/gamepad/gamepad.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/gamepad/gamepad.c) orchestrates the detection process and output generation. The `ffPrintGamepad` function initializes a device list, invokes `ffDetectGamepad`, applies user-configured ignore patterns, and iterates through results.

```c
bool ffPrintGamepad(FFgamepadOptions* options) {
    FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFGamepadDevice));
    const char* error = ffDetectGamepad(&result);                     // [gamepad.c#L54-L55]
    …
    FF_LIST_FOR_EACH (FFGamepadDevice*, pdevice, filtered) {
        printDevice(options, *pdevice, filtered.length > 1 ? ++index : 0); // [gamepad.c#L86-L90]
    }
}

```

The `printDevice` helper handles formatting logic, including battery bar visualization and percentage display based on the `--percent-type` configuration.

## Data Structures and Public API

The detection interface is defined in [`src/detection/gamepad/gamepad.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad.h), which declares the `FFGamepadDevice` structure and the `ffDetectGamepad` function prototype.

Key structure fields:

- `serial`: `FFstrbuf` containing the hardware serial number
- `name`: `FFstrbuf` with the device display name
- `battery`: `uint8_t` representing battery percentage (0-100)

## Practical Usage Examples

### Command-Line Interface

Display all connected gamepads with battery information:

```bash
fastfetch --module gamepad

```

Configure battery display format:

```bash

# Show only numeric percentage

fastfetch --module gamepad --percent-type num

# Hide specific controllers using prefix matching

fastfetch --module gamepad --ignore "Xbox"

```

### Programmatic Integration

Fastfetch exposes its detection API for library usage:

```c
#include "fastfetch.h"
#include "detection/gamepad/gamepad.h"

int main(void) {
    FFlist devices;
    ffListInit(&devices, sizeof(FFGamepadDevice));

    const char *err = ffDetectGamepad(&devices);
    if (err) {
        fprintf(stderr, "Gamepad detection failed: %s\n", err);
        return 1;
    }

    FF_LIST_FOR_EACH (FFGamepadDevice, dev, devices) {
        printf("Name: %s\n", dev.name.chars);
        printf("Serial: %s\n", dev.serial.chars);
        printf("Battery: %u%%\n", dev.battery);
    }

    ffListDestroy(&devices);
    return 0;
}

```

## Summary

- The **fastfetch gamepad detection module** implements platform-specific discovery in `src/detection/gamepad/` using native APIs: sysfs on Linux, Raw Input on Windows, and IOKit on macOS.
- Each detection source populates a standardized `FFGamepadDevice` structure containing **serial**, **name**, and **battery** fields.
- The **presentation layer** in [`src/modules/gamepad/gamepad.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/modules/gamepad/gamepad.c) filters results and formats output according to user preferences.
- The module supports **battery level reporting** where hardware allows, retrieving data from power supply sysfs entries on Linux and HID input reports on Windows.
- Programmatic access is available through the public `ffDetectGamepad` API defined in [`gamepad.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/gamepad.h).

## Frequently Asked Questions

### Which gamepads are supported by Fastfetch's detection module?

Fastfetch detects any controller exposing standard HID interfaces or sysfs entries. On Windows, known vendors like Sony (DualShock/DualSense), Nintendo, and Logitech receive friendly name mappings. Linux supports any controller creating `/sys/class/input/jsX` nodes. Battery reporting works only on controllers exposing battery status through standard OS APIs.

### How does Fastfetch read gamepad battery levels on Linux?

The Linux implementation in [`src/detection/gamepad/gamepad_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad_linux.c) searches for power supply subdirectories within the device's sysfs entry, reading `capacity` or `_level` files to determine battery percentage. If no power supply information exists, the battery field returns 0.

### Can I use the gamepad detection code in my own project?

Yes. The detection layer is designed as a reusable library. Include [`src/detection/gamepad/gamepad.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/gamepad/gamepad.h), link against the Fastfetch detection sources, and call `ffDetectGamepad` with an initialized `FFlist`. The function returns NULL on success or an error string on failure, populating the list with `FFGamepadDevice` structures.

### Why doesn't my controller show up in Fastfetch?

Ensure your controller uses standard HID protocols and is recognized by the operating system. On Linux, verify `/sys/class/input/js0` or similar nodes exist. On Windows, check that the device appears in Device Manager as a game controller. The `--ignore` flag may also filter out devices if a pattern matches your controller name.