mirror of
https://github.com/kevinporetti/UnrealImGui.git
synced 2025-02-23 12:40:33 +00:00
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.
This commit is contained in:
parent
e83f37d518
commit
82729a12c8
@ -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)
|
if (bKeyboard)
|
||||||
{
|
{
|
||||||
@ -100,6 +100,11 @@ void FImGuiInputState::Reset(bool bKeyboard, bool bMouse)
|
|||||||
{
|
{
|
||||||
ClearModifierKeys();
|
ClearModifierKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bNavigation)
|
||||||
|
{
|
||||||
|
ClearNavigationInputs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FImGuiInputState::ClearUpdateState()
|
void FImGuiInputState::ClearUpdateState()
|
||||||
@ -152,3 +157,10 @@ void FImGuiInputState::ClearModifierKeys()
|
|||||||
bIsShiftDown = false;
|
bIsShiftDown = false;
|
||||||
bIsAltDown = false;
|
bIsAltDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FImGuiInputState::ClearNavigationInputs()
|
||||||
|
{
|
||||||
|
using std::fill;
|
||||||
|
fill(NavigationInputs, &NavigationInputs[Utilities::GetArraySize(NavigationInputs)], 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ public:
|
|||||||
// Array for key states.
|
// Array for key states.
|
||||||
using FKeysArray = ImGuiInterops::ImGuiTypes::FKeysArray;
|
using FKeysArray = ImGuiInterops::ImGuiTypes::FKeysArray;
|
||||||
|
|
||||||
|
// Array for navigation input states.
|
||||||
|
using FNavInputArray = ImGuiInterops::ImGuiTypes::FNavInputArray;
|
||||||
|
|
||||||
// Pair of indices defining range in mouse buttons array.
|
// Pair of indices defining range in mouse buttons array.
|
||||||
using FMouseButtonsIndexRange = Utilities::TArrayIndexRange<FMouseButtonsArray, uint32>;
|
using FMouseButtonsIndexRange = Utilities::TArrayIndexRange<FMouseButtonsArray, uint32>;
|
||||||
|
|
||||||
@ -47,9 +50,14 @@ public:
|
|||||||
const FKeysIndexRange& GetKeysUpdateRange() const { return KeysUpdateRange; }
|
const FKeysIndexRange& GetKeysUpdateRange() const { return KeysUpdateRange; }
|
||||||
|
|
||||||
// Change state of the key in the keys array and expand range bounding dirty part of the array.
|
// 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
|
// @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.
|
// Get reference to the array with mouse button down states.
|
||||||
const FMouseButtonsArray& GetMouseButtons() const { return MouseButtonsDown; }
|
const FMouseButtonsArray& GetMouseButtons() const { return MouseButtonsDown; }
|
||||||
@ -58,9 +66,14 @@ public:
|
|||||||
const FMouseButtonsIndexRange& GetMouseButtonsUpdateRange() const { return MouseButtonsUpdateRange; }
|
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.
|
// 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
|
// @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.
|
// Get mouse wheel delta accumulated during the last frame.
|
||||||
float GetMouseWheelDelta() const { return MouseWheelDelta; }
|
float GetMouseWheelDelta() const { return MouseWheelDelta; }
|
||||||
@ -81,7 +94,7 @@ public:
|
|||||||
|
|
||||||
// Set whether input has active mouse pointer.
|
// Set whether input has active mouse pointer.
|
||||||
// @param bHasPointer - True, if 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.
|
// Get Control down state.
|
||||||
bool IsControlDown() const { return bIsControlDown; }
|
bool IsControlDown() const { return bIsControlDown; }
|
||||||
@ -104,18 +117,18 @@ public:
|
|||||||
// @param bIsDown - True, if Alt is down
|
// @param bIsDown - True, if Alt is down
|
||||||
void SetAltDown(bool bIsDown) { bIsAltDown = bIsDown; }
|
void SetAltDown(bool bIsDown) { bIsAltDown = bIsDown; }
|
||||||
|
|
||||||
// Reset state and mark as dirty.
|
// Get reference to the array with navigation input states.
|
||||||
void ResetState() { Reset(true, true); }
|
const FNavInputArray& GetNavigationInputs() const { return NavigationInputs; }
|
||||||
|
|
||||||
// Reset keyboard state and mark as dirty.
|
// Change state of the navigation input associated with this gamepad key.
|
||||||
void ResetKeyboardState() { Reset(true, false); }
|
// @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.
|
// Change state of the navigation input associated with this gamepad axis.
|
||||||
void ResetMouseState() { Reset(false, true); }
|
// @param AnalogInputEvent - Analogue input event with gamepad axis input
|
||||||
|
// @param Value - Analogue value that should be set for this axis
|
||||||
// Clear part of the state that is meant to be updated in every frame like: accumulators, buffers and information
|
void SetGamepadNavigationAxis(const FAnalogInputEvent& AnalogInputEvent, float Value) { ImGuiInterops::SetGamepadNavigationAxis(NavigationInputs, AnalogInputEvent.GetKey(), Value); }
|
||||||
// about dirty parts of keys or mouse buttons arrays.
|
|
||||||
void ClearUpdateState();
|
|
||||||
|
|
||||||
// Check whether keyboard navigation is enabled.
|
// Check whether keyboard navigation is enabled.
|
||||||
bool IsKeyboardNavigationEnabled() const { return bKeyboardNavigationEnabled; }
|
bool IsKeyboardNavigationEnabled() const { return bKeyboardNavigationEnabled; }
|
||||||
@ -124,15 +137,49 @@ public:
|
|||||||
// @param bEnabled - True, if navigation is enabled
|
// @param bEnabled - True, if navigation is enabled
|
||||||
void SetKeyboardNavigationEnabled(bool bEnabled) { bKeyboardNavigationEnabled = bEnabled; }
|
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:
|
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 ClearCharacters();
|
||||||
void ClearKeys();
|
void ClearKeys();
|
||||||
void ClearMouseButtons();
|
void ClearMouseButtons();
|
||||||
void ClearMouseAnalogue();
|
void ClearMouseAnalogue();
|
||||||
void ClearModifierKeys();
|
void ClearModifierKeys();
|
||||||
|
void ClearNavigationInputs();
|
||||||
|
|
||||||
FVector2D MousePosition = FVector2D::ZeroVector;
|
FVector2D MousePosition = FVector2D::ZeroVector;
|
||||||
float MouseWheelDelta = 0.f;
|
float MouseWheelDelta = 0.f;
|
||||||
@ -146,6 +193,8 @@ private:
|
|||||||
FKeysArray KeysDown;
|
FKeysArray KeysDown;
|
||||||
FKeysIndexRange KeysUpdateRange;
|
FKeysIndexRange KeysUpdateRange;
|
||||||
|
|
||||||
|
FNavInputArray NavigationInputs;
|
||||||
|
|
||||||
bool bHasMousePointer = false;
|
bool bHasMousePointer = false;
|
||||||
|
|
||||||
bool bIsControlDown = false;
|
bool bIsControlDown = false;
|
||||||
@ -153,4 +202,6 @@ private:
|
|||||||
bool bIsAltDown = false;
|
bool bIsAltDown = false;
|
||||||
|
|
||||||
bool bKeyboardNavigationEnabled = false;
|
bool bKeyboardNavigationEnabled = false;
|
||||||
|
bool bGamepadNavigationEnabled = false;
|
||||||
|
bool bHasGamepad = false;
|
||||||
};
|
};
|
||||||
|
@ -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
|
// Input State Copying
|
||||||
//====================================================================================================
|
//====================================================================================================
|
||||||
@ -210,6 +281,13 @@ namespace ImGuiInterops
|
|||||||
Copy(InputState.GetCharacters(), IO.InputCharacters);
|
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_NavEnableKeyboard, InputState.IsKeyboardNavigationEnabled());
|
||||||
|
SetFlag(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, InputState.IsGamepadNavigationEnabled());
|
||||||
|
SetFlag(IO.BackendFlags, ImGuiBackendFlags_HasGamepad, InputState.HasGamepad());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ namespace ImGuiInterops
|
|||||||
{
|
{
|
||||||
using FMouseButtonsArray = decltype(ImGuiIO::MouseDown);
|
using FMouseButtonsArray = decltype(ImGuiIO::MouseDown);
|
||||||
using FKeysArray = decltype(ImGuiIO::KeysDown);
|
using FKeysArray = decltype(ImGuiIO::KeysDown);
|
||||||
|
using FNavInputArray = decltype(ImGuiIO::NavInputs);
|
||||||
|
|
||||||
using FInputCharactersBuffer = decltype(ImGuiIO::InputCharacters);
|
using FInputCharactersBuffer = decltype(ImGuiIO::InputCharacters);
|
||||||
|
|
||||||
@ -54,8 +55,21 @@ namespace ImGuiInterops
|
|||||||
return GetMouseIndex(MouseEvent.GetEffectingButton());
|
return GetMouseIndex(MouseEvent.GetEffectingButton());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert from ImGuiMouseCursor type to EMouseCursor.
|
||||||
EMouseCursor::Type ToSlateMouseCursor(ImGuiMouseCursor MouseCursor);
|
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
|
// Input State Copying
|
||||||
|
@ -25,7 +25,7 @@ constexpr int32 IMGUI_WIDGET_Z_ORDER = 10000;
|
|||||||
DEFINE_LOG_CATEGORY_STATIC(LogImGuiWidget, Warning, All);
|
DEFINE_LOG_CATEGORY_STATIC(LogImGuiWidget, Warning, All);
|
||||||
|
|
||||||
#define TEXT_INPUT_MODE(Val) (\
|
#define TEXT_INPUT_MODE(Val) (\
|
||||||
(Val) == EInputMode::MouseAndKeyboard ? TEXT("MouseAndKeyboard") :\
|
(Val) == EInputMode::Full ? TEXT("Full") :\
|
||||||
(Val) == EInputMode::MousePointerOnly ? TEXT("MousePointerOnly") :\
|
(Val) == EInputMode::MousePointerOnly ? TEXT("MousePointerOnly") :\
|
||||||
TEXT("None"))
|
TEXT("None"))
|
||||||
|
|
||||||
@ -52,9 +52,11 @@ namespace CVars
|
|||||||
ECVF_Default);
|
ECVF_Default);
|
||||||
|
|
||||||
TAutoConsoleVariable<int> InputNavigation(TEXT("ImGui.InputNavigation"), 0,
|
TAutoConsoleVariable<int> 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("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);
|
ECVF_Default);
|
||||||
|
|
||||||
TAutoConsoleVariable<int> DrawMouseCursor(TEXT("ImGui.DrawMouseCursor"), 0,
|
TAutoConsoleVariable<int> 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)
|
FReply SImGuiWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
|
||||||
{
|
{
|
||||||
|
if (KeyEvent.GetKey().IsGamepadKey())
|
||||||
|
{
|
||||||
|
if (InputState.IsGamepadNavigationEnabled())
|
||||||
|
{
|
||||||
|
InputState.SetGamepadNavigationKey(KeyEvent, true);
|
||||||
|
|
||||||
|
return FReply::Handled();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Super::OnKeyDown(MyGeometry, KeyEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (IsConsoleOpened() || IgnoreKeyEvent(KeyEvent))
|
if (IsConsoleOpened() || IgnoreKeyEvent(KeyEvent))
|
||||||
{
|
{
|
||||||
return FReply::Unhandled();
|
return FReply::Unhandled();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputState.SetKeyDown(ImGuiInterops::GetKeyIndex(KeyEvent), true);
|
InputState.SetKeyDown(KeyEvent, true);
|
||||||
CopyModifierKeys(KeyEvent);
|
CopyModifierKeys(KeyEvent);
|
||||||
|
|
||||||
UpdateCanvasMapMode(KeyEvent);
|
UpdateCanvasMapMode(KeyEvent);
|
||||||
|
|
||||||
return WithMouseLockRequests(FReply::Handled());
|
return WithMouseLockRequests(FReply::Handled());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
|
FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
|
||||||
{
|
{
|
||||||
|
if (KeyEvent.GetKey().IsGamepadKey())
|
||||||
|
{
|
||||||
|
if (InputState.IsGamepadNavigationEnabled())
|
||||||
|
{
|
||||||
|
InputState.SetGamepadNavigationKey(KeyEvent, false);
|
||||||
|
|
||||||
|
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
|
// 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.
|
// pressed before suppressing keyboard input.
|
||||||
InputState.SetKeyDown(ImGuiInterops::GetKeyIndex(KeyEvent), false);
|
InputState.SetKeyDown(KeyEvent, false);
|
||||||
CopyModifierKeys(KeyEvent);
|
CopyModifierKeys(KeyEvent);
|
||||||
|
|
||||||
UpdateCanvasMapMode(KeyEvent);
|
UpdateCanvasMapMode(KeyEvent);
|
||||||
|
|
||||||
// If console is opened we notify key change but we also let event trough, so it can be handled by console.
|
// 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());
|
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)
|
FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||||||
{
|
{
|
||||||
InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), true);
|
InputState.SetMouseDown(MouseEvent, true);
|
||||||
CopyModifierKeys(MouseEvent);
|
CopyModifierKeys(MouseEvent);
|
||||||
|
|
||||||
UpdateCanvasMapMode(MouseEvent);
|
UpdateCanvasMapMode(MouseEvent);
|
||||||
@ -193,7 +241,7 @@ FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPoint
|
|||||||
|
|
||||||
FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||||||
{
|
{
|
||||||
InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), true);
|
InputState.SetMouseDown(MouseEvent, true);
|
||||||
CopyModifierKeys(MouseEvent);
|
CopyModifierKeys(MouseEvent);
|
||||||
|
|
||||||
UpdateCanvasMapMode(MouseEvent);
|
UpdateCanvasMapMode(MouseEvent);
|
||||||
@ -204,7 +252,7 @@ FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const
|
|||||||
|
|
||||||
FReply SImGuiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
FReply SImGuiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||||||
{
|
{
|
||||||
InputState.SetMouseDown(ImGuiInterops::GetMouseIndex(MouseEvent), false);
|
InputState.SetMouseDown(MouseEvent, false);
|
||||||
CopyModifierKeys(MouseEvent);
|
CopyModifierKeys(MouseEvent);
|
||||||
|
|
||||||
UpdateCanvasMapMode(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 })
|
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
|
// 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
|
// this manual check. We still allow the above code to run, even if we need to suppress keyboard input right after
|
||||||
// that.
|
// that.
|
||||||
if (bInputEnabled && !GameViewport->Viewport->IsForegroundWindow() && InputMode == EInputMode::MouseAndKeyboard)
|
if (bInputEnabled && !GameViewport->Viewport->IsForegroundWindow() && InputMode == EInputMode::Full)
|
||||||
{
|
{
|
||||||
UpdateInputMode(false, IsDirectlyHovered());
|
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)
|
void SImGuiWidget::UpdateInputMode(bool bHasKeyboardFocus, bool bHasMousePointer)
|
||||||
{
|
{
|
||||||
const EInputMode NewInputMode =
|
const EInputMode NewInputMode =
|
||||||
bHasKeyboardFocus ? EInputMode::MouseAndKeyboard :
|
bHasKeyboardFocus ? EInputMode::Full :
|
||||||
bHasMousePointer ? EInputMode::MousePointerOnly :
|
bHasMousePointer ? EInputMode::MousePointerOnly :
|
||||||
EInputMode::None;
|
EInputMode::None;
|
||||||
|
|
||||||
@ -466,16 +520,17 @@ void SImGuiWidget::UpdateInputMode(bool bHasKeyboardFocus, bool bHasMousePointer
|
|||||||
{
|
{
|
||||||
InputState.ResetState();
|
InputState.ResetState();
|
||||||
}
|
}
|
||||||
else if (InputMode == EInputMode::MouseAndKeyboard)
|
else if (InputMode == EInputMode::Full)
|
||||||
{
|
{
|
||||||
InputState.ResetKeyboardState();
|
InputState.ResetKeyboardState();
|
||||||
|
InputState.ResetNavigationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputMode = NewInputMode;
|
InputMode = NewInputMode;
|
||||||
|
|
||||||
ClearMouseEventNotification();
|
ClearMouseEventNotification();
|
||||||
|
|
||||||
if (InputMode != EInputMode::MouseAndKeyboard)
|
if (InputMode != EInputMode::Full)
|
||||||
{
|
{
|
||||||
SetCanvasMapMode(false);
|
SetCanvasMapMode(false);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
|
|
||||||
virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent) override;
|
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 OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
|
||||||
|
|
||||||
virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
|
virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
|
||||||
@ -80,8 +82,8 @@ private:
|
|||||||
None,
|
None,
|
||||||
// Mouse pointer only without user focus
|
// Mouse pointer only without user focus
|
||||||
MousePointerOnly,
|
MousePointerOnly,
|
||||||
// Full input with user focus
|
// Full input with user focus (mouse, keyboard and depending on navigation mode gamepad)
|
||||||
MouseAndKeyboard
|
Full
|
||||||
};
|
};
|
||||||
|
|
||||||
// If needed, add to event reply a mouse lock or unlock request.
|
// If needed, add to event reply a mouse lock or unlock request.
|
||||||
|
Loading…
Reference in New Issue
Block a user