227 lines
7.3 KiB
C++
227 lines
7.3 KiB
C++
|
|
#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
|