2021-05-02 20:59:45 +01:00
using System ;
2026-08-10 14:57:50 +01:00
using System.Collections ;
2021-05-02 20:59:45 +01:00
using System.Collections.Generic ;
2026-08-10 14:57:50 +01:00
using System.IO ;
2021-05-03 23:15:29 +01:00
using System.Linq ;
2026-08-10 14:57:50 +01:00
using MessagePack ;
using Newtonsoft.Json ;
using Newtonsoft.Json.Serialization ;
using TMPro ;
using UniRx ;
2021-05-02 20:59:45 +01:00
using UnityEngine ;
2021-05-03 23:15:29 +01:00
using UnityEngine.InputSystem ;
2026-08-10 14:57:50 +01:00
using UnityEngine.UI ;
using UnityEngine.UI.Extensions ;
using Unity.Mathematics ;
using UnityEngine.EventSystems ;
using static Unity . Mathematics . math ;
2021-05-02 20:59:45 +01:00
public class InputDisplayLayout : MonoBehaviour
{
2026-08-10 14:57:50 +01:00
public RectTransform UnassignedBindingsGroup ;
public RectTransform AssignedBindingsGroup ;
public InputDisplayButton MouseLeft ;
public InputDisplayButton MouseRight ;
public InputDisplayButton MouseMiddle ;
public InputDisplayButton MouseForward ;
public InputDisplayButton MouseBack ;
public VerticalLayoutGroup RowContainer ;
public TextAsset LayoutFile ;
public Prototype LabelPrototype ;
public Prototype LinePrototype ;
//public UILineRendererList LineRenderer;
public Prototype RowPrototype ;
public Prototype RowSpacerPrototype ;
public int KeySize = 64 ;
public Color DefaultColor ;
public Color HighlightColor ;
public float FillBrightness = . 5f ;
public float FillAlpha ;
public float FillMultiplier = . 25f ;
public float InactiveMultiplier = . 333f ;
public int PlacementSearchArea = 4 ;
public float TestPadding = 4 ;
public float BoxLineExpand = - 1 ;
public float GlobalHue = . 333f ;
public float Saturation ;
public float GlobalHueRange = . 1f ;
private Canvas _canvas ;
private InputLayout _inputLayout ;
private ActionMapping _dragAction ;
private ButtonMapping _originalButton ;
private ButtonMapping _previewButton ;
private ActionMapping _previewOriginalAction ;
private bool _previewOriginallyActionBar ;
public InputActionAsset Input { get ; set ; }
private class ButtonMapping
2026-06-21 09:37:54 +01:00
{
2026-08-10 14:57:50 +01:00
public InputAction TestAction ;
public IBindableButton Button ;
public InputDisplayButton DisplayButton ;
public ActionMapping ActionMapping ;
public UILineRenderer LabelLine ;
public bool IsActionBarButton ;
public Rect ButtonRect = > DisplayButton . GetComponent < RectTransform > ( ) . ScreenSpaceRect ( ) ;
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
private class ActionMapping
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
public string Name ;
public InputBinding Binding ;
public InputAction Action ;
public InputDisplayLabel Label ;
public float Hue ;
public List < ButtonMapping > ButtonMappings = new List < ButtonMapping > ( ) ;
public Rect LabelRect = > Label . GetComponent < RectTransform > ( ) . ScreenSpaceRect ( ) ;
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
private Dictionary < string , ButtonMapping > _bindButtons = new Dictionary < string , ButtonMapping > ( ) ;
private List < ButtonMapping > _buttonMappings = new List < ButtonMapping > ( ) ;
private List < ActionMapping > _actionMappings = new List < ActionMapping > ( ) ;
void Start ( )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
_canvas = transform . root . GetComponent < Canvas > ( ) ;
var path = Path . Combine ( ActionGameManager . GameDataDirectory . CreateSubdirectory ( "KeyboardLayouts" ) . FullName , $"{LayoutFile.name}.msgpack" ) ;
// _inputLayout = ParseJson(LayoutFile.text);
RegisterResolver . Register ( ) ;
_inputLayout = MessagePackSerializer . Deserialize < InputLayout > ( File . ReadAllBytes ( path ) ) ;
// _inputLayout = JsonConvert.DeserializeObject<InputLayout>(File.ReadAllText(path));
// SaveLayout();
DisplayLayout ( _inputLayout ) ;
_buttonMappings . Add ( MapMouseButton ( MouseLeft , "<Mouse>/leftButton" ) ) ;
_buttonMappings . Add ( MapMouseButton ( MouseRight , "<Mouse>/rightButton" ) ) ;
_buttonMappings . Add ( MapMouseButton ( MouseMiddle , "<Mouse>/middleButton" ) ) ;
_buttonMappings . Add ( MapMouseButton ( MouseForward , "<Mouse>/forwardButton" ) ) ;
_buttonMappings . Add ( MapMouseButton ( MouseBack , "<Mouse>/backButton" ) ) ;
Canvas . ForceUpdateCanvases ( ) ;
foreach ( var buttonMapping in _buttonMappings )
2021-05-07 19:51:23 +01:00
{
2026-08-10 14:57:50 +01:00
_bindButtons [ buttonMapping . Button . InputSystemPath ] = buttonMapping ;
buttonMapping . TestAction = new InputAction ( binding : buttonMapping . Button . InputSystemPath ) ;
buttonMapping . TestAction . started + = context = >
{
buttonMapping . DisplayButton . Outline . color = HighlightColor ;
buttonMapping . DisplayButton . Outline . gameObject . SetActive ( true ) ;
var fillColor = HighlightColor ;
fillColor * = FillBrightness ;
fillColor . a = FillAlpha ;
buttonMapping . DisplayButton . Fill . color = fillColor ;
} ;
buttonMapping . TestAction . canceled + = context = > AssignColor ( buttonMapping ) ;
buttonMapping . TestAction . Enable ( ) ;
2021-05-07 19:51:23 +01:00
}
2026-08-10 14:57:50 +01:00
foreach ( var actionBarInput in ActionGameManager . PlayerSettings . InputSettings . ActionBarInputs )
2021-05-06 18:43:23 +01:00
{
2026-08-10 14:57:50 +01:00
if ( ! _bindButtons . ContainsKey ( actionBarInput ) ) Debug . LogError ( $"Unable to find input button for \" { actionBarInput } \ "" ) ;
else
{
_bindButtons [ actionBarInput ] . IsActionBarButton = true ;
AssignColor ( _bindButtons [ actionBarInput ] ) ;
}
2021-05-06 18:43:23 +01:00
}
2026-08-10 14:57:50 +01:00
if ( Input = = null )
{
var input = new AetheriaInput ( ) ;
Input = input . asset ;
}
ProcessActions ( Input ) ;
// input.Enable();
// input.Global.Interact.performed += context => Debug.Log($"Interact Performed! Time = {((int) (Time.time * 1000)).ToString()}ms");
2026-06-13 04:56:50 +01:00
2026-08-10 14:57:50 +01:00
Observable . NextFrame ( ) . Subscribe ( _ = >
{
foreach ( var actionMapping in _actionMappings )
{
actionMapping . Label = CreateLabel ( actionMapping ) ;
PlaceLabel ( actionMapping ) ;
}
2026-06-17 08:41:06 +01:00
2026-08-10 14:57:50 +01:00
RegisterMouseCallbacks ( ) ;
} ) ;
2026-06-17 08:41:06 +01:00
2026-08-10 14:57:50 +01:00
//StartCoroutine(AssociateInputKeys(_inputLayout));
2026-06-17 08:41:06 +01:00
}
2021-05-06 02:34:19 +01:00
2026-08-10 14:57:50 +01:00
private ButtonMapping MapMouseButton ( InputDisplayButton button , string path )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
var mapping = new ButtonMapping
2021-05-03 23:15:29 +01:00
{
2026-08-10 14:57:50 +01:00
Button = new InputLayoutMouseButton { Path = path } ,
DisplayButton = button
} ;
AssignUnboundColor ( mapping . DisplayButton ) ;
return mapping ;
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
private void ProcessActions ( InputActionAsset input )
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
var bindableActions = input . Where ( a = > a . actionMap . name ! = "UI" & & ( a . type = = InputActionType . Button | | a . bindings . Any ( b = > b . isComposite ) ) ) . ToArray ( ) ;
for ( var i = 0 ; i < bindableActions . Length ; i + + )
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
var action = bindableActions [ i ] ;
foreach ( var binding in action . bindings )
2021-05-03 23:15:29 +01:00
{
2026-08-10 14:57:50 +01:00
if ( _bindButtons . ContainsKey ( binding . effectivePath ) )
{
var name = action . name . Replace ( ' ' , '\n' ) ;
if ( binding . isPartOfComposite ) name = $"{name} {binding.name}" ;
var actionMapping = new ActionMapping
{
Name = name ,
Binding = binding ,
Action = action ,
Hue = action . actionMap . name = = "Global"
? GlobalHue
: frac ( GlobalHue + GlobalHueRange + ( float ) i / ( bindableActions . Length - 1 ) * ( 1 - GlobalHueRange * 2 ) )
} ;
_actionMappings . Add ( actionMapping ) ;
var buttonMapping = _bindButtons [ binding . effectivePath ] ;
buttonMapping . ActionMapping = actionMapping ;
AssignColor ( buttonMapping ) ;
actionMapping . ButtonMappings . Add ( buttonMapping ) ;
}
2021-05-03 23:15:29 +01:00
}
}
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
private void AssignColor ( ButtonMapping buttonMapping )
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
if ( buttonMapping . IsActionBarButton )
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
var outlineColor = Color . white ;
var fillColor = Color . white * FillBrightness ;
fillColor . a = FillAlpha ;
buttonMapping . DisplayButton . Fill . color = fillColor ;
buttonMapping . DisplayButton . Outline . gameObject . SetActive ( true ) ;
buttonMapping . DisplayButton . Outline . color = outlineColor ;
if ( buttonMapping . DisplayButton is InputDisplayKey key ) key . MainLabel . color = key . AltLabel . color = outlineColor ;
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
else if ( buttonMapping . ActionMapping ! = null )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
var outlineColor = Color . HSVToRGB ( buttonMapping . ActionMapping . Hue , Saturation , 1 ) ;
var fillColor = Color . HSVToRGB ( buttonMapping . ActionMapping . Hue , 1 , FillBrightness ) ;
fillColor . a = FillAlpha ;
buttonMapping . DisplayButton . Fill . color = fillColor ;
buttonMapping . DisplayButton . Outline . gameObject . SetActive ( true ) ;
buttonMapping . DisplayButton . Outline . color = outlineColor ;
if ( buttonMapping . DisplayButton is InputDisplayKey key ) key . MainLabel . color = key . AltLabel . color = outlineColor ;
2026-06-17 08:41:06 +01:00
}
2026-08-10 14:57:50 +01:00
else AssignUnboundColor ( buttonMapping . DisplayButton ) ;
2021-05-06 02:34:19 +01:00
}
2021-05-03 23:15:29 +01:00
2026-08-10 14:57:50 +01:00
private void AssignUnboundColor ( InputDisplayButton button , bool bindable = true )
2021-05-06 02:34:19 +01:00
{
2026-08-10 14:57:50 +01:00
button . Outline . gameObject . SetActive ( false ) ;
var outlineColor = DefaultColor ;
outlineColor . a * = InactiveMultiplier ;
var fillColor = DefaultColor * FillBrightness ;
fillColor * = FillBrightness ;
if ( ! bindable )
fillColor * = InactiveMultiplier ;
fillColor . a = FillAlpha ;
button . Fill . color = fillColor ;
if ( button is InputDisplayKey key ) key . MainLabel . color = key . AltLabel . color = Color . Lerp ( outlineColor , fillColor , . 5f ) ;
2021-05-06 02:34:19 +01:00
}
2026-08-10 14:57:50 +01:00
private InputDisplayLabel CreateLabel ( ActionMapping actionMapping )
2021-05-03 23:15:29 +01:00
{
2026-08-10 14:57:50 +01:00
var label = LabelPrototype . Instantiate < InputDisplayLabel > ( ) ;
label . Label . color = Color . HSVToRGB ( actionMapping . Hue , Saturation , 1 ) ;
actionMapping . Label = label ;
label . Label . text = actionMapping . Name ;
return label ;
2021-05-03 23:15:29 +01:00
}
2026-08-10 14:57:50 +01:00
private void PlaceLabel ( ActionMapping actionMapping )
2021-05-03 23:15:29 +01:00
{
2026-08-10 14:57:50 +01:00
if ( actionMapping . ButtonMappings . Any ( ) )
2021-05-03 23:15:29 +01:00
{
2026-08-10 14:57:50 +01:00
var labelRect = actionMapping . Label . Label . rectTransform ;
LayoutRebuilder . ForceRebuildLayoutImmediate ( labelRect ) ;
var rect = FindLabelPosition ( actionMapping . ButtonMappings . First ( ) . DisplayButton . GetComponent < RectTransform > ( ) , labelRect ) ;
//actionMapping.LabelRect = rect;
actionMapping . Label . transform . parent = AssignedBindingsGroup ;
actionMapping . Label . transform . position = rect . center ;
2021-05-03 23:15:29 +01:00
}
2026-08-10 14:57:50 +01:00
else
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
actionMapping . Label . transform . parent = UnassignedBindingsGroup ;
2026-06-17 08:41:06 +01:00
}
2026-08-10 14:57:50 +01:00
foreach ( var buttonMapping in actionMapping . ButtonMappings ) ConnectButtonToLabel ( buttonMapping ) ;
2021-05-02 20:59:45 +01:00
}
2026-08-10 14:57:50 +01:00
private void ConnectButtonToLabel ( ButtonMapping buttonMapping )
2026-06-13 22:00:46 +01:00
{
2026-08-10 14:57:50 +01:00
if ( buttonMapping . ActionMapping ! = null )
2026-06-21 09:37:54 +01:00
{
2026-08-10 14:57:50 +01:00
var keyBounds = buttonMapping . DisplayButton . Outline . rectTransform . GetBounds ( BoxLineExpand ) ;
var labelPoint = ( Vector2 ) buttonMapping . ActionMapping . Label . Label . rectTransform . GetBounds ( ) . ClosestPoint ( keyBounds . center ) ;
var keyPoint = ( Vector2 ) keyBounds . ClosestPoint ( labelPoint ) ;
labelPoint / = _canvas . scaleFactor ;
keyPoint / = _canvas . scaleFactor ;
buttonMapping . LabelLine ? ? = LinePrototype . Instantiate < UILineRenderer > ( ) ;
buttonMapping . LabelLine . color = buttonMapping . ActionMapping . Label . Label . color ;
buttonMapping . LabelLine . Points = new [ ] { keyPoint , labelPoint } ;
2026-06-21 09:37:54 +01:00
}
2026-08-10 14:57:50 +01:00
else
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
buttonMapping . LabelLine ? . GetComponent < Prototype > ( ) . ReturnToPool ( ) ;
buttonMapping . LabelLine = null ;
2026-06-17 08:41:06 +01:00
}
2026-06-13 22:00:46 +01:00
}
2026-08-10 14:57:50 +01:00
private Rect FindLabelPosition ( RectTransform key , RectTransform label )
2021-05-08 07:35:16 +01:00
{
2026-08-10 14:57:50 +01:00
var keyRect = key . ScreenSpaceRect ( ) ;
var labelRect = label . ScreenSpaceRect ( TestPadding * _canvas . scaleFactor ) ;
var localRects = Overlap ( key . ScreenSpaceRect ( PlacementSearchArea * KeySize * _canvas . scaleFactor ) ) ;
var centroid = localRects . Aggregate ( Vector2 . zero , ( v , r ) = > v + r . center ) / localRects . Length ;
var keyCenter = keyRect . center ;
var dir = ( keyCenter - centroid ) . normalized ;
for ( int dist = KeySize ; dist < PlacementSearchArea * KeySize ; dist + + )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
for ( float theta = 0 ; theta < PI * 2 ; theta + = PI / 32 )
{
for ( int s = - 1 ; s < = 1 ; s + = 2 )
{
var testPos = keyCenter + dir . Rotate ( theta * s ) * dist * _canvas . scaleFactor ;
var testRect = new Rect ( testPos - labelRect . size / 2 , labelRect . size ) ;
if ( ! localRects . Any ( r = > r . Overlaps ( testRect ) ) )
{
return testRect ;
}
}
}
2026-06-17 08:41:06 +01:00
}
2026-08-10 14:57:50 +01:00
return default ;
2021-05-08 07:35:16 +01:00
}
2026-08-10 14:57:50 +01:00
private ActionMapping [ ] OverlappingLabels ( Rect rect ) = > _actionMappings
. Where ( a = > a . LabelRect . Overlaps ( rect ) ) . ToArray ( ) ;
private Rect [ ] Overlap ( Rect rect ) = > _buttonMappings
. Where ( b = > b . IsActionBarButton | | b . ActionMapping ! = null )
. Select ( b = > b . ButtonRect )
. Concat ( _actionMappings
. Where ( a = > a . Label & & a . LabelRect . width > . 1f )
. Select ( a = > a . LabelRect ) )
. Where ( r = > r . Overlaps ( rect ) ) . ToArray ( ) ;
public void DisplayLayout ( InputLayout layout )
2021-05-08 07:35:16 +01:00
{
2026-08-10 14:57:50 +01:00
foreach ( var row in layout . Rows )
2021-05-08 07:35:16 +01:00
{
2026-08-10 14:57:50 +01:00
if ( row is InputLayoutKeyRow keyRow )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
var displayRow = RowPrototype . Instantiate < InputDisplayRow > ( ) ;
foreach ( var column in keyRow . Columns )
{
if ( column is InputLayoutColumnSpacer )
{
displayRow . KeySpacerPrototype . Instantiate < LayoutElement > ( ) . preferredWidth = KeySize * column . Width ;
}
else if ( column is InputLayoutKey )
{
var displayKey = displayRow . KeyPrototype . Instantiate < InputDisplayKey > ( ) ;
displayKey . LayoutElement . preferredHeight = KeySize ;
displayKey . LayoutElement . preferredWidth = KeySize * column . Width ;
displayKey . Outline . gameObject . SetActive ( false ) ;
displayKey . Outline . color = DefaultColor ;
AssignUnboundColor ( displayKey , column is InputLayoutBindableKey ) ;
if ( column is InputLayoutBindableKey key )
{
var buttonMapping = new ButtonMapping
{
Button = key ,
DisplayButton = displayKey
} ;
_bindButtons [ key . InputSystemPath ] = buttonMapping ;
_buttonMappings . Add ( buttonMapping ) ;
displayKey . MainLabel . text = key . MainLabel ;
displayKey . AltLabel . text = key . AltLabel ;
if ( column is InputLayoutMultiRowKey multiRowKey )
{
displayKey . Outline . rectTransform . anchorMin =
displayKey . MainLabel . rectTransform . anchorMin =
displayKey . AltLabel . rectTransform . anchorMin =
displayKey . Fill . rectTransform . anchorMin = Vector2 . down * ( multiRowKey . Height - 1 ) ;
}
}
else
{
displayKey . MainLabel . text = "" ;
displayKey . AltLabel . text = "" ;
}
}
else
{
throw new ArgumentOutOfRangeException ( nameof ( column ) ) ;
}
}
}
else if ( row is InputLayoutRowSpacer rowSpacer )
{
RowSpacerPrototype . Instantiate < LayoutElement > ( ) . preferredHeight = KeySize * rowSpacer . Height ;
}
else
{
throw new ArgumentOutOfRangeException ( nameof ( row ) ) ;
}
}
2026-06-17 08:41:06 +01:00
}
2021-05-08 07:35:16 +01:00
2026-08-10 14:57:50 +01:00
public InputLayout ParseJson ( string layout )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
var rows = new List < InputLayoutRow > ( ) ;
var nextWidth = 1f ;
var nextHeight = 1 ;
var reader = new JsonTextReader ( new StringReader ( layout ) ) ;
reader . Read ( ) ;
if ( reader . TokenType ! = JsonToken . StartArray )
throw new JsonReaderException ( $"Unexpected JSON format in line {reader.LineNumber}:{reader.LinePosition}, expected: StartArray, received: {Enum.GetName(typeof(JsonToken), reader.TokenType)}" ) ;
while ( reader . Read ( ) & & reader . TokenType ! = JsonToken . EndArray )
2026-06-17 08:41:06 +01:00
{
2026-08-10 14:57:50 +01:00
if ( reader . TokenType ! = JsonToken . StartArray )
throw new JsonReaderException ( $"Unexpected JSON format in line {reader.LineNumber}:{reader.LinePosition}, expected: StartArray, received: {Enum.GetName(typeof(JsonToken), reader.TokenType)}" ) ;
2021-05-08 07:35:16 +01:00
2026-08-10 14:57:50 +01:00
var row = new InputLayoutKeyRow ( ) ;
var columns = new List < InputLayoutColumn > ( ) ;
2026-06-13 04:56:50 +01:00
2026-08-10 14:57:50 +01:00
while ( reader . Read ( ) & & reader . TokenType ! = JsonToken . EndArray )
{
switch ( reader . TokenType )
{
case JsonToken . StartObject :
while ( reader . Read ( ) & & reader . TokenType ! = JsonToken . EndObject )
{
switch ( reader . Value . ToString ( ) )
{
case "a" : break ;
case "w" :
nextWidth = ( float ) ( reader . ReadAsDouble ( ) ? ? 1.0 ) ;
break ;
case "h" :
nextHeight = reader . ReadAsInt32 ( ) ? ? 1 ;
break ;
case "y" :
rows . Add ( new InputLayoutRowSpacer { Height = ( float ) ( reader . ReadAsDouble ( ) ? ? 0.0 ) } ) ;
break ;
case "x" :
columns . Add ( new InputLayoutColumnSpacer { Width = ( float ) ( reader . ReadAsDouble ( ) ? ? 0.0 ) } ) ;
break ;
}
}
break ;
case JsonToken . String :
InputLayoutKey key ;
var v = reader . Value . ToString ( ) . Trim ( ) ;
if ( ! string . IsNullOrEmpty ( v ) )
{
var labels = v . Split ( '\n' ) ;
key = nextHeight ! = 1 ? new InputLayoutMultiRowKey { Height = nextHeight } : new InputLayoutBindableKey ( ) ;
nextHeight = 1 ;
( ( InputLayoutBindableKey ) key ) . MainLabel = labels . Length = = 2 ? labels [ 1 ] : v ;
( ( InputLayoutBindableKey ) key ) . AltLabel = labels . Length = = 2 ? labels [ 0 ] : "" ;
}
else
key = new InputLayoutKey ( ) ;
key . Width = nextWidth ;
columns . Add ( key ) ;
nextWidth = 1f ;
break ;
default :
throw new JsonReaderException ( $"Unexpected JSON format in line {reader.LineNumber}:{reader.LinePosition}" ) ;
}
}
row . Columns = columns . ToArray ( ) ;
rows . Add ( row ) ;
2021-05-08 07:35:16 +01:00
}
2026-06-17 08:41:06 +01:00
2026-08-10 14:57:50 +01:00
return new InputLayout { Rows = rows . ToArray ( ) } ;
2021-05-08 07:35:16 +01:00
}
2026-08-10 14:57:50 +01:00
private IEnumerator AssociateInputKeys ( )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
var path = "" ;
var keyPress = new InputAction ( binding : "/<Keyboard>/<button>" ) ;
keyPress . performed + = context = >
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
if ( context . control . path . EndsWith ( "anyKey" ) ) return ;
path = context . control . path ;
} ;
keyPress . Enable ( ) ;
foreach ( var button in _buttonMappings )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
button . DisplayButton . Outline . color = HighlightColor ;
var fillColor = HighlightColor ;
fillColor * = FillMultiplier ;
fillColor . a = FillAlpha ;
button . DisplayButton . Fill . color = fillColor ;
path = "" ;
while ( string . IsNullOrEmpty ( path ) ) yield return null ;
button . Button . InputSystemPath = path ;
//Debug.Log($"Bound \"{path}\" to \"{bindableKey.MainLabel}\"");
button . DisplayButton . Outline . color = DefaultColor ;
fillColor = DefaultColor ;
fillColor * = FillMultiplier ;
fillColor . a = FillAlpha ;
button . DisplayButton . Fill . color = fillColor ;
2026-06-25 18:09:33 +01:00
}
2026-08-10 14:57:50 +01:00
keyPress . Disable ( ) ;
SaveLayout ( ) ;
2026-06-25 18:09:33 +01:00
}
2026-08-10 14:57:50 +01:00
private void SaveLayout ( )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
RegisterResolver . Register ( ) ;
File . WriteAllBytes (
Path . Combine ( ActionGameManager . GameDataDirectory . CreateSubdirectory ( "KeyboardLayouts" ) . FullName , $"{LayoutFile.name}.msgpack" ) ,
MessagePackSerializer . Serialize ( _inputLayout ) ) ;
}
2026-06-25 18:09:33 +01:00
2026-08-10 14:57:50 +01:00
private void OnEnable ( )
{
foreach ( var buttonMapping in _buttonMappings )
buttonMapping . TestAction . Enable ( ) ;
RegisterMouseCallbacks ( ) ;
2026-06-25 18:09:33 +01:00
}
2026-08-10 14:57:50 +01:00
private void RegisterMouseCallbacks ( )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
void EndDrag ( PointerEventData _ )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
if ( _previewButton = = null )
{
if ( _originalButton ! = null )
{
_originalButton . ActionMapping = _dragAction ;
_dragAction . ButtonMappings . Add ( _originalButton ) ;
AssignColor ( _originalButton ) ;
}
PlaceLabel ( _dragAction ) ;
}
else
{
_dragAction . Binding . overridePath = _previewButton . Button . InputSystemPath ;
_dragAction . Action . ApplyBindingOverride ( _dragAction . Binding ) ;
ActionGameManager . PlayerSettings . InputSettings . InputActionMap [ ( _dragAction . Action . name ,
_dragAction . Action . GetBindingIndex ( _dragAction . Binding ) ) ] = _previewButton . Button . InputSystemPath ;
// TODO: Assign New Binding
}
foreach ( var action in _actionMappings )
action . Label . Label . raycastTarget = true ;
_dragAction = null ;
_originalButton = null ;
_previewButton = null ;
_previewOriginalAction = null ;
2026-06-25 18:09:33 +01:00
}
2026-08-10 14:57:50 +01:00
foreach ( var buttonMapping in _buttonMappings )
2026-06-25 18:09:33 +01:00
{
2026-08-10 14:57:50 +01:00
// On click: when a specific action is not assigned, toggle its availability on the action bar
buttonMapping . DisplayButton . ClickTrigger . OnPointerClickAsObservable ( )
. Where ( _ = > buttonMapping . ActionMapping = = null )
. Subscribe ( data = >
{
buttonMapping . IsActionBarButton = ! buttonMapping . IsActionBarButton ;
if ( buttonMapping . IsActionBarButton )
{
ActionGameManager . PlayerSettings . InputSettings . ActionBarInputs . Add ( buttonMapping . Button . InputSystemPath ) ;
foreach ( var overlap in OverlappingLabels ( buttonMapping . ButtonRect ) )
PlaceLabel ( overlap ) ;
}
else
{
ActionGameManager . PlayerSettings . InputSettings . ActionBarInputs . Remove ( buttonMapping . Button . InputSystemPath ) ;
}
AssignColor ( buttonMapping ) ;
} ) ;
buttonMapping . DisplayButton . BeginDragTrigger . OnBeginDragAsObservable ( )
. Where ( _ = > buttonMapping . ActionMapping ! = null )
. Subscribe ( _ = >
{
_originalButton = buttonMapping ;
buttonMapping . LabelLine . Points = new Vector2 [ 0 ] ;
_dragAction = buttonMapping . ActionMapping ;
foreach ( var action in _actionMappings )
action . Label . Label . raycastTarget = false ;
} ) ;
buttonMapping . DisplayButton . EnterTrigger . OnPointerEnterAsObservable ( )
. Where ( _ = > _dragAction ! = null )
. Subscribe ( _ = >
{
_previewButton = buttonMapping ;
_previewOriginalAction = buttonMapping . ActionMapping ;
_previewOriginallyActionBar = buttonMapping . IsActionBarButton ;
buttonMapping . IsActionBarButton = false ;
buttonMapping . ActionMapping ? . ButtonMappings . Remove ( buttonMapping ) ;
buttonMapping . ActionMapping = _dragAction ;
_dragAction . ButtonMappings . Add ( buttonMapping ) ;
if ( _previewOriginalAction ! = null )
PlaceLabel ( _previewOriginalAction ) ;
PlaceLabel ( _dragAction ) ;
AssignColor ( buttonMapping ) ;
foreach ( var overlap in OverlappingLabels ( buttonMapping . ButtonRect ) )
PlaceLabel ( overlap ) ;
} ) ;
buttonMapping . DisplayButton . ExitTrigger . OnPointerExitAsObservable ( )
. Where ( _ = > _dragAction ! = null )
. Subscribe ( _ = >
{
_dragAction . ButtonMappings . Remove ( buttonMapping ) ;
if ( buttonMapping = = _originalButton )
{
buttonMapping . ActionMapping = null ;
}
else if ( buttonMapping = = _previewButton )
{
buttonMapping . IsActionBarButton = _previewOriginallyActionBar ;
buttonMapping . ActionMapping = _previewOriginalAction ;
if ( ! _previewOriginallyActionBar )
{
if ( _previewOriginalAction ! = null )
{
_previewOriginalAction . ButtonMappings . Add ( buttonMapping ) ;
PlaceLabel ( _previewOriginalAction ) ;
}
}
}
ConnectButtonToLabel ( buttonMapping ) ;
AssignColor ( buttonMapping ) ;
_previewButton = null ;
_previewOriginalAction = null ;
} ) ;
buttonMapping . DisplayButton . EndDragTrigger . OnEndDragAsObservable ( )
. Where ( _ = > _dragAction ! = null )
. Subscribe ( EndDrag ) ;
}
foreach ( var actionMapping in _actionMappings )
{
actionMapping . Label . BeginDragTrigger . OnBeginDragAsObservable ( ) . Subscribe ( _ = >
{
_dragAction = actionMapping ;
actionMapping . Label . transform . parent = AssignedBindingsGroup ;
foreach ( var action in _actionMappings )
action . Label . Label . raycastTarget = false ;
if ( actionMapping . ButtonMappings . Count = = 1 )
{
var buttonMapping = actionMapping . ButtonMappings [ 0 ] ;
_originalButton = buttonMapping ;
buttonMapping . LabelLine . Points = new Vector2 [ 0 ] ;
buttonMapping . ActionMapping = null ;
actionMapping . ButtonMappings . Clear ( ) ;
ConnectButtonToLabel ( buttonMapping ) ;
AssignColor ( buttonMapping ) ;
}
} ) ;
actionMapping . Label . EndDragTrigger . OnEndDragAsObservable ( ) . Subscribe ( EndDrag ) ;
2026-06-25 18:09:33 +01:00
}
}
2026-08-10 14:57:50 +01:00
private void OnDisable ( )
2021-05-08 07:35:16 +01:00
{
2026-08-10 14:57:50 +01:00
foreach ( var buttonMapping in _buttonMappings )
buttonMapping . TestAction . Disable ( ) ;
2021-05-08 07:35:16 +01:00
}
2026-08-10 14:57:50 +01:00
void Update ( )
{
if ( _dragAction ! = null & & _previewButton = = null )
{
_dragAction . Label . transform . position = Mouse . current . position . ReadValue ( ) ;
}
}
2021-05-02 20:59:45 +01:00
}