Skip to content

Commit a99725c

Browse files
authored
Merge branch 'develop' into ekcoh/rebinding-issues-events
2 parents 980abc0 + 9506d23 commit a99725c

28 files changed

+390
-62
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS && UNITY_6000_0_OR_NEWER
2+
3+
using System;
4+
using NUnit.Framework;
5+
using System.Collections;
6+
using System.Linq;
7+
using UnityEditor;
8+
using UnityEngine;
9+
using UnityEngine.InputSystem;
10+
using UnityEngine.InputSystem.Editor;
11+
using UnityEngine.TestTools;
12+
using UnityEngine.UIElements;
13+
14+
internal enum SomeEnum
15+
{
16+
OptionA = 10,
17+
OptionB = 20
18+
}
19+
20+
#if UNITY_EDITOR
21+
[InitializeOnLoad]
22+
#endif
23+
internal class CustomProcessor : InputProcessor<float>
24+
{
25+
public SomeEnum SomeEnum;
26+
27+
#if UNITY_EDITOR
28+
static CustomProcessor()
29+
{
30+
Initialize();
31+
}
32+
33+
#endif
34+
35+
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
36+
private static void Initialize()
37+
{
38+
InputSystem.RegisterProcessor<CustomProcessor>();
39+
}
40+
41+
public override float Process(float value, InputControl control)
42+
{
43+
return value;
44+
}
45+
}
46+
47+
internal class CustomProcessorEnumTest : UIToolkitBaseTestWindow<InputActionsEditorWindow>
48+
{
49+
InputActionAsset m_Asset;
50+
51+
public override void OneTimeSetUp()
52+
{
53+
base.OneTimeSetUp();
54+
m_Asset = AssetDatabaseUtils.CreateAsset<InputActionAsset>();
55+
56+
var actionMap = m_Asset.AddActionMap("Action Map");
57+
58+
actionMap.AddAction("Action", InputActionType.Value, processors: "Custom(SomeEnum=10)");
59+
}
60+
61+
public override void OneTimeTearDown()
62+
{
63+
AssetDatabaseUtils.Restore();
64+
base.OneTimeTearDown();
65+
}
66+
67+
public override IEnumerator UnitySetup()
68+
{
69+
m_Window = InputActionsEditorWindow.OpenEditor(m_Asset);
70+
yield return null;
71+
}
72+
73+
[UnityTest]
74+
public IEnumerator ProcessorEnum_ShouldSerializeByValue_WhenSerializedToAsset()
75+
{
76+
// Serialize current asset to JSON, and check that initial JSON contains default enum value for OptionA
77+
var json = m_Window.currentAssetInEditor.ToJson();
78+
79+
Assert.That(json.Contains("Custom(SomeEnum=10)"), Is.True,
80+
"Serialized JSON does not contain the expected custom processor string for OptionA.");
81+
82+
// Query the dropdown with exactly two enum choices and check that the drop down is present in the UI
83+
var dropdownList = m_Window.rootVisualElement.Query<DropdownField>().Where(d => d.choices.Count == 2).ToList();
84+
Assume.That(dropdownList.Count > 0, Is.True, "Enum parameter dropdown not found in the UI.");
85+
86+
// Determine the new value to be set in the dropdown, focus the dropdown before dispatching the change
87+
var dropdown = dropdownList.First();
88+
var newValue = dropdown.choices[1];
89+
dropdown.Focus();
90+
dropdown.value = newValue;
91+
92+
// Create and send a change event from OptionA to OptionB
93+
var changeEvent = ChangeEvent<Enum>.GetPooled(SomeEnum.OptionA, SomeEnum.OptionB);
94+
changeEvent.target = dropdown;
95+
dropdown.SendEvent(changeEvent);
96+
97+
// Find the save button in the window, focus and click the save button to persist the changes
98+
var saveButton = m_Window.rootVisualElement.Q<Button>("save-asset-toolbar-button");
99+
Assume.That(saveButton, Is.Not.Null, "Save Asset button not found in the UI.");
100+
saveButton.Focus();
101+
SimulateClickOn(saveButton);
102+
103+
Assert.That(dropdown.value, Is.EqualTo(newValue));
104+
105+
// Verify that the updated JSON contains the new enum value for OpitonB
106+
var updatedJson = m_Window.currentAssetInEditor.ToJson();
107+
Assert.That(updatedJson.Contains("Custom(SomeEnum=20)"), Is.True, "Serialized JSON does not contain the updated custom processor string for OptionB.");
108+
109+
yield return null;
110+
}
111+
}
112+
#endif

Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Tests/InputSystem.Editor/ProjectWideInputActionsEditorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ public void Report(string message)
236236
}
237237
}
238238

