From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/gamepad/gamepad_linux.c | 97 +++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/detection/gamepad/gamepad_linux.c (limited to 'src/detection/gamepad/gamepad_linux.c') diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c new file mode 100644 index 0000000..6bb4ee2 --- /dev/null +++ b/src/detection/gamepad/gamepad_linux.c @@ -0,0 +1,97 @@ +#include "gamepad.h" +#include "common/io.h" +#include "common/strutil.h" + +static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path) { + uint32_t baseLen = path->length; + FFGamepadDevice* device = FF_LIST_ADD(FFGamepadDevice, *devices); + ffStrbufInit(&device->serial); + ffStrbufInitMove(&device->name, name); + device->battery = 0; + + ffStrbufAppendS(path, "uniq"); + if (ffAppendFileBuffer(path->chars, &device->serial)) { + ffStrbufTrimRightSpace(&device->serial); + } + + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "device/power_supply/"); // /sys/class/input/jsX/device/device/power_supply + + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(path->chars); + if (dirp) { + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_name[0] == '.' || (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)) { + continue; + } + ffStrbufAppendS(path, entry->d_name); + ffStrbufAppendS(path, "/capacity"); // /sys/class/input/jsX/device/device/power_supply/XXX/capacity + char capacity[32]; + ssize_t nRead = ffReadFileData(path->chars, ARRAY_SIZE(capacity) - 1, capacity); + if (nRead > 0) // Tested with a PS4 controller + { + capacity[nRead] = '\0'; + device->battery = (uint8_t) strtoul(capacity, NULL, 10); + break; + } + + ffStrbufAppendS(path, "_level"); + nRead = ffReadFileData(path->chars, ARRAY_SIZE(capacity) - 1, capacity); + if (nRead > 0) // Tested with a NS Pro controller + { + // https://github.com/torvalds/linux/blob/52b1853b080a082ec3749c3a9577f6c71b1d4a90/drivers/power/supply/power_supply_sysfs.c#L124 + switch (capacity[0]) { + case 'C': + device->battery = 1; + break; // Critical + case 'L': + device->battery = 25; + break; // Low + case 'N': + device->battery = 50; + break; // Normal + case 'H': + device->battery = 75; + break; // High + case 'F': + device->battery = 100; + break; // Full + } + } + } + } +} + +const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) { + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/input/"); + if (dirp == NULL) { + return "opendir(\"/sys/class/input/\") == NULL"; + } + + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/class/input/"); + uint32_t baseLen = path.length; + + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (!ffStrStartsWith(entry->d_name, "js")) { + continue; + } + if (!ffCharIsDigit(entry->d_name[strlen("js")])) { + continue; + } + + ffStrbufAppendS(&path, entry->d_name); + ffStrbufAppendS(&path, "/device/name"); + + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + if (ffAppendFileBuffer(path.chars, &name)) { + ffStrbufTrimRightSpace(&name); + ffStrbufSubstrBefore(&path, path.length - 4); + detectGamepad(devices, &name, &path); + } + + ffStrbufSubstrBefore(&path, baseLen); + } + + return NULL; +} -- cgit v1.2.3