Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: Allow Copy/Paste between windows (ISX-1823). #1844

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4d21dbf
FIX: Allow Copy/Paste between windows by intercepting the commands hi…
graham-huws Feb 15, 2024
4e41f29
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
lyndon-unity Feb 18, 2024
9cda4d8
Address feedback, and fix focusing when tabbing in to the window for …
graham-huws Feb 20, 2024
108c268
Catch errors, and simplify OnExecuteCommand.
graham-huws Feb 20, 2024
5b5e663
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Feb 20, 2024
384cb74
Avoid array OOB.
graham-huws Feb 20, 2024
b7617fe
Deduplicate Paste handling.
graham-huws Feb 21, 2024
2e64bb2
Fix SelectBinding not doing so, and simplify Paste handling.
graham-huws Feb 21, 2024
7ae236a
Fix array index bounds. Clamp doesn't work if arraySize is 0.
graham-huws Feb 22, 2024
a5e7de0
Catch issue with pasting a binding into an empty map.
graham-huws Feb 22, 2024
9a9cf85
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Feb 22, 2024
78904a7
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
Pauliusd01 Feb 22, 2024
1b56964
Fix formatting after merge
graham-huws Feb 22, 2024
3179bf0
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Feb 23, 2024
0774a65
Merge remote-tracking branch 'origin/develop' into ISX-1823-cut-copy-…
ritamerkl Feb 26, 2024
5c4aa27
Stop propagation of paste event when we handle it.
graham-huws Feb 27, 2024
2bad8bb
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Feb 29, 2024
d1d99a9
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Mar 4, 2024
519abd9
Update after merging develop
graham-huws Mar 4, 2024
80b2705
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Mar 12, 2024
6227e7e
Make use of allowUICommandExecution protection bool like in other Views.
graham-huws Mar 12, 2024
0abdaef
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws Apr 4, 2024
81f78f9
Merge branch 'develop' into ISX-1823-cut-copy-between-windows
graham-huws May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ however, it has to be formatted properly to pass verification tests.
- Fixed InputManager.asset file growing in size on each Reset call.
- Fixed Opening InputDebugger throws 'Action map must have state at this point' error.
- Fixed Cut/Paste behaviour to match Editor - Cut items will now be cleared from clipboard after pasting.
- Fixed Pasting items between Input Action Editor windows having no effect until an item in the Action Map/Action lists was selected.
- Improved window layout to avoid elements being hidden (both the Input Actions in Project Settings, and standalone Input Actions Editor windows).
- Fixed InputAction asset appearing dirty after rename [ISXB-695](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-749).
- Fixed Error logged when InputActionEditor window opened without a valid asset.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public InputActionsEditorState SelectBinding(int index)
//if no binding selected (due to no bindings in list) set selection type to action
if (index == -1)
return With(selectedBindingIndex: index, selectionType: SelectionType.Action);
return With(selectedBindingIndex: index);
return With(selectedBindingIndex: index, selectionType: SelectionType.Binding);
}

public InputActionsEditorState SelectAction(int index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ private bool HasAssetChanged(SerializedObject serializedAsset)
return newAssetJson != m_AssetJson;
}

private void OnFocus()
{
// Apply focus here so that Paste works when users tab into the window (handled in InputActionsEditorView)
rootVisualElement.Focus();
}

private void OnLostFocus()
{
// Auto-save triggers on focus-lost instead of on every change
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)

