Hello! Great catch.
The whole keyboard-mouse input management in UE isn’t handled the same way it’s handled with gamepad unfortunately, which means:
- When you switch between mouse and gamepad,
GetDesiredFocusTarget()is called and focus is re-evaluated. This doesn’t happen when you switch between mouse and keyboard. That’s because UE assumes you might still be using mouse-based navigation alongside keyboard shortcuts. - This is annoying when we want to implement a focus-based navigation, because we have no way of automatically refreshing the focus when switching from mouse to keyboard.
The other annoying thing is that when you click on a non-focusable widget (like a background image or border, or even a button that is hit-testable but not focusable, like our Equip and Junk buttons), Unreal sets focus to the viewport instead of maintaining focus within the UI.
Then, when you switch to keyboard, no widget is focused, so navigation doesn’t work, but if you switch to gamepad, Unreal detects an input method change, so it will trigger a focus re-evaluation calling the various GetDesiredFocusTarget() functions.
I can tell you in advance that there is no elegant way of solving this that I know of (and I suppose it’s not a surprise that in many games keyboard navigation is poorly supported), but there are still a couple of workarounds we can implement that use our SelectionVM and GetDesiredFocusTarget().
So there are 2 issues we need to fix:
- not lose focus when clicking on a background element, like a background image or the text in the item details panel
- not lose focus when clicking on a non-focusable button (the Equip and Junk buttons)
keeping in mind that:
- we want to avoid using events and delegates, keeping loose dependencies
- we want to avoid calling
SetFocus()and instead preferRequestRefreshFocus()andGetDesiredFocusTarget()
So here’s what we’re going to do:
- Add a utility function in the SelectionVM to request a focus refresh (this is so that any widget might request a focus refresh, and not only Common Activatable Widgets)
- Add a new FieldNotify property in the SelectionVM so that the widgets that can handle focus can also listen to external refresh focus requests from other widgets
- Introduce a FocusCatcher button to catch click events to the inventory background. This way we can catch the focus and redirect it before losing it
- Have our non-focusable buttons use the new utility function in the SelectionVM to re-evaluate the focus when they’re clicked, instead of just allowing Slate to panic
So let’s go:
- In the SelectionVM view model class, add the new function
RequestRefreshFocus()and a new property boolFocusRefreshRequested

- In WBP_Inventory add a new button to the hierarchy (Button_FocusCatcher) that spans the whole viewport, set it as Focusable and Visible



- When the new button is clicked (= when we click somewhere on the screen), we now call the
RequestRefreshFocus()function of the SelectionVM
- We now create a new function in WBP_Inventory to listen to the View Binding of our new property. We call this
ForceFocusEvaluation()and it will take the new property as input. If the bool is true, means we have a focus refresh request, so we can now use a widget that is Common Activatable Widget to actually call the properRequestRefreshFocus()function of activatable widgets.
But there’s a catch! One thing I haven’t mentioned in the tutorial (didn’t want to overload with information) is thatRequestRefreshFocus()will trigger a focus re-evaluation ONLY if requested by the leaf-most active activatable widget. What does this mean? It means that in our case our activatable widgets are WBP_Inventory and WBP_Category, and the leaf-most active is WBP_Category (because it’s deeper in the hierarchy). So if we callRequestRefreshFocus()from WBP_Inventory, nothing will happen, because WBP_Inventory isn’t our leaf-most active widget. So instead we need to call it from WBP_Category.
So we can either add ourForceFocusEvaluation()function to WBP_Category, or we can just implement the function in a way that it will callRequestRefreshFocus()on WBP_Category instead of self - which is what I chose for the screenshot.
- We can now create the view binding that binds the SelectionVM property to the
ForceFocusEvaluation()function

So this part takes case of the case when you click somewhere on a screen. You’ll now see that when you click around instead of losing focus, the focus will be refresh to the currently selected item tile.
Next is solving the bug when clicking on the Equip and Junk buttons.
- We open WBP_ItemDetails and simply call
RequestRefreshFocus()of the SelectionVM on theOnClikedevents of both buttons.
And this should fix those issues! As I said, not the most elegant solution, but should do the trick for the moment. At Epic we’re discussing focus issues and how to improve this on a regular basis, so I hope we’ll get to better keyboard support as soon as possible.
Let me know how this goes - I might add this as an appendix to the tutorial.




