#pragma once #ifndef NOMINMAX #define NOMINMAX #endif #include #include #include #include namespace XCEngine::UI::Editor::Host { class InputModifierTracker { public: void Reset() { m_leftShift = false; m_rightShift = false; m_leftControl = false; m_rightControl = false; m_leftAlt = false; m_rightAlt = false; m_leftSuper = false; m_rightSuper = false; } void SyncFromSystemState() { m_leftShift = (GetKeyState(VK_LSHIFT) & 0x8000) != 0; m_rightShift = (GetKeyState(VK_RSHIFT) & 0x8000) != 0; m_leftControl = (GetKeyState(VK_LCONTROL) & 0x8000) != 0; m_rightControl = (GetKeyState(VK_RCONTROL) & 0x8000) != 0; m_leftAlt = (GetKeyState(VK_LMENU) & 0x8000) != 0; m_rightAlt = (GetKeyState(VK_RMENU) & 0x8000) != 0; m_leftSuper = (GetKeyState(VK_LWIN) & 0x8000) != 0; m_rightSuper = (GetKeyState(VK_RWIN) & 0x8000) != 0; } ::XCEngine::UI::UIInputModifiers GetCurrentModifiers() const { return BuildModifiers(); } ::XCEngine::UI::UIInputModifiers BuildPointerModifiers(std::size_t wParam) const { ::XCEngine::UI::UIInputModifiers modifiers = BuildModifiers(); modifiers.shift = modifiers.shift || (wParam & MK_SHIFT) != 0; modifiers.control = modifiers.control || (wParam & MK_CONTROL) != 0; return modifiers; } ::XCEngine::UI::UIInputModifiers ApplyKeyMessage( ::XCEngine::UI::UIInputEventType type, WPARAM wParam, LPARAM lParam) { if (type == ::XCEngine::UI::UIInputEventType::KeyDown) { SetModifierState(ResolveModifierKey(wParam, lParam), true); } else if (type == ::XCEngine::UI::UIInputEventType::KeyUp) { SetModifierState(ResolveModifierKey(wParam, lParam), false); } return BuildModifiers(); } private: enum class ModifierKey : std::uint8_t { None = 0, LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper }; static bool IsExtendedKey(LPARAM lParam) { return (static_cast(lParam) & 0x01000000u) != 0u; } static std::uint32_t ExtractScanCode(LPARAM lParam) { return (static_cast(lParam) >> 16u) & 0xffu; } static ModifierKey ResolveModifierKey(WPARAM wParam, LPARAM lParam) { switch (static_cast(wParam)) { case VK_SHIFT: { const UINT shiftVirtualKey = MapVirtualKeyW(ExtractScanCode(lParam), MAPVK_VSC_TO_VK_EX); return shiftVirtualKey == VK_RSHIFT ? ModifierKey::RightShift : ModifierKey::LeftShift; } case VK_LSHIFT: return ModifierKey::LeftShift; case VK_RSHIFT: return ModifierKey::RightShift; case VK_CONTROL: return IsExtendedKey(lParam) ? ModifierKey::RightControl : ModifierKey::LeftControl; case VK_LCONTROL: return ModifierKey::LeftControl; case VK_RCONTROL: return ModifierKey::RightControl; case VK_MENU: return IsExtendedKey(lParam) ? ModifierKey::RightAlt : ModifierKey::LeftAlt; case VK_LMENU: return ModifierKey::LeftAlt; case VK_RMENU: return ModifierKey::RightAlt; case VK_LWIN: return ModifierKey::LeftSuper; case VK_RWIN: return ModifierKey::RightSuper; default: return ModifierKey::None; } } void SetModifierState(ModifierKey key, bool pressed) { switch (key) { case ModifierKey::LeftShift: m_leftShift = pressed; break; case ModifierKey::RightShift: m_rightShift = pressed; break; case ModifierKey::LeftControl: m_leftControl = pressed; break; case ModifierKey::RightControl: m_rightControl = pressed; break; case ModifierKey::LeftAlt: m_leftAlt = pressed; break; case ModifierKey::RightAlt: m_rightAlt = pressed; break; case ModifierKey::LeftSuper: m_leftSuper = pressed; break; case ModifierKey::RightSuper: m_rightSuper = pressed; break; case ModifierKey::None: default: break; } } ::XCEngine::UI::UIInputModifiers BuildModifiers() const { ::XCEngine::UI::UIInputModifiers modifiers = {}; modifiers.shift = m_leftShift || m_rightShift; modifiers.control = m_leftControl || m_rightControl; modifiers.alt = m_leftAlt || m_rightAlt; modifiers.super = m_leftSuper || m_rightSuper; return modifiers; } bool m_leftShift = false; bool m_rightShift = false; bool m_leftControl = false; bool m_rightControl = false; bool m_leftAlt = false; bool m_rightAlt = false; bool m_leftSuper = false; bool m_rightSuper = false; }; } // namespace XCEngine::UI::Editor::Host