Input Handling

Since the Scaleform CLIK components derive from the Flash MovieClip class, for the most part they behave the same as any other MovieClip instance when receiving user input. Mouse events are caught by components if they install mouse handlers. However, there is a major conceptual change in CLIK related to how keyboard or equivalent controller events are handled.

Usage and Best Practices

All non-mouse input is intercepted by the InputDelegate manager class (scaleform.clik.managers.InputDelegate). The InputDelegate converts input commands into InputDetails objects (scaleform.clik.ui.InputDetails) either internally, or by requesting the value of an input command from the game engine. The latter involves modifying the InputDelegate.readInput() method to support the target application. Once InputDetails have been created, an input event is dispatched from the InputDelegate.

InputDetails consist of the following properties:

The FocusHandler listens for InputEvents dispatched from InputDelegate and then re-dispatches the same InputEvent from the currently focused component to be handled by that component or another component in the event’s bubble chain. The focused component is used to determine the focus path, which is a top-down list of components in the display-list hierarchy that implement the handleInput() method.

Figure 62: The handleInput() chain.

When the InputEvent has been handled, the handled property should be set to true. This allows for other components who receive the event to check event.isDefaultPrevented() to discern whether the event has already been handled.

override public function handleInput(event:InputEvent):void {
// Check whether the event has already been handled by another component.
if (event.isDefaultPrevented()) { return; } 
var details:InputDetails = event.details;
            
switch (details.navEquivalent) {
    case NavigationCode.ENTER:
        if (details.value == InputValue.KEY_DOWN) {
              // Do something.
              event.handled = true;
        }
          break;
        default:
          break;
}

The InputEvent will be bubbled automatically by the ActionScript 3 event system assuming that its .bubble property has not been modified. In some cases, like ScrollingList, the component may want to pass the InputEvent on to its children before attempting to handle the event itself. For instance, if the Enter key is pressed, the ListItemRenderer should generate a ButtonEvent.CLICK event and the List, who dispatched the event, will do nothing.)

override public function handleInput(event:InputEvent):void {
      if (event.isDefaultPrevented()) { return; }   
      // Pass on to selected renderer first
var renderer:IListItemRenderer = getRendererAt(_selectedIndex, _scrollPosition);
      if (renderer != null) {
        // Since we are just passing on the event, it won't bubble, and should properly stopPropagation.
        renderer.handleInput(event);            
            if (event.handled) { return; }
      }
    . . .
}

It is also possible to listen for the input event manually by adding an event listener to the InputDelegate.instance, and handle the input that way. Note that the input will still be captured by the FocusHandler and passed down the focus hierarchy.

InputDelegate.instance.addEventListener(InputEvent.INPUT, handleInput);
function handleInput(e:InputEvent):void {
        var details:InputDetails = e.details;
        if (details.value = Key.TAB) { doSomething(); }
}

The InputDelegate should be tailored to the game to manage the expected input. The default InputDelegate handles keyboard control, and converts the arrow keys, as well as the common game navigation keys W, A, S, and D into directional navigation equivalents.

Multiple Mouse Cursors

A few systems, such as the Nintendo Wii™, support multiple cursor devices. The CLIK component framework supports multiple cursors, but will not allow multiple components to be focused in a single SWF. If two users click on separate buttons, the last clicked item will be the focused item.

All mouse events dispatched in the framework contain a controllerIdx property, which is the index of the input device that generated the event.

myButton.addEventListener(ButtonEvent.CLICK, onCursorClick);
function onCursorClick(event:ButtonEvent):void {
        trace(event.controllerIdx);
}