From 82729a12c867f859cf9450bade30bc800646b439 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 17 May 2018 23:25:47 +0100 Subject: [PATCH] Enabled experimental ImGui gamepad navigation feature: - Updated InputNavigation CVar to support 1: keyboard navigation, 2: gamepad navigation and 3: keyboard + gamepad navigation simultaneously. - Added ImGui interoperability utilities mapping gamepad input events to values in ImGui navigation inputs array. - Added to ImGui Input State support for gamepad navigation inputs. - Refactored ImGui Input State to keep consistent interface for keyboard, mouse and gamepad updates. --- Source/ImGui/Private/ImGuiInputState.cpp | 14 ++- Source/ImGui/Private/ImGuiInputState.h | 85 +++++++++++--- .../ImGui/Private/ImGuiInteroperability.cpp | 78 +++++++++++++ Source/ImGui/Private/ImGuiInteroperability.h | 14 +++ Source/ImGui/Private/SImGuiWidget.cpp | 105 +++++++++++++----- Source/ImGui/Private/SImGuiWidget.h | 6 +- 6 files changed, 257 insertions(+), 45 deletions(-) diff --git a/Source/ImGui/Private/ImGuiInputState.cpp b/Source/ImGui/Private/ImGuiInputState.cpp index c562227..52086ef 100644 --- a/Source/ImGui/Private/ImGuiInputState.cpp +++ b/Source/ImGui/Private/ImGuiInputState.cpp @@ -82,7 +82,7 @@ void FImGuiInputState::SetMouseDown(uint32 MouseIndex, bool bIsDown) } } -void FImGuiInputState::Reset(bool bKeyboard, bool bMouse) +void FImGuiInputState::Reset(bool bKeyboard, bool bMouse, bool bNavigation) { if (bKeyboard) { @@ -100,6 +100,11 @@ void FImGuiInputState::Reset(bool bKeyboard, bool bMouse) { ClearModifierKeys(); } + + if (bNavigation) + { + ClearNavigationInputs(); + } } void FImGuiInputState::ClearUpdateState() @@ -152,3 +157,10 @@ void FImGuiInputState::ClearModifierKeys() bIsShiftDown = false; bIsAltDown = false; } + +void FImGuiInputState::ClearNavigationInputs() +{ + using std::fill; + fill(NavigationInputs, &NavigationInputs[Utilities::GetArraySize(NavigationInputs)], 0.f); +} + diff --git a/Source/ImGui/Private/ImGuiInputState.h b/Source/ImGui/Private/ImGuiInputState.h index 65b7a3b..dcb52de 100644 --- a/Source/ImGui/Private/ImGuiInputState.h +++ b/Source/ImGui/Private/ImGuiInputState.h @@ -20,6 +20,9 @@ public: // Array for key states. using FKeysArray = ImGuiInterops::ImGuiTypes::FKeysArray; + // Array for navigation input states. + using FNavInputArray = ImGuiInterops::ImGuiTypes::FNavInputArray; + // Pair of indices defining range in mouse buttons array. using FMouseButtonsIndexRange = Utilities::TArrayIndexRange; @@ -47,9 +50,14 @@ public: const FKeysIndexRange& GetKeysUpdateRange() const { return KeysUpdateRange; } // Change state of the key in the keys array and expand range bounding dirty part of the array. - // @param KeyIndex - Index of the key + // @param KeyEvent - Key event representing the key // @param bIsDown - True, if key is down - void SetKeyDown(uint32 KeyIndex, bool bIsDown); + void SetKeyDown(const FKeyEvent& KeyEvent, bool bIsDown) { SetKeyDown(ImGuiInterops::GetKeyIndex(KeyEvent), bIsDown); } + + // Change state of the key in the keys array and expand range bounding dirty part of the array. + // @param Key - Keyboard key + // @param bIsDown - True, if key is down + void SetKeyDown(const FKey& Key, bool bIsDown) { SetKeyDown(ImGuiInterops::GetKeyIndex(Key), bIsDown); } // Get reference to the array with mouse button down states. const FMouseButtonsArray& GetMouseButtons() const { return MouseButtonsDown; } @@ -58,9 +66,14 @@ public: const FMouseButtonsIndexRange& GetMouseButtonsUpdateRange() const { return MouseButtonsUpdateRange; } // Change state of the button in the mouse buttons array and expand range bounding dirty part of the array. - // @param MouseIndex - Index of the mouse button + // @param MouseEvent - Mouse event representing mouse button // @param bIsDown - True, if button is down - void SetMouseDown(uint32 MouseIndex, bool IsDown); + void SetMouseDown(const FPointerEvent& MouseEvent, bool bIsDown) { SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), bIsDown); } + + // Change state of the button in the mouse buttons array and expand range bounding dirty part of the array. + // @param MouseButton - Mouse button key + // @param bIsDown - True, if button is down + void SetMouseDown(const FKey& MouseButton, bool bIsDown) { SetMouseDown(ImGuiInterops::GetMouseIndex(MouseButton), bIsDown); } // Get mouse wheel delta accumulated during the last frame. float GetMouseWheelDelta() const { return MouseWheelDelta; } @@ -81,7 +94,7 @@ public: // Set whether input has active mouse pointer. // @param bHasPointer - True, if input has active mouse pointer - void SetMousePointer(bool bHasPointer) { bHasMousePointer = bHasPointer; } + void SetMousePointer(bool bInHasMousePointer) { bHasMousePointer = bInHasMousePointer; } // Get Control down state. bool IsControlDown() const { return bIsControlDown; } @@ -104,35 +117,69 @@ public: // @param bIsDown - True, if Alt is down void SetAltDown(bool bIsDown) { bIsAltDown = bIsDown; } - // Reset state and mark as dirty. - void ResetState() { Reset(true, true); } + // Get reference to the array with navigation input states. + const FNavInputArray& GetNavigationInputs() const { return NavigationInputs; } - // Reset keyboard state and mark as dirty. - void ResetKeyboardState() { Reset(true, false); } + // Change state of the navigation input associated with this gamepad key. + // @param KeyEvent - Key event with gamepad key input + // @param bIsDown - True, if key is down + void SetGamepadNavigationKey(const FKeyEvent& KeyEvent, bool bIsDown) { ImGuiInterops::SetGamepadNavigationKey(NavigationInputs, KeyEvent.GetKey(), bIsDown); } - // Reset mouse state and mark as dirty. - void ResetMouseState() { Reset(false, true); } - - // Clear part of the state that is meant to be updated in every frame like: accumulators, buffers and information - // about dirty parts of keys or mouse buttons arrays. - void ClearUpdateState(); + // Change state of the navigation input associated with this gamepad axis. + // @param AnalogInputEvent - Analogue input event with gamepad axis input + // @param Value - Analogue value that should be set for this axis + void SetGamepadNavigationAxis(const FAnalogInputEvent& AnalogInputEvent, float Value) { ImGuiInterops::SetGamepadNavigationAxis(NavigationInputs, AnalogInputEvent.GetKey(), Value); } // Check whether keyboard navigation is enabled. - bool IsKeyboardNavigationEnabled() const { return bKeyboardNavigationEnabled; } + bool IsKeyboardNavigationEnabled() const { return bKeyboardNavigationEnabled; } // Set whether keyboard navigation is enabled. // @param bEnabled - True, if navigation is enabled void SetKeyboardNavigationEnabled(bool bEnabled) { bKeyboardNavigationEnabled = bEnabled; } + // Check whether gamepad navigation is enabled. + bool IsGamepadNavigationEnabled() const { return bGamepadNavigationEnabled; } + + // Set whether gamepad navigation is enabled. + // @param bEnabled - True, if navigation is enabled + void SetGamepadNavigationEnabled(bool bEnabled) { bGamepadNavigationEnabled = bEnabled; } + + // Check whether gamepad is attached. + bool HasGamepad() const { return bHasGamepad; } + + // Set whether gamepad is attached. + // @param bInHasGamepad - True, if gamepad is attached + void SetGamepad(bool bInHasGamepad) { bHasGamepad = bInHasGamepad; } + + // Reset the whole state and mark as dirty. + void ResetState() { Reset(true, true, true); } + + // Reset keyboard state and mark as dirty. + void ResetKeyboardState() { Reset(true, false, false); } + + // Reset mouse state and mark as dirty. + void ResetMouseState() { Reset(false, true, false); } + + // Reset navigation state. + void ResetNavigationState() { Reset(false, false, true); } + + // Clear part of the state that is meant to be updated in every frame like: accumulators, buffers, navigation data + // and information about dirty parts of keys or mouse buttons arrays. + void ClearUpdateState(); + private: - void Reset(bool bKeyboard, bool bMouse); + void SetKeyDown(uint32 KeyIndex, bool bIsDown); + void SetMouseDown(uint32 MouseIndex, bool IsDown); + + void Reset(bool bKeyboard, bool bMouse, bool bNavigation); void ClearCharacters(); void ClearKeys(); void ClearMouseButtons(); void ClearMouseAnalogue(); void ClearModifierKeys(); + void ClearNavigationInputs(); FVector2D MousePosition = FVector2D::ZeroVector; float MouseWheelDelta = 0.f; @@ -146,6 +193,8 @@ private: FKeysArray KeysDown; FKeysIndexRange KeysUpdateRange; + FNavInputArray NavigationInputs; + bool bHasMousePointer = false; bool bIsControlDown = false; @@ -153,4 +202,6 @@ private: bool bIsAltDown = false; bool bKeyboardNavigationEnabled = false; + bool bGamepadNavigationEnabled = false; + bool bHasGamepad = false; }; diff --git a/Source/ImGui/Private/ImGuiInteroperability.cpp b/Source/ImGui/Private/ImGuiInteroperability.cpp index 9ef2b4c..c038511 100644 --- a/Source/ImGui/Private/ImGuiInteroperability.cpp +++ b/Source/ImGui/Private/ImGuiInteroperability.cpp @@ -159,6 +159,77 @@ namespace ImGuiInterops } } + namespace + { + inline void UpdateKey(const FKey& Key, const FKey& KeyCondition, float& Value, bool bIsDown) + { + if (Key == KeyCondition) + { + Value = (bIsDown) ? 1.f : 0.f; + } + } + + inline void UpdateAxisValues(float& Axis, float& Opposite, float Value) + { + constexpr float AxisInputThreshold = 0.166f; + + // Filter out small values to avoid false positives (helpful in case of worn controllers). + Axis = FMath::Max(0.f, Value - AxisInputThreshold); + Opposite = 0.f; + } + + inline void UpdateSymmetricAxis(const FKey& Key, const FKey& KeyCondition, float& Negative, float& Positive, float Value) + { + if (Key == KeyCondition) + { + if (Value < 0.f) + { + UpdateAxisValues(Negative, Positive, -Value); + } + else + { + UpdateAxisValues(Positive, Negative, Value); + } + } + } + } + + void SetGamepadNavigationKey(ImGuiTypes::FNavInputArray& NavInputs, const FKey& Key, bool bIsDown) + { +#define MAP_KEY(KeyCondition, NavIndex) UpdateKey(Key, KeyCondition, NavInputs[NavIndex], bIsDown) + + if (Key.IsGamepadKey()) + { + MAP_KEY(EKeys::Gamepad_FaceButton_Bottom, ImGuiNavInput_Activate); + MAP_KEY(EKeys::Gamepad_FaceButton_Right, ImGuiNavInput_Cancel); + MAP_KEY(EKeys::Gamepad_FaceButton_Top, ImGuiNavInput_Input); + MAP_KEY(EKeys::Gamepad_FaceButton_Left, ImGuiNavInput_Menu); + MAP_KEY(EKeys::Gamepad_DPad_Left, ImGuiNavInput_DpadLeft); + MAP_KEY(EKeys::Gamepad_DPad_Right, ImGuiNavInput_DpadRight); + MAP_KEY(EKeys::Gamepad_DPad_Up, ImGuiNavInput_DpadUp); + MAP_KEY(EKeys::Gamepad_DPad_Down, ImGuiNavInput_DpadDown); + MAP_KEY(EKeys::Gamepad_LeftShoulder, ImGuiNavInput_FocusPrev); + MAP_KEY(EKeys::Gamepad_RightShoulder, ImGuiNavInput_FocusNext); + MAP_KEY(EKeys::Gamepad_LeftShoulder, ImGuiNavInput_TweakSlow); + MAP_KEY(EKeys::Gamepad_RightShoulder, ImGuiNavInput_TweakFast); + } + +#undef MAP_KEY + } + + void SetGamepadNavigationAxis(ImGuiTypes::FNavInputArray& NavInputs, const FKey& Key, float Value) + { +#define MAP_SYMMETRIC_AXIS(KeyCondition, NegNavIndex, PosNavIndex) UpdateSymmetricAxis(Key, KeyCondition, NavInputs[NegNavIndex], NavInputs[PosNavIndex], Value) + + if (Key.IsGamepadKey()) + { + MAP_SYMMETRIC_AXIS(EKeys::Gamepad_LeftX, ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight); + MAP_SYMMETRIC_AXIS(EKeys::Gamepad_LeftY, ImGuiNavInput_LStickDown, ImGuiNavInput_LStickUp); + } + +#undef MAP_SYMMETRIC_AXIS + } + //==================================================================================================== // Input State Copying //==================================================================================================== @@ -210,6 +281,13 @@ namespace ImGuiInterops Copy(InputState.GetCharacters(), IO.InputCharacters); } + if (InputState.IsGamepadNavigationEnabled() && InputState.HasGamepad()) + { + Copy(InputState.GetNavigationInputs(), IO.NavInputs); + } + SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, InputState.IsKeyboardNavigationEnabled()); + SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, InputState.IsGamepadNavigationEnabled()); + SetFlag(IO.BackendFlags, ImGuiBackendFlags_HasGamepad, InputState.HasGamepad()); } } diff --git a/Source/ImGui/Private/ImGuiInteroperability.h b/Source/ImGui/Private/ImGuiInteroperability.h index 12d845f..c53ee69 100644 --- a/Source/ImGui/Private/ImGuiInteroperability.h +++ b/Source/ImGui/Private/ImGuiInteroperability.h @@ -22,6 +22,7 @@ namespace ImGuiInterops { using FMouseButtonsArray = decltype(ImGuiIO::MouseDown); using FKeysArray = decltype(ImGuiIO::KeysDown); + using FNavInputArray = decltype(ImGuiIO::NavInputs); using FInputCharactersBuffer = decltype(ImGuiIO::InputCharacters); @@ -54,8 +55,21 @@ namespace ImGuiInterops return GetMouseIndex(MouseEvent.GetEffectingButton()); } + // Convert from ImGuiMouseCursor type to EMouseCursor. EMouseCursor::Type ToSlateMouseCursor(ImGuiMouseCursor MouseCursor); + // Set in the target array navigation input corresponding to gamepad key. + // @param NavInputs - Target array + // @param Key - Gamepad key mapped to navigation input (non-mapped keys will be ignored) + // @param bIsDown - True, if key is down + void SetGamepadNavigationKey(ImGuiTypes::FNavInputArray& NavInputs, const FKey& Key, bool bIsDown); + + // Set in the target array navigation input corresponding to gamepad axis. + // @param NavInputs - Target array + // @param Key - Gamepad axis key mapped to navigation input (non-axis or non-mapped inputs will be ignored) + // @param Value - Axis value (-1..1 values from Unreal are mapped to separate ImGui axes with values in range 0..1) + void SetGamepadNavigationAxis(ImGuiTypes::FNavInputArray& NavInputs, const FKey& Key, float Value); + //==================================================================================================== // Input State Copying diff --git a/Source/ImGui/Private/SImGuiWidget.cpp b/Source/ImGui/Private/SImGuiWidget.cpp index 0101168..e677f56 100644 --- a/Source/ImGui/Private/SImGuiWidget.cpp +++ b/Source/ImGui/Private/SImGuiWidget.cpp @@ -25,7 +25,7 @@ constexpr int32 IMGUI_WIDGET_Z_ORDER = 10000; DEFINE_LOG_CATEGORY_STATIC(LogImGuiWidget, Warning, All); #define TEXT_INPUT_MODE(Val) (\ - (Val) == EInputMode::MouseAndKeyboard ? TEXT("MouseAndKeyboard") :\ + (Val) == EInputMode::Full ? TEXT("Full") :\ (Val) == EInputMode::MousePointerOnly ? TEXT("MousePointerOnly") :\ TEXT("None")) @@ -52,9 +52,11 @@ namespace CVars ECVF_Default); TAutoConsoleVariable InputNavigation(TEXT("ImGui.InputNavigation"), 0, - TEXT("[EXPERIMENTAL, WIP] Set ImGui navigation mode.\n") + TEXT("EXPERIMENTAL Set ImGui navigation mode.\n") TEXT("0: navigation is disabled\n") - TEXT("1: keyboard navigation"), + TEXT("1: keyboard navigation\n") + TEXT("2: gamepad navigation (gamepad input is consumed)\n") + TEXT("3: keyboard and gamepad navigation (gamepad input is consumed)"), ECVF_Default); TAutoConsoleVariable DrawMouseCursor(TEXT("ImGui.DrawMouseCursor"), 0, @@ -154,35 +156,81 @@ FReply SImGuiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEven FReply SImGuiWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent) { - if (IsConsoleOpened() || IgnoreKeyEvent(KeyEvent)) + if (KeyEvent.GetKey().IsGamepadKey()) { - return FReply::Unhandled(); + if (InputState.IsGamepadNavigationEnabled()) + { + InputState.SetGamepadNavigationKey(KeyEvent, true); + + return FReply::Handled(); + } + else + { + return Super::OnKeyDown(MyGeometry, KeyEvent); + } } + else + { + if (IsConsoleOpened() || IgnoreKeyEvent(KeyEvent)) + { + return FReply::Unhandled(); + } - InputState.SetKeyDown(ImGuiInterops::GetKeyIndex(KeyEvent), true); - CopyModifierKeys(KeyEvent); + InputState.SetKeyDown(KeyEvent, true); + CopyModifierKeys(KeyEvent); - UpdateCanvasMapMode(KeyEvent); + UpdateCanvasMapMode(KeyEvent); - return WithMouseLockRequests(FReply::Handled()); + return WithMouseLockRequests(FReply::Handled()); + } } FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent) { - // Even if we don't send new keystrokes to ImGui, we still handle key up events, to make sure that we clear keys - // pressed before suppressing keyboard input. - InputState.SetKeyDown(ImGuiInterops::GetKeyIndex(KeyEvent), false); - CopyModifierKeys(KeyEvent); + if (KeyEvent.GetKey().IsGamepadKey()) + { + if (InputState.IsGamepadNavigationEnabled()) + { + InputState.SetGamepadNavigationKey(KeyEvent, false); - UpdateCanvasMapMode(KeyEvent); + return FReply::Handled(); + } + else + { + return Super::OnKeyUp(MyGeometry, KeyEvent); + } + } + else + { + // Even if we don't send new keystrokes to ImGui, we still handle key up events, to make sure that we clear keys + // pressed before suppressing keyboard input. + InputState.SetKeyDown(KeyEvent, false); + CopyModifierKeys(KeyEvent); - // If console is opened we notify key change but we also let event trough, so it can be handled by console. - return IsConsoleOpened() ? FReply::Unhandled() : WithMouseLockRequests(FReply::Handled()); + UpdateCanvasMapMode(KeyEvent); + + // If console is opened we notify key change but we also let event trough, so it can be handled by console. + return IsConsoleOpened() ? FReply::Unhandled() : WithMouseLockRequests(FReply::Handled()); + } +} + +FReply SImGuiWidget::OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& AnalogInputEvent) +{ + if (AnalogInputEvent.GetKey().IsGamepadKey() && InputState.IsGamepadNavigationEnabled()) + { + InputState.SetGamepadNavigationAxis(AnalogInputEvent, AnalogInputEvent.GetAnalogValue()); + + return FReply::Handled(); + } + else + { + return Super::OnAnalogValueChanged(MyGeometry, AnalogInputEvent); + } } FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), true); + InputState.SetMouseDown(MouseEvent, true); CopyModifierKeys(MouseEvent); UpdateCanvasMapMode(MouseEvent); @@ -193,7 +241,7 @@ FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPoint FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), true); + InputState.SetMouseDown(MouseEvent, true); CopyModifierKeys(MouseEvent); UpdateCanvasMapMode(MouseEvent); @@ -204,7 +252,7 @@ FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FReply SImGuiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), false); + InputState.SetMouseDown(MouseEvent, false); CopyModifierKeys(MouseEvent); UpdateCanvasMapMode(MouseEvent); @@ -299,7 +347,7 @@ void SImGuiWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent { for (const FKey& Button : { EKeys::LeftMouseButton, EKeys::MiddleMouseButton, EKeys::RightMouseButton, EKeys::ThumbMouseButton, EKeys::ThumbMouseButton2 }) { - InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(Button), MouseEvent.IsMouseButtonDown(Button)); + InputState.SetMouseDown(Button, MouseEvent.IsMouseButtonDown(Button)); } } @@ -440,18 +488,24 @@ void SImGuiWidget::UpdateInputEnabled() // We don't get any events when application loses focus (we get OnMouseLeave but not always) but we fix it with // this manual check. We still allow the above code to run, even if we need to suppress keyboard input right after // that. - if (bInputEnabled && !GameViewport->Viewport->IsForegroundWindow() && InputMode == EInputMode::MouseAndKeyboard) + if (bInputEnabled && !GameViewport->Viewport->IsForegroundWindow() && InputMode == EInputMode::Full) { UpdateInputMode(false, IsDirectlyHovered()); } - InputState.SetKeyboardNavigationEnabled(CVars::InputNavigation.GetValueOnGameThread() > 0); + if (bInputEnabled) + { + InputState.SetKeyboardNavigationEnabled(CVars::InputNavigation.GetValueOnGameThread() & 1); + InputState.SetGamepadNavigationEnabled(CVars::InputNavigation.GetValueOnGameThread() & 2); + const auto& Application = FSlateApplication::Get().GetPlatformApplication(); + InputState.SetGamepad(Application.IsValid() && Application->IsGamepadAttached()); + } } void SImGuiWidget::UpdateInputMode(bool bHasKeyboardFocus, bool bHasMousePointer) { const EInputMode NewInputMode = - bHasKeyboardFocus ? EInputMode::MouseAndKeyboard : + bHasKeyboardFocus ? EInputMode::Full : bHasMousePointer ? EInputMode::MousePointerOnly : EInputMode::None; @@ -466,16 +520,17 @@ void SImGuiWidget::UpdateInputMode(bool bHasKeyboardFocus, bool bHasMousePointer { InputState.ResetState(); } - else if (InputMode == EInputMode::MouseAndKeyboard) + else if (InputMode == EInputMode::Full) { InputState.ResetKeyboardState(); + InputState.ResetNavigationState(); } InputMode = NewInputMode; ClearMouseEventNotification(); - if (InputMode != EInputMode::MouseAndKeyboard) + if (InputMode != EInputMode::Full) { SetCanvasMapMode(false); } diff --git a/Source/ImGui/Private/SImGuiWidget.h b/Source/ImGui/Private/SImGuiWidget.h index 461e4da..7a6e502 100644 --- a/Source/ImGui/Private/SImGuiWidget.h +++ b/Source/ImGui/Private/SImGuiWidget.h @@ -53,6 +53,8 @@ public: virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent) override; + virtual FReply OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& AnalogInputEvent) override; + virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; @@ -80,8 +82,8 @@ private: None, // Mouse pointer only without user focus MousePointerOnly, - // Full input with user focus - MouseAndKeyboard + // Full input with user focus (mouse, keyboard and depending on navigation mode gamepad) + Full }; // If needed, add to event reply a mouse lock or unlock request.