From 5b4a26393d44d53ba65e1074f6c9318b1372f9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 20:40:20 +0800 Subject: [PATCH] Gamepad (Linux): detect battery capacity --- src/detection/gamepad/gamepad.h | 1 + src/detection/gamepad/gamepad_apple.c | 1 + src/detection/gamepad/gamepad_bsd.c | 1 + src/detection/gamepad/gamepad_linux.c | 59 +++++++++++++++++++------ src/detection/gamepad/gamepad_windows.c | 1 + src/modules/gamepad/gamepad.c | 13 +++++- 6 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/detection/gamepad/gamepad.h b/src/detection/gamepad/gamepad.h index be63e9dea..441b095dc 100644 --- a/src/detection/gamepad/gamepad.h +++ b/src/detection/gamepad/gamepad.h @@ -6,6 +6,7 @@ typedef struct FFGamepadDevice { FFstrbuf identifier; FFstrbuf name; + uint8_t battery; // 0-100% } FFGamepadDevice; const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */); diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c index b1a8436ca..6927d6213 100644 --- a/src/detection/gamepad/gamepad_apple.c +++ b/src/detection/gamepad/gamepad_apple.c @@ -13,6 +13,7 @@ static void enumSet(const void* value, void *context) ffCfStrGetString(serialNumber, &device->identifier); ffStrbufInit(&device->name); ffCfStrGetString(product, &device->name); + device->battery = 0; } const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) diff --git a/src/detection/gamepad/gamepad_bsd.c b/src/detection/gamepad/gamepad_bsd.c index ade8fb996..019fec23c 100644 --- a/src/detection/gamepad/gamepad_bsd.c +++ b/src/detection/gamepad/gamepad_bsd.c @@ -44,6 +44,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); ffStrbufInitS(&device->identifier, di.udi_serial); ffStrbufInitF(&device->name, "%s %s", di.udi_vendor, di.udi_product); + device->battery = 0; } } } diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c index a5273a0fa..ec584aad5 100644 --- a/src/detection/gamepad/gamepad_linux.c +++ b/src/detection/gamepad/gamepad_linux.c @@ -5,39 +5,72 @@ #include #include +static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path) +{ + uint32_t baseLen = path->length; + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); + ffStrbufInit(&device->identifier); + ffStrbufInitMove(&device->name, name); + device->battery = 0; + + ffStrbufAppendS(path, "uniq"); + if (ffAppendFileBuffer(path->chars, &device->identifier)) + ffStrbufTrimRightSpace(&device->identifier); + + 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, sizeof(capacity) - 1, capacity); + if (nRead > 0) + { + capacity[nRead] = '\0'; + device->battery = (uint8_t) strtoul(capacity, NULL, 10); + } + } + } +} + const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) { - DIR* dirp = opendir("/sys/class/input/"); - if(dirp == NULL) + 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) + while ((entry = readdir(dirp)) != NULL) { - if(!ffStrStartsWith(entry->d_name, "js")) + if (!ffStrStartsWith(entry->d_name, "js")) continue; - if(!isdigit(entry->d_name[2])) + if (!isdigit(entry->d_name[2])) continue; ffStrbufAppendS(&path, entry->d_name); ffStrbufAppendS(&path, "/device/name"); - if (ffPathExists(path.chars, FF_PATHTYPE_FILE)) + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + if (ffAppendFileBuffer(path.chars, &name)) { - FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInitS(&device->identifier, entry->d_name); - ffStrbufInit(&device->name); - if (ffAppendFileBuffer(path.chars, &device->name)) - ffStrbufTrimRightSpace(&device->name); + ffStrbufTrimRightSpace(&name); + ffStrbufSubstrBefore(&path, path.length - 4); + detectGamepad(devices, &name, &path); } ffStrbufSubstrBefore(&path, baseLen); } - closedir(dirp); - return NULL; } diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index 8a5799717..a95f273c9 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -119,6 +119,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); ffStrbufInitWS(&device->identifier, devName); ffStrbufInit(&device->name); + device->battery = 0; const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId); if (knownGamepad) diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index f48be7bf9..55a2aba00 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -1,3 +1,4 @@ +#include "common/bar.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/gamepad/gamepad.h" @@ -10,14 +11,21 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if(options->moduleArgs.outputFormat.length == 0) { + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name); ffPrintLogoAndKey(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufPutTo(&device->name, stdout); + if (device->battery > 0 && device->battery <= 100) + { + ffStrbufAppendC(&buffer, ' '); + ffAppendPercentNum(&buffer, device->battery, 51, 21, true); + } + ffStrbufPutTo(&buffer, stdout); } else { ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier}, + {FF_FORMAT_ARG_TYPE_UINT8, &device->battery}, }); } } @@ -121,7 +129,8 @@ void ffPrintGamepadHelpFormat(void) { ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { "Name", - "Identifier" + "Identifier", + "Battery", }); }