239-
[Test(Description = "Verifies that the default asset do not generate any verification errors (Regardless of existing requirements)")]
239+
[Test(Description = "Verifies that the default asset does not generate any verification errors (Regardless of existing requirements)")]
240240
[Category(kTestCategory)]
241241
public void ProjectWideActions_ShouldSupportAssetVerification_AndHaveNoVerificationErrorsForDefaultAsset()
242242
{

Assets/Tests/InputSystem/CoreTests_Actions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5215,8 +5215,8 @@ public void Actions_CanConvertAssetToAndFromJson()
52155215
static string MinimalJson(string name = null)
52165216
{
52175217
if (name != null)
5218-
return "{\n \"name\": \"" + name + "\",\n \"maps\": [],\n \"controlSchemes\": []\n}";
5219-
return "{\n \"maps\": [],\n \"controlSchemes\": []\n}";
5218+
return "{\n \"version\": 0,\n \"name\": \"" + name + "\",\n \"maps\": [],\n \"controlSchemes\": []\n}";
5219+
return "{\n \"version\": 0,\n \"maps\": [],\n \"controlSchemes\": []\n}";
52205220
}
52215221

52225222
[Test]

Assets/Tests/InputSystem/Plugins/UITests.InputModuleTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,23 @@ public IEnumerator PointerExitChildShouldFullyExit()
157157
Assert.IsTrue(callbackCheck.pointerData.fullyExited == true);
158158
}
159159

