using UnityEngine;
using System; // For IntPtr - No longer needed here
using System.Diagnostics; // For Process - Keep if Watchdog re-enabled
using Debug = UnityEngine.Debug; // Keep alias
using Screen = UnityEngine.Screen; // Use UnityEngine.Screen directly
using System.IO; // For Path.Combine
// Make sure NativeOverlayInterface, OverlayHResult, CoVinceOverlayTextAlignment are accessible
// TODO, when start videorecording, get red border, then start screenshare, still red border
// after stop recording, and still screenshare, need to get green border
public class WindowsOverlayController : MonoBehaviour // Assuming _BaseController provides log/logError instance methods
{
// --- Static Coordination State for Border ---
// These track the *requests* for showing the border overlay for different reasons
private static bool s_isOverlayActive = false; // Tracks if the border overlay window is currently shown via this coordinator
private static bool s_isOverlayForRecording = false;
private static bool s_isOverlayForSharing = false;
// --- Instance Variables ---
// These might be set if multiple instances are used, determines THIS instance's purpose
public bool isForRecording;
//private Process watchdogProcess; // Keep if needed later
private int displayNumber = 0; // Monitor index this instance relates to (if needed)
// Test variables - keep for Update() test code
private bool useTestControls = true; // Toggle testing via Inspector
public bool showText = false;
public int fontSize = 20;
// Define image paths using StreamingAssets for build compatibility
private string imagePath1;
private string imagePath2;
public CoVinceOverlayTextAlignment textAlignment = CoVinceOverlayTextAlignment.TOP;
private void Awake()
{
//C:/ Users / denni / AppData / LocalLow / DefaultCompany / covinceplatform
// log ($"[WindowsOverlayController] Awake - Show File Path: " + GlobalConstants.DATA_FOLDERPATH);
// imagePath1 = Path.Combine(GlobalConstants.DATA_FOLDERPATH, "Images", "BurgerTEST.png");
// imagePath2 = Path.Combine(GlobalConstants.DATA_FOLDERPATH, "Images", "PizzaTEST.png");
}
// --- Unity Lifecycle ---
// OnEnable can potentially signal intent if needed, but OnDestroy is more critical
// private void OnEnable() { }
private void OnDestroy()
{
// Signal that this instance's reason for showing the overlay is gone
if (isForRecording)
{
s_isOverlayForRecording = false;
}
else // Assume it was for sharing if not for recording
{
s_isOverlayForSharing = false;
}
// Update the appearance based on remaining requests
UpdateOverlayAppearance(displayNumber); // Pass monitor index needed by ShowOverlayOnMonitor
// Watchdog cleanup remains commented
}
void OnApplicationQuit()
{
// Clear all requests on quit
s_isOverlayForRecording = false;
s_isOverlayForSharing = false;
// Hide overlay explicitly on quit as a safety measure
// (although DllMain DETACH also calls HideOverlay)
OverlayHResult result = NativeOverlayInterface.HideOverlay();
if (result != OverlayHResult.S_OK)
{
// Use instance logger if available, otherwise Debug.LogError
//logError($"[WindowsOverlayController] OnApplicationQuit - HideOverlay failed (might be ok). HRESULT: 0x{(int)result:X}");
}
}
// --- Static Coordination Logic for Border ---
/// <summary>
/// Checks the static flags and calls the Native Interface to show/hide/update
/// the border overlay based on priority (Recording > Sharing > Hidden).
/// </summary>
private static void UpdateOverlayAppearance(int displayNr)
{
// Ensure DLL is ready before calling its functions
if (!NativeOverlayInterface.IsSupportedPlatform) return;
int desiredState = 0; // 0 = Hidden, 1 = ShareScreen (Green), 2 = Recording (Red)
Color desiredColor = Color.black;
int desiredBorderWidth = 0;
// Determine highest priority active state
if (s_isOverlayForRecording)
{
desiredState = 2;
desiredColor = Color.red;
desiredBorderWidth = 15; // Example width
}
else if (s_isOverlayForSharing)
{
desiredState = 1;
desiredColor = Color.green;
desiredBorderWidth = 10; // Example width
}
// else desiredState remains 0 (Hidden)
// Call DLL via NativeOverlayInterface based on desired state
OverlayHResult result;
if (desiredState > 0) // Show or Update
{
// Call ShowOverlayOnMonitor - this function in the DLL handles both showing initially
// and updating the state (color/width) because it calls HideOverlay internally first.
result = NativeOverlayInterface.ShowOverlayOnMonitor(
displayNr, // Target monitor
"", // No text for border overlay
false, // No text
desiredBorderWidth,
desiredColor, // Pass Color struct
1, // Dummy font size
0 // Dummy alignment
);
if (result == OverlayHResult.S_OK)
{
s_isOverlayActive = true;
}
else
{
// Use Debug.LogError as this is a static method
//logError($"[WindowsOverlayController] UpdateOverlayAppearance - Static Update: Failed to show/update overlay. HRESULT: 0x{(int)result:X}");
//Debug.LogError($"[WindowsOverlayController] UpdateOverlayAppearance - Static Update: Failed to show/update overlay. HRESULT: 0x{(int)result:X}");
}
}
else // Hide
{
if (s_isOverlayActive) // Only hide if coordinator thinks it's active
{
result = NativeOverlayInterface.HideOverlay();
if (result == OverlayHResult.S_OK)
{
s_isOverlayActive = false;
}
else
{
// Use Debug.LogError
//logError($"[WindowsOverlayController] UpdateOverlayAppearance - Static Update: Failed to hide the overlay. HRESULT: 0x{(int)result:X}");
//Debug.LogError($"[WindowsOverlayController] UpdateOverlayAppearance - Static Update: Failed to hide the overlay. HRESULT: 0x{(int)result:X}");
}
}
}
}
// --- Public Methods to Control Border State ---
/// <summary>
/// Call this to signal the start of recording or sharing.
/// </summary>
public void showBorder(bool isForRecordingOverlay, int displayIndex = 0)
{
this.isForRecording = isForRecordingOverlay; // Store purpose of this instance
this.displayNumber = displayIndex;
if (isForRecordingOverlay)
{
s_isOverlayForRecording = true;
}
else
{
s_isOverlayForSharing = true;
}
UpdateOverlayAppearance(displayNumber);
}
/// <summary>
/// Call this to signal the end of recording or sharing associated with this instance.
/// </summary>
public void hideBorder()
{
if (isForRecording)
{
s_isOverlayForRecording = false;
}
else
{
s_isOverlayForSharing = false;
}
// Reset instance flags
isForRecording = false;
// Don't reset displayNumber? Or maybe set to 0?
UpdateOverlayAppearance(displayNumber);
}
// --- Direct DLL Wrappers (Optional - Can call NativeOverlayInterface directly elsewhere) ---
// These just pass calls through and log errors using the instance logger
public void showOverlayText(bool show)
{
OverlayHResult result = NativeOverlayInterface.ShowOverlayText(show);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] ShowOverlayText - Failed. HRESULT: 0x{(int)result:X}");
}
}
public void updateOverlayText(string newOverlayText)
{
OverlayHResult result = NativeOverlayInterface.UpdateOverlayText(newOverlayText);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] UpdateOverlayText - Failed. HRESULT: 0x{(int)result:X}");
}
}
public void updateOverlayTextSize(int newTextSize)
{
OverlayHResult result = NativeOverlayInterface.UpdateOverlayFontSize(newTextSize);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] UpdateOverlayTextSize - Failed. HRESULT: 0x{(int)result:X}");
}
}
public void updateOverlayBorderColor(Color newBorderColor)
{
OverlayHResult result = NativeOverlayInterface.UpdateOverlayColor(newBorderColor);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] UpdateOverlayBorderColor - Failed. HRESULT: 0x{(int)result:X}");
}
}
public void updateOverlayBorderWidth(int newBorderWidth)
{
OverlayHResult result = NativeOverlayInterface.UpdateOverlayWidth(newBorderWidth);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] UpdateOverlayBorderWidth - Failed. HRESULT: 0x{(int)result:X}");
}
}
public void updateOverlayTextAlignment(CoVinceOverlayTextAlignment alignment)
{
OverlayHResult result = NativeOverlayInterface.UpdateOverlayAlignment(alignment);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] UpdateOverlayTextAlignment - Failed. HRESULT: 0x{(int)result:X}");
}
}
// --- Pointer Wrappers (Can call NativeOverlayInterface directly elsewhere) ---
public void addOrUpdatePointer(string userId, string userName, int x, int y, string imagePath, int desiredWidth, int desiredHeight)
{
OverlayHResult result = NativeOverlayInterface.AddOrUpdatePointer(userId, userName, x, y, imagePath, desiredWidth, desiredHeight);
if (result != OverlayHResult.S_OK)
{
//logError($"[WindowsOverlayController] AddOrUpdatePointer - Failed for {userId}. HRESULT: 0x{(int)result:X}");
}
}
public void removePointer(string userId)
{
OverlayHResult result = NativeOverlayInterface.RemovePointer(userId);
if (result != OverlayHResult.S_OK)
{ // Check if RemovePointer returns error on failure
//logError($"[WindowsOverlayController] RemovePointer - Failed for {userId}. HRESULT: 0x{(int)result:X}");
}
}
public void clearAllPointers()
{
OverlayHResult result = NativeOverlayInterface.ClearAllPointers();
if (result != OverlayHResult.S_OK)
{ // Check if ClearAllPointers returns error on failure
//logError($"[WindowsOverlayController] ClearAllPointers - Failed. HRESULT: 0x{(int)result:X}");
}
}
// --- Update Method for Testing ---
void Update()
{
// Only run test controls if enabled via inspector
if (!useTestControls) return;
// Check if the platform is supported by the native plugin
if (!NativeOverlayInterface.IsSupportedPlatform) return;
// --- Test Pointer Controls ---
if (Input.GetKey(KeyCode.LeftControl) && Input.GetMouseButton(0))
{
int mouseX = (int)Input.mousePosition.x;
int mouseY = (int)(Screen.height - Input.mousePosition.y); // Flip Y for screen coords
// Using instance method which calls static interface method
addOrUpdatePointer("TestUser1", "Dennis 1", mouseX, mouseY, imagePath1, 64, 64);
}
if (Input.GetKeyUp(KeyCode.LeftControl) || Input.GetMouseButtonUp(0)) // Basic stop on key/mouse release
{
removePointer("TestUser1");
}
if (Input.GetKeyDown(KeyCode.I))
{
string imagePath1 = @"C:\Users\denni\AppData\LocalLow\DefaultCompany\covinceplatform\Images\BurgerTEST.png"; // Use verbatim path
string imagePath2 = @"C:\Users\denni\AppData\LocalLow\DefaultCompany\covinceplatform\Images\PizzaTEST.png"; // Use verbatim path
// Verify paths before calling
//log($"DLL Image Path 1: {imagePath1}");
//log($"DLL Image Path 2: {imagePath2}");
//if (!System.IO.File.Exists(imagePath1)) logError("Burger Image NOT FOUND");
//if (!System.IO.File.Exists(imagePath2)) logError("Pizza Image NOT FOUND");
addOrUpdatePointer("TestUser1", "Dennis 1", 100, 200, imagePath1, 128, 128);
addOrUpdatePointer("TestUser2", "Dennis 2", 400, 600, imagePath2, 64, 64);
}
if (Input.GetKeyDown(KeyCode.O)) { removePointer("TestUser2"); }
if (Input.GetKeyDown(KeyCode.P)) { clearAllPointers(); }
// --- Test Border Controls (Using public Show/Hide Border methods) ---
if (Input.GetKeyDown(KeyCode.R))
{
// Simulate starting recording (Red border)
showBorder(true, 0); // Pass true for recording, monitor 0
//log("Test: Show Recording Border requested.");
}
if (Input.GetKeyDown(KeyCode.G))
{
// Simulate starting sharing (Green border)
showBorder(false, 0); // Pass false for sharing, monitor 0
//log("Test: Show Sharing Border requested.");
}
if (Input.GetKeyDown(KeyCode.X))
{
// Simulate stopping whatever THIS instance was responsible for
hideBorder();
//log("Test: Hide Border requested.");
}
// Test direct Update calls (Using public wrapper methods)
if (Input.GetKeyDown(KeyCode.B)) { updateOverlayBorderColor(Color.blue); }
if (Input.GetKeyDown(KeyCode.W)) { updateOverlayBorderWidth(UnityEngine.Random.Range(5, 25)); } // Example width change
if (Input.GetKeyDown(KeyCode.H)) { showOverlayText(!showText); showText = !showText; } // Toggle text visibility
if (Input.GetKeyDown(KeyCode.T)) { updateOverlayText($"Test {Time.time:F1}"); }
// Alignment cycle remains complex, keep as is for testing if needed
if (Input.GetKeyDown(KeyCode.A))
{
textAlignment = textAlignment switch
{
// If current is Center (CENTER | VCENTER), next is Top (CENTER | TOP)
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.VCENTER =>
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.TOP,
// If current is Top (CENTER | TOP), next is Top Right (RIGHT | TOP)
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.TOP =>
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.VCENTER,
// If current is Top Right (RIGHT | TOP), next is Right (RIGHT | VCENTER)
CoVinceOverlayTextAlignment.RIGHT | CoVinceOverlayTextAlignment.TOP =>
CoVinceOverlayTextAlignment.RIGHT | CoVinceOverlayTextAlignment.VCENTER,
// If current is Right (RIGHT | VCENTER), next is Bottom Right (RIGHT | BOTTOM)
CoVinceOverlayTextAlignment.RIGHT | CoVinceOverlayTextAlignment.VCENTER =>
CoVinceOverlayTextAlignment.RIGHT | CoVinceOverlayTextAlignment.BOTTOM,
// If current is Bottom Right (RIGHT | BOTTOM), next is Bottom (CENTER | BOTTOM)
CoVinceOverlayTextAlignment.RIGHT | CoVinceOverlayTextAlignment.BOTTOM =>
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.BOTTOM,
// If current is Bottom (CENTER | BOTTOM), next is Bottom Left (LEFT | BOTTOM)
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.BOTTOM =>
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.BOTTOM,
// If current is Bottom Left (LEFT | BOTTOM), next is Left (LEFT | VCENTER)
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.BOTTOM =>
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.VCENTER,
// If current is Left (LEFT | VCENTER), next is Top Left (LEFT | TOP)
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.VCENTER =>
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.TOP,
// If current is Top Left (LEFT | TOP), next is Center (CENTER | VCENTER)
CoVinceOverlayTextAlignment.LEFT | CoVinceOverlayTextAlignment.TOP =>
CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.VCENTER,
// Default case (e.g., if starting state wasn't one of the above) -> go to Center (CENTER | VCENTER)
_ => CoVinceOverlayTextAlignment.CENTER | CoVinceOverlayTextAlignment.VCENTER,
};
updateOverlayTextAlignment(textAlignment);
//log($"Test: Alignment Changed to {(int)textAlignment} ({textAlignment})");
}
if (Input.GetKeyDown(KeyCode.F))
{
fontSize += 2;
updateOverlayTextSize(fontSize);
//log($"Test: Font Size Changed to {fontSize}");
}
} // End Update()
} // End Class