Input Mapper

Input Mapper is a class that greatly simplifies the process of remapping controls. It handles listening for controller input, conflict checking, and creating Action-element assignments in a Controller Map.

Please see How To's - Creating a Control Mapping Screen before creating a control remapping system using Input Mapper.

Usage

The basic process is as follows:

  1. Create an Input Mapper.
  2. Configure Options.
  3. Subscribe to events.
  4. Create a mapping Context.
  5. Start listening for input.
  6. Handle assignment conflicts (optional).
  7. Advanced operations (optional).

For additional issues, see the FAQ.

1. Create an Input Mapper

You can either create a new instance of an Input Mapper or use the Default instance as shown below:

// Create a new instance
InputMapper inputMapper = new InputMapper();
inputMapper.Start(context);

// Or you can use the Default instance instead if you only need one Input Mapper 
InputMapper.Default.Start(context);

2. Configure Options

Each Input Mapper has an Options object which allows you to configure various settings to fit your needs. These settings should be configured before starting the Input Mapper. Each available option is described in the class documentation.

inputMapper.options.timeout = 5f; // set the timeout to 5 seconds
inputMapper.options.ignoreMouseXAxis = true; // ignore the mouse X axis when polling for input
inputMapper.options.ignoreMouseYAxis = true; // ignore the mouse Y axis when polling for input

3. Subscribe to events

There are numerous events to which you can subscribe to receive notifications when important events take place such as when an input assignment is made or when an assignment conflict is found.

inputMapper.InputMappedEvent += OnInputMapped;
inputMapper.ConflictFoundEvent += OnConflictFound;

4. Create a mapping Context

A mapping context provides information about the current mapping session. The mapping context is just a few pieces of information that informs the Input Mapper about what is being mapped.

InputMapper.Context context = new InputMapper.Context() {
  actionId = action.id, // the id of the Action being mapped
controllerMap = controllerMap, // the Controller Map which will have the new mapping added
actionRange = AxisRange.Full, // the range of the Action being mapped
actionElementMapToReplace = actionElementMap // the Action Element Map to be replaced (optional)
};

5. Start listening for input

inputMapper.Start(context);

6. Handle assignment conflicts (optional)

Conflict checking is enabled by default in InputMapper.Options. See How To's - Conflict Checking for more information.

If you subscribed to the InputMapper.ConflictFoundEvent, you will receive a notification when a conflicting assignment was found during input mapping. The object returned contains complete information about the assignment, the conflicts that were found, and provides a callback to be used to respond to the event.

private InputMapper.ConflictFoundEventData conflictData;

void OnConflictFound(InputMapper.ConflictFoundEventData data) {
    conflictData = data; // store the event data for use in user response

    if(data.isProtected) { // the conflicting assignment was protected and cannot be replaced
        // Display some message to the user asking whether to cancel or add the new assignment.
        // Protected assignments cannot be replaced.
        // ...

        // ... After the user has made a decision
        conflictData.responseCallback(InputMapper.ConflictResponse.Cancel); // cancel polling

    } else {
        // Display some message to the user asking whether to cancel, replace the existing,
        // or add the new assignment.
        // ...

        // ... After the user has made a decision

        // Tell the Input Mapper to replace the conflicting assignments
        conflictData.responseCallback(InputMapper.ConflictResponse.Replace);
    }
}

If you do not subscribe to the ConflictsFoundEvent and you have left conflict checking enabled in the Options.checkForConflicts property, the default action specified in Options.defaultActionWhenConflictFound will be used to resolve the conflict(s).

7. Advanced operations (optional)

Ignoring certain controller elements:

void Setup() {
    // When setting up Options, add a callback to handle element confirmation
    inputMapper.options.isElementAllowedCallback = OnIsElementAllowed; // manually allow or ignore specific elements
}

// Called by InputMapper when a controller element is activated while polling
bool OnIsElementAllowed(ControllerPollingInfo info) {
    // Ignore the Space key on the keyboard
    if(info.controllerType == ControllerType.Keyboard && info.keyboardKey == KeyCode.Space) return false;
    
    // Allow all other controller elements
    return true;
}

Using multiple Input Mappers to listen to multiple input devices at the same time:

See Simple Combined Keyboard Mouse Remapping example for a working example.

// Begin listening for input on both keyboard and mouse at the same time

inputMapper_keyboard.Start(
        new InputMapper.Context() {
        actionId = actionId,
        controllerMap = keyboardMap,
        actionRange = actionRange,
        actionElementMapToReplace = keyboardMap.GetElementMap(actionElementMapToReplaceId)
    }
);
            
inputMapper_mouse.Start(
    new InputMapper.Context() {
        actionId = actionId,
        controllerMap = mouseMap,
        actionRange = actionRange,
        actionElementMapToReplace = mouseMap.GetElementMap(actionElementMapToReplaceId)
    }
);    

 


 

Frequently Asked Questions

Why is binding replacement not working?

You must pass the ActionElementMap to be replaced in InputMapper.Context.actionElementMapToReplace when calling InputMapper.Start. After an ActionElementMap is replaced, a new ActionElementMap is created. If you are storing a reference to the ActionElementMap and then it is replaced, the reference to the old ActionElementMap is no longer valid because itpoints to an ActionElementMap that is no longer present in the Controller Map. If you are storing a reference to the ActionElementMap, you must update your reference to the new ActionElementMap after it is replaced.

In addition, whether replacement happens automatically when a mapping conflict is found is determined by InputMapper.Options.defaultActionWhenConflictFound. You can also handle conflicts manually and determine what happens to conflicting bindings.