添加基础的桌面透明功能

This commit is contained in:
997146918 2025-10-02 19:28:58 +08:00
parent dc714bfd03
commit dac6c48d38
17 changed files with 669 additions and 2 deletions

View File

@ -8028,6 +8028,18 @@
{
"Path": "$(ProjectDir)/Binaries/Win64/UnrealEditor.modules",
"Type": "RequiredResource"
},
{
"Path": "$(ProjectDir)/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.dll",
"Type": "DynamicLibrary"
},
{
"Path": "$(ProjectDir)/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.pdb",
"Type": "SymbolFile"
},
{
"Path": "$(ProjectDir)/Plugins/DeskMode/Binaries/Win64/UnrealEditor.modules",
"Type": "RequiredResource"
}
],
"RuntimeDependencies": [
@ -33759,6 +33771,10 @@
"Path": "$(EngineDir)/Plugins/XGEController/XGEController.uplugin",
"Type": "UFS"
},
{
"Path": "$(ProjectDir)/Plugins/DeskMode/DeskMode.uplugin",
"Type": "UFS"
},
{
"Path": "$(ProjectDir)/ProjectFish.uproject",
"Type": "UFS"
@ -33827,6 +33843,7 @@
"Dataflow",
"DatasmithContent",
"DeformerGraph",
"DeskMode",
"DumpGPUServices",
"EOSShared",
"EditorDataStorage",

View File

@ -29,10 +29,12 @@ r.Lumen.TraceMeshSDFs=0
r.Lumen.Reflections.HardwareRayTracing.Translucent.Refraction.EnableForProject=True
r.Lumen.TranslucencyReflections.FrontLayer.EnableForProject=False
r.Shadow.TranslucentPerObject.ProjectEnabled=False
r.PostProcessing.PropagateAlpha=True
r.D3D11.UseAllowTearing=0
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
DefaultGraphicsRHI=DefaultGraphicsRHI_DX11
DefaultGraphicsRHI=DefaultGraphicsRHI_DX11
-D3D12TargetedShaderFormats=PCD3D_SM5
+D3D12TargetedShaderFormats=PCD3D_SM6
-D3D11TargetedShaderFormats=PCD3D_SM5

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
{
"BuildId": "37670630",
"Modules":
{
"DeskMode": "UnrealEditor-DeskMode.dll"
}
}

View File

@ -0,0 +1,24 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "DeskMode",
"Description": "",
"Category": "Other",
"CreatedBy": "",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "DeskMode",
"Type": "Runtime",
"LoadingPhase": "Default"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,54 @@
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class DeskMode : ModuleRules
{
public DeskMode(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
"UnrealEd"
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}

View File

@ -0,0 +1,73 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "DeskMode.h"
#include "WindowTransparency.h"
#include "Features/EditorFeatures.h"
#include "Features/IPluginsEditorFeature.h"
DEFINE_LOG_CATEGORY_STATIC(LogDeskMode, Log, All);
#define LOCTEXT_NAMESPACE "FDeskModeModule"
void FDeskModeModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
//绑定module注册回调
IModularFeatures& ModularFeatures = IModularFeatures::Get();
ModularFeatures.OnModularFeatureRegistered().AddRaw(this, &FDeskModeModule::OnModularFeatureRegistered);
//防止plugin模块先加载
if (ModularFeatures.IsModularFeatureAvailable(EditorFeatures::PluginsEditor))
{
OnModularFeatureRegistered(EditorFeatures::PluginsEditor, &ModularFeatures.GetModularFeature<IPluginsEditorFeature>(EditorFeatures::PluginsEditor));
}
}
void FDeskModeModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
if (IsValid(WindowTransparency))
{
#if PLATFORM_WINDOWS
UE_LOG(LogDeskMode, Log, TEXT("WindowTransparency is valid, attempting to restore settings."));
WindowTransparency->RestoreDefaultWindowSettings();
#endif
}
}
void FDeskModeModule::OnModularFeatureRegistered(const FName& Name, IModularFeature* ModularFeature)
{
}
TObjectPtr<class UWindowTransparency> FDeskModeModule::GetWindowTransparency()
{
FDeskModeModule* Module = FModuleManager::GetModulePtr<FDeskModeModule>("DeskMode");
if (Module)
{
Module->WindowTransparency = nullptr;
#if PLATFORM_WINDOWS
if (!Module->WindowTransparency && !IsRunningCommandlet() && !IsRunningDedicatedServer() && GEngine)
{
Module->WindowTransparency = NewObject<UWindowTransparency>();
if (Module->WindowTransparency->Initialize())
{
UE_LOG(LogDeskMode, Log, TEXT("WindowTransparency instance created and initialized."));
}
else
{
UE_LOG(LogDeskMode, Error, TEXT("WindowTransparency instance created but failed to initialize HWND."));
}
}
#endif
return Module->WindowTransparency;
}
UE_LOG(LogDeskMode, Log, TEXT("WindowTransparency is null, GetWindowTransparency() error."));
return nullptr;
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FDeskModeModule, DeskMode)

