# Cross Input Support

## 🎮 CrossInputSupport Class

The `CrossInputSupport` class provides keyboard and controller navigation support for Inventool's UI when set up properly with the `PlayerInput` and `UIDocument` components.

> **Namespace:** `Esper.Inventool.Input`\
> **Access:** `public`\
> **Type:** `class`\
> **Inherits:** `MonoBehaviour`

***

### 📦 Fields

| Access      | Field                      | Type                                                   | Description                                                                        |
| ----------- | -------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `public`    | `autoHideSelector`         | `bool`                                                 | If the selector should automatically be hidden after redetermining the top window. |
| `public`    | `playerMap`                | `string`                                               | The player input map name.                                                         |
| `public`    | `menuMap`                  | `string`                                               | The menu input map name.                                                           |
| `public`    | `selector`                 | `VisualElement`                                        | The targetter visual element.                                                      |
| `public`    | `focusables`               | `List<VisualElement>`                                  | A list of focusable visual elements of the top document.                           |
| `public`    | `selectedFocusable`        | `VisualElement`                                        | The currently targeted focusable.                                                  |
| `public`    | `initialFocusable`         | `VisualElement`                                        | The initial focusable element.                                                     |
| `public`    | `initialFocusablePosition` | `InitialFocusablePosition`                             | The placement of the initial focusable.                                            |
| `public`    | `scrollingSensitivity`     | `float`                                                | The scrolling sensitivity used when locked on a scroller.                          |
| `public`    | `onTab`                    | `UnityEvent`                                           | Callback for when the tab button is pressed.                                       |
| `public`    | `onCancel`                 | `UnityEvent`                                           | Callback for when the cancel button is pressed.                                    |
| `public`    | `onConfirm`                | `UnityEvent`                                           | Callback for when the confirm button is pressed.                                   |
| `public`    | `onMove`                   | `UnityEvent`                                           | Callback for when a move button is pressed.                                        |
| `public`    | `windows`                  | `List<CrossInputSupportedWindow>`                      | A list of all registered UI documents in the scene.                                |
| `public`    | `document`                 | `UIDocument`                                           | The UI document solely for the element selector. *(Hidden in inspector)*           |
| `public`    | `input`                    | `PlayerInput`                                          | The player input component. *(Hidden in inspector)*                                |
| `public`    | `top`                      | `CrossInputSupportedWindow`                            | The document currently over all others. *(Hidden in inspector)*                    |
| `protected` | `lastFocusables`           | `Dictionary<CrossInputSupportedWindow, VisualElement>` | The last focusables of each window.                                                |
| `private`   | `animationCoroutine`       | `Coroutine`                                            | The coroutine that handles the selector’s animation.                               |
| `private`   | `moveHeldCoroutine`        | `Coroutine`                                            | A coroutine that handles move button holding.                                      |
| `private`   | `lockedMoveAction`         | `Action`                                               | An action to execute when the selector is locked on a focusable.                   |
| `private`   | `moveDirection`            | `Vector2`                                              | The current move direction.                                                        |
| `private`   | `isLocked`                 | `bool`                                                 | If the selector is currently locked on the selected focusable.                     |

***

### 🔍 Properties

| Access          | Property   | Type                | Description                      |
| --------------- | ---------- | ------------------- | -------------------------------- |
| `public static` | `Instance` | `CrossInputSupport` | The active instance (singleton). |

***

### 🧰 Methods

