Forum rules - please read before posting.

Detecting Controller Axis input, mouse input, and keyboard input - and switching on the fly.

So, I'm a big fan of seamless integration of control scheme switching without the use of a settings menu. I like it when you're playing a game with mouse and keyboard, but then you want to use your controller for a specific section, and the game just swaps over to controller input without having to pause.

So that's what I've been trying to set up, but I'm banging my head against a wall because I can't get it quite right.

Vitals
Unity 2021.3.5f1 (I know I should probably update, but I just haven't wanted to lately)
Adventure Creator 1.79.3
Unity Input System 1.3.0

So I've got my project set up to use the Input System Package rather than Input Manager, and I took a script from this forum to start my efforts to create a swapping script.

Currently the script knows if you've clicked with the mouse and then switches to mouse input using point and click movement, and detects if you hit a key on the keyboard and switches to keyboard or controller with direct input. It also swaps around the mouse cursor show/hide, etc. Currently it does not detect face buttons on the controller to engage keyboard or controller, but I had that working earlier. I just took it out because of the problem below.

What I'm at my wits end about - and this is after I've tried a bunch of different alternate methods to pick up analog stick input from the controller, using totally different methods for doing so, but it never works right - likely due to the fact that I am an AWFUL programmer. I don't want the face buttons to be the swap to controller method, even though I had that working, because the instinct for most players (myself included) is "If I push the analog stick, it should switch to the controller."

Does anyone have any ideas about how to make this work?

Script as follows:

using AC;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;

public class DetectInputMethod : MonoBehaviour
{

    public InputMethod defaultInputMethod;

    private void Start ()
    {
        //SetInputMethod (defaultInputMethod);
    }

    private void OnGUI ()
    {
        Event currentEvent = Event.current;
        if (currentEvent != null)
        {
            switch (currentEvent.type)
            {
                case EventType.Repaint:
                case EventType.Layout:
                    return;

                default:
                    break;
            }

            if (currentEvent.keyCode == KeyCode.Escape)
            {
                return;
            }

            if (currentEvent.isMouse)
            {
                Debug.Log ("Switch to mouse input. Event type: " + currentEvent.type);
                SetInputMethod (InputMethod.MouseAndKeyboard);
                AC.KickStarter.settingsManager.movementMethod = MovementMethod.PointAndClick;
                AC.KickStarter.cursorManager.allowMainCursor = true;
            }

            else
            {

                Debug.Log ("Switch to direct input. Event type: " + currentEvent.type + ", Keycode: " + currentEvent.keyCode);
                SetInputMethod (InputMethod.KeyboardOrController);
                AC.KickStarter.settingsManager.movementMethod = MovementMethod.Direct;
                AC.KickStarter.cursorManager.allowMainCursor = false;
            }
        }
    }

    private void SetInputMethod (InputMethod inputMethod)
    {
        if (KickStarter.settingsManager.inputMethod != inputMethod)
        {
            KickStarter.settingsManager.inputMethod = inputMethod;

            bool directMenuControl = (inputMethod == InputMethod.KeyboardOrController);

            KickStarter.menuManager.keyboardControlWhenPaused = directMenuControl;
            KickStarter.menuManager.keyboardControlWhenDialogOptions = directMenuControl;
            KickStarter.menuManager.keyboardControlWhenCutscene = directMenuControl;

            foreach (Menu menu in PlayerMenus.GetMenus ())
            {
                menu.autoSelectFirstVisibleElement = directMenuControl;
            }
        }
    }

}

Comments

  • Apologies for the post temporarily being hidden - it can happen sometimes if you edit a post. I've verified your account, so it shouldn't happen again.

    Just so I'm clear: this issue is about wanting the input method to only change to Keyboard Or Controller if you detect an axis move, and ignore face buttons?

    I think the issue above is that you're using Unity's built-in Event system - and not reading from the new Input System directly.

    In my experience, getting Input System to report what scheme you're currently using is actually quite tricky. The way AC's own Input System integration (available on the Downloads page) handles is this to hook into each input's "performed" event, and then iterate through the various devices to find the one that matches that input.

    You can find this technique in the ControlsReader script's OnInputActionPerformed function.

    This package automatically supports the switching of AC's Input method based on the current device, however. If you don't mind face buttons also allowing for a switch, it might be enough for you to use without the added script.

    If you want to make further changes upon switching device (for example, change the direct-control Menu options), you can hook into the Controls Reader component's On Set Control Scheme event, which passes the control sceheme as a string parameter.

  • Actually, I figured this out last night before the post even showed. I'll explain the goal and then the solution in case anyone else ever runs into this, so the forum will have a record.

    You're correct that the above code doesn't interface with the Input System. To clarify the issue: I had code that would switch to mouse & point and click if a mouse click was detected, or would switch to keyboard & controller and direct input if a keyboard input was detected (or a face button on the controller, but I stripped that code out in the above sample) - but it wasn't getting any controller axis input until AFTER switching to direct control. Like, if I used WASD it would switch and then I could use the controller's analog stick as normal, but it wouldn't register the analog input without a keyboard or face button press.

    The problem was twofold:

    1. The old unity Input Manager's event system doesn't recognize analog axis input as an "event" natively, and you have to do some strange behind the scenes stuff - I found solutions using .NET with IObservable or something, but I was like "There has to be an easier way." The Event system has no problems with face buttons as events, tho, which is why they worked fine with the above system.
    2. The Input System is very picky about being set up "just so" for everything to work right, and a lot of Unity's internal docs don't go over that setup in its entirety - they just say "don't worry about that right now". Unfortunately, for it to work the way I wanted it to, I did have to worry about that.

    My solution to get it to integrate with AC and do what I want:
    1. Set up the Input System fully.
    2. This meant generating a .inputsettings file for Project Settings to hook into, because I had to explicitly define supported devices - it says "just don't list any and it'll detect what you have" - that was not working for me, at least with AC integration
    3. Creating an explicitly named Control scheme and adding those devices (Mouse, Keyboard, Gamepad) to it, and making sure to set Gamepad to optional, the other two being required.
    4. I had already created an action map for the player, and actions for it. But for analog detection I had to create a new Action I named "AnalogInput" that only had the left analog stick and D-Pad tied to it.
    5. The Player Prefab AC picks up for the start point element HAS to have two new components on it: Player Input, and the script with your control swapping C# in it.
    6. The Player Input component on the prefab lets you define your Input System assets, which should be straightforward. For Behavior, I used Invoke Unity Events, because then I didn't have to dig into C# too much and could control the hookups in the editor. Under Player events, on AnalogInput, you can define what script is being used. This HAS to be the script component on your player prefab, NOT one in asset manager. Drag and drop into the field for it, and then under function you select the name of the script, and the function you're calling to swap.

    This could probably be done pretty quickly with code and NOT messing about with components, but as I said: I'm a terrible programmer, so the less I have to do in the guts the better.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.