// Most compatible approach - store result and let Papyrus poll for it
// This works with ALL SKSE versions
namespace PapyrusInterface {
// Global state (add these if not already present)
std::atomic<bool> g_isRunning{false};
std::atomic<bool> g_cancelFlag{false};
std::atomic<bool> g_resultReady{false}; // Add this flag
std::mutex g_resultMutex;
std::string g_result = "Success";
// Worker thread function - simplified version
void CaptureWorkerThread(
std::string basePath,
std::string imageType,
float jpgCompression,
std::string compressionMode,
float gifMultiFrameDuration
) {
logger::info("Capture worker thread started");
// ... [existing capture code] ...
// Perform capture
auto result = ScreenCapture::CaptureScreen(params);
// Update global result (simplified - no ModEvent needed)
{
std::lock_guard<std::mutex> lock(g_resultMutex);
if (g_cancelFlag.load()) {
g_result = "Cancelled";
} else {
g_result = result.message;
}
g_isRunning = false;
g_resultReady = true; // Signal that result is ready
}
logger::info("Capture completed with result: {}", g_result);
}
// Enhanced Get_Result function that acts as a callback
RE::BSFixedString Get_Result(RE::StaticFunctionTag*) {
std::lock_guard<std::mutex> lock(g_resultMutex);
// Check if we have a new result
if (g_resultReady.load()) {
g_resultReady = false; // Reset flag
// Trigger the Papyrus event manually by returning a special result
// The Papyrus script can check for this and call its own event
if (g_result == "Success") {
return RE::BSFixedString("CALLBACK_SUCCESS");
} else if (g_result == "Cancelled") {
return RE::BSFixedString("CALLBACK_CANCELLED");
} else {
return RE::BSFixedString(("CALLBACK_ERROR:" + g_result).c_str());
}
}
// Return current status if no new result
if (g_isRunning.load()) {
return RE::BSFixedString("Running");
}
return RE::BSFixedString(g_result.c_str());
}
}
//================================== Papyrus associated code ============================================================
; Add this to your Papyrus MainQuest script
; Start a polling timer when screenshot begins
Function Printscreen(String path, String imageType, Float compression, String Mode, float GIF_MultiFrame_Duration)
Debug.Trace("Starting latent screenshot: " + path + ", " + imageType)
if(Menu)
Debug.Trace("Menu control is active, hiding HUD")
HideHud()
else
Debug.Trace("Menu control is inactive, HUD will remain visible")
endif
; Start the latent function
String startResult = Printscreen_Formula_script.TakePhoto(path, imageType, compression, Mode, GIF_MultiFrame_Duration)
if (startResult == "Started")
; Start polling for completion
StartTimer(0.5, 1) ; Poll every 0.5 seconds using timer ID 1
else
; Failed to start
Debug.Notification("Failed to start screenshot: " + startResult)
IsLatentScreenshotActive = false
if (Menu)
ShowHud()
endif
endif
EndFunction
; Timer event for polling
Event OnTimer(int aiTimerID)
if (aiTimerID == 1) ; Screenshot polling timer
String result = Printscreen_Formula_script.Get_Result()
if (StringUtil.Find(result, "CALLBACK_") == 0)
; We got a callback result - process it
if (result == "CALLBACK_SUCCESS")
OnScreenshotCompleted("PrintScreenComplete", "Success", 0.0, None)
elseif (result == "CALLBACK_CANCELLED")
OnScreenshotCompleted("PrintScreenComplete", "Cancelled", 0.0, None)
elseif (StringUtil.Find(result, "CALLBACK_ERROR:") == 0)
String errorMsg = StringUtil.Substring(result, 15) ; Remove "CALLBACK_ERROR:" prefix
OnScreenshotCompleted("PrintScreenComplete", errorMsg, 0.0, None)
endif
elseif (result == "Running")
; Still running, continue polling
StartTimer(0.5, 1)
else
; Unexpected result, treat as error
OnScreenshotCompleted("PrintScreenComplete", result, 0.0, None)
endif
endif
EndEvent
; Your existing completion handler
Function OnScreenshotCompleted(String eventName, String strArg, Float numArg, Form akSender)
Result = strArg
Debug.Trace("Screenshot completed with result: " + Result)
if(Result == "Success")
Shots = shots + 1
Debug.Notification("Screenshot #" +Shots + " saved successfully!")
else
Debug.Notification("Screenshot failed: " + Result)
OnScreenshotFailed()
endif
if(IsLatentScreenshotActive && Menu)
showHUD()
endif
IsLatentScreenshotActive = false
EndFunction