Files
XCEngine/new_editor/src/XCUIBackend/ImGuiXCUIInputAdapter.cpp

227 lines
7.3 KiB
C++
Raw Normal View History

2026-04-05 04:55:25 +08:00
#include "XCUIBackend/ImGuiXCUIInputAdapter.h"
#include <algorithm>
#include <cmath>
#include <limits>
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<float>::max() * 0.5f &&
position.y > -std::numeric_limits<float>::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<XCUIInputBridgeKeyState>& 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<std::size_t>(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<std::uint32_t>(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<std::int32_t>(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<std::int32_t>(mapping.keyCode);
}
}
return static_cast<std::int32_t>(KeyCode::None);
}
} // namespace XCUIBackend
} // namespace Editor
} // namespace XCEngine