View File

@ -0,0 +1,22 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DeskModeFunctionLibrary.h"
#include "DeskMode.h"
#include "WindowTransparency.h"
void UDeskModeFunctionLibrary::SetWindowFeatures(bool bEnableWindowTransparency, bool bEnableBorderless,
bool bEnableClickThrough, bool bSetWindowTopmost)
{
#if PLATFORM_WINDOWS
TObjectPtr<UWindowTransparency> WindowTransparency = FDeskModeModule::GetWindowTransparency();
if (IsValid(WindowTransparency))
{
WindowTransparency->EnableBorderless(bEnableWindowTransparency);
WindowTransparency->EnableWindowTransparency(bEnableWindowTransparency);
WindowTransparency->EnableClickThrough(bEnableClickThrough);
WindowTransparency->SetWIndowsTopmost(bSetWindowTopmost);
}
#endif
}

View File

@ -0,0 +1,372 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "WindowTransparency.h"
#include "Widgets/SViewport.h"
DEFINE_LOG_CATEGORY_STATIC(LogWindowTransparency, Log, All);
HWND UWindowTransparency::GetGameHWnd()
{
if (GEngine->GameViewport->GetWindow())
{
TSharedPtr<SWindow> StrongSWindow = GEngine->GameViewport->GetWindow();
if (StrongSWindow.IsValid() && StrongSWindow->GetNativeWindow().IsValid()) {
void* Handle = StrongSWindow->GetNativeWindow()->GetOSWindowHandle();
UE_LOG(LogWindowTransparency, Verbose, TEXT("GetGameHWnd: Returning HWND from cached GameSWindowPtr: %p"), Handle);
return static_cast<HWND>(Handle);
}
}
// if (GEngine && GEngine->GameViewport && GEngine->GameViewport->GetWindow().IsValid())
// {
// TSharedPtr<SWindow> GameSWindow = GEngine->GameViewport->GetWindow();
// const_cast<UWindowTransparencyHelper*>(this)->GameSWindowPtr = GameSWindow;
// if (GameSWindow.IsValid() && GameSWindow->GetNativeWindow().IsValid())
// {
// void* Handle = GameSWindow->GetNativeWindow()->GetOSWindowHandle();
// UE_LOG(LogWindowTransparency, Verbose, TEXT("GetGameHWnd: Returning HWND from GEngine->GameViewport and caching SWindow: %p"), Handle);
// return static_cast<HWND>(Handle);
// }
// }
// if (FSlateApplication::IsInitialized())
// {
// TSharedPtr<SWindow> ActiveWindow = FSlateApplication::Get().GetActiveTopLevelWindow();
// if (ActiveWindow.IsValid() && ActiveWindow->GetNativeWindow().IsValid())
// {
// void* Handle = ActiveWindow->GetNativeWindow()->GetOSWindowHandle();
// UE_LOG(LogWindowTransparency, Verbose, TEXT("GetGameHWnd: Returning HWND from GetActiveTopLevelWindow (fallback): %p"), Handle);
// return static_cast<HWND>(Handle);
// }
// }
// UE_LOG(LogWindowTransparency, Warning, TEXT("GetGameHWnd: Could not retrieve HWND."));
return nullptr;
}
bool UWindowTransparency::Initialize()
{
#if PLATFORM_WINDOWS
if (GameHWnd)
{
return true;
}
GameHWnd = GetGameHWnd();
if (GameHWnd)
{
OriginalWindowStyle = GetWindowLongPtr(GameHWnd, GWL_STYLE);
OriginalExWindowStyle = GetWindowLongPtr(GameHWnd, GWL_EXSTYLE);
LONG_PTR CurrentExStyle = GetWindowLongPtr(GameHWnd, GWL_EXSTYLE);
bIsClickThroughStateOS = (CurrentExStyle & WS_EX_TRANSPARENT) != 0;
return true;
}
else
{
UE_LOG(LogWindowTransparency, Warning, TEXT("WindowTransparencyHelper: Could not get game HWND during Initialize."));
return false;
}
#endif
}
void UWindowTransparency::RestoreDefaultWindowSettings()
{
#if PLATFORM_WINDOWS
UE_LOG(LogWindowTransparency, Log, TEXT("Attempting to restore default window settings..."));
if (!GameHWnd || !IsWindow(GameHWnd))
{
UE_LOG(LogWindowTransparency, Warning, TEXT("Cannot restore default settings: HWND is null or invalid."));
bIsClickThroughStateOS = false;
return;
}
if (GetWindowLongPtr(GameHWnd, GWL_EXSTYLE) != OriginalExWindowStyle)
{
SetWindowLongPtr(GameHWnd, GWL_EXSTYLE, OriginalExWindowStyle);
UE_LOG(LogWindowTransparency, Log, TEXT("Restored OriginalExWindowStyle."));
}
SetWindowPos(GameHWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
InvalidateRect(GameHWnd, NULL, true);
UpdateWindow(GameHWnd);
UE_LOG(LogWindowTransparency, Log, TEXT("Window settings restoration commands issued."));
#endif
}
void UWindowTransparency::EnableBorderless(bool bEnableWindowTransparency)
{
#if PLATFORM_WINDOWS
if (!GameHWnd)
{
UE_LOG(LogWindowTransparency, Error, TEXT("EnableBorderless failed, GameHWnd is null"));
return;
}
LONG_PTR CurrentStyle = GetWindowLongPtr(GameHWnd, GWL_STYLE);
bool bIsCurrentlyBorderless = !(CurrentStyle & WS_CAPTION) && !(CurrentStyle & WS_THICKFRAME);
LONG_PTR NewStyle = bEnableWindowTransparency ? ((OriginalWindowStyle & ~WS_OVERLAPPEDWINDOW) | WS_POPUP) : OriginalWindowStyle;
SetWindowLongPtr(GameHWnd, GWL_STYLE, NewStyle);
SetWindowPos(GameHWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
InvalidateRect(GameHWnd, NULL, true);
UpdateWindow(GameHWnd);
UE_LOG(LogWindowTransparency, Log, TEXT("Borderless mode set to: %s"), bEnableWindowTransparency ? TEXT("true") : TEXT("false"));
#endif
}
void UWindowTransparency::EnableWindowTransparency(bool bEnableWindowTransparency)
{
#if PLATFORM_WINDOWS
if (!GameHWnd)
{
UE_LOG(LogWindowTransparency, Error, TEXT("EnableWindowTransparency failed, GameHWnd is null"));
return;
}
//设置窗口透明
MARGINS margins = bEnableWindowTransparency ? MARGINS{ -1 } : MARGINS{ 0, 0, 0, 0 };
HRESULT hr = DwmExtendFrameIntoClientArea(GameHWnd, &margins);
if (!SUCCEEDED(hr))
{
UE_LOG(LogWindowTransparency, Error, TEXT("DwmExtendFrameIntoClientArea %s failed with HRESULT: 0x%08lX"), bEnableWindowTransparency ? TEXT("enable") : TEXT("disable"), hr);
}
InvalidateRect(GameHWnd, NULL, true);
UpdateWindow(GameHWnd);
UE_LOG(LogWindowTransparency, Log, TEXT("DWM Transparency set to: %s"), bEnableWindowTransparency ? TEXT("true") : TEXT("false"));
#endif
}
void UWindowTransparency::EnableClickThrough(bool bEnableClickThrough)
{
#if PLATFORM_WINDOWS
if (!GameHWnd)
{
UE_LOG(LogWindowTransparency, Warning, TEXT("EnableClickThrough: Not initialized or HWND is null. Cannot set OS click-through state."));
return;
}
LONG_PTR CurrentExStyle = GetWindowLongPtr(GameHWnd, GWL_EXSTYLE);
bool bIsCurrentlyClickThroughOSLevel = (CurrentExStyle & WS_EX_TRANSPARENT) != 0;
LONG_PTR NewExStyle;
if (bEnableClickThrough)
{
NewExStyle = CurrentExStyle | WS_EX_LAYERED | WS_EX_TRANSPARENT;
}
else
{
NewExStyle = CurrentExStyle & ~WS_EX_TRANSPARENT;
}
bIsClickThroughStateOS = bEnableClickThrough;
SetWindowLongPtr(GameHWnd, GWL_EXSTYLE, NewExStyle);
LONG_PTR StyleAfterSet = GetWindowLongPtr(GameHWnd, GWL_EXSTYLE);
bool bSetSuccessfully = (bEnableClickThrough && (StyleAfterSet & WS_EX_TRANSPARENT)) || (!bEnableClickThrough && !(StyleAfterSet & WS_EX_TRANSPARENT));
UE_LOG(LogWindowTransparency, Log, TEXT("EnableClickThrough: OS Click-Through set to %s. OldExStyle: 0x%p, Attempted NewExStyle: 0x%p, Actual StyleAfterSet: 0x%p. Success: %s"),
bEnableClickThrough ? TEXT("true") : TEXT("false"),
(void*)CurrentExStyle,
(void*)NewExStyle,
(void*)StyleAfterSet,
bSetSuccessfully ? TEXT("Yes") : TEXT("No"));
if (bSetSuccessfully) {
SetWindowPos(GameHWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
}
else {
UE_LOG(LogWindowTransparency, Error, TEXT("EnableClickThrough: Failed to apply desired ExStyle change!"));
}
#endif
}
void UWindowTransparency::SetWIndowsTopmost(bool bSetWindowTopmost)
{
#if PLATFORM_WINDOWS
if (!GameHWnd)
{
UE_LOG(LogWindowTransparency, Warning, TEXT("SetWIndowsTopmost: Not initialized or HWND is null."));
return;
}
LONG_PTR CurrentExStyle = GetWindowLongPtr(GameHWnd, GWL_EXSTYLE);
HWND HwndInsertAfter = bSetWindowTopmost ? HWND_TOPMOST : HWND_NOTOPMOST;
SetWindowPos(GameHWnd, HwndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
UE_LOG(LogWindowTransparency, Log, TEXT("Window topmost set to: %s"), bSetWindowTopmost ? TEXT("true") : TEXT("false"));
#endif
}
void UWindowTransparency::Tick(float DeltaTime)
{
if (!bIsClickThroughStateOS)
{
return;
}
UpdateHitDetectionLogic(DeltaTime);
bool bShouldBeClickThroughLogically = !bIsMouseOverOpaqueAreaLogic;
if (bIsClickThroughStateOS != bShouldBeClickThroughLogically)
{
UE_LOG(LogWindowTransparency, Verbose, TEXT("Tick: Logic dictates click-through: %s. OS state is: %s. Updating OS state."),
bShouldBeClickThroughLogically ? TEXT("true") : TEXT("false"),
bIsClickThroughStateOS ? TEXT("true") : TEXT("false"));
EnableClickThrough(bShouldBeClickThroughLogically);
}
}
TStatId UWindowTransparency::GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(UWindowTransparency, STATGROUP_Tickables);
}
void UWindowTransparency::UpdateHitDetectionLogic(float DeltaTime)
{
#if PLATFORM_WINDOWS
bool bMousePosSuccess;
FVector2D MousePosInWindow = GetMousePositionInWindow(bMousePosSuccess);
if (!bMousePosSuccess)
{
bIsMouseOverOpaqueAreaLogic = false;
UE_LOG(LogWindowTransparency, Verbose, TEXT("UpdateHitDetectionLogic: Mouse position not retrieved. Assuming transparent area."));
return;
}
bIsMouseOverOpaqueAreaLogic = SimulateGameRaycastUnderMouse(MousePosInWindow);
// const UEnum* EnumPtr = StaticEnum<ECollisionChannel>();
// FString ChannelName = EnumPtr ? EnumPtr->GetNameStringByValue(static_cast<int64>(GameRaycastTraceChannelLogic)) : FString::FromInt(static_cast<int32>(GameRaycastTraceChannelLogic));
// UE_LOG(LogWindowTransparency, Log, TEXT("GameRaycastTest Result: bIsMouseOverOpaqueAreaLogic = %s at Pos: %s (Channel: %s)"),
// bIsMouseOverOpaqueAreaLogic ? TEXT("true (Opaque)") : TEXT("false (Transparent)"), *MousePosInWindow.ToString(), *ChannelName);
#endif
}
FVector2D UWindowTransparency::GetMousePositionInWindow(bool& bMousePosSuccess)
{
bMousePosSuccess = false;
#if PLATFORM_WINDOWS
POINT CursorPosScreen;
if (::GetCursorPos(&CursorPosScreen))
{
RECT WindowRect;
if (::GetWindowRect(GameHWnd, &WindowRect))
{
bMousePosSuccess = true;
return FVector2D(static_cast<float>(CursorPosScreen.x - WindowRect.left), static_cast<float>(CursorPosScreen.y - WindowRect.top));
}
else
{
DWORD ErrorCode = GetLastError();
UE_LOG(LogWindowTransparency, Error, TEXT("GetMousePositionInWindow: GetWindowRect failed for HWND %p. Error code: %u"), GameHWnd, ErrorCode);
}
}
#endif
return FVector2D::ZeroVector;
}
bool UWindowTransparency::SimulateGameRaycastUnderMouse(FVector2D MousePos)
{
UWorld* World = GetWorld();
APlayerController* PC = nullptr;
if (World)
{
PC = Cast<APlayerController>(GetWorld()->GetFirstLocalPlayerFromController());
}
if (!PC)
{
return false;
}
//检测3D世界是否有碰撞
FHitResult HitResult3D;
FCollisionQueryParams CollisionParams3D(SCENE_QUERY_STAT(WindowTransparencyRaycast3D), true);
bool bHit3D = PC->GetHitResultAtScreenPosition(
MousePos,
ECC_Visibility,
CollisionParams3D,
HitResult3D
);
if (bHit3D && HitResult3D.GetActor())
{
// AActor* HitActor = HitResult3D.GetActor();
// const UEnum* EnumPtr = StaticEnum<ECollisionChannel>();
// FString ChannelName = EnumPtr ? EnumPtr->GetNameStringByValue(static_cast<int64>(this->GameRaycastTraceChannelLogic)) : FString::FromInt(static_cast<int32>(this->GameRaycastTraceChannelLogic));
// UE_LOG(LogWindowHelper, Verbose, TEXT("GameRaycastTest: Hit 3D Actor: %s (Component: %s) using Channel %s"),
// *HitActor->GetName(),
// HitResult3D.GetComponent() ? *HitResult3D.GetComponent()->GetName() : TEXT("None"),
// *ChannelName);
return true;
}
//2D检测是否有可点击UI
if (FSlateApplication::IsInitialized() && GEngine && GEngine->GameViewport)
{
TSharedPtr<SWindow> GameSWindow = GEngine->GameViewport->GetWindow();
if (GameSWindow.IsValid())
{
TArray<TSharedRef<SWindow>> WindowsToSearch;
WindowsToSearch.Add(GameSWindow.ToSharedRef());
FVector2D MousePosScreen = MousePos + GEngine->GameViewport->GetGameViewportWidget()->GetCachedGeometry().GetAbsolutePosition();
FWidgetPath WidgetPath = FSlateApplication::Get().LocateWindowUnderMouse(
MousePosScreen,
WindowsToSearch,
false, /*bAllowDisabledWidgets*/
PC->GetLocalPlayer() ? PC->GetLocalPlayer()->GetControllerId() : 0
);
if (WidgetPath.IsValid() && WidgetPath.Widgets.Num() > 0)
{
const FArrangedWidget& LastWidgetArranged = WidgetPath.Widgets.Last();
TSharedRef<SWidget> HitWidget = LastWidgetArranged.Widget;
FString WidgetType = HitWidget->GetTypeAsString();
FString WidgetDesc = HitWidget->ToString();
UE_LOG(LogWindowTransparency, Verbose, TEXT("GameRaycastTest: UI Hit Candidate: Type: %s, Desc: %s, Visible: %d, Enabled: %d, PathLen: %d"),
*WidgetType, *WidgetDesc, HitWidget->GetVisibility().IsVisible(), HitWidget->IsEnabled(), WidgetPath.Widgets.Num());
if (HitWidget->GetVisibility().IsVisible() && HitWidget->IsEnabled())
{
if (WidgetType == TEXT("SWindow") ||
WidgetType == TEXT("SGameLayerManager") ||
WidgetType == TEXT("SViewport") ||
(WidgetType == TEXT("SBorder") && WidgetPath.Widgets.Num() <= 2) ||
(WidgetType == TEXT("SOverlay") && WidgetPath.Widgets.Num() <= 2) ||
(WidgetType == TEXT("SScaleBox") && WidgetPath.Widgets.Num() <= 2) ||
(WidgetType == TEXT("SCanvasPanel") && WidgetPath.Widgets.Num() <= 2) ||
(WidgetType == TEXT("SObjectWidget") && WidgetPath.Widgets.Num() <= 1)
)
{
UE_LOG(LogWindowTransparency, Verbose, TEXT("GameRaycastTest: UI Hit on %s (%s), but considering it non-blocking/transparent due to type/context."), *WidgetType, *WidgetDesc);
}
else
{
UE_LOG(LogWindowTransparency, Verbose, TEXT("GameRaycastTest: Hit blocking UI Widget: %s (%s)"), *WidgetType, *WidgetDesc);
return true;
}
}
}
}
}
// const UEnum* EnumPtr = StaticEnum<ECollisionChannel>();
// FString ChannelName = EnumPtr ? EnumPtr->GetNameStringByValue(static_cast<int64>(this->GameRaycastTraceChannelLogic)) : FString::FromInt(static_cast<int32>(this->GameRaycastTraceChannelLogic));
// UE_LOG(LogWindowTransparency, Verbose, TEXT("GameRaycastTest: No blocking hit found on 3D (using Channel %s) or UI. Assuming transparent."), *ChannelName);
return false;
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,19 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Modules/ModuleManager.h"
class FDeskModeModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
void OnModularFeatureRegistered(const FName& Name, IModularFeature* ModularFeature);
static TObjectPtr<class UWindowTransparency> GetWindowTransparency();
private:
TObjectPtr<class UWindowTransparency> WindowTransparency;
};

View File

@ -0,0 +1,20 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "DeskModeFunctionLibrary.generated.h"
/**
*
*/
UCLASS()
class DESKMODE_API UDeskModeFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "DeskMode")
static void SetWindowFeatures(bool bEnableWindowTransparency, bool bEnableBorderless, bool bEnableClickThrough, bool bSetWindowTopmost);
};

View File

@ -0,0 +1,54 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#if PLATFORM_WINDOWS
#include "Windows/AllowWindowsPlatformTypes.h"
#include <dwmapi.h>
#include <WinUser.h>
#include "Windows/HideWindowsPlatformTypes.h"
#endif
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "WindowTransparency.generated.h"
/**
*
*/
UCLASS()
class DESKMODE_API UWindowTransparency : public UObject, public FTickableGameObject
{
GENERATED_BODY()
public:
HWND GetGameHWnd();
bool Initialize();
void RestoreDefaultWindowSettings();
//设置窗口无边框
void EnableBorderless(bool bEnableWindowTransparency);
//设置窗口透明
void EnableWindowTransparency(bool bEnableWindowTransparency);
//设置窗口是否点击穿透
void EnableClickThrough(bool bEnableClickThrough);
//设置窗口顶层
void SetWIndowsTopmost(bool bSetWindowTopmost);
FVector2D GetMousePositionInWindow(bool& bMousePosSuccess);
bool SimulateGameRaycastUnderMouse(FVector2D MousePos);
//更新鼠标位置逻辑判断
void UpdateHitDetectionLogic(float DeltaTime);
//////////Tick////////////////
virtual void Tick(float DeltaTime) override;
virtual ETickableTickType GetTickableTickType() const override { return ETickableTickType::Always; }
virtual TStatId GetStatId() const override;
virtual bool IsTickableWhenPaused() const override { return true; }
virtual bool IsTickableInEditor() const override { return false; }
private:
#if PLATFORM_WINDOWS
HWND GameHWnd;
LONG_PTR OriginalWindowStyle;
LONG_PTR OriginalExWindowStyle;
#endif
bool bIsMouseOverOpaqueAreaLogic;; //鼠标是否经过程序的可点击区域
bool bIsClickThroughStateOS; //当前的点击穿透状态
};

View File

@ -24,11 +24,13 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APublic_002Fd_003AUObject_002Ff_003AUObjectGlobals_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APrivate_002Fd_003AMisc_002Ff_003AGuid_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AContainers_002Ff_003AArray_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AContainers_002Ff_003AMap_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003ADelegates_002Ff_003ADelegateSignatureImpl_002Einl/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003ADelegates_002Ff_003ADelegate_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AMath_002Ff_003AUnrealMathUtility_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AMisc_002Ff_003AGuid_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AMisc_002Ff_003AMTAccessDetector_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003AModules_002Ff_003AModuleInterface_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003ATasks_002Ff_003ATaskPrivate_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APrivate_002Fd_003AUObject_002Ff_003AClass_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APrivate_002Fd_003AUObject_002Ff_003AGarbageCollection_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String>
@ -38,6 +40,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APublic_002Fd_003AUObject_002Ff_003AUnrealType_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APublic_002Fd_003AUObject_002Ff_003AUObjectArray_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACoreUObject_002Fd_003APublic_002Fd_003AUObject_002Ff_003AUObjectBase_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003ACore_002Fd_003APublic_002Fd_003ATemplates_002Ff_003ATuple_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003AEngine_002Fd_003AClasses_002Fd_003AGameFramework_002Ff_003ACharacterMovementComponent_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003AEngine_002Fd_003APrivate_002Fd_003AComponents_002Ff_003ACharacterMovementComponent_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=72263A5F_002DD5F9_002D3915_002D8DA0_002DCD45C38A70E5_002Fdl_003ASource_003AF_0021_003FEpic_003FUE_005F5_002E5_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003AEngine_002Fd_003APrivate_002Ff_003AGameplayStatics_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String>