games.noio.input-hints icon indicating copy to clipboard operation
games.noio.input-hints copied to clipboard

Bulk Configuring all Input Actions

Open STARasGAMES opened this issue 5 months ago • 3 comments

It's quite tedious to hunt for all input action paths, especially if your game supports key rebinding. It would be cool to have a built-in mechanism to populate Input Hints Config with all input paths. Here is what I ended up adding to InputHintsConfig.cs

        [ContextMenu("Auto Fill Sprites")]
        private void AutoFillSprites()
        {
            var layouts = InputSystem.ListLayouts()
                .Select(InputSystem.LoadLayout)
                .Where(l => l.isGenericTypeOfDevice);
            var validLayoutNames = new HashSet<string>() { "Gamepad", "Keyboard", "Mouse" };
            
            foreach (var layout in layouts)
            {
                try
                {
                    if (validLayoutNames.Contains(layout.displayName) == false)
                        continue;
                    Debug.Log($"Processing layout {layout.displayName} {layout.name}");

                    Undo.RecordObject(this, $"{layout.displayName} Add Sprite Mapping");
                    var device = InputSystem.AddDevice(layout.name);
                    foreach (var control in device.allControls)
                    {
                        var relativePath = control.path.Substring(device.path.Length + 1);
                        var humanReadableString = InputControlPath.ToHumanReadableString(control.path, out _,
                            out var controlPath, InputControlPath.HumanReadableStringOptions.OmitDevice, control);
                        Debug.Log(
                            $"<{layout.name}>{relativePath} ({control.synthetic}) ({control.path}) ({humanReadableString}) ({controlPath})");
                        var sprite = _sprites.FirstOrDefault(x => x.ControlPath == controlPath);
                        if (sprite == null)
                        {
                            sprite = new ControlPathToSpriteMapping(controlPath, FirstCharToUpper(controlPath),
                                layout.displayName);
                            _sprites.Add(sprite);
                        }
                        else
                        {
                            sprite.SpriteName = FirstCharToUpper(controlPath);
                            sprite.SpriteCategory = layout.displayName;
                        }
                    }

                    EditorUtility.SetDirty(this);

                    InputSystem.RemoveDevice(device);
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                    Debug.LogError($"Error while processing layout {layout.displayName} ({layout.name})");
                }
            }

            LocalizationSettings.SelectedLocale = LocalizationSettings.SelectedLocale;

            OnChanged();
        }

STARasGAMES avatar Jul 05 '25 09:07 STARasGAMES

Ah yeah, that's cool!

But maybe it should go through the same path that's used for 'missing bindings' ?

(not sure if you have seen this but when the plugin tries to show a binding that you haven't added yet, it will add an entry with a button to add that binding and select a sprite)

noio avatar Jul 05 '25 11:07 noio

Ah I see! You're also auto-mapping the sprites! Based on the fact that their name is similar to the control path (upper case letter)..

I didn't do any magic there because I did not want to assume anything about the names of the sprites in the sprite sheet.

But maybe I should expose some more API so users can hook into the InputHintsConfig with some code like you posted here... (if they DO know things about the Sprite Names, that is..)

e.g. I should maybe expose _sprites or an "AddSprite" method or something..

noio avatar Jul 05 '25 11:07 noio

(not sure if you have seen this but when the plugin tries to show a binding that you haven't added yet, it will add an entry with a button to add that binding and select a sprite)

I saw that, and that's cool! The problem is with keyboard input rebinding, where players can choose whatever the hell they want. Like you can't prohibit a player from using Backspace as a MoveForward input action. Eventually you will add all the available paths anyway, so why not simply prefill ALL paths and let developers filter(delete from the list) paths they don't need or they have no icons for?

Even with gamepads: My game uses less than 50% of the available buttons, but it feels easier to config all available icons so that in the future you won't come back to this task, because 99% of the time you already have input path configured.

Ah I see! You're also auto-mapping the sprites!

Actually, I used "auto-mapping" only for letters, digits, and F1-F12. Every special key path(ctrl, alt, etc) and every gamepad input path I double checked using the incredible pick tool you've provided! To be on the safe side.

Also, instead of some fancy auto-mapping editor interface shenanigans, it would be better simply to mark invalid sprite names in the list with a red color or some error icon.

STARasGAMES avatar Jul 07 '25 10:07 STARasGAMES