I’m currently working on a UI for our current project, specifically controller navigation. By default, navigating around UMG widgets with the analog stick is quite difficult and imprecise- it feels incredibly oversensitive.
I’ve had a poke around and looked at FSlateApplication, FGenericApplicationMessageHandler, as well as the input interfaces (ex. XInputInterface), and it looks like the analog events are currently being passed directly through to Slate without any deadzone at all.
So, my question is, how can I apply a deadzone to these inputs? From what I’ve seen, there’s no framework in place to do this, and is thus likely to involve modifying engine code. Can you provide some official pointers as to how I’d implement this, or let me know if it’s planned to be integrated into an upcoming release?
If you’re using the virtualized key presses such as GamePad_LeftStick_Left then there is a deadzone applied based on the xinput defines for deadzone.
If you’re using just the raw Gamepad_LeftX/Y analog inputs you’re right that at the UMG level there is no deadzone being applied to it. The game inputcomponent layer has AxisConfig input settings to set up deadzones for axes, but slate (currently at least) has nothing similar.
Generally I would have suggested using the virtualized key presses for navigating between widgets. If it is simply that you’re finding those to be too sensitive perhaps we need to think about creating a way of enhancing that deadzone threshold, but at the moment we don’t have any specific plans to do such a thing.
Note that, OnKeyDown - has the platform deadzone. Where as OnAnalogValueChanged does not.
If I wanted to add in generic - more customized handling, I would look at the way it currently works in OnKeyDown, and do something similar in OnAnalogValueChanged.
I would begin by doing the same kind of thing as OnKeyDown, then I would improve FNavigationConfig, to optionally take in an axis value and have maybe a virtual function or a deadzone member users can set. To better customize when to trigger the navigation requests.
The idea behind FNavigationConfig was that it could be inherited by games and be used to further customize the general rules slate obeys for all builtin widgets for navigation. e.g. We disable all but the Tab navigation in Paragon.
Would probably also need to move the analog keys out of the key press nav set and maybe make a new set just for analog input? Because you don’t want the simulated key presses to continue to trigger if you want customized dead zone handling.
Thanks for the direction, that info was very helpful!
@Marc: I hadn’t modified anything on the navigation config side at the time of writing this question, so having examined FNavigationConfig it looks like we were indeed using the virtualized key presses.
Unfortunately, they’re too sensitive for our needs. The deadzone being applied is quite small and appears to be configured in a cross shape, which makes it too easy to accidentally trigger a diagonal input when all you want is horizontal or vertical.
@Nick: I’ve gone in and followed your advice to create a subclass of FNavigationConfig that handles analog navigation with custom deadzone logic. It’s working as desired, but I’m not sure of the best place to put it; I’ve been trying to work it in without touching engine code, as we’ve not made the call to start compiling a custom version of UE4 yet.
Currently I’m creating a TSharedRef to an instance of our custom FNavigationConfig (FDFNavigationConfig) in the game module’s StartupModule() implementation, and passing it to slate from there using FSlateApplication::Get().SetNavigationConfig().
Our custom slate widgets (subclasses of SButton, SSlider and SCheckBox) all have a custom implementation of OnAnalogValueChanged that calls GetNavigationDirectionFromAnalog, which is a static function inside FDFNavigationConfig that I’ve modelled after GetNavigationDirectionFromKey.
Really, I’d like to be instantiating FDFNavigationConfig somewhere that I can easily reference from a Slate widget, and then calling GetNavigationDirectionFromAnalog on that instance instead of doing it with statics. So far I’ve looked at FSlateApplication, UGameEngine and UGameInstance, but they’ve proved to be either infeasible to subclass/replace or difficult to access from my Slate widgets. Can you provide any advice on that front?
I would modify engine code and set those functions up as virtual so you could just call them on the current navigational config - without resorting to statics. Don’t think there’s a better way without making engine mods, we don’t really allow subclassing of FSlateApplication.
Right, I see. I have a feeling that we’ll be moving toward modifying engine code fairly soon, so that should be doable. Thanks!