Compare commits

..

7 commits

58 changed files with 1462 additions and 2322 deletions

3
.gitattributes vendored
View file

@ -37,6 +37,3 @@
*.exe binary *.exe binary
*.out binary *.out binary
*.app binary *.app binary
# Linux shell files must always be LF
*.sh text eol=lf

7
.gitignore vendored
View file

@ -15,15 +15,12 @@ build/**
!Images/* !Images/*
!.github/** !.github/**
!HarmonyLinkLib/** !LibHarmonyLink/**
!HarmonyLinkTest/** !HarmonyLinkTest/**
!HarmonyLinkTest_CPP/**
# Blacklist specific build directories # Blacklist specific build directories
linuxbuild/ linuxbuild/
build/ build/
.idea/ .idea/
winbuild/ winbuild/
!Compile.sh
!Compile.bat
HarmonyLinkLib/.vscode/

View file

@ -44,17 +44,18 @@ elseif(UNIX)
endif() endif()
# Set global output directories for all build types # Set global output directories for all build types
#foreach(TYPE IN ITEMS DEBUG RELEASE) foreach(TYPE IN ITEMS DEBUG RELEASE)
# string(TOUPPER ${TYPE} TYPE_UPPER) string(TOUPPER ${TYPE} TYPE_UPPER)
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/bin/${TYPE}") 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_LIBRARY_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/lib/${TYPE}")
# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${TYPE_UPPER} "${CMAKE_BINARY_DIR}/archive/${TYPE}")
#endforeach() endforeach()
# Add the library and executable directories # Add the library and executable directories
add_subdirectory(HarmonyLinkLib) add_subdirectory(LibHarmonyLink)
add_subdirectory(HarmonyLinkTest) add_subdirectory(HarmonyLinkTest)
add_subdirectory(HarmonyLinkTest_CPP)
# Add Google Test as a subdirectory # Add Google Test as a subdirectory
#add_subdirectory(ThirdParty/googletest) #add_subdirectory(ThirdParty/googletest)

View file

@ -1,68 +0,0 @@
@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 ..

View file

@ -1,127 +0,0 @@
#!/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

View file

@ -1,237 +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(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()

View file

@ -1,38 +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
// 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

View file

@ -1,29 +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 <cstdint>
// 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,
};
}

View file

@ -1,177 +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 <memory>
#include <cstring>
#include <string>
#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<char>(std::tolower(static_cast<unsigned char>(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<HarmonyLinkLib::FString> {
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<unsigned char>(str[i]);
// Equivalent to hashValue * 33 + str[i]
}
return hashValue;
}
};
}

View file

@ -1,62 +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.
/**
* 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();
}

View file

@ -1,27 +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
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;
}
};

View file

@ -1,36 +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 <cstdint>
#include <iostream>
#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<int>(battery_percent) << "%'" << '\n';
}
};
}

View file

@ -1,54 +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 <cstdint>
#include <unordered_set>
#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<FString> 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());
}
};
}

View file

@ -1,64 +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 "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());
}
};
}

View file

@ -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.
#pragma once
#include "Core.h"
#include <Version.generated.h>
#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
}
};
}

View file

@ -1,137 +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 "HarmonyLinkLib.h"
#include <iostream>
#include "Platform/IPlatformUtilities.h"
#include "Version.h"
namespace HarmonyLinkLib
{
std::shared_ptr<IPlatformUtilities> 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<FCPUInfo> 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<FDevice> 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<FOSVerInfo> 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<FBattery> new_battery = PlatformUtilities->get_battery_status();
if (!new_battery)
{
return nullptr;
}
FBattery* battery = new FBattery(*new_battery);
return battery;
}
}

View file

@ -1,245 +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 "IPlatformUtilities.h"
#include <fmt/core.h>
#include <set>
#include <unordered_map>
#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<IPlatformUtilities> INSTANCE = nullptr;
std::shared_ptr<IPlatformUtilities>& IPlatformUtilities::GetInstance()
{
if (!INSTANCE)
{
#if BUILD_WINDOWS
INSTANCE = std::make_shared<WindowsUtilities>();
#elif BUILD_LINUX
INSTANCE = std::make_shared<LinuxUtilities>();
#elif BUILD_MAC
INSTANCE = std::make_shared<MacUtilities>();
#elif BUILD_UNIX
INSTANCE = std::make_shared<UnixUtilities>();
// ... 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<FDevice> 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<FDevice> 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<FDevice> IPlatformUtilities::get_device()
{
FDevice new_device;
if (is_linux())
{
new_device.platform = EPlatform::LINUX;
}
else
{
new_device.platform = EPlatform::WINDOWS;
}
const std::shared_ptr<FBattery> 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<FDevice>(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<FCPUInfo> 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<FString, ESteamDeck> 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<FOSVerInfo> 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<FBattery> battery = get_battery_status();
return battery && battery->is_connected_to_ac;
}
bool IPlatformUtilities::is_charging()
{
const std::shared_ptr<FBattery> battery = get_battery_status();
return battery && battery->has_battery && battery->is_connected_to_ac;
}
}

View file

@ -1,60 +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 "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<IPlatformUtilities>& 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<FDevice> get_device();
virtual std::shared_ptr<FCPUInfo> get_cpu_info() = 0;
virtual std::shared_ptr<FBattery> get_battery_status() = 0;
virtual std::shared_ptr<FOSVerInfo> 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
};
}

View file

@ -1,37 +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 "Structs/FOSVerInfo.h"
#include "Platform/Unix/UnixUtilities.h"
namespace HarmonyLinkLib
{
class LinuxUtilities : public UnixUtilities {
public:
// Implementation for other Linux-specific functions
std::shared_ptr<FBattery> get_battery_status() override;
std::shared_ptr<FOSVerInfo> get_os_version() override;
std::shared_ptr<FCPUInfo> get_cpu_info() override;
bool is_linux() override
{
return true;
}
};
}

View file

@ -1,20 +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 "MacUtilities.h"
namespace HarmonyLinkLib
{
}

View file

@ -1,72 +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 "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<FCPUInfo> UnixUtilities::get_cpu_info()
{
std::wcout << "This feature is not supported on unix systems yet.\n";
return nullptr;
}
std::shared_ptr<FBattery> UnixUtilities::get_battery_status()
{
std::wcout << "This feature is not supported on unix systems yet.\n";
return nullptr;
}
std::shared_ptr<FOSVerInfo> 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;
}
}

View file

@ -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.
#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<FCPUInfo> get_cpu_info() override;
std::shared_ptr<FBattery> get_battery_status() override;
std::shared_ptr<FOSVerInfo> 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
};
}

View file

@ -1,177 +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 "WindowsUtilities.h"
#include <sstream>
#include <Windows.h>
#include <XInput.h>
#pragma comment(lib, "XInput.lib")
#include "Platform/WineUtilities.h"
#include <algorithm>
namespace HarmonyLinkLib
{
std::shared_ptr<FBattery> 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<FBattery>(result);
}
std::shared_ptr<FCPUInfo> WindowsUtilities::get_cpu_info()
{
if (is_linux())
{
return WineUtilities::get_cpu_info();
}
return {};
}
std::shared_ptr<FOSVerInfo> 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<OSVERSIONINFO*>(&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<LPBYTE>(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<FOSVerInfo>(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<RAWINPUTDEVICELIST> 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<RAWINPUTDEVICELIST> 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;
}
}

View file

@ -1,40 +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 "Platform/IPlatformUtilities.h"
namespace HarmonyLinkLib
{
class WindowsUtilities : public IPlatformUtilities
{
public:
std::shared_ptr<FBattery> get_battery_status() override;
std::shared_ptr<FCPUInfo> get_cpu_info() override;
std::shared_ptr<FOSVerInfo> 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;
};
}

View file

@ -1,218 +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 "WineUtilities.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <ghc/filesystem.hpp>
#ifdef BUILD_WINDOWS
#include <windows.h>
#endif
namespace fs = ghc::filesystem;
namespace HarmonyLinkLib
{
bool force_detect_wine = false;
std::shared_ptr<HarmonyLinkLib::FBattery> 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<uint8_t>(std::stoi(status));
break; // assuming you only need data from the first battery found
}
}
}
return std::make_shared<FBattery>(result);
}
std::shared_ptr<FCPUInfo> 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<HarmonyLinkLib::FString, HarmonyLinkLib::FString> 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<FCPUInfo>(cpu_info);
}
std::shared_ptr<FOSVerInfo> 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<HarmonyLinkLib::FString, HarmonyLinkLib::FString> 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<FOSVerInfo>(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();
}
}

View file

@ -1,60 +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 "Structs/FBattery.h"
#include "Structs/FCPUInfo.h"
#include "Structs/FOSVerInfo.h"
namespace HarmonyLinkLib
{
class WineUtilities
{
public:
static std::shared_ptr<FBattery> get_battery_status();
static std::shared_ptr<FCPUInfo> 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<FOSVerInfo> 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();
};
}

View file

@ -1,53 +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 <iostream>
#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
}

View file

@ -1,30 +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 "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);
};
}

View file

@ -15,22 +15,29 @@ cmake_minimum_required(VERSION 3.10)
project(HarmonyLinkTest) project(HarmonyLinkTest)
# Specify the C++ standard # Specify the C++ standard
set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_C_STANDARD_REQUIRED True)
# Automatically add all .cpp and .h/.hpp files in the src directory # Automatically add all .cpp and .h/.hpp files in the src directory
file(GLOB_RECURSE TEST_SOURCES "src/*.cpp") file(GLOB_RECURSE TEST_SOURCES "src/*.c")
file(GLOB_RECURSE TEST_HEADERS "src/*.h" "src/*.hpp") 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 for static library
add_executable(HarmonyLinkTestStatic ${TEST_SOURCES} ${TEST_HEADERS}) add_executable(HarmonyLinkTestStatic ${TEST_SOURCES} ${TEST_HEADERS})
target_link_libraries(HarmonyLinkTestStatic PRIVATE HarmonyLinkLibStatic) target_link_libraries(HarmonyLinkTestStatic PRIVATE LibHarmonyLinkStatic)
target_compile_definitions(HarmonyLinkTestStatic PRIVATE HARMONYLINKLIB_STATIC) target_compile_definitions(HarmonyLinkTestStatic PRIVATE HARMONYLINK_STATIC)
# Add executable for shared library # Add executable for shared library
add_executable(HarmonyLinkTestShared ${TEST_SOURCES} ${TEST_HEADERS}) add_executable(HarmonyLinkTestShared ${TEST_SOURCES} ${TEST_HEADERS})
target_link_libraries(HarmonyLinkTestShared PRIVATE HarmonyLinkLibShared) target_link_libraries(HarmonyLinkTestShared PRIVATE LibHarmonyLinkShared)
target_compile_definitions(HarmonyLinkTestShared PRIVATE HARMONYLINKLIB_SHARED) target_compile_definitions(HarmonyLinkTestShared PRIVATE HARMONYLINK_SHARED)
# Set output directories for all build types # Set output directories for all build types
foreach(TYPE IN ITEMS DEBUG RELEASE) foreach(TYPE IN ITEMS DEBUG RELEASE)
@ -54,5 +61,5 @@ endforeach()
# Copy the DLL to the executable directory after building the shared test executable # Copy the DLL to the executable directory after building the shared test executable
add_custom_command(TARGET HarmonyLinkTestShared POST_BUILD add_custom_command(TARGET HarmonyLinkTestShared POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:HarmonyLinkLibShared>" "$<TARGET_FILE:LibHarmonyLinkShared>"
"$<TARGET_FILE_DIR:HarmonyLinkTestShared>") "$<TARGET_FILE_DIR:HarmonyLinkTestShared>")

View file

@ -12,27 +12,26 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "LinuxUtilities.h" #include <wchar.h>
#include "LibHarmonyLink.h"
int main(void)
#include <fstream>
#include <string>
#include "Platform/WineUtilities.h"
namespace HarmonyLinkLib
{ {
std::shared_ptr<FBattery> LinuxUtilities::get_battery_status() wprintf(L"Hello from C!\n");
if (!HL_Init())
{ {
return WineUtilities::get_battery_status(); wprintf(L"Error: Failed to initialise HarmonyLink!\n");
return 1;
} }
std::shared_ptr<FOSVerInfo> LinuxUtilities::get_os_version() wprintf(L"Successfully Initialised HarmonyLink!\n");
{
return WineUtilities::get_linux_info();
}
std::shared_ptr<FCPUInfo> LinuxUtilities::get_cpu_info() const wchar_t* IsLinux = HL_Is_Linux() ? L"True" : L"False";
{ wprintf(L"Is Linux: %ls\n", IsLinux);
return WineUtilities::get_cpu_info();
} const wchar_t* IsWine = HL_Is_Wine() ? L"True" : L"False";
wprintf(L"Is Wine: %ls\n", IsWine);
return 0;
} }

View file

@ -0,0 +1,65 @@
# 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
"$<TARGET_FILE:LibHarmonyLinkShared>"
"$<TARGET_FILE_DIR:HarmonyLinkTestShared_CPP>")

View file

@ -17,7 +17,7 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include "HarmonyLinkLib.h" #include "LibHarmonyLink.h"
// Include necessary headers for platform-specific functionality // Include necessary headers for platform-specific functionality
#ifdef BUILD_WINDOWS #ifdef BUILD_WINDOWS
@ -32,9 +32,11 @@
std::atomic<bool> quitFlag(false); std::atomic<bool> quitFlag(false);
std::atomic<bool> HasError(false);
// Function to clear the screen cross-platform // Function to clear the screen cross-platform
void clearScreen() { void clearScreen() {
#ifdef _WIN32 #ifdef BUILD_WINDOWS
system("cls"); system("cls");
#else #else
std::cout << "\x1B[2J\x1B[H"; std::cout << "\x1B[2J\x1B[H";
@ -44,7 +46,7 @@ void clearScreen() {
// Function to check if 'q' or 'Q' is pressed in Windows // Function to check if 'q' or 'Q' is pressed in Windows
void checkForQuit() { void checkForQuit() {
while (!quitFlag) { while (!quitFlag || !HasError) {
#ifdef BUILD_WINDOWS #ifdef BUILD_WINDOWS
if (_kbhit()) { if (_kbhit()) {
const char c = static_cast<char>(_getch()); const char c = static_cast<char>(_getch());
@ -85,62 +87,68 @@ void checkForQuit() {
int main() int main()
{ {
std::cout << "Hello, World!\n"; std::cout << "Hello, World!" << '\n';
std::thread inputThread(checkForQuit); if (!LibHarmonyLink::HL_Init())
if (!HarmonyLinkLib::HL_Init())
{ {
std::cout << "Failed to init HarmonyLinkLib\n"; printf("Failed to Initialize HarmonyLink!\n");
HasError = true;
return 1; return 1;
} }
std::cout << "HarmonyLinkLib successfully initialised!\n"; printf("HarmonyLink Initialized!\n");
const bool isWine = HarmonyLinkLib::get_is_wine(); std::thread inputThread(checkForQuit);
const char* isLinux = LibHarmonyLink::HL_Is_Linux() ? "is" : "isn't";
printf("This program %s running under Linux.\n", isLinux);
const bool isWine = LibHarmonyLink::HL_Is_Wine();
const char* test = isWine ? "is" : "isn't"; const char* test = isWine ? "is" : "isn't";
const HarmonyLinkLib::FOSVerInfo* os_info = HarmonyLinkLib::get_os_version(); printf("This program %s running under wine.\n", test);
const HarmonyLinkLib::FDevice* device_info = HarmonyLinkLib::get_device_info(); //const HarmonyLinkLib::FOSVerInfo* os_info = HarmonyLinkLib::get_os_version();
const HarmonyLinkLib::FCPUInfo* cpu_info = HarmonyLinkLib::get_cpu_info(); //const HarmonyLinkLib::FDevice* device_info = HarmonyLinkLib::get_device_info();
//const HarmonyLinkLib::FCPUInfo* cpu_info = HarmonyLinkLib::get_cpu_info();
HasError = true;
// This loop is to test how stable & expensive these functions are // This loop is to test how stable & expensive these functions are
while (!quitFlag) while (!quitFlag || !HasError)
{ {
// Clear the screen // Clear the screen
clearScreen(); clearScreen();
std::wcout << "This program " << test << " running under wine.\n"; //if (cpu_info)
//{
// cpu_info->print();
//}
if (cpu_info) //if (os_info)
{ //{
cpu_info->print(); // os_info->print();
} //}
if (os_info) //if (device_info)
{ //{
os_info->print(); // wprintf(L"Is SteamDeck: %s\n", device_info->device == HarmonyLinkLib::EDevice::STEAM_DECK ? L"true" : L"false");
} //}
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 // we can't do this before the loop because we need updated values
if (const HarmonyLinkLib::FBattery* battery = HarmonyLinkLib::get_battery_status()) //if (const HarmonyLinkLib::FBattery* battery = HarmonyLinkLib::get_battery_status())
{ //{
battery->to_string(); // battery->print();
battery->free(); // 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)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
@ -150,20 +158,20 @@ int main()
inputThread.join(); inputThread.join();
} }
if (os_info) //if (os_info)
{ //{
os_info->free(); // os_info->free();
} //}
if (device_info) //if (device_info)
{ //{
device_info->free(); // device_info->free();
} //}
if (cpu_info) //if (cpu_info)
{ //{
cpu_info->free(); // cpu_info->free();
} //}
return 0; return 0;
} }

View file

@ -0,0 +1,174 @@
# 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()

View file

@ -14,12 +14,17 @@
#pragma once #pragma once
#include "Platform/Unix/UnixUtilities.h" // Use a preprocessor definition to switch between export and import declarations
#ifdef _WIN32
namespace HarmonyLinkLib #ifdef HARMONYLINK_STATIC
{ #define HARMONYLINK_API
class MacUtitities : public UnixUtilities { #else
public: #ifdef HARMONYLINK_SHARED
// Mac-specific overrides and additional functionality #define HARMONYLINK_API __declspec(dllexport)
}; #else
} #define HARMONYLINK_API __declspec(dllimport)
#endif
#endif
#else
#define HARMONYLINK_API
#endif

View file

@ -0,0 +1,52 @@
// 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

View file

@ -0,0 +1,46 @@
// 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

View file

@ -0,0 +1,44 @@
// 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

View file

@ -0,0 +1,90 @@
// 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 <stdbool.h>
#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

View file

@ -14,19 +14,27 @@
#pragma once #pragma once
#include <HarmonyLinkStruct.h> #include <stdbool.h>
#include "Enums/EDevice.h" #include "Core.h"
#include "Enums/EPlatform.h"
#include "Enums/ESteamDeck.h"
namespace HarmonyLinkLib #ifdef __cplusplus
{ namespace LibHarmonyLink {
// Struct to represent a specific device with both platform and device type extern "C" {
struct FDevice : HarmonyLinkStruct #endif
{
EPlatform platform = EPlatform::UNKNOWN; typedef struct {
EDevice device = EDevice::UNKNOWN; bool has_battery;
ESteamDeck steam_deck_model = ESteamDeck::NONE; 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
} }
}
#endif

View file

@ -0,0 +1,57 @@
// 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 <stdio.h>
#include <stdbool.h>
#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

View file

@ -0,0 +1,47 @@
// 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

View file

@ -0,0 +1,49 @@
// 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 <stdio.h>
#include <stdbool.h>
#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

View file

@ -0,0 +1,61 @@
// 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 <stdio.h>
#include <stdbool.h>
#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

View file

@ -12,19 +12,17 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#pragma once #include <wchar.h>
#include <cstdint> #ifdef __cplusplus
namespace LibHarmonyLink {
extern "C" {
#endif
// Enum class for representing different operating platforms // Utility function to convert char* to wchar_t*
namespace HarmonyLinkLib wchar_t *convertToWideChar(const char *str);
{
enum class EPlatform : uint8_t #ifdef __cplusplus
{
UNKNOWN,
WINDOWS,
LINUX,
MAC,
UNIX,
};
} }
}
#endif

View file

@ -14,24 +14,27 @@
#pragma once #pragma once
// Undefine the LINUX macro to avoid conflicts with the enum definition. #include <stdbool.h>
#undef LINUX #include "Core.h"
#include <cstdint> #ifdef __cplusplus
namespace LibHarmonyLink {
extern "C" {
#endif
// Enum class for representing different types of devices HARMONYLINK_API char* HL_version_get_string(void);
namespace HarmonyLinkLib
{
enum class EDevice : uint8_t
{
UNKNOWN,
DESKTOP,
LAPTOP,
HANDHELD,
STEAM_DECK, HARMONYLINK_API char* HL_version_build_timestamp(void);
// ROG_ALLY
// AYONEO_SLIDE HARMONYLINK_API char* HL_git_branch(void);
// etc...
}; HARMONYLINK_API char* HL_git_commit_timestamp(void);
HARMONYLINK_API bool HL_is_debug(void);
HARMONYLINK_API void HL_version_print(void);
#ifdef __cplusplus
} }
}
#endif

View file

@ -15,11 +15,11 @@
// Version.h.in // Version.h.in
#pragma once #pragma once
#define HARMONYLINK_VERSION_MAJOR @HarmonyLinkLib_VERSION_MAJOR@ #define HARMONYLINK_VERSION_MAJOR @LibHarmonyLink_VERSION_MAJOR@
#define HARMONYLINK_VERSION_MINOR @HarmonyLinkLib_VERSION_MINOR@ #define HARMONYLINK_VERSION_MINOR @LibHarmonyLink_VERSION_MINOR@
#define HARMONYLINK_VERSION_PATCH @HarmonyLinkLib_VERSION_PATCH@ #define HARMONYLINK_VERSION_PATCH @LibHarmonyLink_VERSION_PATCH@
#define HARMONYLINK_VERSION_TWEAK @HarmonyLinkLib_VERSION_TWEAK@ #define HARMONYLINK_VERSION_TWEAK @LibHarmonyLink_VERSION_TWEAK@
#define HARMONYLINK_VERSION "@HarmonyLinkLib_VERSION@" #define HARMONYLINK_VERSION "@LibHarmonyLink_VERSION@"
#define GIT_BRANCH_NAME "@GIT_BRANCH_NAME@" #define GIT_BRANCH_NAME "@GIT_BRANCH_NAME@"
#define GIT_COMMIT_TIMESTAMP "@GIT_COMMIT_TIMESTAMP@" #define GIT_COMMIT_TIMESTAMP "@GIT_COMMIT_TIMESTAMP@"

View file

@ -12,4 +12,19 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "Version.h" #pragma once
#include <stdbool.h>
#include "Core.h"
#ifdef __cplusplus
namespace LibHarmonyLink {
extern "C" {
#endif
bool Detect_Wine(void);
#ifdef __cplusplus
}
}
#endif

View file

@ -0,0 +1,84 @@
// 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 <stdbool.h>
#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();
}

View file

@ -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.
#include "Structs/Battery.h"
#include <wchar.h>
#include <malloc.h>
#include <stdio.h>
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'");
}

View file

@ -0,0 +1,83 @@
// 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 <stdlib.h>
#include <string.h>
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);
}

View file

@ -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.
#include "Structs/Device.h"
#include "Utilities.h"
#include <malloc.h>
#include <stdio.h>
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);
}
}

View file

@ -0,0 +1,55 @@
// 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 <malloc.h>
#include <string.h>
#include <wchar.h>
#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);
}

View file

@ -0,0 +1,121 @@
// 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 <stdlib.h>
#include <string.h>
// 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);
}
}

View file

@ -0,0 +1,44 @@
// 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 <stdlib.h>
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;
}

View file

@ -0,0 +1,57 @@
// 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 <Version.generated.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
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");
}

41
LibHarmonyLink/src/Wine.c Normal file
View file

@ -0,0 +1,41 @@
// 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 <stdio.h>
#include <stdbool.h>
#ifdef BUILD_WINDOWS
#include <windows.h>
#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
}

View file

@ -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: Integrate HarmonyLink 2.0 into your game project with ease:
1. Download the latest version of HarmonyLink 2.0 from the [releases page](https://git.bbgames.dev/jordon/HarmonyLink/releases/latest). 1. Download the latest version of HarmonyLink 2.0 from the [releases page](https://github.com/Jordonbc/HarmonyLink/releases/latest).
2. Add the HarmonyLink DLL to your project according to your development environment's specifications. 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. 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://git.bbgames.dev/jordon/HarmonyLink/wiki) for detailed instructions. Refer to the [integration documentation](https://github.com/Jordonbc/HarmonyLink/wiki/Integration-Guide) for detailed instructions.
### Unreal Engine 5 Plugin ### Unreal Engine 5 Plugin
For developers leveraging Unreal Engine 5.3 or newer*, HarmonyLink 2.0 is readily accessible as a 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://git.bbgames.dev/jordon/HarmonyLinkUE). 1. Clone or download the HarmonyLink UE5 Plugin from the [Unreal Engine Plugin repository](https://github.com/Jordonbc/HarmonyLinkUE).
2. Place the HarmonyLink plugin folder into the `Plugins` directory of your Unreal Engine 5 project. 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. 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. 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://git.bbgames.dev/jordon/HarmonyLinkUE/wiki) on our wiki. For a step-by-step guide, visit the [Unreal Engine 5 Plugin instructions](https://github.com/Jordonbc/HarmonyLinkUE/wiki/Integration-Guide) on our wiki.
*With potential backward compatibility, not verified. *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`. 5. Compile the code by running `cmake --build build --config Release`.
6. The built DLL will be located in the `build/bin/HarmonyLinkLib` directory. 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://git.bbgames.dev/jordon/HarmonyLink/wiki). For additional building options and troubleshooting, refer to the [building from source documentation](https://github.com/Jordonbc/HarmonyLink/wiki/Building-From-Source).
## How It Works ## How It Works