Add XCUI input state validation sandbox batch
This commit is contained in:
@@ -27,6 +27,7 @@ using ::XCEngine::UI::UIInputEvent;
|
||||
using ::XCEngine::UI::UIInputEventType;
|
||||
using ::XCEngine::UI::UIInputModifiers;
|
||||
using ::XCEngine::UI::UIPoint;
|
||||
using ::XCEngine::UI::UIPointerButton;
|
||||
using ::XCEngine::UI::UIRect;
|
||||
using ::XCEngine::UI::Runtime::UIScreenFrameInput;
|
||||
|
||||
@@ -57,6 +58,19 @@ std::string TruncateText(const std::string& text, std::size_t maxLength) {
|
||||
return text.substr(0, maxLength - 3u) + "...";
|
||||
}
|
||||
|
||||
std::string ExtractStateKeyTail(const std::string& stateKey) {
|
||||
if (stateKey.empty()) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const std::size_t separator = stateKey.find_last_of('/');
|
||||
if (separator == std::string::npos || separator + 1u >= stateKey.size()) {
|
||||
return stateKey;
|
||||
}
|
||||
|
||||
return stateKey.substr(separator + 1u);
|
||||
}
|
||||
|
||||
std::string FormatFloat(float value) {
|
||||
std::ostringstream stream;
|
||||
stream.setf(std::ios::fixed, std::ios::floatfield);
|
||||
@@ -255,6 +269,29 @@ void Application::OnResize(UINT width, UINT height) {
|
||||
m_renderer.Resize(width, height);
|
||||
}
|
||||
|
||||
void Application::QueuePointerEvent(UIInputEventType type, UIPointerButton button, WPARAM wParam, LPARAM lParam) {
|
||||
UIInputEvent event = {};
|
||||
event.type = type;
|
||||
event.pointerButton = button;
|
||||
event.position = UIPoint(
|
||||
static_cast<float>(GET_X_LPARAM(lParam)),
|
||||
static_cast<float>(GET_Y_LPARAM(lParam)));
|
||||
event.modifiers = BuildInputModifiers(static_cast<size_t>(wParam));
|
||||
m_pendingInputEvents.push_back(event);
|
||||
}
|
||||
|
||||
void Application::QueuePointerLeaveEvent() {
|
||||
UIInputEvent event = {};
|
||||
event.type = UIInputEventType::PointerLeave;
|
||||
if (m_hwnd != nullptr) {
|
||||
POINT clientPoint = {};
|
||||
GetCursorPos(&clientPoint);
|
||||
ScreenToClient(m_hwnd, &clientPoint);
|
||||
event.position = UIPoint(static_cast<float>(clientPoint.x), static_cast<float>(clientPoint.y));
|
||||
}
|
||||
m_pendingInputEvents.push_back(event);
|
||||
}
|
||||
|
||||
void Application::QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARAM lParam) {
|
||||
if (m_hwnd == nullptr) {
|
||||
return;
|
||||
@@ -272,7 +309,6 @@ void Application::QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARAM
|
||||
event.wheelDelta = static_cast<float>(wheelDelta);
|
||||
event.modifiers = BuildInputModifiers(static_cast<size_t>(wParam));
|
||||
m_pendingInputEvents.push_back(event);
|
||||
m_autoScreenshot.RequestCapture("wheel");
|
||||
}
|
||||
|
||||
bool Application::LoadStructuredScreen(const char* triggerReason) {
|
||||
@@ -286,10 +322,6 @@ bool Application::LoadStructuredScreen(const char* triggerReason) {
|
||||
m_runtimeStatus = loaded ? "Authored XCUI" : "Fallback Sandbox";
|
||||
m_runtimeError = loaded ? std::string() : m_screenPlayer.GetLastError();
|
||||
RebuildTrackedFileStates();
|
||||
|
||||
std::string screenshotReason = triggerReason != nullptr ? triggerReason : "update";
|
||||
screenshotReason += loaded ? "_authored" : "_fallback";
|
||||
m_autoScreenshot.RequestCapture(std::move(screenshotReason));
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@@ -380,47 +412,31 @@ void Application::AppendRuntimeOverlay(UIDrawData& drawData, float width, float
|
||||
: "Using native fallback while authored UI is invalid.");
|
||||
|
||||
if (authoredMode) {
|
||||
const auto& scrollDebug = m_documentHost.GetScrollDebugSnapshot();
|
||||
if (!scrollDebug.primaryTargetStateKey.empty()) {
|
||||
detailLines.push_back(
|
||||
"Primary: " +
|
||||
TruncateText(scrollDebug.primaryTargetStateKey, 52u));
|
||||
detailLines.push_back(
|
||||
"Primary viewport: " +
|
||||
FormatRect(scrollDebug.primaryViewportRect));
|
||||
detailLines.push_back(
|
||||
"Primary overflow: " +
|
||||
FormatFloat(scrollDebug.primaryOverflow));
|
||||
}
|
||||
const auto& inputDebug = m_documentHost.GetInputDebugSnapshot();
|
||||
detailLines.push_back(
|
||||
"Wheel total/handled: " +
|
||||
std::to_string(scrollDebug.totalWheelEventCount) +
|
||||
" / " +
|
||||
std::to_string(scrollDebug.handledWheelEventCount));
|
||||
if (scrollDebug.totalWheelEventCount > 0u) {
|
||||
"Hover | Focus: " +
|
||||
ExtractStateKeyTail(inputDebug.hoveredStateKey) +
|
||||
" | " +
|
||||
ExtractStateKeyTail(inputDebug.focusedStateKey));
|
||||
detailLines.push_back(
|
||||
"Active | Capture: " +
|
||||
ExtractStateKeyTail(inputDebug.activeStateKey) +
|
||||
" | " +
|
||||
ExtractStateKeyTail(inputDebug.captureStateKey));
|
||||
if (!inputDebug.lastEventType.empty()) {
|
||||
detailLines.push_back(
|
||||
"Last wheel " +
|
||||
FormatFloat(scrollDebug.lastWheelDelta) +
|
||||
"Last input: " +
|
||||
inputDebug.lastEventType +
|
||||
" at " +
|
||||
FormatPoint(scrollDebug.lastPointerPosition));
|
||||
FormatPoint(inputDebug.pointerPosition));
|
||||
detailLines.push_back(
|
||||
"Route: " +
|
||||
inputDebug.lastTargetKind +
|
||||
" -> " +
|
||||
ExtractStateKeyTail(inputDebug.lastTargetStateKey));
|
||||
detailLines.push_back(
|
||||
"Result: " +
|
||||
(scrollDebug.lastResult.empty() ? std::string("n/a") : scrollDebug.lastResult));
|
||||
if (!scrollDebug.lastTargetStateKey.empty()) {
|
||||
detailLines.push_back(
|
||||
"Target: " +
|
||||
TruncateText(scrollDebug.lastTargetStateKey, 52u));
|
||||
detailLines.push_back(
|
||||
"Viewport: " +
|
||||
FormatRect(scrollDebug.lastViewportRect));
|
||||
detailLines.push_back(
|
||||
"Overflow/offset: " +
|
||||
FormatFloat(scrollDebug.lastOverflow) +
|
||||
" | " +
|
||||
FormatFloat(scrollDebug.lastOffsetBefore) +
|
||||
" -> " +
|
||||
FormatFloat(scrollDebug.lastOffsetAfter));
|
||||
}
|
||||
(inputDebug.lastResult.empty() ? std::string("n/a") : inputDebug.lastResult));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,6 +444,8 @@ void Application::AppendRuntimeOverlay(UIDrawData& drawData, float width, float
|
||||
detailLines.push_back("Shot pending...");
|
||||
} else if (!m_autoScreenshot.GetLastCaptureSummary().empty()) {
|
||||
detailLines.push_back(TruncateText(m_autoScreenshot.GetLastCaptureSummary(), 78u));
|
||||
} else {
|
||||
detailLines.push_back("Screenshots: manual only (F12)");
|
||||
}
|
||||
|
||||
if (!m_runtimeError.empty()) {
|
||||
@@ -494,12 +512,57 @@ LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT message, WPARAM wParam, LP
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
if (application != nullptr) {
|
||||
if (!application->m_trackingMouseLeave) {
|
||||
TRACKMOUSEEVENT trackMouseEvent = {};
|
||||
trackMouseEvent.cbSize = sizeof(trackMouseEvent);
|
||||
trackMouseEvent.dwFlags = TME_LEAVE;
|
||||
trackMouseEvent.hwndTrack = hwnd;
|
||||
if (TrackMouseEvent(&trackMouseEvent)) {
|
||||
application->m_trackingMouseLeave = true;
|
||||
}
|
||||
}
|
||||
application->QueuePointerEvent(UIInputEventType::PointerMove, UIPointerButton::None, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSELEAVE:
|
||||
if (application != nullptr) {
|
||||
application->m_trackingMouseLeave = false;
|
||||
application->QueuePointerLeaveEvent();
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
if (application != nullptr) {
|
||||
SetFocus(hwnd);
|
||||
SetCapture(hwnd);
|
||||
application->QueuePointerEvent(UIInputEventType::PointerButtonDown, UIPointerButton::Left, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
if (application != nullptr) {
|
||||
if (GetCapture() == hwnd) {
|
||||
ReleaseCapture();
|
||||
}
|
||||
application->QueuePointerEvent(UIInputEventType::PointerButtonUp, UIPointerButton::Left, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
if (application != nullptr) {
|
||||
application->QueuePointerWheelEvent(GET_WHEEL_DELTA_WPARAM(wParam), wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
if (application != nullptr && wParam == VK_F12) {
|
||||
application->m_autoScreenshot.RequestCapture("manual_f12");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_ERASEBKGND:
|
||||
return 1;
|
||||
case WM_DESTROY:
|
||||
|
||||
Reference in New Issue
Block a user