#include "XCUIBackend/ImGuiXCUIInputAdapter.h" #include #include #include namespace XCEngine { namespace Editor { namespace XCUIBackend { namespace { using XCEngine::Input::KeyCode; struct ImGuiKeyMappingEntry { ImGuiKey imguiKey = ImGuiKey_None; KeyCode keyCode = KeyCode::None; }; constexpr ImGuiKeyMappingEntry kImGuiKeyMappings[] = { { ImGuiKey_A, KeyCode::A }, { ImGuiKey_B, KeyCode::B }, { ImGuiKey_C, KeyCode::C }, { ImGuiKey_D, KeyCode::D }, { ImGuiKey_E, KeyCode::E }, { ImGuiKey_F, KeyCode::F }, { ImGuiKey_G, KeyCode::G }, { ImGuiKey_H, KeyCode::H }, { ImGuiKey_I, KeyCode::I }, { ImGuiKey_J, KeyCode::J }, { ImGuiKey_K, KeyCode::K }, { ImGuiKey_L, KeyCode::L }, { ImGuiKey_M, KeyCode::M }, { ImGuiKey_N, KeyCode::N }, { ImGuiKey_O, KeyCode::O }, { ImGuiKey_P, KeyCode::P }, { ImGuiKey_Q, KeyCode::Q }, { ImGuiKey_R, KeyCode::R }, { ImGuiKey_S, KeyCode::S }, { ImGuiKey_T, KeyCode::T }, { ImGuiKey_U, KeyCode::U }, { ImGuiKey_V, KeyCode::V }, { ImGuiKey_W, KeyCode::W }, { ImGuiKey_X, KeyCode::X }, { ImGuiKey_Y, KeyCode::Y }, { ImGuiKey_Z, KeyCode::Z }, { ImGuiKey_0, KeyCode::Zero }, { ImGuiKey_1, KeyCode::One }, { ImGuiKey_2, KeyCode::Two }, { ImGuiKey_3, KeyCode::Three }, { ImGuiKey_4, KeyCode::Four }, { ImGuiKey_5, KeyCode::Five }, { ImGuiKey_6, KeyCode::Six }, { ImGuiKey_7, KeyCode::Seven }, { ImGuiKey_8, KeyCode::Eight }, { ImGuiKey_9, KeyCode::Nine }, { ImGuiKey_Space, KeyCode::Space }, { ImGuiKey_Tab, KeyCode::Tab }, { ImGuiKey_Enter, KeyCode::Enter }, { ImGuiKey_KeypadEnter, KeyCode::Enter }, { ImGuiKey_Escape, KeyCode::Escape }, { ImGuiKey_LeftShift, KeyCode::LeftShift }, { ImGuiKey_RightShift, KeyCode::RightShift }, { ImGuiKey_LeftCtrl, KeyCode::LeftCtrl }, { ImGuiKey_RightCtrl, KeyCode::RightCtrl }, { ImGuiKey_LeftAlt, KeyCode::LeftAlt }, { ImGuiKey_RightAlt, KeyCode::RightAlt }, { ImGuiKey_UpArrow, KeyCode::Up }, { ImGuiKey_DownArrow, KeyCode::Down }, { ImGuiKey_LeftArrow, KeyCode::Left }, { ImGuiKey_RightArrow, KeyCode::Right }, { ImGuiKey_Home, KeyCode::Home }, { ImGuiKey_End, KeyCode::End }, { ImGuiKey_PageUp, KeyCode::PageUp }, { ImGuiKey_PageDown, KeyCode::PageDown }, { ImGuiKey_Delete, KeyCode::Delete }, { ImGuiKey_Backspace, KeyCode::Backspace }, { ImGuiKey_F1, KeyCode::F1 }, { ImGuiKey_F2, KeyCode::F2 }, { ImGuiKey_F3, KeyCode::F3 }, { ImGuiKey_F4, KeyCode::F4 }, { ImGuiKey_F5, KeyCode::F5 }, { ImGuiKey_F6, KeyCode::F6 }, { ImGuiKey_F7, KeyCode::F7 }, { ImGuiKey_F8, KeyCode::F8 }, { ImGuiKey_F9, KeyCode::F9 }, { ImGuiKey_F10, KeyCode::F10 }, { ImGuiKey_F11, KeyCode::F11 }, { ImGuiKey_F12, KeyCode::F12 }, { ImGuiKey_Minus, KeyCode::Minus }, { ImGuiKey_Equal, KeyCode::Equals }, { ImGuiKey_LeftBracket, KeyCode::BracketLeft }, { ImGuiKey_RightBracket, KeyCode::BracketRight }, { ImGuiKey_Semicolon, KeyCode::Semicolon }, { ImGuiKey_Apostrophe, KeyCode::Quote }, { ImGuiKey_Comma, KeyCode::Comma }, { ImGuiKey_Period, KeyCode::Period }, { ImGuiKey_Slash, KeyCode::Slash }, { ImGuiKey_Backslash, KeyCode::Backslash }, { ImGuiKey_GraveAccent, KeyCode::Backtick }, }; bool IsPointerPositionValid(const ImVec2& position) { return std::isfinite(position.x) && std::isfinite(position.y) && position.x > -std::numeric_limits::max() * 0.5f && position.y > -std::numeric_limits::max() * 0.5f; } bool SnapshotHasKeyRepeat(const ImGuiIO& io, ImGuiKey key) { if (key < ImGuiKey_NamedKey_BEGIN || key >= ImGuiKey_NamedKey_END) { return false; } const ImGuiKeyData& data = io.KeysData[key - ImGuiKey_NamedKey_BEGIN]; return data.Down && data.DownDurationPrev >= 0.0f && ImGui::IsKeyPressed(key, true); } void UpsertKeyState( std::vector& states, std::int32_t keyCode, bool down, bool repeat) { if (keyCode == 0) { return; } for (XCUIInputBridgeKeyState& state : states) { if (state.keyCode != keyCode) { continue; } state.down = state.down || down; state.repeat = state.repeat || repeat; return; } XCUIInputBridgeKeyState state = {}; state.keyCode = keyCode; state.down = down; state.repeat = repeat; states.push_back(state); } void SortSnapshotKeys(XCUIInputBridgeFrameSnapshot& snapshot) { std::sort( snapshot.keys.begin(), snapshot.keys.end(), [](const XCUIInputBridgeKeyState& lhs, const XCUIInputBridgeKeyState& rhs) { return lhs.keyCode < rhs.keyCode; }); } } // namespace XCUIInputBridgeFrameSnapshot ImGuiXCUIInputAdapter::CaptureSnapshot( const ImGuiIO& io, const XCUIInputBridgeCaptureOptions& options) { XCUIInputBridgeFrameSnapshot snapshot = {}; snapshot.pointerPosition = UI::UIPoint( io.MousePos.x - options.pointerOffset.x, io.MousePos.y - options.pointerOffset.y); snapshot.pointerInside = options.hasPointerInsideOverride ? options.pointerInsideOverride : IsPointerPositionValid(io.MousePos); snapshot.wheelDelta = UI::UIPoint(io.MouseWheelH, io.MouseWheel); snapshot.modifiers.shift = io.KeyShift; snapshot.modifiers.control = io.KeyCtrl; snapshot.modifiers.alt = io.KeyAlt; snapshot.modifiers.super = io.KeySuper; snapshot.windowFocused = options.windowFocused; snapshot.wantCaptureMouse = io.WantCaptureMouse; snapshot.wantCaptureKeyboard = io.WantCaptureKeyboard; snapshot.wantTextInput = io.WantTextInput; snapshot.timestampNanoseconds = options.timestampNanoseconds; for (std::size_t index = 0; index < XCUIInputBridgeFrameSnapshot::PointerButtonCount; ++index) { snapshot.pointerButtonsDown[index] = io.MouseDown[index]; } snapshot.characters.reserve(static_cast(io.InputQueueCharacters.Size)); for (int index = 0; index < io.InputQueueCharacters.Size; ++index) { const ImWchar character = io.InputQueueCharacters[index]; if (character != 0) { snapshot.characters.push_back(static_cast(character)); } } snapshot.keys.reserve(sizeof(kImGuiKeyMappings) / sizeof(kImGuiKeyMappings[0])); for (const ImGuiKeyMappingEntry& mapping : kImGuiKeyMappings) { if (mapping.keyCode == KeyCode::None) { continue; } const bool isDown = ImGui::IsKeyDown(mapping.imguiKey); const bool isRepeat = SnapshotHasKeyRepeat(io, mapping.imguiKey); if (!isDown && !isRepeat) { continue; } UpsertKeyState( snapshot.keys, static_cast(mapping.keyCode), isDown, isRepeat); } SortSnapshotKeys(snapshot); return snapshot; } std::int32_t ImGuiXCUIInputAdapter::MapKeyCode(ImGuiKey key) { for (const ImGuiKeyMappingEntry& mapping : kImGuiKeyMappings) { if (mapping.imguiKey == key) { return static_cast(mapping.keyCode); } } return static_cast(KeyCode::None); } } // namespace XCUIBackend } // namespace Editor } // namespace XCEngine