160+
[UnityTest]
161+
[Description("Regression test for https://jira.unity3d.com/browse/ISXB-1493")]
162+
public IEnumerator DisablingDoesNotResetUserActions()
163+
{
164+
var actions = new DefaultInputActions();
165+
m_InputModule.actionsAsset = actions.asset;
166+
m_InputModule.cancel = InputActionReference.Create(actions.UI.Cancel);
167+
168+
m_InputModule.enabled = false;
169+
170+
yield return null;
171+
172+
Assert.IsNotNull(m_InputModule.cancel, "Disabling component shouldn't lose its data.");
173+
174+
actions.Dispose();
175+
}
176+
160177
public class PointerExitCallbackCheck : MonoBehaviour, IPointerExitHandler
161178
{
162179
public PointerEventData pointerData { get; private set; }

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ however, it has to be formatted properly to pass verification tests.
1111
## [Unreleased] - yyyy-mm-dd
1212

1313
### Changed
14-
- Expanded `RebindingUISample` to include a "game mode" state and a "menu state" to be more similar to a real game. Also added action-performed indicators illustrating when actions get triggered.
14+
- Expanded `RebindingUISample` to include a "game mode" state and a "menu state" to be more similar to a real game. Also added action-performed indicators (`InputActionIndicator`) illustrating when actions get triggered.
1515

1616
### Added
1717
- Support for Xbox controllers over USB on macOS, using macOS's default driver. [ISXB-1548]
1818
- Added a new run-time setting `InputSystem.inputEventHandledPolicy` which allows changing how the system processes input events marked as "handled". The new alternative setting (not default) allows for allowing handled events to propagate into state changes but still suppresses action interactions from being processed.
1919
- Added a new fluent API `WithSuppressedActionPropagation()` to `UnityEngine.InputSystem.InputActionRebindingExtensions` that allows suppressing actions from firing during interactive rebinding while allowing state updates to avoid actions triggering after state event suppression (default). ISXB-1546.
20+
- Added a new Monobehavior `InputActionLabel` to rebinding sample to allow dynamic text showing relevant binding for an `InputAction`.
2021

2122
### Fixed
2223
- Fixed an analytics event being invoked twice when the Save button in the Actions view was pressed. [ISXB-1378](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1378)
@@ -32,14 +33,21 @@ however, it has to be formatted properly to pass verification tests.
3233
- Fixed Gamepad stick up/down inputs that were not recognized in WebGL. [ISXB-1090](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1090)
3334
- Fixed reenabling the VirtualMouseInput component may sometimes lead to NullReferenceException. [ISXB-1096](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1096)
3435
- Fixed the default button press point not being respected in Editor (as well as some other Touchscreen properties). [ISXB-1152](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1152)
36+
- Fixed the TreeView compilation warnings when used with Unity 6.2 beta (ISX-2320)
37+
- Fixed actions being reset when disabling the InputSystemUIInputModule component [ISXB-1493](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1493)
38+
- Fixed a memory leak when disabling and enabling the InputSystemUIInputModule component at runtime [ISXB-1573](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1573)
39+
- Fixed all InputControls being changed at once when you change just one by reverting `2a37caac288ac09bc9122234339dc5df8d3a0ca6`, which was an attempt at fixing [ISXB-1221] that introduced this regression [ISXB-1531] (https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1493)
3540
- Fixed PlayerInput component automatically switching away from the default ActionMap set to 'None'.
3641
- Fixed a console error being shown when targeting visionOS builds in 2022.3.
3742
- Fixed a Tap Interaction issue with analog controls. The Tap interaction would keep re-starting after timeout. [ISXB-627](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-627)
3843
- Fixed the defaultActionMap dropdown in the PlayerInput component defaulting to <None> instead of the first ActionMap.
3944
- Fixed TrackedPoseDriver stops updating position and rotation when device is added after its initialization. [ISXB-1555](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1555)
4045
- Fixed PlayerInput component not working with C# Wrappers (ISXB-1535). This reverted changes done to fix [ISXB-920](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-920) but users can now fix it themselves.
46+
- Fixed an issue that caused input processors with enum properties to incorrectly serialise by index instead of by value [ISXB-1474](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1474).
4147
- Fixed an issue in `RebindingUISample` that fired actions bound to the same control as the target control in a rebinding process. ISXB-1524.
4248
- Fixed an issue in `RebindingUISample` preventing UI navigation without Keyboard and Mouse present.
49+
- Fixed an issue in `RebindActionUI` which resulted in active binding not being shown after a scene reload. ISXB-1588.
50+
- Fixed an issue in `GamepadIconExample` which resulted in icons for left and right triggers not being displayed after a rebind to the exact same controls. ISXB-1593.
4351

4452
## [1.14.0] - 2025-03-20
4553

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Reflection;
6+
using UnityEngine.InputSystem.Editor;
47
using UnityEngine.InputSystem.Utilities;
58

69
////TODO: make the FindAction logic available on any IEnumerable<InputAction> and IInputActionCollection via extension methods
@@ -275,6 +278,21 @@ public InputAction this[string actionNameOrId]
275278
return action;
276279
}
277280
}
281+
/// <summary>
282+
/// File‐format version constants for InputActionAsset JSON.
283+
/// </summary>
284+
static class JsonVersion
285+
{
286+
/// <summary>The original JSON version format for InputActionAsset.</summary>
287+
public const int Version0 = 0;
288+
289+
/// <summary>Updated JSON version format for InputActionAsset.</summary>
290+
/// <remarks>Changes representation of parameter values from being serialized by value to being serialized by value.</remarks>
291+
public const int Version1 = 1;
292+
293+
/// <summary>The current version.</summary>
294+
public const int Current = Version1;
295+
}
278296