if (allowUICommandExecution)
{
// NB: Paste is handled in InputActionsEditorView.
switch (evt.commandName)
{
case CmdEvents.Rename:
Expand All @@ -173,11 +174,6 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)
case CmdEvents.Cut:
CutItems();
break;
case CmdEvents.Paste:
var isActionCopied = CopyPasteHelper.GetCopiedClipboardType() == typeof(InputAction);
if (CopyPasteHelper.HasPastableClipboardData(typeof(InputActionMap)))
PasteItems(isActionCopied);
break;
default:
return; // Skip StopPropagation if we didn't execute anything
}
Expand All @@ -191,6 +187,7 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)
private void OnValidateCommand(ValidateCommandEvent evt)
{
// Mark commands as supported for Execute by stopping propagation of the event
// Paste is handled in InputActionsEditorView.
switch (evt.commandName)
{
case CmdEvents.Rename:
Expand All @@ -199,7 +196,6 @@ private void OnValidateCommand(ValidateCommandEvent evt)
case CmdEvents.Duplicate:
case CmdEvents.Copy:
case CmdEvents.Cut:
case CmdEvents.Paste:
evt.StopPropagation();
break;
}
Expand All @@ -211,7 +207,8 @@ private void OnPointerDown(PointerDownEvent evt)
if (evt.button == (int)MouseButton.RightMouse && evt.clickCount == 1)
{
var actionMap = (evt.target as VisualElement).GetFirstAncestorOfType<InputActionMapsTreeViewItem>();
m_ListView.SetSelection(actionMap.parent.IndexOf(actionMap));
if (actionMap != null)
m_ListView.SetSelection(actionMap.parent.IndexOf(actionMap));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)

if (allowUICommandExecution)
{
// NB: Paste is handled in InputActionsEditorView.
var data = (ActionOrBindingData)m_ActionsTreeView.selectedItem;
switch (evt.commandName)
{
Expand All @@ -409,11 +410,6 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)
case CmdEvents.Cut:
CutItems();
break;
case CmdEvents.Paste:
var hasPastableData = CopyPasteHelper.HasPastableClipboardData(data.isAction ? typeof(InputAction) : typeof(InputBinding));
if (hasPastableData)
PasteItems();
break;
default:
return; // Skip StopPropagation if we didn't execute anything
}
Expand All @@ -427,6 +423,7 @@ private void OnExecuteCommand(ExecuteCommandEvent evt)
private void OnValidateCommand(ValidateCommandEvent evt)
{
// Mark commands as supported for Execute by stopping propagation of the event
// Paste is handled in InputActionsEditorView.
switch (evt.commandName)
{
case CmdEvents.Rename:
Expand All @@ -435,7 +432,6 @@ private void OnValidateCommand(ValidateCommandEvent evt)
case CmdEvents.Duplicate:
case CmdEvents.Copy:
case CmdEvents.Cut:
case CmdEvents.Paste:
evt.StopPropagation();
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,13 @@ private static void PasteActionsFromClipboard(InputActionsEditorState state, boo
: Selectors.GetSelectedActionMap(state)?.wrappedProperty;
var actionArray = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Actions));
if (actionArray == null) return;

var index = state.selectedActionIndex;
if (addLast)
if (addLast || index >= actionArray.arraySize)
index = actionArray.arraySize - 1;
if (index < 0)
index = 0;
graham-huws marked this conversation as resolved.
Show resolved Hide resolved

PasteData(EditorHelpers.GetSystemCopyBufferContents(), new[] {index}, actionArray);
}

Expand All @@ -222,6 +226,11 @@ private static void PasteBindingsFromClipboard(InputActionsEditorState state)
var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
var bindingsArray = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Bindings));
var actions = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Actions));

// Don't do anything if there's no valid array to paste into.
if (state.selectedActionIndex == -1 || actions == null || actions.arraySize == 0 || bindingsArray == null)
return;

