What's the best practice for changing focus in Scaleform using a controller?

I’m starting to use SteamInput to navigate my menu system now. I have an idea of what I want to do, but I wanted to try to understand the GFxUDKFrontEnd system first. How does changing focus work using a controller in GFxUDKFrontEnd? I think it interprets controller inputs as keyboard inputs. That’s not going to work for me because I want SteamInput, and not the GFxMoviePlayer, to capture controller input. But I’d still like to know how it works so I can recreate the same effect using SteamInput.

So first off, how does GFxUDKFrontEnd change focus from one UIComponent to another? I think these are the most important functions.

MenuManager.as

public function setSelectionFocus(mc:MovieClip):Void {        
        Selection.setFocus(mc); 
}

function handleInput(details:InputDetails, pathToFocus:Array):Boolean {          
    var nextItem:MovieClip = MovieClip(pathToFocus.shift());
    var handled:Boolean = nextItem.handleInput(details, pathToFocus);
    if (handled) { return true; }	
    
    // Maps Escape-KeyUp to _global.OnEscapeKeyPress(), a function object defined in UnrealScript
    // and set by each view which calls some method. Generally this pops a view from the view stack.
    if (details.navEquivalent == NavigationCode.ESCAPE && details.value == "keyUp") {            
        _global.OnEscapeKeyPress();
        return true;
    }
    
    return false; // or true if handled
} 

View.as

function handleInput(details:InputDetails, pathToFocus:Array):Boolean {   
    var nextItem:MovieClip = MovieClip(pathToFocus.shift());
    var handled:Boolean = nextItem.handleInput(details, pathToFocus);
    if (handled) { return true; }
    return false; // or true if handled
}

Can someone tell me what calls handleInput? Where does pathToFocus come from?

Well, I have something that works. It feels like this is overly complicated for something that you would think the engine would just already know how to do on its own. But just for future reference, if you want to navigate through a menu using a controller or the keyboard, and you want the game and not the movie to capture and process the input, then this is one way to do it.

Put this in the actionscript class that has the button bar that you want to navigate through. In my case have a button bar named “sideButtons.”

	public function selectPrevButton():void
	{
		if(stage.focus != sideButtons)
		{
			stage.focus = sideButtons;
			sideButtons.selectedIndex = 0;
		}
		else
		{
			sideButtons.selectedIndex = sideButtons.selectedIndex - 1 < 0 ? 0: sideButtons.selectedIndex - 1;
		}
		var details:InputDetails = new InputDetails("key", 38, null, NavigationCode.DOWN, 0, false, false, false);
		var inputEvent:InputEvent = new InputEvent("key", details);
		sideButtons.handleInput(inputEvent);
	}

	public function selectNextButton():void
	{
		if(stage.focus != sideButtons)
		{
			stage.focus = sideButtons;
			sideButtons.selectedIndex = 0;
		}
		else
		{
			sideButtons.selectedIndex = sideButtons.selectedIndex + 1 > sideButtons.dataProvider.length - 1 ? sideButtons.dataProvider.length - 1: sideButtons.selectedIndex + 1;
		}
		var details:InputDetails = new InputDetails("key", 38, null, NavigationCode.UP, 0, false, false, false);
		var inputEvent:InputEvent = new InputEvent("key", details);
		sideButtons.handleInput(inputEvent);
	}

The “else” statements in there are not necessary when you are testing inside Flash/Animate. When you put the else statements in, the movie will jump 2 buttons in my button bar instead of 1. I think that might be because Flash/Animate automatically captures keyboard input or something. But those elses are necessary in the game. Make your UnrealScript do an ActionScriptVoid to call those functions and focus will move from one button to the next.

And to polish things up a bit, you need to give sideButtons an event listener to call this function when sideButtons loses focus.

	public function focusLost(e:FocusEvent):void
	{
		sideButtons.selectedIndex = -1;
	}

Without that, you’ll see a visual bug where if sideButtons regains focus, it will look like two buttons have focus for a moment.

in your file main file_view like ours is class GFxPBStore_View extends GFxUIView in that file in function OnViewLoaded() add this.

/** Reference to the PBStorePlayerController(PC) owner of the 
 MenuManager, same as using "MenuManager.PlayerOwner" just 
 shortened for easier calls in any view. */
  var PBPlayerStoreController PC;

 /** Reference to the manager which drives the front end. */
 var GFxPBStore MenuManager;

function OnViewLoaded()
{
    //Use your player controller
    PC = PBPlayerStoreController(MenuManager.PlayerOwner);
    //`log("what is PC in view? " $PC);
 }

Then all you have to do anywhere in your menu files is use PC. for access to it.