279297
/// <summary>
280298
/// Return a JSON representation of the asset.
@@ -296,8 +314,10 @@ public InputAction this[string actionNameOrId]
296314
/// <seealso cref="FromJson"/>
297315
public string ToJson()
298316
{
317+
var hasContent = m_ActionMaps.LengthSafe() > 0 || m_ControlSchemes.LengthSafe() > 0;
299318
return JsonUtility.ToJson(new WriteFileJson
300319
{
320+
version = hasContent ? JsonVersion.Current : JsonVersion.Version0,
301321
name = name,
302322
maps = InputActionMap.WriteFileJson.FromMaps(m_ActionMaps).maps,
303323
controlSchemes = InputControlScheme.SchemeJson.ToJson(m_ControlSchemes),
@@ -379,6 +399,7 @@ public void LoadFromJson(string json)
379399
throw new ArgumentNullException(nameof(json));
380400

381401
var parsedJson = JsonUtility.FromJson<ReadFileJson>(json);
402+
MigrateJson(ref parsedJson);
382403
parsedJson.ToAsset(this);
383404
}
384405

@@ -950,6 +971,7 @@ private void OnDestroy()
950971
[Serializable]
951972
internal struct WriteFileJson
952973
{
974+
public int version;
953975
public string name;
954976
public InputActionMap.WriteMapJson[] maps;
955977
public InputControlScheme.SchemeJson[] controlSchemes;
@@ -965,6 +987,7 @@ internal struct WriteFileJsonNoName
965987
[Serializable]
966988
internal struct ReadFileJson
967989
{
990+
public int version;
968991
public string name;
969992
public InputActionMap.ReadMapJson[] maps;
970993
public InputControlScheme.SchemeJson[] controlSchemes;
@@ -981,5 +1004,73 @@ public void ToAsset(InputActionAsset asset)
9811004
map.m_Asset = asset;
9821005
}
9831006
}
1007+
1008+
/// <summary>
1009+
/// If parsedJson.version is older than Current, rewrite every
1010+
/// action.processors entry to replace “enumName(Ordinal=…)” with
1011+
/// “enumName(Value=…)” and bump parsedJson.version.
1012+
/// </summary>
1013+
internal void MigrateJson(ref ReadFileJson parsedJson)
1014+
{
1015+
if (parsedJson.version >= JsonVersion.Version1)
1016+
return;
1017+
if ((parsedJson.maps?.Length ?? 0) > 0 && (parsedJson.version) < JsonVersion.Version1)
1018+
{
1019+
for (var mi = 0; mi < parsedJson.maps.Length; ++mi)
1020+
{
1021+
var mapJson = parsedJson.maps[mi];
1022+
for (var ai = 0; ai < mapJson.actions.Length; ++ai)
1023+
{
1024+
var actionJson = mapJson.actions[ai];
1025+
var raw = actionJson.processors;
1026+
if (string.IsNullOrEmpty(raw))
1027+
continue;
1028+
1029+
var list = NameAndParameters.ParseMultiple(raw).ToList();
1030+
var rebuilt = new List<string>(list.Count);
1031+
foreach (var nap in list)
1032+
{
1033+
var procType = InputSystem.TryGetProcessor(nap.name);
1034+
if (nap.parameters.Count == 0 || procType == null)
1035+
{
1036+
rebuilt.Add(nap.ToString());
1037+
continue;
1038+
}
1039+
1040+
var dict = nap.parameters.ToDictionary(p => p.name, p => p.value.ToString());
1041+
var anyChanged = false;
1042+
foreach (var field in procType.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(f => f.FieldType.IsEnum))
1043+
{
1044+
if (dict.TryGetValue(field.Name, out var ordS) && int.TryParse(ordS, out var ord))
1045+
{
1046+
var values = Enum.GetValues(field.FieldType).Cast<object>().ToArray();
1047+
if (ord >= 0 && ord < values.Length)
1048+
{
1049+
dict[field.Name] = Convert.ToInt32(values[ord]).ToString();
1050+
anyChanged = true;
1051+
}
1052+
}
1053+
}
1054+
1055+
if (!anyChanged)
1056+
{
1057+
rebuilt.Add(nap.ToString());
1058+
}
1059+
else
1060+
{
1061+
var paramText = string.Join(",", dict.Select(kv => $"{kv.Key}={kv.Value}"));
1062+
rebuilt.Add($"{nap.name}({paramText})");
1063+
}
1064+
}
1065+
1066+
actionJson.processors = string.Join(";", rebuilt);
1067+
mapJson.actions[ai] = actionJson;
1068+
}
1069+
parsedJson.maps[mi] = mapJson;
1070+
}
1071+
}
1072+
// Bump the version so we never re-migrate
1073+
parsedJson.version = JsonVersion.Version1;
1074+
}
9841075
}
9851076
}

0 commit comments

Comments
 (0)