var index = state.selectionType == SelectionType.Action ? Selectors.GetBindingIndexBeforeAction(actions, state.selectedActionIndex, bindingsArray) : state.selectedBindingIndex;
PasteData(EditorHelpers.GetSystemCopyBufferContents(), new[] {index}, bindingsArray);
}
Expand Down Expand Up @@ -298,13 +307,16 @@ private static void PasteAction(SerializedProperty arrayProperty, string jsonToI
private static int PasteBindingOrComposite(SerializedProperty arrayProperty, string json, int index, string actionName, bool createCompositeParts = true)
{
var pastePartOfComposite = IsPartOfComposite(json);
if (index > 0)
var currentPropertyIndex = index - 1;
// We don't care about these checks if the array index is invalid
if (currentPropertyIndex >= 0 && currentPropertyIndex < arrayProperty.arraySize)
{
var currentProperty = arrayProperty.GetArrayElementAtIndex(index - 1);
var currentProperty = arrayProperty.GetArrayElementAtIndex(currentPropertyIndex);
var currentIsComposite = IsComposite(currentProperty) || IsPartOfComposite(currentProperty);
if (pastePartOfComposite && !currentIsComposite) //prevent pasting part of composite into non-composite
return index;
}

index = pastePartOfComposite || s_State.selectionType == SelectionType.Action ? index : Selectors.GetSelectedBindingIndexAfterCompositeBindings(s_State) + 1;
if (json.Contains(k_BindingData)) //copied data is composite with bindings - only true for directly copied composites, not for composites from copied actions
return PasteCompositeFromJson(arrayProperty, json, index, actionName);
Expand Down Expand Up @@ -361,7 +373,7 @@ private static bool IsPartOfComposite(string json)
private static SerializedProperty AddElement(SerializedProperty arrayProperty, string name, int index = -1)
{
var uniqueName = InputActionSerializationHelpers.FindUniqueName(arrayProperty, name);
if (index < 0)
if (index < 0 || index > arrayProperty.arraySize)
graham-huws marked this conversation as resolved.
Show resolved Hide resolved
index = arrayProperty.arraySize;

arrayProperty.InsertArrayElementAtIndex(index);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
using CmdEvents = UnityEngine.InputSystem.Editor.InputActionsEditorConstants.CommandEvents;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -86,6 +87,10 @@ public InputActionsEditorView(VisualElement root, StateContainer stateContainer,
selectedControlSchemeIndex = state.selectedControlSchemeIndex,
selectedDeviceIndex = state.selectedDeviceRequirementIndex
});

root.RegisterCallback<ValidateCommandEvent>(OnValidateCommand);
root.RegisterCallback<ExecuteCommandEvent>(OnExecuteCommand);
root.focusable = true; // Required for CommandEvents to work
}

private void OnReset()
Expand Down Expand Up @@ -221,6 +226,36 @@ public class ViewState
public int selectedControlSchemeIndex;
public int selectedDeviceIndex;
}

void OnExecuteCommand(ExecuteCommandEvent evt)
graham-huws marked this conversation as resolved.
Show resolved Hide resolved
{
if (evt.commandName != CmdEvents.Paste)
return;

var copiedType = CopyPasteHelper.GetCopiedClipboardType();

if (copiedType == typeof(InputActionMap))
{
evt.StopPropagation();
Dispatch(Commands.PasteActionMaps());
}
else if (copiedType == typeof(InputAction) || copiedType == typeof(InputBinding))
{
evt.StopPropagation();
Dispatch(Commands.PasteActionsOrBindings());
}
}

void OnValidateCommand(ValidateCommandEvent evt)
{
// Mark commands as supported for Execute by stopping propagation of the event
switch (evt.commandName)
{
case CmdEvents.Paste:
evt.StopPropagation();
break;
}
}
}

internal static partial class Selectors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static int GetSelectedBindingIndexAfterCompositeBindings(InputActionsEdit
var item = new SerializedInputBinding(bindings?.GetArrayElementAtIndex(state.selectedBindingIndex));
var index = state.selectedBindingIndex + (item.isComposite || item.isPartOfComposite ? 1 : 0);
var toSkip = 0;
while (new SerializedInputBinding(bindings?.GetArrayElementAtIndex(index)).isPartOfComposite)
while (index < bindings.arraySize && new SerializedInputBinding(bindings?.GetArrayElementAtIndex(index)).isPartOfComposite)
{
toSkip++;
index++;
Expand Down