diff --git a/.gitattributes b/.gitattributes index 970e13f..92bbb8f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -36,4 +36,7 @@ # Executables *.exe binary *.out binary -*.app binary \ No newline at end of file +*.app binary + +# Linux shell files must always be LF +*.sh text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 390d006..2e552b2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,12 +15,15 @@ build/** !Images/* !.github/** -!LibHarmonyLink/** +!HarmonyLinkLib/** !HarmonyLinkTest/** -!HarmonyLinkTest_CPP/** # Blacklist specific build directories linuxbuild/ build/ .idea/ winbuild/ + +!Compile.sh +!Compile.bat +HarmonyLinkLib/.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a0e4c8..a394d22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,18 +44,17 @@ elseif(UNIX) endif() # Set global output directories for all build types -foreach(TYPE IN ITEMS DEBUG RELEASE) - string(TOUPPER ${TYPE} TYPE_UPPER) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}") - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}") -endforeach() +#foreach(TYPE IN ITEMS DEBUG RELEASE) +# string(TOUPPER ${TYPE} TYPE_UPPER) +# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}") +# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}") +# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}") +#endforeach() # Add the library and executable directories -add_subdirectory(LibHarmonyLink) +add_subdirectory(HarmonyLinkLib) add_subdirectory(HarmonyLinkTest) -add_subdirectory(HarmonyLinkTest_CPP) # Add Google Test as a subdirectory #add_subdirectory(ThirdParty/googletest) diff --git a/Compile.bat b/Compile.bat new file mode 100644 index 0000000..ccad60c --- /dev/null +++ b/Compile.bat @@ -0,0 +1,68 @@ +@echo off +setlocal enabledelayedexpansion + +REM Clear the screen +cls + +REM Define the color codes +set GREEN= +set NC= + +REM Prompt the user to choose a compiler +echo %GREEN%Select the compiler to use:%NC% +echo 1^ ) MSBuild (default) +echo 2^ ) MinGW +echo 3^ ) Ninja +set /p choice=Enter the number of your choice: + +REM Set the generator and compiler based on the user's choice +if "%choice%"=="2" ( + set "GENERATOR=MinGW Makefiles" + set "COMPILER_OPTION=-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++" +) else if "%choice%"=="3" ( + set "GENERATOR=Ninja" + set "COMPILER_OPTION=" +) else ( + set "GENERATOR=Visual Studio 17 2022" + set "COMPILER_OPTION=-A x64" + set "choice=1" +) + +echo Using generator: %GENERATOR% + +REM Prompt the user to choose a build type +echo %GREEN%Select the build type:%NC% +echo 1^ ) Release (default) +echo 2^ ) Debug +set /p build_choice=Enter the number of your choice: + +REM Set the build type based on the user's choice +if "%build_choice%"=="2" ( + set "BUILD_TYPE=Debug" +) else ( + set "BUILD_TYPE=Release" +) + +echo Build type: %BUILD_TYPE% + +REM Create the build directory if it doesn't exist +if not exist "winbuild" ( + mkdir winbuild +) + +cd winbuild + +REM Get the number of processors +for /f "tokens=2 delims==" %%a in ('wmic cpu get NumberOfLogicalProcessors /value') do set "NUM_PROCESSORS=%%a" + +REM Run CMake with the selected generator and build type +cmake -G "%GENERATOR%" %COMPILER_OPTION% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. + +REM Build the project +if "%choice%"=="1" ( + cmake --build . --config %BUILD_TYPE% -- /m:%NUM_PROCESSORS% +) else ( + cmake --build . --config %BUILD_TYPE% -- -j %NUM_PROCESSORS% +) + +cd .. diff --git a/Compile.sh b/Compile.sh new file mode 100644 index 0000000..63ea1c3 --- /dev/null +++ b/Compile.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +set -e + +clear + +# Define color codes +GREEN='\033[0;32m' +NC='\033[0m' # No Color +PURPLE='\033[0;35m' +GRAY='\033[1;30m' + +# Ensure dialog is installed +if ! command -v dialog &> /dev/null +then + echo "dialog could not be found. Please install it to use this script." + exit +fi + +# Function to check if a compiler is installed +check_compiler() { + if command -v $1 &> /dev/null + then + COMPILER_OPTIONS+=("$2" "$3" "$4") + fi +} + +# Array to store the menu options +COMPILER_OPTIONS=() + +# Add available compilers to the options array +check_compiler g++ "1" "g++ (default)" "on" +check_compiler clang++ "2" "clang++" "off" +check_compiler clang++-15 "3" "clang++ 15" "off" +check_compiler clang++-16 "4" "clang++ 16" "off" +check_compiler clang++-17 "5" "clang++ 17" "off" + +# Debug: print the compiler options +echo "Compiler options: ${COMPILER_OPTIONS[@]}" + +# Check if any compilers are available +if [ ${#COMPILER_OPTIONS[@]} -eq 0 ]; then + dialog --msgbox "No compilers found. Please install a compiler to use this script." 10 40 + exit +fi + +# Prompt the user to choose one or more compilers +compiler_choices=$(dialog --colors --title "\Zb\Z5Select Compiler\Zn" --checklist "\nChoose one or more compilers:" 15 60 ${#COMPILER_OPTIONS[@]} "${COMPILER_OPTIONS[@]}" 3>&1 1>&2 2>&3) + +# Process the selected compilers +C_COMPILERS=() +CXX_COMPILERS=() + +# Debug: print the compiler choices +echo "Compiler choices: $compiler_choices" + +for choice in $compiler_choices; do + case $choice in + 1) + C_COMPILERS+=("gcc") + CXX_COMPILERS+=("g++") + ;; + 2) + C_COMPILERS+=("clang") + CXX_COMPILERS+=("clang++") + ;; + 3) + C_COMPILERS+=("clang-15") + CXX_COMPILERS+=("clang++-15") + ;; + 4) + C_COMPILERS+=("clang-16") + CXX_COMPILERS+=("clang++-16") + ;; + 5) + C_COMPILERS+=("clang-17") + CXX_COMPILERS+=("clang++-17") + ;; + esac +done + +# Output the chosen compilers +msg="Chosen compilers:\n" +for i in "${!C_COMPILERS[@]}"; do + msg+="C compiler: ${C_COMPILERS[$i]}, C++ compiler: ${CXX_COMPILERS[$i]}\n" +done + +dialog --colors --msgbox "\Zb\Z5$msg\Zn" 20 60 + +# Prompt the user to choose a build type +build_choice=$(dialog --colors --title "\Zb\Z5Select Build Type\Zn" --menu "\nChoose a build type:" 10 40 2 \ +1 "Release (default)" \ +2 "Debug" 3>&1 1>&2 2>&3) + +# Set the build type based on the user's choice +case $build_choice in + 2) + BUILD_TYPE=Debug + ;; + *) + BUILD_TYPE=Release + ;; +esac + +# Output the chosen build type +dialog --colors --msgbox "\Zb\Z5Build type:\Zn $BUILD_TYPE" 10 40 + +clear + +# Create the build directory if it doesn't exist +if [ ! -d "linuxbuild" ]; then + mkdir linuxbuild +fi + +cd linuxbuild + +# Run CMake with the selected compilers and build type +for i in "${!C_COMPILERS[@]}"; do + cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_COMPILER=${C_COMPILERS[$i]} -DCMAKE_CXX_COMPILER=${CXX_COMPILERS[$i]} .. + # Build the project + cmake --build . --config $BUILD_TYPE -j 15 #--clean-first #--verbose +done + +cd .. + +# End with a success message +dialog --colors --msgbox "\Zb\Z5Build(s) completed successfully!\Zn" 10 40 diff --git a/HarmonyLinkLib/CMakeLists.txt b/HarmonyLinkLib/CMakeLists.txt new file mode 100644 index 0000000..de087b6 --- /dev/null +++ b/HarmonyLinkLib/CMakeLists.txt @@ -0,0 +1,237 @@ +# Copyright (c) 2024 Jordon Brooks +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.10) +project(HarmonyLinkLib VERSION 2.1.2 LANGUAGES CXX) + +include(FetchContent) + +# Fetch fmt library +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 10.2.1 # Specify the desired version of {fmt} +) + +FetchContent_MakeAvailable(fmt) + +set_target_properties(fmt PROPERTIES FOLDER External) +set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + +# Fetch ghc library +FetchContent_Declare( + ghc_filesystem + GIT_REPOSITORY https://github.com/gulrak/filesystem.git + GIT_TAG v1.5.14 # Specify the desired version of ghc +) + +FetchContent_MakeAvailable(ghc_filesystem) + +set_target_properties(ghc_filesystem PROPERTIES FOLDER External) +set_target_properties(ghc_filesystem PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + +# Find the current Git branch and the last commit timestamp +find_package(Git QUIET) +if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH_NAME + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --format=%ct + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_TIMESTAMP + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +else() + set(GIT_BRANCH_NAME "Unknown") + set(GIT_COMMIT_TIMESTAMP "Unknown") +endif() + +configure_file(include/Version.h.in Version.generated.h) + +# Specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Define metadata variables +set(FILE_DESCRIPTION "Enhances handheld gaming with intelligent hardware recognition, dynamic adaptability, and robust API access for Windows and Linux, including Steam Deck and Wine support.") +set(INTERNAL_NAME "HarmonyLinkLib") +set(ORIGINAL_FILENAME "HarmonyLinkLib.dll") +set(PRODUCT_NAME "HarmonyLinkLib") +set(COMMENTS "") + +# Configure version.rc file for shared library +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Resources/Version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) + +# Explicitly list source files +set(COMMON_SOURCES + "src/Platform/IPlatformUtilities.cpp" + "src/HarmonyLinkLib.cpp" + "src/Version.cpp" + "src/Platform/WineUtilities.cpp" + "src/Utilities.cpp" +) + +# Explicitly list include files +set(COMMON_INCLUDES + "include/Core.h" + "include/Structs/FBattery.h" + "include/Structs/FOSVerInfo.h" + "include/Structs/FDevice.h" + "include/Structs/FCPUInfo.h" + "include/Enums/EDevice.h" + "include/Enums/EPlatform.h" + "include/Enums/ESteamDeck.h" + "include/FString.h" + "include/HarmonyLinkLib.h" + "include/Version.h" + "src/Platform/IPlatformUtilities.h" + "src/Platform/WineUtilities.h" + "src/Utilities.h" +) + +set(WINDOWS_SOURCES + "src/Platform/Windows/WindowsUtilities.cpp" +) + +set(WINDOWS_INCLUDES + "src/Platform/Windows/WindowsUtilities.h" +) + +set(LINUX_SOURCES + "src/Platform/Unix/Linux/LinuxUtilities.cpp" + "src/Platform/Unix/UnixUtilities.cpp" +) + +set(LINUX_INCLUDES + "src/Platform/Unix/Linux/LinuxUtilities.h" + "src/Platform/Unix/UnixUtilities.h" +) + +set(MAC_SOURCES + "src/Platform/Unix/Mac/MacUtilities.cpp" + "src/Platform/Unix/UnixUtilities.cpp" +) + +set(MAC_INCLUDES + "src/Platform/Unix/Mac/MacUtilities.h" + "src/Platform/Unix/UnixUtilities.h" +) + +# Platform-specific definitions +if(WIN32) + add_definitions(-DBUILD_WINDOWS) +elseif(UNIX) + if(APPLE) + add_definitions(-DBUILD_MACOS) + else() + add_definitions(-DBUILD_LINUX) + endif() + add_definitions(-DBUILD_UNIX) +endif() + +# Platform-specific definitions +if(WIN32) + message(STATUS "Compiling for Windows...") + list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${WINDOWS_SOURCES}) + list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${WINDOWS_INCLUDES}) + list(APPEND SHARED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +elseif(UNIX) + message(STATUS "Compiling for Unix-based systems...") + if(APPLE) + message(STATUS "Compiling for Mac...") + list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${MAC_SOURCES}) + list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${MAC_INCLUDES}) + else() + message(STATUS "Compiling for Linux...") + list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${LINUX_SOURCES}) + list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${LINUX_INCLUDES}) + endif() +endif() + +# Detect the compiler name +get_filename_component(COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME) + +# Replace forbidden characters in file names (optional, if needed) +string(REPLACE "." "_" COMPILER_NAME ${COMPILER_NAME}) +string(REPLACE "/" "_" COMPILER_NAME ${COMPILER_NAME}) +string(REPLACE "\\" "_" COMPILER_NAME ${COMPILER_NAME}) + +# Create the shared library +add_library(HarmonyLinkLibShared SHARED ${LIB_SOURCES} ${SHARED_SOURCES} ${LIB_INCLUDES}) +target_include_directories(HarmonyLinkLibShared + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + PUBLIC + "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/include" +) +target_compile_definitions(HarmonyLinkLibShared PRIVATE HARMONYLINKLIB_SHARED) +set_target_properties(HarmonyLinkLibShared PROPERTIES OUTPUT_NAME "HarmonyLinkLibShared_${COMPILER_NAME}") + +# Create the static library +add_library(HarmonyLinkLibStatic STATIC ${LIB_SOURCES} ${LIB_INCLUDES}) +target_include_directories(HarmonyLinkLibStatic + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + PUBLIC + "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/include" +) +target_compile_definitions(HarmonyLinkLibStatic PRIVATE HARMONYLINKLIB_STATIC) +set_target_properties(HarmonyLinkLibStatic PROPERTIES OUTPUT_NAME "HarmonyLinkLibStatic_${COMPILER_NAME}") + +# Set output directories for all build types +#foreach(TYPE IN ITEMS DEBUG RELEASE) +# string(TOUPPER ${TYPE} TYPE_UPPER) +# set_target_properties(HarmonyLinkLibShared PROPERTIES +# RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}/HarmonyLinkLib" +# LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}/HarmonyLinkLib" +# ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkLib" +# ) +# set_target_properties(HarmonyLinkLibStatic PROPERTIES +# ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkLibStatic" +# ) +#endforeach() + +# Link fmt to HarmonyLinkLib +target_link_libraries(HarmonyLinkLibStatic PRIVATE fmt::fmt-header-only) +target_link_libraries(HarmonyLinkLibShared PRIVATE fmt::fmt-header-only) + +# Link ghc to HarmonyLinkLib +target_link_libraries(HarmonyLinkLibStatic PRIVATE ghc_filesystem) +target_link_libraries(HarmonyLinkLibShared PRIVATE ghc_filesystem) + +# Determine the compiler and set appropriate flags for libc++ +if (UNIX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Use libc++ instead of libstdc++ with Clang + target_compile_options(HarmonyLinkLibStatic PRIVATE -stdlib=libc++) + target_compile_options(HarmonyLinkLibShared PRIVATE -stdlib=libc++) + target_link_options(HarmonyLinkLibStatic PRIVATE -stdlib=libc++) + target_link_options(HarmonyLinkLibShared PRIVATE -stdlib=libc++) + + # Link against the libc++ library and the filesystem library + target_link_libraries(HarmonyLinkLibStatic PRIVATE c++ c++abi c++experimental) + target_link_libraries(HarmonyLinkLibShared PRIVATE c++ c++abi c++experimental) +elseif (UNIX AND CMAKE_CXX_COMPILER_ID MATCHES "GNU") + # Use libstdc++ with GCC + target_link_options(HarmonyLinkLibStatic PRIVATE -static-libgcc -static-libstdc++) + target_link_options(HarmonyLinkLibShared PRIVATE -static-libgcc -static-libstdc++) + + # Link against the libstdc++ filesystem library if necessary + #target_link_libraries(HarmonyLinkLibStatic PRIVATE stdc++fs) + #target_link_libraries(HarmonyLinkLibShared PRIVATE stdc++fs) +endif() diff --git a/LibHarmonyLink/Resources/Version.rc.in b/HarmonyLinkLib/Resources/Version.rc.in similarity index 100% rename from LibHarmonyLink/Resources/Version.rc.in rename to HarmonyLinkLib/Resources/Version.rc.in diff --git a/HarmonyLinkLib/include/Core.h b/HarmonyLinkLib/include/Core.h new file mode 100644 index 0000000..90babed --- /dev/null +++ b/HarmonyLinkLib/include/Core.h @@ -0,0 +1,38 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +// Use a preprocessor definition to switch between export and import declarations +#ifdef BUILD_WINDOWS + #ifdef HARMONYLINKLIB_STATIC + #define HARMONYLINKLIB_API + #else + #ifdef HARMONYLINKLIB_SHARED + #define HARMONYLINKLIB_API __declspec(dllexport) + #else + #define HARMONYLINKLIB_API __declspec(dllimport) + #endif + #endif +#else + #ifdef HARMONYLINKLIB_SHARED + #ifdef __clang__ + #define HARMONYLINKLIB_API __attribute__((visibility("default"))) + #else + #define HARMONYLINKLIB_API + #endif + #else + #define HARMONYLINKLIB_API + #endif +#endif diff --git a/LibHarmonyLink/include/Version.h b/HarmonyLinkLib/include/Enums/EDevice.h similarity index 58% rename from LibHarmonyLink/include/Version.h rename to HarmonyLinkLib/include/Enums/EDevice.h index d238e47..c11919d 100644 --- a/LibHarmonyLink/include/Version.h +++ b/HarmonyLinkLib/include/Enums/EDevice.h @@ -14,27 +14,24 @@ #pragma once -#include -#include "Core.h" +// Undefine the LINUX macro to avoid conflicts with the enum definition. +#undef LINUX -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif +#include -HARMONYLINK_API char* HL_version_get_string(void); - -HARMONYLINK_API char* HL_version_build_timestamp(void); - -HARMONYLINK_API char* HL_git_branch(void); - -HARMONYLINK_API char* HL_git_commit_timestamp(void); - -HARMONYLINK_API bool HL_is_debug(void); - -HARMONYLINK_API void HL_version_print(void); - -#ifdef __cplusplus +// Enum class for representing different types of devices +namespace HarmonyLinkLib +{ + enum class EDevice : uint8_t + { + UNKNOWN, + DESKTOP, + LAPTOP, + HANDHELD, + + STEAM_DECK, + // ROG_ALLY + // AYONEO_SLIDE + // etc... + }; } -} -#endif diff --git a/LibHarmonyLink/include/Utilities.h b/HarmonyLinkLib/include/Enums/EPlatform.h similarity index 70% rename from LibHarmonyLink/include/Utilities.h rename to HarmonyLinkLib/include/Enums/EPlatform.h index cffd96e..ffa2be7 100644 --- a/LibHarmonyLink/include/Utilities.h +++ b/HarmonyLinkLib/include/Enums/EPlatform.h @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software @@ -12,17 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#pragma once -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif +#include -// Utility function to convert char* to wchar_t* -wchar_t *convertToWideChar(const char *str); - -#ifdef __cplusplus +// Enum class for representing different operating platforms +namespace HarmonyLinkLib +{ + enum class EPlatform : uint8_t + { + UNKNOWN, + WINDOWS, + LINUX, + MAC, + UNIX, + }; } -} -#endif diff --git a/HarmonyLinkLib/include/Enums/ESteamDeck.h b/HarmonyLinkLib/include/Enums/ESteamDeck.h new file mode 100644 index 0000000..9fbad64 --- /dev/null +++ b/HarmonyLinkLib/include/Enums/ESteamDeck.h @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +// Enum class for representing different types of devices +namespace HarmonyLinkLib +{ + enum class ESteamDeck : uint8_t + { + NONE, // Device is not a steam deck + UNKNOWN, // Device is a steam deck but model cannot be determined + LCD, + OLED, + }; +} diff --git a/HarmonyLinkLib/include/FString.h b/HarmonyLinkLib/include/FString.h new file mode 100644 index 0000000..68ae766 --- /dev/null +++ b/HarmonyLinkLib/include/FString.h @@ -0,0 +1,177 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "Core.h" // Replace with actual API export macro + +/** + * @file FString.h + * @brief FString Class - Custom String Management for DLL Export + * + * The FString class is a custom string management class designed to safely encapsulate + * string handling and memory management, especially for use in DLLs (Dynamic Link Libraries). + * It resolves the common issue of exporting classes containing standard library types, + * such as std::string, across DLL boundaries, which can lead to compiler warnings or errors. + * + * Features: + * - Implements basic string operations such as construction, destruction, copy, and move semantics. + * - Utilizes smart pointers (std::unique_ptr) for automatic memory management, reducing the risk of memory leaks. + * - Provides a simple interface for interacting with character strings, similar to std::string. + * - Includes both deep copy semantics for safety and move semantics for performance in object transfers. + * + * Usage: + * FString can be used as a safer alternative to std::string for classes that are exported from a DLL. + * It handles memory allocation/deallocation automatically and provides a basic set of string operations. + * + * Example: + * FString myString("Hello, world!"); + * std::cout << myString.c_str() << std::endl; // Output: Hello, world! + * + * Note: + * - The class is currently designed with basic functionality. Additional features such as + * string concatenation, substring, and comparison operations can be added as needed. + * - Ensure that the HarmonyLinkLibApi.h (or equivalent) file correctly defines the export macro + * for DLL usage. + * + */ + namespace HarmonyLinkLib + { + class HARMONYLINKLIB_API FString { + public: + FString() : data_(new char[1]) { + data_[0] = '\0'; + } + + FString(const char* str) { + const size_t len = strlen(str); + data_ = new char[len + 1]; + memcpy(data_, str, len + 1); + } + + // Copy constructor + FString(const FString& other) { + const size_t len = strlen(other.data_); + data_ = new char[len + 1]; + memcpy(data_, other.data_, len + 1); + } + + ~FString() { + delete[] data_; + } + + // Copy assignment operator + FString& operator=(const FString& other) { + if (this != &other) { + delete[] data_; + const size_t len = strlen(other.data_); + data_ = new char[len + 1]; + memcpy(data_, other.data_, len + 1); + } + return *this; + } + + // Concatenation operator for FString objects + FString operator+(const FString& other) const { + size_t thisLen = strlen(this->data_); + size_t otherLen = strlen(other.data_); + char* concatenated = new char[thisLen + otherLen + 1]; + + memcpy(concatenated, this->data_, thisLen); + memcpy(concatenated + thisLen, other.data_, otherLen + 1); + + FString result(concatenated); + delete[] concatenated; + return result; + } + + // Concatenation operator for const char* + FString operator+(const char* other) const { + return *this + FString(other); + } + + // Friend function to allow concatenation with const char* on the left-hand side + friend FString operator+(const char* lhs, const FString& rhs) { + return FString(lhs) + rhs; + } + + // Move constructor + FString(FString&& other) noexcept : data_(other.data_) { + other.data_ = nullptr; + } + + FString(const std::string& str) { + const size_t len = str.length(); + data_ = new char[len + 1]; + memcpy(data_, str.c_str(), len + 1); + } + + // Move assignment operator + FString& operator=(FString&& other) noexcept { + if (this != &other) { + delete[] data_; + data_ = other.data_; + other.data_ = nullptr; + } + return *this; + } + + bool operator==(const FString& other) const { + return strcmp(data_, other.data_) == 0; + } + + // Method to get a lowercase version of the string + static FString to_lower(FString& from) + { + for (size_t i = 0; i < strlen(from.data_); ++i) { + from.data_[i] = static_cast(std::tolower(static_cast(from.data_[i]))); + } + return from; + } + + // Overloaded static method to handle const char* + static FString to_lower(const char* from) { + FString temp_string(from); // Create an FString from const char* + return to_lower(temp_string); // Reuse the existing to_lower method + } + + const char* c_str() const { + return data_; + } + + private: + char* data_ = nullptr; + }; + } + +namespace std { + template<> + struct hash { + size_t operator()(const HarmonyLinkLib::FString& s) const { + size_t hashValue = 5381; // Starting value recommended by the djb2 algorithm + const char* str = s.c_str(); + + for (size_t i = 0; str[i] != '\0'; ++i) { + hashValue = ((hashValue << 5) + hashValue) + static_cast(str[i]); + // Equivalent to hashValue * 33 + str[i] + } + + return hashValue; + } + }; +} diff --git a/HarmonyLinkLib/include/HarmonyLinkLib.h b/HarmonyLinkLib/include/HarmonyLinkLib.h new file mode 100644 index 0000000..0298e2d --- /dev/null +++ b/HarmonyLinkLib/include/HarmonyLinkLib.h @@ -0,0 +1,62 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * IMPORTANT REMINDER: + * Do NOT use standard output functions like std::cout and printf anywhere in this codebase. + * + * Reason: + * Unreal Engine 5's packaging tool encounters issues with these functions, leading to + * packaging failures. The engine sets stdout to UTF-8, which can cause conflicts with + * these standard functions, resulting in a "SECURE CRT: Invalid parameter detected" error + * during packaging. + * + * This issue once required an extensive debugging effort that lasted over 8 hours. + * To prevent similar issues in the future and ensure smooth packaging, always use + * wide-character versions of these functions, such as wprintf and std::wcout, when working + * within the DLL. These functions are compatible with the UTF-8 setting in Unreal Engine 5. + * + */ + + +#pragma once + +#include "Core.h" +#include "Structs/FBattery.h" +#include "Structs/FCPUInfo.h" +#include "Structs/FDevice.h" +#include "Structs/FOSVerInfo.h" + + +class IPlatformUtilities; + +namespace HarmonyLinkLib +{ + HARMONYLINKLIB_API bool HL_Init(); + + HARMONYLINKLIB_API bool get_is_wine(); + + HARMONYLINKLIB_API bool get_is_linux(); + + HARMONYLINKLIB_API bool get_is_docked(); + + HARMONYLINKLIB_API FCPUInfo* get_cpu_info(); + + HARMONYLINKLIB_API FDevice* get_device_info(); + + HARMONYLINKLIB_API FOSVerInfo* get_os_version(); + + HARMONYLINKLIB_API FBattery* get_battery_status(); +} diff --git a/HarmonyLinkLib/include/HarmonyLinkStruct.h b/HarmonyLinkLib/include/HarmonyLinkStruct.h new file mode 100644 index 0000000..362750b --- /dev/null +++ b/HarmonyLinkLib/include/HarmonyLinkStruct.h @@ -0,0 +1,27 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +struct HarmonyLinkStruct +{ + // Virtual destructor is important for proper cleanup of derived types + virtual ~HarmonyLinkStruct() = default; + + // Method to deallocate the object + void free() const + { + delete this; + } +}; diff --git a/HarmonyLinkLib/include/Structs/FBattery.h b/HarmonyLinkLib/include/Structs/FBattery.h new file mode 100644 index 0000000..3a40095 --- /dev/null +++ b/HarmonyLinkLib/include/Structs/FBattery.h @@ -0,0 +1,36 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "HarmonyLinkStruct.h" + +namespace HarmonyLinkLib +{ + struct FBattery : HarmonyLinkStruct + { + bool has_battery; + bool is_connected_to_ac; + uint8_t battery_percent; + + void to_string() const { + std::wcout << "Battery present: " << (has_battery ? "'Yes'" : "'No'") << '\n'; + std::wcout << "Connected to AC: " << (is_connected_to_ac ? "'Yes'" : "'No'") << '\n'; + std::wcout << "Battery percent: '" << static_cast(battery_percent) << "%'" << '\n'; + } + }; +} diff --git a/HarmonyLinkLib/include/Structs/FCPUInfo.h b/HarmonyLinkLib/include/Structs/FCPUInfo.h new file mode 100644 index 0000000..827bc40 --- /dev/null +++ b/HarmonyLinkLib/include/Structs/FCPUInfo.h @@ -0,0 +1,54 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include "FString.h" + +#include "HarmonyLinkStruct.h" + +namespace HarmonyLinkLib +{ + struct FCPUInfo : HarmonyLinkStruct + { + FString VendorID; + FString Model_Name; + uint32_t Physical_Cores = 0; + uint32_t Logical_Cores = 0; + std::unordered_set Flags; + + void print() const + { + wprintf(L"VendorID: '%hs'\n", VendorID.c_str()); + wprintf(L"Model_Name: '%hs'\n", Model_Name.c_str()); + wprintf(L"Physical_Cores: '%d'\n", Physical_Cores); + wprintf(L"Logical_Cores: '%d'\n", Logical_Cores); + + // Initialize a string to hold all flags + std::string allFlags; + for (const auto& flag : Flags) { + allFlags += std::string(flag.c_str()) + " "; // Append each flag followed by a space + } + + // Remove the trailing space + if (!allFlags.empty()) { + allFlags.pop_back(); + } + + wprintf(L"Flags: '%hs'\n", allFlags.c_str()); + } + }; +} diff --git a/LibHarmonyLink/include/Structs/Battery.h b/HarmonyLinkLib/include/Structs/FDevice.h similarity index 58% rename from LibHarmonyLink/include/Structs/Battery.h rename to HarmonyLinkLib/include/Structs/FDevice.h index 0fe6614..b574d6a 100644 --- a/LibHarmonyLink/include/Structs/Battery.h +++ b/HarmonyLinkLib/include/Structs/FDevice.h @@ -14,27 +14,19 @@ #pragma once -#include +#include -#include "Core.h" +#include "Enums/EDevice.h" +#include "Enums/EPlatform.h" +#include "Enums/ESteamDeck.h" -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef struct { - bool has_battery; - bool is_connected_to_ac; - unsigned char battery_percent; -} FBattery; - -HARMONYLINK_API FBattery* HL_FBattery_Init(bool has_battery, bool is_connected_to_ac, unsigned char battery_percent); - -HARMONYLINK_API void HL_FBattery_print(const FBattery *self); - -#ifdef __cplusplus +namespace HarmonyLinkLib +{ + // Struct to represent a specific device with both platform and device type + struct FDevice : HarmonyLinkStruct + { + EPlatform platform = EPlatform::UNKNOWN; + EDevice device = EDevice::UNKNOWN; + ESteamDeck steam_deck_model = ESteamDeck::NONE; + }; } -} -#endif - diff --git a/HarmonyLinkLib/include/Structs/FOSVerInfo.h b/HarmonyLinkLib/include/Structs/FOSVerInfo.h new file mode 100644 index 0000000..a308a22 --- /dev/null +++ b/HarmonyLinkLib/include/Structs/FOSVerInfo.h @@ -0,0 +1,64 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "FString.h" +#include "HarmonyLinkStruct.h" + +namespace HarmonyLinkLib +{ + struct FOSVerInfo : HarmonyLinkStruct { + // 'name' represents the operating system's name, e.g., "Ubuntu" in Linux or "Windows" in Windows systems. + FString name; + + // 'version' is a numerical representation of the OS version. In Linux, it might be the kernel version, + // whereas in Windows, it could be the major version number like 10 for Windows 10. + uint32_t version = 0; + + // 'id' is a unique identifier for the OS. In Linux, it might be a lower-case string like "ubuntu". + // In Windows, this could map to the edition ID, such as "Professional". + FString id; + + // 'version_id' is a string representing the specific version of the OS. + // For example, "20.04" in Ubuntu or "1909" in Windows 10. + FString version_id; + + // 'version_codename' is a codename for the OS version, if available. + // This is common in Linux distributions (e.g., "focal" for Ubuntu 20.04) but not typically used in Windows. + FString version_codename; + + // 'pretty_name' is a more readable version of the name, potentially including the version and codename. + // For example, "Ubuntu 20.04 LTS (Focal Fossa)" or "Windows 10 Pro". + FString pretty_name; + + // 'variant_id' is an identifier for the specific variant of the OS, if available. + // For example, in Linux distributions, this might be "desktop" for the desktop edition, + // "server" for the server edition, or "core" for a minimal installation. It helps distinguish + // between different flavors or editions of the same version. + // On the Steam Deck, this is set to "steamdeck". + FString variant_id; + + void print() const + { + wprintf(L"Name: '%hs'\n", name.c_str()); + wprintf(L"Version: '%d'\n", version); + wprintf(L"ID: '%hs'\n", id.c_str()); + wprintf(L"Version ID: '%hs'\n", version_id.c_str()); + wprintf(L"Version Codename: '%hs'\n", version_codename.c_str()); + wprintf(L"Pretty Name: '%hs'\n", pretty_name.c_str()); + wprintf(L"Variant ID: '%hs'\n", variant_id.c_str()); + } +}; +} diff --git a/HarmonyLinkLib/include/Version.h b/HarmonyLinkLib/include/Version.h new file mode 100644 index 0000000..dcc9d33 --- /dev/null +++ b/HarmonyLinkLib/include/Version.h @@ -0,0 +1,58 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Core.h" +#include + +#include "FString.h" + +namespace HarmonyLinkLib +{ + class HARMONYLINKLIB_API version + { + public: + version() = default; + + static FString ToString() + { + return HARMONYLINK_VERSION; + } + + static FString get_build_timestamp() + { + return {__TIMESTAMP__}; + } + + static FString get_git_branch() + { + return {GIT_BRANCH_NAME}; + } + + static FString get_git_commit_timestamp() + { + return {GIT_COMMIT_TIMESTAMP}; + } + + static bool is_debug() + { +#ifdef DEBUG_MODE + return true; +#else + return false; +#endif + } + }; +} diff --git a/LibHarmonyLink/include/Version.h.in b/HarmonyLinkLib/include/Version.h.in similarity index 69% rename from LibHarmonyLink/include/Version.h.in rename to HarmonyLinkLib/include/Version.h.in index 9b03890..08881c5 100644 --- a/LibHarmonyLink/include/Version.h.in +++ b/HarmonyLinkLib/include/Version.h.in @@ -15,11 +15,11 @@ // Version.h.in #pragma once -#define HARMONYLINK_VERSION_MAJOR @LibHarmonyLink_VERSION_MAJOR@ -#define HARMONYLINK_VERSION_MINOR @LibHarmonyLink_VERSION_MINOR@ -#define HARMONYLINK_VERSION_PATCH @LibHarmonyLink_VERSION_PATCH@ -#define HARMONYLINK_VERSION_TWEAK @LibHarmonyLink_VERSION_TWEAK@ -#define HARMONYLINK_VERSION "@LibHarmonyLink_VERSION@" +#define HARMONYLINK_VERSION_MAJOR @HarmonyLinkLib_VERSION_MAJOR@ +#define HARMONYLINK_VERSION_MINOR @HarmonyLinkLib_VERSION_MINOR@ +#define HARMONYLINK_VERSION_PATCH @HarmonyLinkLib_VERSION_PATCH@ +#define HARMONYLINK_VERSION_TWEAK @HarmonyLinkLib_VERSION_TWEAK@ +#define HARMONYLINK_VERSION "@HarmonyLinkLib_VERSION@" #define GIT_BRANCH_NAME "@GIT_BRANCH_NAME@" #define GIT_COMMIT_TIMESTAMP "@GIT_COMMIT_TIMESTAMP@" diff --git a/HarmonyLinkLib/src/HarmonyLinkLib.cpp b/HarmonyLinkLib/src/HarmonyLinkLib.cpp new file mode 100644 index 0000000..f57feac --- /dev/null +++ b/HarmonyLinkLib/src/HarmonyLinkLib.cpp @@ -0,0 +1,137 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "HarmonyLinkLib.h" + +#include +#include "Platform/IPlatformUtilities.h" +#include "Version.h" + +namespace HarmonyLinkLib +{ + std::shared_ptr PlatformUtilities = nullptr; + + bool HL_Init() + { + std::wcout << "HarmonyLink V" << version::ToString().c_str() << " Copyright (C) 2023 Jordon Brooks\n"; + PlatformUtilities = IPlatformUtilities::GetInstance(); + + return PlatformUtilities != nullptr; + } + + bool get_is_wine() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return false; + } + + return PlatformUtilities->is_running_under_wine(); + } + + bool get_is_linux() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return false; + } + + return PlatformUtilities->is_linux(); + } + + bool get_is_docked() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return false; + } + + return PlatformUtilities->is_docked(); + } + + FCPUInfo* get_cpu_info() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return nullptr; + } + + const std::shared_ptr cpu_info = PlatformUtilities->get_cpu_info(); + if (!cpu_info) + { + return nullptr; + } + + FCPUInfo* new_cpu_info = new FCPUInfo(*cpu_info); + return new_cpu_info; + } + + FDevice* get_device_info() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return nullptr; + } + + const std::shared_ptr device = PlatformUtilities->get_device(); + if (!device) + { + return nullptr; + } + + FDevice* new_device = new FDevice(*device); + return new_device; + } + + FOSVerInfo* get_os_version() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return nullptr; + } + + const std::shared_ptr os_version_info = PlatformUtilities->get_os_version(); + if (!os_version_info) + { + return nullptr; + } + + FOSVerInfo* new_os_info = new FOSVerInfo(*os_version_info); + return new_os_info; + } + + FBattery* get_battery_status() + { + if (!PlatformUtilities) + { + std::wcout << "Failed to get platform utilities!\n"; + return nullptr; + } + + const std::shared_ptr new_battery = PlatformUtilities->get_battery_status(); + if (!new_battery) + { + return nullptr; + } + + FBattery* battery = new FBattery(*new_battery); + return battery; + } +} diff --git a/HarmonyLinkLib/src/Platform/IPlatformUtilities.cpp b/HarmonyLinkLib/src/Platform/IPlatformUtilities.cpp new file mode 100644 index 0000000..555cc10 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/IPlatformUtilities.cpp @@ -0,0 +1,245 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "IPlatformUtilities.h" + +#include +#include +#include + +#include "Utilities.h" + +#include "WineUtilities.h" +#if BUILD_WINDOWS +#include "Windows/WindowsUtilities.h" +#elif BUILD_LINUX +#include "Unix/Linux/LinuxUtilities.h" +#elif BUILD_MAC +#include "Unix/Mac/MacUtilities.h" +#elif BUILD_UNIX +#include "Unix/Mac/MacUtilities.h" +#endif + +namespace HarmonyLinkLib +{ + static std::shared_ptr INSTANCE = nullptr; + + std::shared_ptr& IPlatformUtilities::GetInstance() + { + if (!INSTANCE) + { + #if BUILD_WINDOWS + INSTANCE = std::make_shared(); + #elif BUILD_LINUX + INSTANCE = std::make_shared(); + #elif BUILD_MAC + INSTANCE = std::make_shared(); + #elif BUILD_UNIX + INSTANCE = std::make_shared(); + // ... other platform checks + #else + std::wcout << "Platform is not supported.\n"; + #endif + } + + return INSTANCE; + } + + bool IPlatformUtilities::is_running_under_wine() + { + return WineUtilities::is_wine_present(); + } + + bool IPlatformUtilities::is_linux() + { + #ifdef BUILD_LINUX + return true; + #else + return is_running_under_wine(); + #endif + } + + bool IPlatformUtilities::is_steam_deck() + { + const std::shared_ptr device = get_device(); + + return device && device->device == EDevice::STEAM_DECK; + } + + bool IPlatformUtilities::is_docked() + { + static constexpr uint8_t CHARGING_SCORE = 3; + static constexpr uint8_t EXTERNAL_MONITOR_SCORE = 4; + static constexpr uint8_t STEAM_DECK_RESOLUTION_SCORE = 3; + static constexpr uint8_t KEYBOARD_DETECTION_SCORE = 1; + static constexpr uint8_t MOUSE_DETECTION_SCORE = 2; + static constexpr uint8_t CONTROLLER_DETECTION_SCORE = 3; + static constexpr uint8_t FINAL_TARGET_DETECTION_SCORE = 9; + + + const std::shared_ptr device = get_device(); + + if (!device) + { + std::wcout << "Error: failed to get device.\n"; + return false; + } + + if (device->device != EDevice::STEAM_DECK) + { + std::wcout << "Error: Dock detection is currently only supported on Steam Decks.\n"; + return false; + } + + uint8_t score = 0; + + Utilities::DebugPrint("Detected: ", false); + + if (is_charging()) + { + Utilities::DebugPrint("Charging, ", false); + score += CHARGING_SCORE; + } + + if (get_is_external_monitor_connected()) + { + Utilities::DebugPrint("External monitor, ", false); + score += EXTERNAL_MONITOR_SCORE; + } + + if (get_is_steam_deck_native_resolution()) + { + Utilities::DebugPrint("Non-native resolution, ", false); + score += STEAM_DECK_RESOLUTION_SCORE; + } + + if (get_keyboard_detected()) + { + Utilities::DebugPrint("keyboard ", false); + score += KEYBOARD_DETECTION_SCORE; + } + + if (get_mouse_detected()) + { + Utilities::DebugPrint("mouse, ", false); + score += MOUSE_DETECTION_SCORE; + } + + if (get_external_controller_detected()) + { + Utilities::DebugPrint("external controller, ", false); + score += CONTROLLER_DETECTION_SCORE; + } + + Utilities::DebugPrint(fmt::format("Score: {}/{}", score, FINAL_TARGET_DETECTION_SCORE).c_str()); + + return score >= FINAL_TARGET_DETECTION_SCORE; + } + + std::shared_ptr IPlatformUtilities::get_device() + { + FDevice new_device; + + if (is_linux()) + { + new_device.platform = EPlatform::LINUX; + } + else + { + new_device.platform = EPlatform::WINDOWS; + } + + const std::shared_ptr battery_status = get_battery_status(); + + if (battery_status && !battery_status->has_battery) + { + new_device.device = EDevice::DESKTOP; + } + else + { + new_device.device = EDevice::LAPTOP; + } + + const ESteamDeck steam_deck_model = detect_steam_deck(new_device); + + if (steam_deck_model != ESteamDeck::NONE) { + new_device.device = EDevice::STEAM_DECK; + new_device.steam_deck_model = steam_deck_model; + } + return std::make_shared(new_device); + } + + // Helper function to check if the device is a Steam Deck + ESteamDeck IPlatformUtilities::detect_steam_deck(const FDevice& device) { + // Check if the device is already identified as a Steam Deck + if (device.device == EDevice::STEAM_DECK && device.steam_deck_model != ESteamDeck::NONE) { + return device.steam_deck_model; + } + + ESteamDeck steam_deck_model = ESteamDeck::NONE; + + // Retrieve and process CPU information + const std::shared_ptr cpu_info = get_cpu_info(); + if (!cpu_info) { + wprintf(L"CPU information not available.\n"); + } else { + // Convert the CPU model name to lower case once + FString cpu_model_lower = FString::to_lower(cpu_info->Model_Name); + + // Map of CPU models to their corresponding Steam Deck models + static const std::unordered_map model_map = { + {FString::to_lower("amd custom apu 0405"), ESteamDeck::LCD}, + {FString::to_lower("amd custom apu 0932"), ESteamDeck::OLED} + }; + + auto iterator = model_map.find(cpu_model_lower); + if (iterator != model_map.end()) { + steam_deck_model = iterator->second; + wprintf(L"Steam Deck detected by CPU model name: %hs.\n", cpu_model_lower.c_str()); + } + } + + // Check for Steam Deck by OS version only if no model has been detected yet + if (steam_deck_model == ESteamDeck::NONE) + { + if (const std::shared_ptr version = get_os_version()) + { + if (version->variant_id == "steamdeck" && version->name == "SteamOS") + { + // Use UNKNOWN if OS matches but CPU model doesn't fit known profiles + steam_deck_model = ESteamDeck::UNKNOWN; + wprintf(L"Steam Deck OS detected but model is unknown.\n"); + } + } + else + { + wprintf(L"OS version information not available.\n"); + } + } + + return steam_deck_model; + } + + bool IPlatformUtilities::is_connected_to_ac() + { + const std::shared_ptr battery = get_battery_status(); + return battery && battery->is_connected_to_ac; + } + + bool IPlatformUtilities::is_charging() + { + const std::shared_ptr battery = get_battery_status(); + return battery && battery->has_battery && battery->is_connected_to_ac; + } +} diff --git a/HarmonyLinkLib/src/Platform/IPlatformUtilities.h b/HarmonyLinkLib/src/Platform/IPlatformUtilities.h new file mode 100644 index 0000000..e6f034f --- /dev/null +++ b/HarmonyLinkLib/src/Platform/IPlatformUtilities.h @@ -0,0 +1,60 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Enums/ESteamDeck.h" +#include "Structs/FBattery.h" +#include "Structs/FCPUInfo.h" +#include "Structs/FDevice.h" +#include "Structs/FOSVerInfo.h" + +namespace HarmonyLinkLib +{ + class IPlatformUtilities { + public: + static std::shared_ptr& GetInstance(); + + IPlatformUtilities() = default; + IPlatformUtilities(const IPlatformUtilities& other) = default; + IPlatformUtilities(IPlatformUtilities&& other) = default; + IPlatformUtilities& operator=(const IPlatformUtilities& other) = default; + IPlatformUtilities& operator=(IPlatformUtilities&& other) = default; + virtual ~IPlatformUtilities() = default; + + // General OS-level functions + virtual bool is_running_under_wine(); + virtual bool is_linux(); + virtual bool is_steam_deck(); + virtual bool is_docked(); + + virtual std::shared_ptr get_device(); + virtual std::shared_ptr get_cpu_info() = 0; + virtual std::shared_ptr get_battery_status() = 0; + virtual std::shared_ptr get_os_version() = 0; + virtual bool get_is_external_monitor_connected() = 0; + virtual bool get_keyboard_detected() = 0; + virtual bool get_mouse_detected() = 0; + virtual bool get_external_controller_detected() = 0; + virtual bool get_is_steam_deck_native_resolution() = 0; + //virtual bool get_is_ethernet_connected() = 0; + //virtual bool get_is_external_input_detected() = 0; + + ESteamDeck detect_steam_deck(const FDevice& device); + bool is_connected_to_ac(); + bool is_charging(); + + // Add more virtual functions for other OS interactions here + }; +} diff --git a/HarmonyLinkTest/src/main.c b/HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.cpp similarity index 55% rename from HarmonyLinkTest/src/main.c rename to HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.cpp index 8481c73..490e869 100644 --- a/HarmonyLinkTest/src/main.c +++ b/HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.cpp @@ -12,26 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include "LibHarmonyLink.h" +#include "LinuxUtilities.h" -int main(void) + +#include +#include +#include "Platform/WineUtilities.h" + +namespace HarmonyLinkLib { - wprintf(L"Hello from C!\n"); - - if (!HL_Init()) + std::shared_ptr LinuxUtilities::get_battery_status() { - wprintf(L"Error: Failed to initialise HarmonyLink!\n"); - return 1; + return WineUtilities::get_battery_status(); } - wprintf(L"Successfully Initialised HarmonyLink!\n"); + std::shared_ptr LinuxUtilities::get_os_version() + { + return WineUtilities::get_linux_info(); + } - const wchar_t* IsLinux = HL_Is_Linux() ? L"True" : L"False"; - wprintf(L"Is Linux: %ls\n", IsLinux); - - const wchar_t* IsWine = HL_Is_Wine() ? L"True" : L"False"; - wprintf(L"Is Wine: %ls\n", IsWine); - - return 0; + std::shared_ptr LinuxUtilities::get_cpu_info() + { + return WineUtilities::get_cpu_info(); + } } diff --git a/HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.h b/HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.h new file mode 100644 index 0000000..ee1f516 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Unix/Linux/LinuxUtilities.h @@ -0,0 +1,37 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Structs/FOSVerInfo.h" + +#include "Platform/Unix/UnixUtilities.h" + +namespace HarmonyLinkLib +{ + class LinuxUtilities : public UnixUtilities { + public: + // Implementation for other Linux-specific functions + std::shared_ptr get_battery_status() override; + + std::shared_ptr get_os_version() override; + + std::shared_ptr get_cpu_info() override; + + bool is_linux() override + { + return true; + } + }; +} diff --git a/HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.cpp b/HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.cpp new file mode 100644 index 0000000..001364c --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "MacUtilities.h" + +namespace HarmonyLinkLib +{ + +} \ No newline at end of file diff --git a/LibHarmonyLink/include/Core.h b/HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.h similarity index 60% rename from LibHarmonyLink/include/Core.h rename to HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.h index f561b77..237a0c5 100644 --- a/LibHarmonyLink/include/Core.h +++ b/HarmonyLinkLib/src/Platform/Unix/Mac/MacUtilities.h @@ -14,17 +14,12 @@ #pragma once -// Use a preprocessor definition to switch between export and import declarations -#ifdef _WIN32 - #ifdef HARMONYLINK_STATIC - #define HARMONYLINK_API - #else - #ifdef HARMONYLINK_SHARED - #define HARMONYLINK_API __declspec(dllexport) - #else - #define HARMONYLINK_API __declspec(dllimport) - #endif - #endif -#else - #define HARMONYLINK_API -#endif +#include "Platform/Unix/UnixUtilities.h" + +namespace HarmonyLinkLib +{ + class MacUtitities : public UnixUtilities { + public: + // Mac-specific overrides and additional functionality + }; +} diff --git a/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.cpp b/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.cpp new file mode 100644 index 0000000..0d3b777 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "UnixUtilities.h" + +namespace HarmonyLinkLib +{ + bool UnixUtilities::is_running_under_wine() + { + std::wcout << "This feature is not supported on unix systems yet.\n"; + return false; + } + + std::shared_ptr UnixUtilities::get_cpu_info() + { + std::wcout << "This feature is not supported on unix systems yet.\n"; + return nullptr; + } + + std::shared_ptr UnixUtilities::get_battery_status() + { + std::wcout << "This feature is not supported on unix systems yet.\n"; + return nullptr; + } + + std::shared_ptr UnixUtilities::get_os_version() + { + std::wcout << "This feature is not supported on unix systems yet.\n"; + return nullptr; + } + + bool UnixUtilities::get_is_external_monitor_connected() + { + std::wcout << "This feature is not supported on unix-based systems yet.\n"; + return false; + } + + bool UnixUtilities::get_keyboard_detected() + { + std::wcout << "This feature is not supported on unix-based systems yet.\n"; + return false; + } + + bool UnixUtilities::get_mouse_detected() + { + std::wcout << "This feature is not supported on unix-based systems yet.\n"; + return false; + } + + bool UnixUtilities::get_external_controller_detected() + { + std::wcout << "This feature is not supported on unix-based systems yet.\n"; + return false; + } + + bool UnixUtilities::get_is_steam_deck_native_resolution() + { + std::wcout << "This feature is not supported on unix-based systems yet.\n"; + return false; + } +} \ No newline at end of file diff --git a/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.h b/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.h new file mode 100644 index 0000000..8a06546 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Unix/UnixUtilities.h @@ -0,0 +1,42 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Platform/IPlatformUtilities.h" +namespace HarmonyLinkLib +{ + // This is more of a "catch all" for all unix-based systems + // that don't have their own implementations. + class UnixUtilities : public IPlatformUtilities { + public: + bool is_running_under_wine() override; + + std::shared_ptr get_cpu_info() override; + std::shared_ptr get_battery_status() override; + std::shared_ptr get_os_version() override; + + bool get_is_external_monitor_connected() override; + + bool get_keyboard_detected() override; + + bool get_mouse_detected() override; + + bool get_external_controller_detected() override; + + bool get_is_steam_deck_native_resolution() override; + + // Implementation for other Unix/Linux-specific functions + }; +} diff --git a/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.cpp b/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.cpp new file mode 100644 index 0000000..dfd7aa8 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.cpp @@ -0,0 +1,177 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "WindowsUtilities.h" + +#include +#include + +#include +#pragma comment(lib, "XInput.lib") + +#include "Platform/WineUtilities.h" +#include + +namespace HarmonyLinkLib +{ + std::shared_ptr WindowsUtilities::get_battery_status() + { + if (is_linux()) + { + return WineUtilities::get_battery_status(); + } + FBattery result; + + SYSTEM_POWER_STATUS status; + if (GetSystemPowerStatus(&status)) { + result.has_battery = status.BatteryFlag != 128; // 128 indicates no battery + result.is_connected_to_ac = status.ACLineStatus == 1; + result.battery_percent = result.has_battery ? status.BatteryLifePercent : 0; + } else { + std::wcout << "Failed to get power statistics.\n"; + } + + return std::make_shared(result); + } + + std::shared_ptr WindowsUtilities::get_cpu_info() + { + if (is_linux()) + { + return WineUtilities::get_cpu_info(); + } + + return {}; + } + + std::shared_ptr WindowsUtilities::get_os_version() + { + if (is_linux()) + { + return WineUtilities::get_linux_info(); + } + + OSVERSIONINFOEX os_version_info; + ZeroMemory(&os_version_info, sizeof(OSVERSIONINFOEX)); + os_version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + if (!GetVersionEx(reinterpret_cast(&os_version_info))) { + // Handle error if needed + return nullptr; + } + + FOSVerInfo os_version; + + HKEY h_key; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &h_key) == ERROR_SUCCESS) + { + DWORD dw_size; + DWORD dw_type; + char sz_product_name[256]; + dw_size = sizeof(sz_product_name); + if (RegQueryValueEx(h_key, TEXT("ProductName"), nullptr, &dw_type, reinterpret_cast(sz_product_name), &dw_size) == ERROR_SUCCESS) + { + os_version.pretty_name = sz_product_name; + } + RegCloseKey(h_key); + } + + std::stringstream version; + version << os_version_info.dwMajorVersion << "." << os_version_info.dwMinorVersion; + os_version.version_id = version.str(); + + os_version.name = "Windows"; + os_version.version = os_version_info.dwBuildNumber; // Build number as the version + + return std::make_shared(os_version); + } + + bool WindowsUtilities::get_is_external_monitor_connected() + { + // SM_CMONITORS returns the count of all display monitors. + const int monitorCount = GetSystemMetrics(SM_CMONITORS); + + // More than one monitor implies an external monitor is connected. + return monitorCount > 1; + } + + bool WindowsUtilities::get_keyboard_detected() + { + UINT n_devices; + std::vector devices; + + GetRawInputDeviceList(devices.data(), &n_devices, sizeof(RAWINPUTDEVICELIST)); + + if (n_devices == 0) + { + return false; + } + + return std::any_of(devices.begin(), devices.end(), [](const RAWINPUTDEVICELIST& device) + { + return device.dwType == RIM_TYPEKEYBOARD; + }); + } + + bool WindowsUtilities::get_mouse_detected() + { + UINT n_devices; + std::vector devices; + + GetRawInputDeviceList(devices.data(), &n_devices, sizeof(RAWINPUTDEVICELIST)); + + if (n_devices == 0) + { + return false; + } + + return std::any_of(devices.begin(), devices.end(), [](const RAWINPUTDEVICELIST& device) + { + return device.dwType == RIM_TYPEMOUSE; + }); + } + + bool WindowsUtilities::get_external_controller_detected() + { + static_assert(XUSER_MAX_COUNT <= UINT8_MAX, "XUSER_MAX_COUNT exceeds uint8_t size"); + + uint8_t connectedGamepads = 0; + + for (DWORD i = 0; i < XUSER_MAX_COUNT; ++i) { + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + if (XInputGetState(i, &state) == ERROR_SUCCESS) { + connectedGamepads++; + } + } + + return connectedGamepads > 1; + } + + bool WindowsUtilities::get_is_steam_deck_native_resolution() + { + DEVMODE devMode; + devMode.dmSize = sizeof(DEVMODE); + + // Get the current display settings for the primary monitor + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode)) { + // Check if the resolution is higher than 800p (1280x800) + if (devMode.dmPelsWidth > 1280 || devMode.dmPelsHeight > 800) { + return true; + } + } + return false; + } +} diff --git a/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.h b/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.h new file mode 100644 index 0000000..809b204 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/Windows/WindowsUtilities.h @@ -0,0 +1,40 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Platform/IPlatformUtilities.h" + +namespace HarmonyLinkLib +{ + class WindowsUtilities : public IPlatformUtilities + { + public: + std::shared_ptr get_battery_status() override; + + std::shared_ptr get_cpu_info() override; + + std::shared_ptr get_os_version() override; + + bool get_is_external_monitor_connected() override; + + bool get_keyboard_detected() override; + + bool get_mouse_detected() override; + + bool get_external_controller_detected() override; + + bool get_is_steam_deck_native_resolution() override; + }; +} diff --git a/HarmonyLinkLib/src/Platform/WineUtilities.cpp b/HarmonyLinkLib/src/Platform/WineUtilities.cpp new file mode 100644 index 0000000..fca7352 --- /dev/null +++ b/HarmonyLinkLib/src/Platform/WineUtilities.cpp @@ -0,0 +1,218 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "WineUtilities.h" + +#include +#include +#include +#include +#include + +#ifdef BUILD_WINDOWS +#include +#endif + +namespace fs = ghc::filesystem; + +namespace HarmonyLinkLib +{ + bool force_detect_wine = false; + + std::shared_ptr HarmonyLinkLib::WineUtilities::get_battery_status() + { + std::string append; + if (is_wine_present()) + { + append = "Z:"; + } + + FBattery result = {}; + for (int i = 0; i <= 9; ++i) { + if (std::string bat_path = append + "/sys/class/power_supply/BAT" + std::to_string(i); fs::exists(bat_path)) { + result.has_battery = true; + + std::ifstream status_file(bat_path + "/status"); + std::string status; + if (status_file.is_open() && std::getline(status_file, status)) { + if (status == "Charging" || status == "AC") { + result.is_connected_to_ac = true; + } + } + + std::ifstream capacity_file(bat_path + "/capacity"); + if (capacity_file.is_open() && std::getline(capacity_file, status)) { + result.battery_percent = static_cast(std::stoi(status)); + break; // assuming you only need data from the first battery found + } + } + } + + return std::make_shared(result); + } + + std::shared_ptr WineUtilities::get_cpu_info() + { + std::wcout << "Getting cpu info\n"; + + std::string append; + if (is_wine_present()) + { + append = "Z:"; + } + + FCPUInfo cpu_info; + + std::ifstream file(append + "/proc/cpuinfo"); + std::unordered_map hashmap; + + if (file) { + std::string line; + while (std::getline(file, line)) { + std::istringstream line_stream(line); + std::string key, value; + if (std::getline(line_stream, key, ':')) { + key.erase(key.find_last_not_of(" \t") + 1); // Trim trailing whitespace from key + if (std::getline(line_stream, value)) { + value.erase(0, value.find_first_not_of(" \t")); // Trim leading whitespace from value + + // Aggregate flags + if (key == "flags") { + std::istringstream flag_stream(value); + std::string flag; + while (flag_stream >> flag) { + flag.erase(flag.find_last_not_of(" \t") + 1); // Trim trailing whitespace from flag + cpu_info.Flags.insert(HarmonyLinkLib::FString(flag)); + //printf("Flag detected: %s\n", flag.c_str()); + } + } else { + hashmap[key] = value; + } + } + } + } + file.close(); + } + + // Now you can access the values using the keys: + cpu_info.VendorID = hashmap["vendor_id"]; + cpu_info.Model_Name = hashmap["model name"]; + + try { + cpu_info.Physical_Cores = std::stoi(hashmap["cpu cores"].c_str()); + } catch (const std::invalid_argument& ia) { + std::wcerr << "Invalid argument: " << ia.what() << '\n'; + } catch (const std::out_of_range& oor) { + std::wcerr << "Out of Range error: " << oor.what() << '\n'; + } + + cpu_info.Logical_Cores = (cpu_info.Flags.find("ht") != cpu_info.Flags.end()) ? cpu_info.Physical_Cores * 2 : cpu_info.Physical_Cores; + + return std::make_shared(cpu_info); + } + + std::shared_ptr WineUtilities::get_linux_info() + { + std::string append; + if (is_wine_present()) + { + append = "Z:"; + } + + FOSVerInfo os_info; + + std::ifstream file(append + "/etc/os-release"); + std::unordered_map hashmap; + + if (file) { + std::string line; + while (std::getline(file, line)) { + std::istringstream lineStream(line); + std::string key, value; + if (std::getline(lineStream, key, '=')) { + if (std::getline(lineStream, value)) { + // Remove leading and trailing whitespace + size_t firstNonSpace = value.find_first_not_of(" \t"); + size_t lastNonSpace = value.find_last_not_of(" \t"); + if (firstNonSpace != std::string::npos && lastNonSpace != std::string::npos) { + value = value.substr(firstNonSpace, lastNonSpace - firstNonSpace + 1); + } else { + value.clear(); // If value is all whitespace, make it empty + } + + // Check for double quotes and remove them + if (!value.empty() && value.front() == '"' && value.back() == '"') { + value = value.substr(1, value.length() - 2); + } + + hashmap[key] = value; + } + } + } + file.close(); + } + + // Now you can access the values using the keys: + os_info.name = hashmap["NAME"]; + os_info.id = hashmap["ID"]; + os_info.version_id = hashmap["VERSION_ID"]; + os_info.version_codename = hashmap["VERSION_CODENAME"]; + os_info.pretty_name = hashmap["PRETTY_NAME"]; + + try { + os_info.version = std::stoi(hashmap["VERSION"].c_str()); + } catch (const std::invalid_argument& ia) { + std::cerr << "Invalid argument: " << ia.what() << '\n'; + // Handle the error, perhaps by setting a default value or leaving the field unchanged + } catch (const std::out_of_range& oor) { + std::cerr << "Out of Range error: " << oor.what() << '\n'; + // Handle the error, perhaps by setting a default value or leaving the field unchanged + } + + return std::make_shared(os_info); + } + + bool WineUtilities::is_wine_present() + { + static bool isWineCached = false; // Static variable to store the cached result + static bool isWine = false; // Static variable to indicate if the caching has been done + + if (!isWineCached) + { + // Only detect wine if force_detect_wine is true or if we haven't cached the result yet +#ifdef BUILD_WINDOWS + std::wcout << "Detecting wine...\n"; + bool HasFound = GetProcAddress(GetModuleHandle("ntdll.dll"), "wine_get_version") != nullptr; + + if (!HasFound) + HasFound = GetProcAddress(GetModuleHandle("ntdll.dll"), "proton_get_version") != nullptr; + + wprintf(L"wine %s found\n", HasFound ? L"has been" : L"not"); + + isWine = HasFound; // Cache the result +#else + isWine = false; // In non-Windows builds, always set isWine to false +#endif + isWineCached = true; // Indicate that the result is now cached + } + + return isWine; // Return the cached result + } + + bool WineUtilities::force_detect_wine_presence() + { + force_detect_wine = true; + return is_wine_present(); + } +} diff --git a/HarmonyLinkLib/src/Platform/WineUtilities.h b/HarmonyLinkLib/src/Platform/WineUtilities.h new file mode 100644 index 0000000..5e5bdae --- /dev/null +++ b/HarmonyLinkLib/src/Platform/WineUtilities.h @@ -0,0 +1,60 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Structs/FBattery.h" +#include "Structs/FCPUInfo.h" +#include "Structs/FOSVerInfo.h" + +namespace HarmonyLinkLib +{ + class WineUtilities + { + public: + static std::shared_ptr get_battery_status(); + + static std::shared_ptr get_cpu_info(); + + /** + * @brief Retrieves Linux OS version information from a specified file. + * + * This function parses a file (typically a Linux OS release file) at the given location + * to extract operating system version information. It reads key-value pairs from the file, + * processes them to handle whitespace and quotes, and then stores them in an FOSVerInfo + * structure. If the file location is invalid or the file cannot be opened, it returns an + * empty FOSVerInfo structure. Errors during parsing, such as invalid format or out of range + * values, are handled with exception catching. In Windows builds where Wine is detected, + * this function can use the file location 'Z:/etc/os-release' to retrieve the underlying + * Linux system information. + * + * @param file_location The location of the file containing OS version information. + * @return A shared pointer to a structure containing the parsed OS version information. + */ + static std::shared_ptr get_linux_info(); + + /** + * @brief Detects the presence of Wine or Proton in Windows builds. + * + * This function assesses if the application is running under Wine or Proton by + * querying specific functions in the 'ntdll.dll' module. It is only active in + * Windows builds, returning false for non-Windows builds. + * + * @return bool True if Wine or Proton is detected, false otherwise. + */ + static bool is_wine_present(); + + static bool force_detect_wine_presence(); + }; +} diff --git a/HarmonyLinkLib/src/Utilities.cpp b/HarmonyLinkLib/src/Utilities.cpp new file mode 100644 index 0000000..608437c --- /dev/null +++ b/HarmonyLinkLib/src/Utilities.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Utilities.h" + +#include + +#include "FString.h" + +void HarmonyLinkLib::Utilities::DebugPrint(const FString& String, bool AddNewline) +{ +#ifdef DEBUG_MODE + std::wcout << String.c_str(); + + if (AddNewline) + { + std::wcout << L"\n"; + } +#endif +} + +void HarmonyLinkLib::Utilities::DebugPrint(const char* String, bool AddNewline) +{ +#ifdef DEBUG_MODE + std::wcout << std::wstring(String, String + std::strlen(String)); + + if (AddNewline) { + std::wcout << L"\n"; + } +#endif +} + +void HarmonyLinkLib::Utilities::DebugPrint(const wchar_t* String, bool AddNewline) +{ +#ifdef DEBUG_MODE + std::wcout << String; + + if (AddNewline) { + std::wcout << L"\n"; + } +#endif +} diff --git a/HarmonyLinkLib/src/Utilities.h b/HarmonyLinkLib/src/Utilities.h new file mode 100644 index 0000000..d6114c8 --- /dev/null +++ b/HarmonyLinkLib/src/Utilities.h @@ -0,0 +1,30 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "HarmonyLinkLib.h" + +namespace HarmonyLinkLib +{ + class FString; + + class Utilities + { + public: + static void DebugPrint(const FString& String, bool AddNewline = true); + static void DebugPrint(const char* String, bool AddNewline = true); + static void DebugPrint(const wchar_t* String, bool AddNewline = true); + }; +} diff --git a/LibHarmonyLink/include/Wine.h b/HarmonyLinkLib/src/Version.cpp similarity index 77% rename from LibHarmonyLink/include/Wine.h rename to HarmonyLinkLib/src/Version.cpp index 9614ee4..d340da1 100644 --- a/LibHarmonyLink/include/Wine.h +++ b/HarmonyLinkLib/src/Version.cpp @@ -12,19 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -#pragma once - -#include -#include "Core.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -bool Detect_Wine(void); - -#ifdef __cplusplus -} -} -#endif +#include "Version.h" diff --git a/HarmonyLinkTest/CMakeLists.txt b/HarmonyLinkTest/CMakeLists.txt index a7c0d12..949ea4f 100644 --- a/HarmonyLinkTest/CMakeLists.txt +++ b/HarmonyLinkTest/CMakeLists.txt @@ -15,29 +15,22 @@ cmake_minimum_required(VERSION 3.10) project(HarmonyLinkTest) # Specify the C++ standard -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED True) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) # Automatically add all .cpp and .h/.hpp files in the src directory -file(GLOB_RECURSE TEST_SOURCES "src/*.c") +file(GLOB_RECURSE TEST_SOURCES "src/*.cpp") file(GLOB_RECURSE TEST_HEADERS "src/*.h" "src/*.hpp") -# Enable all compiler warnings and errors -if(MSVC) - add_compile_options(/W4 /WX) -else() - add_compile_options(-Wall -Wextra -pedantic -Werror) -endif() - # Add executable for static library add_executable(HarmonyLinkTestStatic ${TEST_SOURCES} ${TEST_HEADERS}) -target_link_libraries(HarmonyLinkTestStatic PRIVATE LibHarmonyLinkStatic) -target_compile_definitions(HarmonyLinkTestStatic PRIVATE HARMONYLINK_STATIC) +target_link_libraries(HarmonyLinkTestStatic PRIVATE HarmonyLinkLibStatic) +target_compile_definitions(HarmonyLinkTestStatic PRIVATE HARMONYLINKLIB_STATIC) # Add executable for shared library add_executable(HarmonyLinkTestShared ${TEST_SOURCES} ${TEST_HEADERS}) -target_link_libraries(HarmonyLinkTestShared PRIVATE LibHarmonyLinkShared) -target_compile_definitions(HarmonyLinkTestShared PRIVATE HARMONYLINK_SHARED) +target_link_libraries(HarmonyLinkTestShared PRIVATE HarmonyLinkLibShared) +target_compile_definitions(HarmonyLinkTestShared PRIVATE HARMONYLINKLIB_SHARED) # Set output directories for all build types foreach(TYPE IN ITEMS DEBUG RELEASE) @@ -61,5 +54,5 @@ endforeach() # Copy the DLL to the executable directory after building the shared test executable add_custom_command(TARGET HarmonyLinkTestShared POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$" + "$" "$") diff --git a/HarmonyLinkTest_CPP/src/main.cpp b/HarmonyLinkTest/src/main.cpp similarity index 61% rename from HarmonyLinkTest_CPP/src/main.cpp rename to HarmonyLinkTest/src/main.cpp index 7680ffd..d4d2d29 100644 --- a/HarmonyLinkTest_CPP/src/main.cpp +++ b/HarmonyLinkTest/src/main.cpp @@ -17,7 +17,7 @@ #include #include -#include "LibHarmonyLink.h" +#include "HarmonyLinkLib.h" // Include necessary headers for platform-specific functionality #ifdef BUILD_WINDOWS @@ -32,11 +32,9 @@ std::atomic quitFlag(false); -std::atomic HasError(false); - // Function to clear the screen cross-platform void clearScreen() { -#ifdef BUILD_WINDOWS +#ifdef _WIN32 system("cls"); #else std::cout << "\x1B[2J\x1B[H"; @@ -46,7 +44,7 @@ void clearScreen() { // Function to check if 'q' or 'Q' is pressed in Windows void checkForQuit() { - while (!quitFlag || !HasError) { + while (!quitFlag) { #ifdef BUILD_WINDOWS if (_kbhit()) { const char c = static_cast(_getch()); @@ -87,68 +85,62 @@ void checkForQuit() { int main() { - std::cout << "Hello, World!" << '\n'; - - if (!LibHarmonyLink::HL_Init()) - { - printf("Failed to Initialize HarmonyLink!\n"); - - HasError = true; - return 1; - } - - printf("HarmonyLink Initialized!\n"); + std::cout << "Hello, World!\n"; std::thread inputThread(checkForQuit); - const char* isLinux = LibHarmonyLink::HL_Is_Linux() ? "is" : "isn't"; - printf("This program %s running under Linux.\n", isLinux); + if (!HarmonyLinkLib::HL_Init()) + { + std::cout << "Failed to init HarmonyLinkLib\n"; + return 1; + } - const bool isWine = LibHarmonyLink::HL_Is_Wine(); + std::cout << "HarmonyLinkLib successfully initialised!\n"; + + const bool isWine = HarmonyLinkLib::get_is_wine(); const char* test = isWine ? "is" : "isn't"; - printf("This program %s running under wine.\n", test); + const HarmonyLinkLib::FOSVerInfo* os_info = HarmonyLinkLib::get_os_version(); - //const HarmonyLinkLib::FOSVerInfo* os_info = HarmonyLinkLib::get_os_version(); + const HarmonyLinkLib::FDevice* device_info = HarmonyLinkLib::get_device_info(); - //const HarmonyLinkLib::FDevice* device_info = HarmonyLinkLib::get_device_info(); + const HarmonyLinkLib::FCPUInfo* cpu_info = HarmonyLinkLib::get_cpu_info(); - //const HarmonyLinkLib::FCPUInfo* cpu_info = HarmonyLinkLib::get_cpu_info(); - - HasError = true; // This loop is to test how stable & expensive these functions are - while (!quitFlag || !HasError) + while (!quitFlag) { // Clear the screen clearScreen(); - //if (cpu_info) - //{ - // cpu_info->print(); - //} + std::wcout << "This program " << test << " running under wine.\n"; - //if (os_info) - //{ - // os_info->print(); - //} + if (cpu_info) + { + cpu_info->print(); + } - //if (device_info) - //{ - // wprintf(L"Is SteamDeck: %s\n", device_info->device == HarmonyLinkLib::EDevice::STEAM_DECK ? L"true" : L"false"); - //} + if (os_info) + { + os_info->print(); + } + + if (device_info) + { + wprintf(L"Is SteamDeck: %s\n", device_info->device == HarmonyLinkLib::EDevice::STEAM_DECK ? L"true" : L"false"); + } // we can't do this before the loop because we need updated values - //if (const HarmonyLinkLib::FBattery* battery = HarmonyLinkLib::get_battery_status()) - //{ - // battery->print(); - // battery->free(); - //} + if (const HarmonyLinkLib::FBattery* battery = HarmonyLinkLib::get_battery_status()) + { + battery->to_string(); + battery->free(); + } - //const bool is_docked = HarmonyLinkLib::get_is_docked(); + const bool is_docked = HarmonyLinkLib::get_is_docked(); - //const char* dock_check_string = is_docked ? "is" : "isn't"; + const char* dock_check_string = is_docked ? "is" : "isn't"; - //wprintf(L"Device %hs docked\n", dock_check_string); + wprintf(L"Device %hs docked\n", dock_check_string); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } @@ -158,20 +150,20 @@ int main() inputThread.join(); } - //if (os_info) - //{ - // os_info->free(); - //} + if (os_info) + { + os_info->free(); + } - //if (device_info) - //{ - // device_info->free(); - //} + if (device_info) + { + device_info->free(); + } - //if (cpu_info) - //{ - // cpu_info->free(); - //} + if (cpu_info) + { + cpu_info->free(); + } return 0; } diff --git a/HarmonyLinkTest_CPP/CMakeLists.txt b/HarmonyLinkTest_CPP/CMakeLists.txt deleted file mode 100644 index 65efc21..0000000 --- a/HarmonyLinkTest_CPP/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2024 Jordon Brooks -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.22.1) -project(HarmonyLinkTest) - -# Specify the C++ standard -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -# Automatically add all .cpp and .h/.hpp files in the src directory -file(GLOB_RECURSE TEST_SOURCES "src/*.cpp") -file(GLOB_RECURSE TEST_HEADERS "src/*.h" "src/*.hpp") - -# Enable all compiler warnings and errors -if(MSVC) - add_compile_options(/W4 /WX) -else() - add_compile_options(-Wall -Wextra -pedantic -Werror) -endif() - -# Add executable for static library -add_executable(HarmonyLinkTestStatic_CPP ${TEST_SOURCES} ${TEST_HEADERS}) -target_link_libraries(HarmonyLinkTestStatic_CPP PRIVATE LibHarmonyLinkStatic) -target_compile_definitions(HarmonyLinkTestStatic_CPP PRIVATE HARMONYLINK_STATIC) - -# Add executable for shared library -add_executable(HarmonyLinkTestShared_CPP ${TEST_SOURCES} ${TEST_HEADERS}) -target_link_libraries(HarmonyLinkTestShared_CPP PRIVATE LibHarmonyLinkShared) -target_compile_definitions(HarmonyLinkTestShared_CPP PRIVATE HARMONYLINK_SHARED) - -# Set output directories for all build types -foreach(TYPE IN ITEMS DEBUG RELEASE) - string(TOUPPER ${TYPE} TYPE_UPPER) - - # Static test executable properties - set_target_properties(HarmonyLinkTestStatic_CPP PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}/HarmonyLinkTestStatic_CPP" - LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}/HarmonyLinkTestStatic_CPP" - ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkTestStatic_CPP" - ) - - # Shared test executable properties - set_target_properties(HarmonyLinkTestShared_CPP PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}/HarmonyLinkTestShared_CPP" - LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}/HarmonyLinkTestShared_CPP" - ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkTestShared_CPP" - ) -endforeach() - -# Copy the DLL to the executable directory after building the shared test executable -add_custom_command(TARGET HarmonyLinkTestShared_CPP POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$" - "$") diff --git a/LibHarmonyLink/CMakeLists.txt b/LibHarmonyLink/CMakeLists.txt deleted file mode 100644 index fd1c097..0000000 --- a/LibHarmonyLink/CMakeLists.txt +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (c) 2024 Jordon Brooks -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.10) -project(LibHarmonyLink VERSION 2.1.1 LANGUAGES C) - -# Specify the C++ standard -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED True) - -# Find the current Git branch and the last commit timestamp -find_package(Git QUIET) -if(GIT_FOUND) - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_BRANCH_NAME - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND ${GIT_EXECUTABLE} log -1 --format=%ct - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_TIMESTAMP - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -else() - set(GIT_BRANCH_NAME "Unknown") - set(GIT_COMMIT_TIMESTAMP "Unknown") -endif() - -configure_file(include/Version.h.in Version.generated.h) - -# Define metadata variables -set(FILE_DESCRIPTION "Enhances handheld gaming with intelligent hardware recognition, dynamic adaptability, and robust API access for Windows and Linux, including Steam Deck and Wine support.") -set(INTERNAL_NAME "LibHarmonyLink") -set(ORIGINAL_FILENAME "LibHarmonyLink.dll") -set(PRODUCT_NAME "LibHarmonyLink") -set(COMMENTS "") - -# Configure version.rc file for shared library -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Resources/Version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) - -# Explicitly list source files -set(COMMON_SOURCES - src/LibHarmonyLink.c - src/Version.c - src/Utilities.c - src/Wine.c - - src/Structs/Battery.c - src/Structs/CPUInfo.c - src/Structs/StringArray.c - src/Structs/Device.c - src/Structs/OSInfo.c -) - -# Explicitly list include files -set(COMMON_INCLUDES - include/Core.h - include/LibHarmonyLink.h - include/Version.h - include/Utilities.h - include/Wine.h - - include/Enums/Device.h - include/Enums/Platform.h - include/Enums/SteamDeck.h - - include/Structs/Battery.h - include/Structs/CPUInfo.h - include/Structs/StringArray.h - include/Structs/Device.h - include/Structs/OSInfo.h -) - -set(WINDOWS_SOURCES -) - -set(WINDOWS_INCLUDES -) - -set(LINUX_SOURCES -) - -set(LINUX_INCLUDES - -) - -set(MAC_SOURCES -) - -set(MAC_INCLUDES -) - -# Platform-specific definitions -if(WIN32) - message(STATUS "Compiling for Windows...") - list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${WINDOWS_SOURCES}) - list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${WINDOWS_INCLUDES}) - list(APPEND SHARED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) -elseif(UNIX) - message(STATUS "Compiling for Unix-based systems...") - if(APPLE) - message(STATUS "Compiling for Mac...") - list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${MAC_SOURCES}) - list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${MAC_INCLUDES}) - else() - message(STATUS "Compiling for Linux...") - list(APPEND LIB_SOURCES ${COMMON_SOURCES} ${LINUX_SOURCES}) - list(APPEND LIB_INCLUDES ${COMMON_INCLUDES} ${LINUX_INCLUDES}) - endif() -endif() - -# Detect the compiler name -get_filename_component(COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME) - -# Replace forbidden characters in file names (optional, if needed) -string(REPLACE "." "_" COMPILER_NAME ${COMPILER_NAME}) -string(REPLACE "/" "_" COMPILER_NAME ${COMPILER_NAME}) -string(REPLACE "\\" "_" COMPILER_NAME ${COMPILER_NAME}) - -# Enable all compiler warnings and errors -if(MSVC) - add_compile_options(/W4 /WX) -else() - add_compile_options(-Wall -Wextra -pedantic -Werror) -endif() - -# Create the shared library -add_library(LibHarmonyLinkShared SHARED ${LIB_SOURCES} ${LIB_INCLUDES} ${SHARED_SOURCES}) -target_include_directories(LibHarmonyLinkShared - PRIVATE - "${PROJECT_SOURCE_DIR}/src" - PUBLIC - "${PROJECT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}/include" -) -target_compile_definitions(LibHarmonyLinkShared PRIVATE HARMONYLINK_SHARED) -set_target_properties(LibHarmonyLinkShared PROPERTIES OUTPUT_NAME "LibHarmonyLink_${COMPILER_NAME}") - -# Create the static library -add_library(LibHarmonyLinkStatic STATIC ${LIB_SOURCES} ${LIB_INCLUDES}) -target_include_directories(LibHarmonyLinkStatic - PRIVATE - "${PROJECT_SOURCE_DIR}/src" - PUBLIC - "${PROJECT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}/include" -) -target_compile_definitions(LibHarmonyLinkStatic PRIVATE HARMONYLINK_STATIC) -set_target_properties(LibHarmonyLinkStatic PROPERTIES OUTPUT_NAME "LibHarmonyLink_${COMPILER_NAME}") - -# Set output directories for all build types -foreach(TYPE IN ITEMS DEBUG RELEASE) - string(TOUPPER ${TYPE} TYPE_UPPER) - set_target_properties(LibHarmonyLinkShared PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}/HarmonyLinkLib" - LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}/HarmonyLinkLib" - ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkLib" - ) - set_target_properties(LibHarmonyLinkStatic PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}/HarmonyLinkLibStatic" - ) -endforeach() diff --git a/LibHarmonyLink/include/Enums/Device.h b/LibHarmonyLink/include/Enums/Device.h deleted file mode 100644 index 66e749c..0000000 --- a/LibHarmonyLink/include/Enums/Device.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "Core.h" - -// Undefine the LINUX macro to avoid conflicts with the enum definition. -#undef LINUX - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef enum { - EDevice_UNKNOWN, - EDevice_DESKTOP, - EDevice_LAPTOP, - EDevice_HANDHELD, - - EDevice_STEAM_DECK, - // EDevice_ROG_ALLY - // EDevice_AYONEO_SLIDE - // etc... -} EDevice; - -HARMONYLINK_API const char* Device_ToString(EDevice device) { - switch (device) { - case EDevice_DESKTOP: return "DESKTOP"; - case EDevice_LAPTOP: return "LAPTOP"; - case EDevice_HANDHELD: return "HANDHELD"; - case EDevice_STEAM_DECK: return "STEAM_DECK"; - default: return "UNKNOWN"; - } -} - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Enums/Platform.h b/LibHarmonyLink/include/Enums/Platform.h deleted file mode 100644 index 247eff9..0000000 --- a/LibHarmonyLink/include/Enums/Platform.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "Core.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef enum { - EPlatform_UNKNOWN, - EPlatform_WINDOWS, - EPlatform_LINUX, - EPlatform_MAC, - EPlatform_UNIX, -} EPlatform; - -// Helper functions to convert enums to strings (must be implemented somewhere in your code) -HARMONYLINK_API const char* Platform_ToString(EPlatform platform) { - switch (platform) { - case EPlatform_WINDOWS: return "WINDOWS"; - case EPlatform_LINUX: return "LINUX"; - case EPlatform_MAC: return "MAC"; - case EPlatform_UNIX: return "UNIX"; - default: return "UNKNOWN"; - } -} - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Enums/SteamDeck.h b/LibHarmonyLink/include/Enums/SteamDeck.h deleted file mode 100644 index b6fe09e..0000000 --- a/LibHarmonyLink/include/Enums/SteamDeck.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "Core.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef enum { - ESteamDeck_NONE, // Device is not a steam deck - ESteamDeck_UNKNOWN, // Device is a steam deck but model cannot be determined - ESteamDeck_LCD, - ESteamDeck_OLED, -} ESteamDeck; - -HARMONYLINK_API const char* SteamDeck_ToString(ESteamDeck steam_deck_model) { - switch (steam_deck_model) { - case ESteamDeck_NONE: return "NONE"; - case ESteamDeck_LCD: return "STEAMDECK_LCD"; - case ESteamDeck_OLED: return "STEAMDECK_OLED"; - // Add other cases as needed - default: return "UNKNOWN"; - } -} - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/LibHarmonyLink.h b/LibHarmonyLink/include/LibHarmonyLink.h deleted file mode 100644 index 9a7d790..0000000 --- a/LibHarmonyLink/include/LibHarmonyLink.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include "Core.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -/** - * @brief Initializes the HarmonyLink library. - * - * This function initializes the HarmonyLink library by printing the version, - * detecting if the application is running under Wine or on Linux. - * - * @return Returns true on successful initialization. - */ -HARMONYLINK_API bool HL_Init(void); -/** - * @brief Checks if the HarmonyLink library is running under Wine. - * - * This function returns the result of Get_IsWine. - * - * @return Returns true if the HarmonyLink library is running under Wine, false otherwise. - */ -HARMONYLINK_API bool HL_Is_Wine(void); - -/** - * @brief Checks if the HarmonyLink library is running on Linux. - * - * This function returns the result of Get_IsLinux. - * - * @return Returns true if the HarmonyLink library is running on Linux, false otherwise. - */ -HARMONYLINK_API bool HL_Is_Linux(void); - -/** - * @brief Handles the detection of Linux. - * - * This function detects if the application is running on Linux and caches the result. - * If the application is not running on Linux, it checks if it is running under Wine. - */ -void Handle_Detect_Linux(void); - -/** - * @brief Handles the detection of Wine. - * - * This function detects if the application is running under Wine and caches the result. - */ -void Handle_Detect_Wine(void); - -/** - * @brief Checks if the application is running under Wine. - * - * This function returns the cached result of the Wine detection. If the result - * is not cached, it will call Handle_Detect_Wine to detect and cache the result. - * - * @return Returns true if the application is running under Wine, false otherwise. - */ -bool Get_IsWine(void); - -/** - * @brief Checks if the application is running on Linux. - * - * This function returns the cached result of the Linux detection. If the result - * is not cached, it will call Handle_Detect_Linux to detect and cache the result. - * - * @return Returns true if the application is running on Linux, false otherwise. - */ -bool Get_IsLinux(void); - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Structs/CPUInfo.h b/LibHarmonyLink/include/Structs/CPUInfo.h deleted file mode 100644 index 36d9d13..0000000 --- a/LibHarmonyLink/include/Structs/CPUInfo.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// include/Structs/CPUInfo.h - -#pragma once - -#include -#include - -#include "Core.h" -#include "Structs/StringArray.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef struct FCPUInfo { - char* VendorID; - char* Model_Name; - unsigned int Physical_Cores; - unsigned int Logical_Cores; - StringArray flagsInfo; -} FCPUInfo; - -// Initialize FCPUInfo -FCPUInfo* FCPUInfo_Init(const char *vendorID, const char *modelName, unsigned int physicalCores, unsigned int logicalCores, - size_t flagsCount); - -// Print FlagsInfo -HARMONYLINK_API void HL_FlagsInfo_Print(const FCPUInfo *cpuInfo); - -// Print FCPUInfo -HARMONYLINK_API void HL_FCPUInfo_Print(const FCPUInfo *cpuInfo); - -// Free FCPUInfo -HARMONYLINK_API void HL_FCPUInfo_Free(FCPUInfo *cpuInfo); - -// Check if a flag exists in FlagsInfo -HARMONYLINK_API bool HL_FlagsInfo_Contains(const FCPUInfo *cpuInfo, const char *flag); - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Structs/Device.h b/LibHarmonyLink/include/Structs/Device.h deleted file mode 100644 index 546f936..0000000 --- a/LibHarmonyLink/include/Structs/Device.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "Core.h" -#include "Enums/Platform.h" -#include "Enums/Device.h" -#include "Enums/SteamDeck.h" - -#define DEFAULT_INITIAL_FLAGS_SIZE 4 - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef struct { - EPlatform platform; - EDevice device; - ESteamDeck steam_deck_model; -} FDevice; - -// Initialize FlagsInfo -FDevice* Device_Init(EPlatform platform, EDevice device, ESteamDeck steam_deck_model); - -// Print FlagsInfo -HARMONYLINK_API void HL_Device_Print(const FDevice* Device); - -// Free FlagsInfo -HARMONYLINK_API void HL_Device_Free(FDevice* Device); - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Structs/OSInfo.h b/LibHarmonyLink/include/Structs/OSInfo.h deleted file mode 100644 index e160a6a..0000000 --- a/LibHarmonyLink/include/Structs/OSInfo.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include - -#include "Core.h" - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef struct { - char* name; - char* version; - unsigned int id; - char* version_id; - char* version_codename; - char* pretty_name; - char* variant_id; -} FOSVerInfo; - -// Initialize FCPUInfo -FOSVerInfo* FOSVerInfo_Init(char* name, char* version, unsigned int id, char* version_id, char* version_codename, char* pretty_name, char* variant_id); - -// Print FlagsInfo -HARMONYLINK_API void HL_FOSVerInfo_Print(const FOSVerInfo* OSVerInfo); - -// Free FCPUInfo -HARMONYLINK_API void HL_FOSVerInfo_Free(FOSVerInfo* OSVerInfo); - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/include/Structs/StringArray.h b/LibHarmonyLink/include/Structs/StringArray.h deleted file mode 100644 index af9beea..0000000 --- a/LibHarmonyLink/include/Structs/StringArray.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// include/Structs/StringArray.h - -#pragma once - -#include -#include - -#include "Core.h" - -#define DEFAULT_INITIAL_FLAGS_SIZE 4 - -#ifdef __cplusplus -namespace LibHarmonyLink { -extern "C" { -#endif - -typedef struct StringArray { - char **data; // Array of strings (flags) - size_t FlagsCount; // Number of flags - size_t AllocatedSize; // Number of allocated slots -} StringArray; - -// Initialize FlagsInfo -void StringArray_Init(StringArray *flagsInfo, size_t overrideInitialSize); - -// Print FlagsInfo -HARMONYLINK_API void HL_StringArray_Print(const StringArray *flagsInfo); - -// Free FlagsInfo -HARMONYLINK_API void HL_StringArray_Free(StringArray *flagsInfo); - -// Check if a flag exists in FlagsInfo -HARMONYLINK_API bool HL_StringArray_Contains(const StringArray *flagsInfo, const char *flag); - -// Add a flag to FlagsInfo -void StringArray_AddFlag(StringArray *flagsInfo, const char *flag); - -// Remove a flag from FlagsInfo by value -void StringArray_Remove(StringArray *flagsInfo, const char *flag); - -// Resize FlagsInfo array -void StringArray_Resize(StringArray *flagsInfo, size_t newSize); - -#ifdef __cplusplus -} -} -#endif diff --git a/LibHarmonyLink/src/LibHarmonyLink.c b/LibHarmonyLink/src/LibHarmonyLink.c deleted file mode 100644 index 18bf5ec..0000000 --- a/LibHarmonyLink/src/LibHarmonyLink.c +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include "LibHarmonyLink.h" - -#include "Version.h" -#include "Wine.h" - -static bool bIsWine = false; -static bool bCachedIsWine = false; - -static bool bIsLinux = false; -static bool bCachedIsLinux = false; - -bool HL_Init(void) -{ - HL_version_print(); - Handle_Detect_Wine(); - Handle_Detect_Linux(); - return 1; -} - -void Handle_Detect_Wine(void) -{ -#ifdef BUILD_WINDOWS - bIsWine = Detect_Wine(); -#else - bIsWine = false; -#endif - -bCachedIsWine = true; -} - -bool Get_IsWine(void) -{ - if (!bCachedIsWine) - { - Handle_Detect_Wine(); - } - - return bIsWine; -} - -bool Get_IsLinux(void) -{ - if (!bCachedIsLinux) - { - Handle_Detect_Linux(); - } - - return bIsLinux; -} - -void Handle_Detect_Linux(void) -{ -#ifdef BUILD_LINUX - bIsLinux = true; -#else - bIsLinux = Get_IsWine(); -#endif - -bCachedIsLinux = true; -} - -bool HL_Is_Wine(void) -{ - return Get_IsWine(); -} -bool HL_Is_Linux(void) -{ - return Get_IsLinux(); -} diff --git a/LibHarmonyLink/src/Structs/Battery.c b/LibHarmonyLink/src/Structs/Battery.c deleted file mode 100644 index 56d69a2..0000000 --- a/LibHarmonyLink/src/Structs/Battery.c +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Structs/Battery.h" - -#include -#include -#include - -FBattery* HL_FBattery_Init(bool has_battery, bool is_connected_to_ac, unsigned char battery_percent) { - FBattery* battery = (FBattery*)malloc(sizeof(FBattery)); - - if (battery == NULL) { - fprintf(stderr, "Memory allocation failed for FCPUInfo.\n"); - return NULL; - //exit(EXIT_FAILURE); - } - - battery->has_battery = has_battery; - battery->battery_percent = is_connected_to_ac; - battery->is_connected_to_ac = battery_percent; - - return battery; -} - -void FBattery_print(const FBattery* self) -{ - wprintf(L"Battery present: %ls\n", self->has_battery ? L"'Yes'" : L"'No'"); - wprintf(L"Connected to AC: %ls\n", self->is_connected_to_ac ? L"'Yes'" : L"'No'"); - wprintf(L"Battery percent: %ls\n", self->battery_percent ? L"'Yes'" : L"'No'"); -} diff --git a/LibHarmonyLink/src/Structs/CPUInfo.c b/LibHarmonyLink/src/Structs/CPUInfo.c deleted file mode 100644 index c88e999..0000000 --- a/LibHarmonyLink/src/Structs/CPUInfo.c +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Structs/CPUInfo.h" -#include "Utilities.h" - -#include -#include - -FCPUInfo* FCPUInfo_Init(const char *vendorID, const char *modelName, unsigned int physicalCores, - unsigned int logicalCores, size_t flagsCount) { - FCPUInfo *cpuInfo = (FCPUInfo*)malloc(sizeof(FCPUInfo)); - - if (cpuInfo == NULL) { - fprintf(stderr, "Memory allocation failed for FCPUInfo.\n"); - exit(EXIT_FAILURE); - } -#if defined(BUILD_WINDOWS) - cpuInfo->VendorID = _strdup(vendorID); - cpuInfo->Model_Name = _strdup(modelName); -#else - cpuInfo->VendorID = strdup(vendorID); - cpuInfo->Model_Name = strdup(modelName); -#endif - - cpuInfo->Physical_Cores = physicalCores; - cpuInfo->Logical_Cores = logicalCores; - StringArray_Init(&cpuInfo->flagsInfo, flagsCount); - - return cpuInfo; -} - -void HL_FlagsInfo_Print(const FCPUInfo* cpuInfo) { - if (!cpuInfo) - { - fprintf(stderr, "cpuInfo is nullptr!\n"); - return; - } - - HL_StringArray_Print(&cpuInfo->flagsInfo); -} - -void HL_FCPUInfo_Print(const FCPUInfo *cpuInfo) { - wchar_t* wVendorID = convertToWideChar(cpuInfo->VendorID); - wchar_t* wModelName = convertToWideChar(cpuInfo->Model_Name); - - wprintf(L"VendorID: %ls\n", wVendorID); - wprintf(L"Model Name: %ls\n", wModelName); - wprintf(L"Physical Cores: %u\n", cpuInfo->Physical_Cores); - wprintf(L"Logical Cores: %u\n", cpuInfo->Logical_Cores); - wprintf(L"Flags:\n"); - HL_StringArray_Print(&cpuInfo->flagsInfo); - - free(wVendorID); - free(wModelName); -} - -bool HL_FlagsInfo_Contains(const FCPUInfo* cpuInfo, const char* flag) { - if (!cpuInfo) - { - fprintf(stderr, "cpuInfo is nullptr!\n"); - return false; - } - - return HL_StringArray_Contains(&cpuInfo->flagsInfo, flag); -} - -void HL_FCPUInfo_Free(FCPUInfo *cpuInfo) { - free(cpuInfo->VendorID); - free(cpuInfo->Model_Name); - HL_StringArray_Free(&cpuInfo->flagsInfo); -} diff --git a/LibHarmonyLink/src/Structs/Device.c b/LibHarmonyLink/src/Structs/Device.c deleted file mode 100644 index 082218b..0000000 --- a/LibHarmonyLink/src/Structs/Device.c +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Structs/Device.h" -#include "Utilities.h" - -#include -#include - -FDevice* Device_Init(EPlatform platform, EDevice device, ESteamDeck steam_deck_model) { - FDevice* newDevice = (FDevice*)malloc(sizeof(FDevice)); - if (newDevice != NULL) { - newDevice->platform = platform; - newDevice->device = device; - newDevice->steam_deck_model = steam_deck_model; - } - return newDevice; -} - -void HL_Device_Print(const FDevice *Device) { - if (Device == NULL) { - wprintf(L"Device is NULL\n"); - return; - } - - // Assuming that EPlatform, EDevice, and ESteamDeck have corresponding string representations - // which should be implemented for a proper print function - - wchar_t* platformStr = convertToWideChar(Platform_ToString(Device->platform)); - wchar_t* deviceStr = convertToWideChar(Device_ToString(Device->device)); - wchar_t* steamDeckStr = convertToWideChar(SteamDeck_ToString(Device->steam_deck_model)); - - wprintf(L"Device Information:\n"); - wprintf(L"Platform: %ls\n", platformStr); - wprintf(L"Device: %ls\n", deviceStr); - wprintf(L"Steam Deck Model: %ls\n", steamDeckStr); - - free(platformStr); - free(deviceStr); - free(steamDeckStr); -} - -void HL_Device_Free(FDevice *Device) { - if (Device != NULL) { - free(Device); - } -} diff --git a/LibHarmonyLink/src/Structs/OSInfo.c b/LibHarmonyLink/src/Structs/OSInfo.c deleted file mode 100644 index d3493ac..0000000 --- a/LibHarmonyLink/src/Structs/OSInfo.c +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include "Structs/OSInfo.h" - -#ifdef _WIN32 -#define strdup _strdup -#endif - -FOSVerInfo* FOSVerInfo_Init(char* name, char* version, unsigned int id, char* version_id, char* version_codename, char* pretty_name, - char* variant_id) { - FOSVerInfo* OSVerInfo = (FOSVerInfo*)malloc(sizeof(FOSVerInfo)); - - if (OSVerInfo == NULL) { - fprintf(stderr, "Memory allocation failed for FOSVerInfo.\n"); - return NULL; - //exit(EXIT_FAILURE); - } - - OSVerInfo->name = strdup(name); - OSVerInfo->version = strdup(version); - OSVerInfo->id = id; - OSVerInfo->version_id = strdup(version_id); - OSVerInfo->version_codename = strdup(version_codename); - OSVerInfo->pretty_name = strdup(pretty_name); - OSVerInfo->variant_id = strdup(variant_id); - - return OSVerInfo; -} - -void HL_FOSVerInfo_Free(FOSVerInfo* osVerInfo) { - if (!osVerInfo) return; - - free(osVerInfo->name); - free(osVerInfo->version); - free(osVerInfo->version_id); - free(osVerInfo->version_codename); - free(osVerInfo->pretty_name); - free(osVerInfo->variant_id); - free(osVerInfo); -} diff --git a/LibHarmonyLink/src/Structs/StringArray.c b/LibHarmonyLink/src/Structs/StringArray.c deleted file mode 100644 index 5165193..0000000 --- a/LibHarmonyLink/src/Structs/StringArray.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Structs/StringArray.h" -#include "Utilities.h" - -#include -#include - -// Initialize FlagsInfo with optional initial size -void StringArray_Init(StringArray *flagsInfo, size_t overrideInitialSize) { - size_t initialSize = DEFAULT_INITIAL_FLAGS_SIZE; - - if (overrideInitialSize > 0) { - initialSize = overrideInitialSize; - } - - flagsInfo->FlagsCount = 0; - flagsInfo->AllocatedSize = initialSize; - flagsInfo->data = (char**)malloc(initialSize * sizeof(char*)); - for (size_t i = 0; i < initialSize; ++i) { - flagsInfo->data[i] = NULL; - } -} - -void StringArray_AddFlag(StringArray *flagsInfo, const char *flag) { - // Check if we need to resize the array - if (flagsInfo->FlagsCount >= flagsInfo->AllocatedSize) { - StringArray_Resize(flagsInfo, flagsInfo->AllocatedSize * 2); - } -#if defined(BUILD_WINDOWS) - flagsInfo->data[flagsInfo->FlagsCount] = _strdup(flag); -#else - flagsInfo->data[flagsInfo->FlagsCount] = strdup(flag); -#endif - flagsInfo->FlagsCount++; -} - -void HL_StringArray_Print(const StringArray *flagsInfo) { - for (size_t i = 0; i < flagsInfo->FlagsCount; ++i) { - if (flagsInfo->data[i] != NULL) { - wchar_t* wstr = convertToWideChar(flagsInfo->data[i]); - wprintf(L" %ls\n", wstr); - free(wstr); - } - } -} - -void HL_StringArray_Free(StringArray *flagsInfo) { - for (size_t i = 0; i < flagsInfo->FlagsCount; ++i) { - free(flagsInfo->data[i]); - } - free(flagsInfo->data); -} - -void StringArray_Remove(StringArray *flagsInfo, const char *flag) { - for (size_t i = 0; i < flagsInfo->FlagsCount; ++i) { - if (flagsInfo->data[i] && strcmp(flagsInfo->data[i], flag) == 0) { - free(flagsInfo->data[i]); - for (size_t j = i; j < flagsInfo->FlagsCount - 1; ++j) { - flagsInfo->data[j] = flagsInfo->data[j + 1]; - } - flagsInfo->data[flagsInfo->FlagsCount - 1] = NULL; - flagsInfo->FlagsCount--; - break; - } - } -} - -bool HL_StringArray_Contains(const StringArray *flagsInfo, const char *flag) { - for (size_t i = 0; i < flagsInfo->FlagsCount; ++i) { - if (flagsInfo->data[i] && strcmp(flagsInfo->data[i], flag) == 0) { - return true; - } - } - return false; -} - -// Resize FlagsInfo array -void StringArray_Resize(StringArray* flagsInfo, size_t newSize) { - // Count the number of non-null pointers - size_t nonNullCount = 0; - for (size_t i = 0; i < flagsInfo->FlagsCount; ++i) { - if (flagsInfo->data[i] != NULL) { - nonNullCount++; - } - } - - // Check if the new size is smaller than the number of non-null pointers - if (newSize < nonNullCount) { - fprintf(stderr, "Resize failed. New size is smaller than the number of non-null pointers.\n"); - return; - } - - char** temp = realloc(flagsInfo->data, newSize * sizeof(char*)); - if (temp != NULL) { - flagsInfo->data = temp; - if (newSize > flagsInfo->AllocatedSize) { - // Initialize new elements to NULL - for (size_t i = flagsInfo->AllocatedSize; i < newSize; ++i) { - flagsInfo->data[i] = NULL; - } - } - flagsInfo->AllocatedSize = newSize; - } else { - // Handle realloc failure - fprintf(stderr, "Realloc failed. Memory not reallocated.\n"); - exit(EXIT_FAILURE); - } -} diff --git a/LibHarmonyLink/src/Utilities.c b/LibHarmonyLink/src/Utilities.c deleted file mode 100644 index 5434fee..0000000 --- a/LibHarmonyLink/src/Utilities.c +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Utilities.h" -#include - -wchar_t* convertToWideChar(const char* str) { - size_t len = 0; - -#if defined(BUILD_WINDOWS) - // Use mbstowcs_s on Windows - mbstowcs_s(&len, NULL, 0, str, 0); -#else - // Use mbstowcs on Linux - len = mbstowcs(NULL, str, 0) + 1; -#endif - - // Allocate memory for the wide string - wchar_t* wstr = (wchar_t*)malloc(len * sizeof(wchar_t)); - if (wstr == NULL) { - return NULL; // Handle memory allocation failure - } - -#if defined(BUILD_WINDOWS) - // Use mbstowcs_s on Windows - mbstowcs_s(&len, wstr, len, str, len - 1); -#else - // Use mbstowcs on Linux - mbstowcs(wstr, str, len); -#endif - - return wstr; -} diff --git a/LibHarmonyLink/src/Version.c b/LibHarmonyLink/src/Version.c deleted file mode 100644 index 01e0a4b..0000000 --- a/LibHarmonyLink/src/Version.c +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Version.h" - -#include -#include -#include -#include - -char* HL_version_get_string(void) -{ - return HARMONYLINK_VERSION; -} - -char* HL_version_build_timestamp(void) -{ - return __TIMESTAMP__; -} - -char* HL_git_branch(void) -{ - return GIT_BRANCH_NAME; -} - -char* HL_git_commit_timestamp(void) -{ - return GIT_COMMIT_TIMESTAMP; -} - -bool HL_is_debug(void) -{ -#ifdef DEBUG_MODE - return true; -#else - return false; -#endif -} - -void HL_version_print(void) { - wprintf(L"HarmonyLink V%hs Copyright (C) 2023 Jordon Brooks\n", HL_version_get_string()); - wprintf(L"Build Timestamp: %hs\n", HL_version_build_timestamp()); - wprintf(L"Git Branch: %hs\n", HL_git_branch()); - wprintf(L"Git Commit Timestamp: %hs\n", HL_git_commit_timestamp()); - wprintf(L"Build type: %ls\n", HL_is_debug() ? L"True" : L"False"); -} diff --git a/LibHarmonyLink/src/Wine.c b/LibHarmonyLink/src/Wine.c deleted file mode 100644 index f2e3b1c..0000000 --- a/LibHarmonyLink/src/Wine.c +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2024 Jordon Brooks -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "Wine.h" - -#include -#include -#ifdef BUILD_WINDOWS -#include -#endif - -bool Detect_Wine(void) -{ - bool isWine = false; - -#ifdef BUILD_WINDOWS - printf("Detecting wine...\n"); - bool HasFound = GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version") != NULL; - - if (!HasFound) - HasFound = GetProcAddress(GetModuleHandleA("ntdll.dll"), "proton_get_version") != NULL; - - printf("wine %s found\n", HasFound ? "has been" : "not"); - - isWine = HasFound; // Cache the result -#else - isWine = false; // In non-Windows builds, always set isWine to false -#endif - return isWine; // Return the cached result -} \ No newline at end of file diff --git a/README.md b/README.md index 81a55f2..f8a5b5e 100644 --- a/README.md +++ b/README.md @@ -61,22 +61,22 @@ As you can see, Even though it's running on Proton, we can still detect the unde Integrate HarmonyLink 2.0 into your game project with ease: -1. Download the latest version of HarmonyLink 2.0 from the [releases page](https://github.com/Jordonbc/HarmonyLink/releases/latest). +1. Download the latest version of HarmonyLink 2.0 from the [releases page](https://git.bbgames.dev/jordon/HarmonyLink/releases/latest). 2. Add the HarmonyLink DLL to your project according to your development environment's specifications. 3. Utilize the provided API to access device-specific metrics and enhance your game's performance on handheld devices. -Refer to the [integration documentation](https://github.com/Jordonbc/HarmonyLink/wiki/Integration-Guide) for detailed instructions. +Refer to the [integration documentation](https://git.bbgames.dev/jordon/HarmonyLink/wiki) for detailed instructions. ### Unreal Engine 5 Plugin For developers leveraging Unreal Engine 5.3 or newer*, HarmonyLink 2.0 is readily accessible as a plugin: -1. Clone or download the HarmonyLink UE5 Plugin from the [Unreal Engine Plugin repository](https://github.com/Jordonbc/HarmonyLinkUE). +1. Clone or download the HarmonyLink UE5 Plugin from the [Unreal Engine Plugin repository](https://git.bbgames.dev/jordon/HarmonyLinkUE). 2. Place the HarmonyLink plugin folder into the `Plugins` directory of your Unreal Engine 5 project. 3. Enable the HarmonyLink plugin from the Edit > Plugins menu within Unreal Engine 5. 4. Access HarmonyLink functionalities via Blueprints or C++ within your project. -For a step-by-step guide, visit the [Unreal Engine 5 Plugin instructions](https://github.com/Jordonbc/HarmonyLinkUE/wiki/Integration-Guide) on our wiki. +For a step-by-step guide, visit the [Unreal Engine 5 Plugin instructions](https://git.bbgames.dev/jordon/HarmonyLinkUE/wiki) on our wiki. *With potential backward compatibility, not verified. @@ -91,7 +91,7 @@ If you prefer to build HarmonyLink 2.0 from the source code, follow these steps: 5. Compile the code by running `cmake --build build --config Release`. 6. The built DLL will be located in the `build/bin/HarmonyLinkLib` directory. -For additional building options and troubleshooting, refer to the [building from source documentation](https://github.com/Jordonbc/HarmonyLink/wiki/Building-From-Source). +For additional building options and troubleshooting, refer to the [building from source documentation](https://git.bbgames.dev/jordon/HarmonyLink/wiki). ## How It Works