| Access              | Method                                          | Returns               | Description                                                             |
| ------------------- | ----------------------------------------------- | --------------------- | ----------------------------------------------------------------------- |
| `public`            | `GetSelectedItemStack(bool includeAny = false)` | `ItemStack`           | Gets the selected item stack (if any).                                  |
| `protected virtual` | `TryReturn()`                                   | `bool`                | Reselects the last focusable if possible.                               |
| `private`           | `SetActionMap()`                                | `void`                | Sets the action map depending on which window is open.                  |
| `public`            | `Register(CrossInputSupportedWindow window)`    | `void`                | Registers an input supported window.                                    |
| `public`            | `Unregister(CrossInputSupportedWindow window)`  | `void`                | Unregisters an input supported window.                                  |
| `public`            | `DetermineTop()`                                | `void`                | Determines the UI document currently on top and repopulates focusables. |
| `public`            | `FindFocusables()`                              | `List<VisualElement>` | Finds the visible focusables of the top document.                       |
| `private`           | `LateFindInitial()`                             | `IEnumerator`         | Calls `FindInitial` after a delay.                                      |
| `public`            | `FindInitial()`                                 | `VisualElement`       | Finds the initial focusable of the top document.                        |
| `public`            | `Select(VisualElement element)`                 | `void`                | Selects a visual element.                                               |
| `public`            | `SelectInitial()`                               | `void`                | Selects the initial focusable.                                          |
| `public`            | `Deselect()`                                    | `void`                | Deselects the selected focusable.                                       |
| `public`            | `AssessSelection()`                             | `void`                | Checks the state of the selected focusable and deselects if necessary.  |
| `public`            | `Unlock()`                                      | `void`                | Unlocks the selector.                                                   |
| `public`            | `Lock()`                                        | `void`                | Locks the selector.                                                     |
| `public`            | `Move(Vector2 dir)`                             | `void`                | Selects the closest focusable in the given direction.                   |
| `private`           | `OnMenuMove(InputValue inputValue)`             | `void`                | Handles directional input for menu navigation.                          |
| `private`           | `OnTab(InputValue inputValue)`                  | `void`                | Handles tab input.                                                      |
| `private`           | `OnCancel(InputValue inputValue)`               | `void`                | Handles cancel input.                                                   |
| `private`           | `OnConfirm(InputValue inputValue)`              | `void`                | Handles confirm input.                                                  |
| `private`           | `OnDeselect()`                                  | `void`                | Handles deselection.                                                    |
| `private`           | `MoveHeld()`                                    | `IEnumerator`         | Handles move button hold.                                               |
| `private`           | `AnimateSelector()`                             | `IEnumerator`         | Animates the selector around the selected focusable.                    |

***

### 🧩 Nested Types

#### `public enum InitialFocusablePosition`

Defines the placement of the initial focusable.

| Name          | Description          |
| ------------- | -------------------- |
| `TopLeft`     | Top‑left corner.     |
| `TopRight`    | Top‑right corner.    |
| `BottomLeft`  | Bottom‑left corner.  |
| `BottomRight` | Bottom‑right corner. |

## Active Instance

You can get the active `CrossInputSupport` instance with `CrossInputSupport.Instance`. Ensure there's an instance of it in your scene before using this field.

## Registration

The `CrossInputSupport` class only works on registered`CrossInputSupportedWindow` components. Use the `Register` method to register a `CrossInputSupportedWindow`.

```csharp
CrossInputSupport.Instance.Register();
```

Use `Unregister` to have the opposite effect.

```csharp
CrossInputSupport.Instance.Unregister();
```

## Top Window

The window at the top of every other one will have navigation control. To update the top window, use the `DetermineTop` method.

```csharp
CrossInputSupport.Instance.DetermineTop();
```

## Focusables

Focusables are `VisualElement`'s that can be focused by the `CrossInputSupport` seelctor.

### Find Focusables

To find all focusables of the top document, use the `FindFocusables` method. This will update the `focusables` field.

```csharp
CrossInputSupport.Instance.FindFocusables();
```

### Find Initial

The initial focusable is the first one selected when navigating as decided by the `initialFocusablePosition` field. Use the FindInitial to get the initial focusable. this will update the `initialFocusable` field.

## Selection

A focusable VisualElement is selected when navigating with any move button. The selected focusable will have the selector targeting it.

### Select

To simulate a selection, use the `Select` method. If the selector is locked, this method will do nothing.

```csharp
CrossInputSupport.Instance.Select(visualElement);
```

To select the initial focusable, use `SelectInitial`.

```csharp
CrossInputSupport.Instance.SelectInitial();
```

### Deselect

Use `Deselect` to deselect the current selection and hide the selector graphic.

```csharp
CrossInputSupport.Instance.Deselect();
```

Alternatively, you can use `AssessSelection`, which will deselect the current selection if it's not enabled or focusable anymore.

```csharp
CrossInputSupport.Instance.AssessSelection();
```

### Locking

To lock on a focusable, when a focusable is selected, use the `Lock` method. When a focusable is locked on, navigation will be prevented.

```csharp
CrossInputSupport.Instance.Lock();
```

### Unlocking

The `Unlock` method will stop locking on to a focusable.

```csharp
CrossInputSupport.Instance.Unlock();
```

### Moving

Use the Move method to move the selector towards a direction.

```csharp
CrossInputSupport.Instance.Move(Vector2.down);
```

## Getting the Selected Item Stack

To get the [item-stack](https://stylishesper.gitbook.io/inventool/scripting/api/items/item-stack "mention") that the selector is currently over, use the `GetSelectedItemStack` method. This method will return null if there is no selected item stack.

```csharp
ItemStack itemStack = CrossInputSupport.Instance.GetSelectedItemStack()
```
