From 4be3ba20c2cd99a8140e1e68398a6922593133c9 Mon Sep 17 00:00:00 2001 From: Alessandro Toia Date: Tue, 8 Feb 2022 17:50:01 -0800 Subject: [PATCH] GAMEPAD: add battery reporting for gamepad devices (xone,xpadneo,ds4,ds5,switch) --- src/gamepad.cpp | 147 +++++++++++++++++++++++++++++++++++++++++ src/gamepad.h | 25 +++++++ src/hud_elements.cpp | 39 ++++++++++- src/hud_elements.h | 2 + src/meson.build | 1 + src/overlay_params.cpp | 1 + src/overlay_params.h | 2 + 7 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/gamepad.cpp create mode 100644 src/gamepad.h diff --git a/src/gamepad.cpp b/src/gamepad.cpp new file mode 100644 index 0000000..969d560 --- /dev/null +++ b/src/gamepad.cpp @@ -0,0 +1,147 @@ +#include "gamepad.h" +#include +#include +#include +#include + +namespace fs = ghc::filesystem; +using namespace std; +std::vector gamepad_data; +std::vector list; +bool gamepad_found = false; +int gamepad_count = 0; +int xone_count = 0; +int ds4_count = 0; +int ds5_count = 0; +int switch_count = 0; +std::string xbox_paths [2]{"gip","xpadneo"}; + +bool operator<(const gamepad& a, const gamepad& b) +{ + return a.name < b.name; +} + + +void gamepad_update(){ + fs::path path("/sys/class/power_supply"); + list.clear(); + xone_count = 0; + ds4_count = 0; + ds5_count = 0; + switch_count = 0; + for (auto &p : fs::directory_iterator(path)) { + string fileName = p.path().filename(); + //CHECK XONE AND XPADNEO DEVICES + for (string n : xbox_paths ) { + if (fileName.find(n) != std::string::npos) { + list.push_back(p.path()); + gamepad_found = true; + xone_count += 1; + } + } + //CHECK FOR DUAL SHOCK 4 DEVICES + if (fileName.find("sony_controller") != std::string::npos) { + list.push_back(p.path()); + gamepad_found = true; + ds4_count +=1 ; + } + if (fileName.find("ps-controller") != std::string::npos) { + list.push_back(p.path()); + gamepad_found = true; + ds5_count +=1 ; + } + //CHECK FOR NINTENDO SWITCH DEVICES + if (fileName.find("nintendo_switch_controller") != std::string::npos) { + list.push_back(p.path()); + gamepad_found = true; + switch_count += 1; + } + } +} + + +void gamepad_info () { + gamepad_count = 0; + gamepad_data.clear(); + int xone_counter = 0; + int ds4_counter = 0; + int ds5_counter = 0; + int switch_counter = 0; + + for (auto &path : list ) { + //Set devices paths + std::string capacity = path + "/capacity"; + std::string capacity_level = path + "/capacity_level"; + std::string status = path + "/status"; + std::ifstream input_capacity(capacity); + std::ifstream input_capacity_level(capacity_level); + std::ifstream input_status(status); + std::string line; + + gamepad_data.push_back(gamepad()); + + //Xone devices + if (path.find("gip") != std::string::npos || path.find("xpadneo") != std::string::npos) { + if (xone_count == 1 ) + gamepad_data[gamepad_count].name = "XBOX PAD"; + else + gamepad_data[gamepad_count].name = "XBOX PAD-" + to_string(xone_counter + 1); + xone_counter++; + } + //DualShock 4 devices + if (path.find("sony_controller") != std::string::npos) { + if (ds4_count == 1) + gamepad_data[gamepad_count].name = "DS4 PAD"; + else + gamepad_data[gamepad_count].name = "DS4 PAD-" + to_string(ds4_counter + 1); + ds4_counter++; + } + //DualSense 5 devices + if (path.find("ps-controller") != std::string::npos) { + if (ds5_count == 1) + gamepad_data[gamepad_count].name = "DS5 PAD"; + else + gamepad_data[gamepad_count].name = "DS5 PAD-" + to_string(ds5_counter + 1); + ds5_counter++; + } + //Nintendo Switch devices + if (path.find("nintendo_switch_controller") != std::string::npos) { + if (switch_count == 1) + gamepad_data[gamepad_count].name = "SWITCH PAD"; + else + gamepad_data[gamepad_count].name = "SWITCH PAD-" + to_string(switch_counter + 1); + switch_counter++; + } + //Get device status + if (std::getline(input_status, line)) + gamepad_data[gamepad_count].state = line; + + //Get device Battery + if (fs::exists(capacity)) { + if (std::getline(input_capacity, line)) { + switch(std::stoi(line)) { + case 0 ... 25: + gamepad_data[gamepad_count].battery = "Low"; + break; + case 26 ... 49: + gamepad_data[gamepad_count].battery = "Normal"; + break; + case 50 ... 74: + gamepad_data[gamepad_count].battery = "High"; + break; + case 75 ... 100: + gamepad_data[gamepad_count].battery = "Full"; + break; + } + } + } + else { + if (std::getline(input_capacity_level, line)) { + gamepad_data[gamepad_count].battery = line; + } + } + std::sort(gamepad_data.begin(), gamepad_data.end()); + gamepad_count += 1; + + } +} diff --git a/src/gamepad.h b/src/gamepad.h new file mode 100644 index 0000000..47a8e5d --- /dev/null +++ b/src/gamepad.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef MANGOHUD_GAMEPAD_H +#define MANGOHUD_GAMEPAD_H +#include +#include + +struct gamepad { + std::string battery; + std::string state; + std::string name; +}; + +extern std::vector gamepad_data; + +extern bool gamepad_found; +extern int gamepad_count; +extern int xone_count; +extern int ds4_count; +extern int ds5_count; +extern int switch_count; +void gamepad_update(); +void gamepad_info(); + + +#endif // MANGOHUD_GAMEPAD_H diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index 88ac2d7..8eb551b 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -8,6 +8,7 @@ #include "hud_elements.h" #include "logging.h" #include "battery.h" +#include "gamepad.h" #include "cpu.h" #include "memory.h" #include "mesa/util/macros.h" @@ -588,7 +589,7 @@ void HudElements::frame_timing(){ int width = ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns - 30; #else int width = ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns; -#endif +#endif ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats, ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, NULL, min_time, max_time, @@ -852,6 +853,41 @@ void HudElements::gamescope_frame_timing(){ #endif } +void HudElements::gamepad_battery() +{ +#ifdef __linux__ + gamepad_update(); + + if (gamepad_found) { + gamepad_info(); + for (int i = 0; i < gamepad_count; i++) { + std::string battery = gamepad_data[i].battery; + std::string state = gamepad_data[i].state; + std::string name = gamepad_data[i].name; + ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::TextColored(HUDElements.colors.engine, "%s", name.c_str()); + ImGui::TableNextColumn(); + if (state == "Charging") + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); + else { + if (battery == "Full") + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_FULL); + else if (battery == "High") + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_THREE_QUARTERS); + else if (battery == "Normal") + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_HALF); + else if (battery == "Low") + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_QUARTER); + else + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); + } + ImGui::PopFont(); + } + } +#endif +} + void HudElements::graphs(){ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); @@ -1003,6 +1039,7 @@ void HudElements::sort_elements(const std::pair& optio if (param == "fps_only") { ordered_functions.push_back({fps_only, value}); } if (param == "fsr") { ordered_functions.push_back({gamescope_fsr, value}); } if (param == "debug") { ordered_functions.push_back({gamescope_frame_timing, value}); } + if (param == "gamepad_battery") { ordered_functions.push_back({gamepad_battery, value}); } if (param == "graphs"){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs]) HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs] = true; diff --git a/src/hud_elements.h b/src/hud_elements.h index 3215b72..ba0e867 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -61,6 +61,8 @@ class HudElements{ static void fps_only(); static void gamescope_fsr(); static void gamescope_frame_timing(); + static void xone_battery(); + static void gamepad_battery(); void convert_colors(struct overlay_params& params); void convert_colors(bool do_conv, struct overlay_params& params); diff --git a/src/meson.build b/src/meson.build index e05d89e..ef291ef 100644 --- a/src/meson.build +++ b/src/meson.build @@ -82,6 +82,7 @@ if is_unixy 'pci_ids.cpp', 'battery.cpp', 'control.cpp', + 'gamepad.cpp', ) opengl_files = files( diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index 8e32490..f382948 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -582,6 +582,7 @@ parse_overlay_config(struct overlay_params *params, params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = true; params->enabled[OVERLAY_PARAM_ENABLED_frametime] = true; params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = false; + params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery] = false; params->fps_sampling_period = 500000000; /* 500ms */ params->width = 0; params->height = 140; diff --git a/src/overlay_params.h b/src/overlay_params.h index 5bb9221..f7b3160 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -78,6 +78,8 @@ typedef unsigned long KeySym; OVERLAY_PARAM_BOOL(fsr) \ OVERLAY_PARAM_BOOL(mangoapp_steam) \ OVERLAY_PARAM_BOOL(debug) \ + OVERLAY_PARAM_BOOL(xone_battery) \ + OVERLAY_PARAM_BOOL(gamepad_battery) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_file) \