Hey all, thanks for taking the time to read through my question.
Background
I am currently using Slate UI to create windows which will always be present throughout the lifetime of the game (The game view port is on the main monitor while the slate windows are on a secondary monitor). The first user (called P1) will be sat in-front of the primary monitor with input devices such as a game-pad controller interacting with the game, and the other user (called P2) will be in-front of the secondary monitor interacting with the Slate UI. These UI elements trigger events that P1 will need to react to.
Problem
Just by the nature of the way this is set up, I need input from the game-pad to be registered at all times regardless of where the focus is. The focus is nearly always on the slate UI as P2 is clicking on buttons, editable text, drop-down menus, etc. I’ve tried a few ways to get this to work, and I’ve come very close (I’ll get more into what I’ve done in a moment), but there is always an issue with getting this to fully work.
Solutions
Solution 1 - Constantly resetting focus back to the game view-port
My first attempt to solve this involved inheriting from UGameViewportClient to override the LostFocus()
& ReceivedFocus()
functions. Essentially, whenever the LostFocus()
function is called, it checks the position of the mouse. If the mouse is hovered over a widget which requires focus such as SEditableText
, SComboButton
, or some other focus-sensitive widget, it would do an early return and then the widget itself would return focus once it was finished. Otherwise, if the mouse was hovered over a non-sensitive widget such as a button, checkbox, or just on the screen it would immediately return focus back to the game view-port.
The obvious drawback of this approach is that P1 loses the ability to interact with the game until P2 is finished interacting with that focus-sensitive widget. Eventually it was such a bad solution, I decided to reattempt the solution.
Solution 2 - All slate UI now registers the input and forwards it on
Round two begins, and I start by inheriting from SCompoundWidget to create my own abstract base widget which all of my UI will use. Now every widget I create inherits from my own base widget. Within this base widget, I override the functionality of OnKeyDown()
and OnKeyUp()
which then tests for the different inputs I want and calls the functions associated with input within my Pawn class.
Everything works wonderfully, except that drop-down menus take focus when you open them, and since those widgets are constructed with the FMenuBuilder
, I have no way to make them inherit my custom widget and therefore they do not respond to input events. I tried making the SComboButton
not accept focus, however, when the drop-down menu has sub-menus, it unfortunately takes focus anyway. I also created my own content to pass into the FMenuBuilder::AddSubMenu
, but that didn’t help as the content is not what takes the focus.
The only other solution I can think of is to inherit and create my own FMenuBuilder
, and then subsequently implement my own widgets, but looking into this seems incredibly complex and I can’t help but think there is a better solution to always be listening to input regardless of if the focus is on the view-port or on my Slate UI widgets.
If anyone has experience with this, or has any suggestions to offer, I would be very glad to receive it. I’ve been stuck on this problem for a few weeks now and I’m about to tell my customer to just accept the limitations.