Help with Input System + holding key + coroutine behaviour

Hello guys,
I can’t make my automatic fire routine behave correctly using the Input System.
In the old system, I could just listen for a GetKey input in Update and start a fire coroutine (looped using, let’s say, yield new WaitForSeconds(1f / fireRate)).
With the new system, the coroutine starts and loops correctly just once, then starts spamming bullets every frame.

Let’s say I have this setup:

  • Turret (parent object)
    • Hardpoint (child of Turret)
      • Weapon (child of Hardpoint)

This is the Weapon script:

using UnityEngine;
using System.Collections;

public class Weapon : MonoBehaviour
{
    public Transform bulletOrigin;
    public GameObject bulletPrefab;
    public float bulletSpeed;
    public float bulletLife;
    public float fireRate;

    private bool canFire;

    private void Start()
    {
        canFire = true;
    }

    public IEnumerator FireWeapon()
    {
        if (canFire)
        {
            canFire = false;
            GameObject bullet = Instantiate(bulletPrefab, bulletOrigin.position, bulletOrigin.rotation);
            bullet.GetComponent<Bullet>().destroyTime = bulletLife;
            bullet.GetComponent<Rigidbody>().linearVelocity = bulletOrigin.forward * bulletSpeed;
        }
        
        yield return new WaitForSeconds(1f / fireRate);

        canFire = true;
    }
}

And this is the input script, attached to the Turret:

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

public class TurretFire : MonoBehaviour
{
    private float fireInput;

    public List<GameObject> hardpoints;
    
    private void Update()
    {
        if (fireInput > 0.1f || fireInput < -0.1f)
        {
            FireInvoked();
        }
    }

    public void OnTurretFire(InputAction.CallbackContext context)
    {
        fireInput = context.ReadValue<float>();
    }

    private void FireInvoked()
    {
        foreach (GameObject hardpoint in hardpoints)
        {
            GameObject weapon = hardpoint.transform.GetChild(0).gameObject;
            StartCoroutine(weapon.GetComponent<Weapon>().FireWeapon());
        }
    }
}

(Note: before you ask, in a separate input handler script I subscribe to both performed and canceled actions)

The code, as said above, doesn’t run correctly. If I keep the fire button pressed (mapped on Left Mouse button), the delay from the 1st and 2nd button is correct, then from the 2nd bullet onwards they start spamming every frame.

With the “old method” it works:

(Update function in Weapon script)

private void Update()
{
    If (Input.GetKey(...))
    {
        StartCoroutine(FireWeapon());
    }
}

What’s wrong in the input script?

Thanks in advance!

Coroutines. They are not appropriate for this problem. Don’t use coroutines here.

Cooldown timers, gun bullet intervals, shot spacing, rate of fire:

GunHeat (gunheat) spawning shooting rate of fire: