hopefully i dont regret doing allat
This commit is contained in:
parent
39e5a6a509
commit
cd74075a2e
9 changed files with 365 additions and 313 deletions
|
@ -5,12 +5,11 @@
|
|||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <dwmapi.h>
|
||||
#include <tlhelp32.h>
|
||||
// clang-format on
|
||||
|
||||
#include <cstring>
|
||||
#include <ranges>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.System.Diagnostics.h>
|
||||
|
@ -60,47 +59,6 @@ namespace {
|
|||
}};
|
||||
// clang-format on
|
||||
|
||||
class ProcessSnapshot {
|
||||
public:
|
||||
ProcessSnapshot() : h_snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) {}
|
||||
|
||||
ProcessSnapshot(ProcessSnapshot&&) = delete;
|
||||
ProcessSnapshot(const ProcessSnapshot&) = delete;
|
||||
fn operator=(ProcessSnapshot&&)->ProcessSnapshot& = delete;
|
||||
fn operator=(const ProcessSnapshot&)->ProcessSnapshot& = delete;
|
||||
|
||||
~ProcessSnapshot() {
|
||||
if (h_snapshot != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(h_snapshot);
|
||||
}
|
||||
|
||||
[[nodiscard]] fn isValid() const -> bool { return h_snapshot != INVALID_HANDLE_VALUE; }
|
||||
|
||||
[[nodiscard]] fn getProcesses() const -> Vec<Pair<DWORD, String>> {
|
||||
Vec<Pair<DWORD, String>> processes;
|
||||
|
||||
if (!isValid())
|
||||
return processes;
|
||||
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(h_snapshot, &pe32))
|
||||
return processes;
|
||||
|
||||
if (Process32First(h_snapshot, &pe32)) {
|
||||
processes.emplace_back(pe32.th32ProcessID, String(reinterpret_cast<const char*>(pe32.szExeFile)));
|
||||
|
||||
while (Process32Next(h_snapshot, &pe32))
|
||||
processes.emplace_back(pe32.th32ProcessID, String(reinterpret_cast<const char*>(pe32.szExeFile)));
|
||||
}
|
||||
|
||||
return processes;
|
||||
}
|
||||
|
||||
HANDLE h_snapshot;
|
||||
};
|
||||
|
||||
fn GetRegistryValue(const HKEY& hKey, const String& subKey, const String& valueName) -> String {
|
||||
HKEY key = nullptr;
|
||||
if (RegOpenKeyExA(hKey, subKey.c_str(), 0, KEY_READ, &key) != ERROR_SUCCESS)
|
||||
|
@ -125,88 +83,74 @@ namespace {
|
|||
return value;
|
||||
}
|
||||
|
||||
fn GetProcessInfo() -> Vec<Pair<DWORD, String>> {
|
||||
const ProcessSnapshot snapshot;
|
||||
return snapshot.isValid() ? snapshot.getProcesses() : std::vector<std::pair<DWORD, String>> {};
|
||||
fn GetProcessInfo() -> Result<Vec<Pair<DWORD, String>>, OsError> {
|
||||
try {
|
||||
using namespace winrt::Windows::System::Diagnostics;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
const IVectorView<ProcessDiagnosticInfo> processInfos = ProcessDiagnosticInfo::GetForProcesses();
|
||||
|
||||
Vec<Pair<DWORD, String>> processes;
|
||||
processes.reserve(processInfos.Size());
|
||||
|
||||
for (const auto& processInfo : processInfos)
|
||||
processes.emplace_back(processInfo.ProcessId(), winrt::to_string(processInfo.ExecutableFileName()));
|
||||
return processes;
|
||||
} catch (const winrt::hresult_error& e) { return Err(OsError(e)); } catch (const std::exception& e) {
|
||||
return Err(OsError(e));
|
||||
}
|
||||
}
|
||||
|
||||
fn IsProcessRunning(const Vec<String>& processes, const String& name) -> bool {
|
||||
return std::ranges::any_of(processes, [&name](const String& proc) -> bool {
|
||||
fn IsProcessRunning(const Vec<String>& processNames, const String& name) -> bool {
|
||||
return std::ranges::any_of(processNames, [&name](const String& proc) -> bool {
|
||||
return _stricmp(proc.c_str(), name.c_str()) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
fn GetParentProcessId(const DWORD pid) -> DWORD {
|
||||
const ProcessSnapshot snapshot;
|
||||
if (!snapshot.isValid())
|
||||
return 0;
|
||||
|
||||
PROCESSENTRY32 pe32 { .dwSize = sizeof(PROCESSENTRY32) };
|
||||
|
||||
if (!Process32First(snapshot.h_snapshot, &pe32))
|
||||
return 0;
|
||||
|
||||
if (pe32.th32ProcessID == pid)
|
||||
return pe32.th32ParentProcessID;
|
||||
|
||||
while (Process32Next(snapshot.h_snapshot, &pe32))
|
||||
if (pe32.th32ProcessID == pid)
|
||||
return pe32.th32ParentProcessID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn GetProcessName(const DWORD pid) -> String {
|
||||
const ProcessSnapshot snapshot;
|
||||
if (!snapshot.isValid())
|
||||
return "";
|
||||
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(snapshot.h_snapshot, &pe32))
|
||||
return "";
|
||||
|
||||
if (pe32.th32ProcessID == pid)
|
||||
return reinterpret_cast<const char*>(pe32.szExeFile);
|
||||
|
||||
while (Process32Next(snapshot.h_snapshot, &pe32))
|
||||
if (pe32.th32ProcessID == pid)
|
||||
return reinterpret_cast<const char*>(pe32.szExeFile);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
template <usize sz>
|
||||
fn FindShellInProcessTree(const DWORD startPid, const Array<Pair<StringView, StringView>, sz>& shellMap)
|
||||
-> std::optional<String> {
|
||||
DWORD pid = startPid;
|
||||
while (pid != 0) {
|
||||
String processName = GetProcessName(pid);
|
||||
-> Option<String> {
|
||||
if (startPid == 0)
|
||||
return None;
|
||||
|
||||
if (processName.empty()) {
|
||||
pid = GetParentProcessId(pid);
|
||||
continue;
|
||||
try {
|
||||
using namespace winrt::Windows::System::Diagnostics;
|
||||
|
||||
ProcessDiagnosticInfo currentProcessInfo = nullptr;
|
||||
|
||||
try {
|
||||
currentProcessInfo = ProcessDiagnosticInfo::TryGetForProcessId(startPid);
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
RETURN_ERR("Failed to get process info for PID {}: {}", startPid, winrt::to_string(e.message()));
|
||||
}
|
||||
|
||||
std::ranges::transform(processName, processName.begin(), [](const u8 character) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(character)));
|
||||
});
|
||||
while (currentProcessInfo) {
|
||||
String processName = winrt::to_string(currentProcessInfo.ExecutableFileName());
|
||||
|
||||
if (processName.length() > 4 && processName.substr(processName.length() - 4) == ".exe")
|
||||
processName.resize(processName.length() - 4);
|
||||
if (!processName.empty()) {
|
||||
std::ranges::transform(processName, processName.begin(), [](const u8 character) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(character)));
|
||||
});
|
||||
|
||||
auto iter = std::ranges::find_if(shellMap, [&](const auto& pair) {
|
||||
return std::string_view { processName } == pair.first;
|
||||
});
|
||||
if (processName.length() > 4 && processName.ends_with(".exe"))
|
||||
processName.resize(processName.length() - 4);
|
||||
|
||||
if (iter != std::ranges::end(shellMap))
|
||||
return String { iter->second };
|
||||
auto iter =
|
||||
std::ranges::find_if(shellMap, [&](const auto& pair) { return StringView { processName } == pair.first; });
|
||||
|
||||
pid = GetParentProcessId(pid);
|
||||
if (iter != std::ranges::end(shellMap))
|
||||
return String { iter->second };
|
||||
}
|
||||
|
||||
currentProcessInfo = currentProcessInfo.Parent();
|
||||
}
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
ERROR_LOG("WinRT error during process tree walk (start PID {}): {}", startPid, winrt::to_string(e.message()));
|
||||
} catch (const std::exception& e) {
|
||||
ERROR_LOG("Standard exception during process tree walk (start PID {}): {}", startPid, e.what());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return None;
|
||||
}
|
||||
|
||||
fn GetBuildNumber() -> Option<u64> {
|
||||
|
@ -227,36 +171,40 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
fn os::GetMemInfo() -> Result<u64, String> {
|
||||
fn os::GetMemInfo() -> Result<u64, OsError> {
|
||||
try {
|
||||
return winrt::Windows::System::Diagnostics::SystemDiagnosticInfo::GetForCurrentSystem()
|
||||
.MemoryUsage()
|
||||
.GetReport()
|
||||
.TotalPhysicalSizeInBytes();
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
return Err(std::format("Failed to get memory info: {}", to_string(e.message())));
|
||||
}
|
||||
} catch (const winrt::hresult_error& e) { return Err(OsError(e)); }
|
||||
}
|
||||
|
||||
fn os::GetNowPlaying() -> Result<String, NowPlayingError> {
|
||||
fn os::GetNowPlaying() -> Result<MediaInfo, NowPlayingError> {
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
using Session = GlobalSystemMediaTransportControlsSession;
|
||||
using SessionManager = GlobalSystemMediaTransportControlsSessionManager;
|
||||
using Session = GlobalSystemMediaTransportControlsSession;
|
||||
using SessionManager = GlobalSystemMediaTransportControlsSessionManager;
|
||||
using MediaProperties = GlobalSystemMediaTransportControlsSessionMediaProperties;
|
||||
|
||||
try {
|
||||
const IAsyncOperation<SessionManager> sessionManagerOp = SessionManager::RequestAsync();
|
||||
const SessionManager sessionManager = sessionManagerOp.get();
|
||||
|
||||
if (const Session currentSession = sessionManager.GetCurrentSession())
|
||||
return winrt::to_string(currentSession.TryGetMediaPropertiesAsync().get().Title());
|
||||
if (const Session currentSession = sessionManager.GetCurrentSession()) {
|
||||
const MediaProperties mediaProperties = currentSession.TryGetMediaPropertiesAsync().get();
|
||||
|
||||
return MediaInfo(
|
||||
winrt::to_string(mediaProperties.Title()), winrt::to_string(mediaProperties.Artist()), None, None
|
||||
);
|
||||
}
|
||||
|
||||
return Err(NowPlayingCode::NoActivePlayer);
|
||||
} catch (const winrt::hresult_error& e) { return Err(e); }
|
||||
} catch (const winrt::hresult_error& e) { return Err(OsError(e)); }
|
||||
}
|
||||
|
||||
fn os::GetOSVersion() -> Result<String, String> {
|
||||
fn os::GetOSVersion() -> Result<String, OsError> {
|
||||
try {
|
||||
const String regSubKey = R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)";
|
||||
|
||||
|
@ -264,26 +212,33 @@ fn os::GetOSVersion() -> Result<String, String> {
|
|||
const String displayVersion = GetRegistryValue(HKEY_LOCAL_MACHINE, regSubKey, "DisplayVersion");
|
||||
|
||||
if (productName.empty())
|
||||
return Err("Failed to read ProductName");
|
||||
return Err(OsError { OsErrorCode::NotFound, "ProductName not found in registry" });
|
||||
|
||||
if (const Option<u64> buildNumber = GetBuildNumber()) {
|
||||
if (*buildNumber >= 22000)
|
||||
if (const usize pos = productName.find("Windows 10");
|
||||
pos != String::npos && (pos == 0 || !isalnum(static_cast<u8>(productName[pos - 1]))) &&
|
||||
(pos + 10 == productName.length() || !isalnum(static_cast<u8>(productName[pos + 10]))))
|
||||
productName.replace(pos, 10, "Windows 11");
|
||||
} else
|
||||
DEBUG_LOG("Warning: Could not get build number via WinRT; Win11 patch relies on registry ProductName only.");
|
||||
if (const Option<u64> buildNumberOpt = GetBuildNumber()) {
|
||||
if (const u64 buildNumber = *buildNumberOpt; buildNumber >= 22000) {
|
||||
if (const size_t pos = productName.find("Windows 10"); pos != String::npos) {
|
||||
const bool startBoundary = (pos == 0 || !isalnum(static_cast<unsigned char>(productName[pos - 1])));
|
||||
const bool endBoundary =
|
||||
(pos + 10 == productName.length() || !isalnum(static_cast<unsigned char>(productName[pos + 10])));
|
||||
|
||||
if (startBoundary && endBoundary) {
|
||||
productName.replace(pos, 10, "Windows 11");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG("Warning: Could not get build number via WinRT; Win11 detection might be inaccurate.");
|
||||
}
|
||||
|
||||
return displayVersion.empty() ? productName : productName + " " + displayVersion;
|
||||
} catch (const Exception& e) { return Err(std::format("Exception occurred getting OS version: {}", e.what())); }
|
||||
} catch (const std::exception& e) { return Err(OsError(e)); }
|
||||
}
|
||||
|
||||
fn os::GetHost() -> String {
|
||||
fn os::GetHost() -> Result<String, OsError> {
|
||||
return GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SYSTEM\HardwareConfig\Current)", "SystemFamily");
|
||||
}
|
||||
|
||||
fn os::GetKernelVersion() -> String {
|
||||
fn os::GetKernelVersion() -> Result<String, OsError> {
|
||||
try {
|
||||
using namespace winrt::Windows::System::Profile;
|
||||
|
||||
|
@ -292,36 +247,47 @@ fn os::GetKernelVersion() -> String {
|
|||
if (const winrt::hstring familyVersion = versionInfo.DeviceFamilyVersion(); !familyVersion.empty())
|
||||
if (auto [major, minor, build, revision] = OSVersion::parseDeviceFamilyVersion(familyVersion); build > 0)
|
||||
return std::format("{}.{}.{}.{}", major, minor, build, revision);
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
ERROR_LOG("WinRT error: {}", winrt::to_string(e.message()));
|
||||
} catch (const Exception& e) { ERROR_LOG("Failed to get kernel version: {}", e.what()); }
|
||||
} catch (const winrt::hresult_error& e) { return Err(OsError(e)); } catch (const Exception& e) {
|
||||
return Err(OsError(e));
|
||||
}
|
||||
|
||||
return "";
|
||||
return Err(OsError { OsErrorCode::NotFound, "Could not determine kernel version" });
|
||||
}
|
||||
|
||||
fn os::GetWindowManager() -> String {
|
||||
const auto processInfo = GetProcessInfo();
|
||||
std::vector<String> processNames;
|
||||
fn os::GetWindowManager() -> Option<String> {
|
||||
if (const Result<Vec<Pair<DWORD, String>>, OsError> processInfoResult = GetProcessInfo()) {
|
||||
const Vec<Pair<DWORD, String>>& processInfo = *processInfoResult;
|
||||
|
||||
processNames.reserve(processInfo.size());
|
||||
for (const auto& name : processInfo | std::views::values) processNames.push_back(name);
|
||||
Vec<String> processNames;
|
||||
processNames.reserve(processInfo.size());
|
||||
|
||||
const std::unordered_map<String, String> wmProcesses = {
|
||||
{ "glazewm.exe", "GlazeWM" },
|
||||
{ "fancywm.exe", "FancyWM" },
|
||||
{ "komorebi.exe", "Komorebi" },
|
||||
{ "komorebic.exe", "Komorebi" }
|
||||
};
|
||||
for (const String& val : processInfo | std::views::values) {
|
||||
if (!val.empty()) {
|
||||
const usize lastSlash = val.find_last_of("/\\");
|
||||
processNames.push_back(lastSlash == String::npos ? val : val.substr(lastSlash + 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [processName, wmName] : wmProcesses)
|
||||
if (IsProcessRunning(processNames, processName))
|
||||
return wmName;
|
||||
const std::unordered_map<String, String> wmProcesses = {
|
||||
{ "glazewm.exe", "GlazeWM" },
|
||||
{ "fancywm.exe", "FancyWM" },
|
||||
{ "komorebi.exe", "Komorebi" },
|
||||
{ "komorebic.exe", "Komorebi" },
|
||||
};
|
||||
|
||||
for (const auto& [processExe, wmName] : wmProcesses)
|
||||
if (IsProcessRunning(processNames, processExe))
|
||||
return wmName;
|
||||
} else {
|
||||
ERROR_LOG("Failed to get process info for WM detection: {}", processInfoResult.error().message);
|
||||
}
|
||||
|
||||
BOOL compositionEnabled = FALSE;
|
||||
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&compositionEnabled)))
|
||||
return compositionEnabled ? "DWM" : "Windows Manager (Basic)";
|
||||
|
||||
return "Windows Manager";
|
||||
return None;
|
||||
}
|
||||
|
||||
fn os::GetDesktopEnvironment() -> Option<String> {
|
||||
|
@ -371,51 +337,60 @@ fn os::GetDesktopEnvironment() -> Option<String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn os::GetShell() -> String {
|
||||
const DWORD currentPid = GetCurrentProcessId();
|
||||
fn os::GetShell() -> Option<String> {
|
||||
try {
|
||||
const DWORD currentPid =
|
||||
winrt::Windows::System::Diagnostics::ProcessDiagnosticInfo::GetForCurrentProcess().ProcessId();
|
||||
|
||||
if (const Result<String, EnvError> msystemResult = GetEnv("MSYSTEM")) {
|
||||
String shellPath;
|
||||
if (const Result<String, EnvError> shellResult = GetEnv("SHELL"); !shellResult->empty())
|
||||
shellPath = *shellResult;
|
||||
else if (const Result<String, EnvError> loginShellResult = GetEnv("LOGINSHELL"); !loginShellResult->empty())
|
||||
shellPath = *loginShellResult;
|
||||
if (const Result<String, EnvError> msystemResult = GetEnv("MSYSTEM"); msystemResult && !msystemResult->empty()) {
|
||||
String shellPath;
|
||||
|
||||
if (!shellPath.empty()) {
|
||||
const usize lastSlash = shellPath.find_last_of("\\/");
|
||||
String shellExe = (lastSlash != String::npos) ? shellPath.substr(lastSlash + 1) : shellPath;
|
||||
if (const Result<String, EnvError> shellResult = GetEnv("SHELL"); shellResult && !shellResult->empty())
|
||||
shellPath = *shellResult;
|
||||
else if (const Result<String, EnvError> loginShellResult = GetEnv("LOGINSHELL");
|
||||
loginShellResult && !loginShellResult->empty())
|
||||
shellPath = *loginShellResult;
|
||||
|
||||
std::ranges::transform(shellExe, shellExe.begin(), [](const u8 c) { return std::tolower(c); });
|
||||
if (!shellPath.empty()) {
|
||||
const usize lastSlash = shellPath.find_last_of("\\/");
|
||||
String shellExe = (lastSlash != String::npos) ? shellPath.substr(lastSlash + 1) : shellPath;
|
||||
|
||||
if (shellExe.ends_with(".exe"))
|
||||
shellExe.resize(shellExe.length() - 4);
|
||||
std::ranges::transform(shellExe, shellExe.begin(), [](const u8 c) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
});
|
||||
|
||||
const auto iter =
|
||||
std::ranges::find_if(msysShellMap, [&](const auto& pair) { return StringView { shellExe } == pair.first; });
|
||||
if (shellExe.ends_with(".exe"))
|
||||
shellExe.resize(shellExe.length() - 4);
|
||||
|
||||
if (iter != std::ranges::end(msysShellMap))
|
||||
return String { iter->second };
|
||||
const auto iter =
|
||||
std::ranges::find_if(msysShellMap, [&](const auto& pair) { return StringView { shellExe } == pair.first; });
|
||||
|
||||
if (iter != std::ranges::end(msysShellMap))
|
||||
return String { iter->second };
|
||||
}
|
||||
|
||||
if (const Option<String> msysShell = FindShellInProcessTree(currentPid, msysShellMap))
|
||||
return *msysShell;
|
||||
|
||||
return "MSYS2 Environment";
|
||||
}
|
||||
|
||||
if (const Option<String> msysShell = FindShellInProcessTree(currentPid, msysShellMap))
|
||||
return *msysShell;
|
||||
if (const Option<String> windowsShell = FindShellInProcessTree(currentPid, windowsShellMap))
|
||||
return *windowsShell;
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
ERROR_LOG("WinRT error during shell detection: {}", winrt::to_string(e.message()));
|
||||
} catch (const std::exception& e) { ERROR_LOG("Standard exception during shell detection: {}", e.what()); }
|
||||
|
||||
return "MSYS2 Environment";
|
||||
}
|
||||
|
||||
if (const Option<String> windowsShell = FindShellInProcessTree(currentPid, windowsShellMap))
|
||||
return *windowsShell;
|
||||
|
||||
return "Unknown Shell";
|
||||
return None;
|
||||
}
|
||||
|
||||
fn os::GetDiskUsage() -> Pair<u64, u64> {
|
||||
fn os::GetDiskUsage() -> Result<DiskSpace, OsError> {
|
||||
ULARGE_INTEGER freeBytes, totalBytes;
|
||||
|
||||
if (GetDiskFreeSpaceExW(L"C:\\", nullptr, &totalBytes, &freeBytes))
|
||||
return { totalBytes.QuadPart - freeBytes.QuadPart, totalBytes.QuadPart };
|
||||
return DiskSpace { .used_bytes = totalBytes.QuadPart - freeBytes.QuadPart, .total_bytes = totalBytes.QuadPart };
|
||||
|
||||
return { 0, 0 };
|
||||
return Err(OsError { OsErrorCode::NotFound, "Failed to get disk usage" });
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue