You basically have to set up a framework for it yourself. Here’s a simple example using the new input system:
using UnityEngine.InputSystem;
public struct Hotkey
{
public Key key;
public bool alt;
public bool ctrl;
public bool shift;
public Hotkey(Key key, bool alt = false, bool ctrl = false, bool shift = false)
{
this.key = key;
this.alt = alt;
this.ctrl = ctrl;
this.shift = shift;
}
public bool WasPressed()
{
var result = true;
if (!Keyboard.current[key].wasPressedThisFrame) result = false;
if (alt && !Keyboard.current.altKey.wasPressedThisFrame) result = false;
if (ctrl && !Keyboard.current.ctrlKey.wasPressedThisFrame) result = false;
if (shift && !Keyboard.current.shiftKey.wasPressedThisFrame) result = false;
return result;
}
}
Hotkey hk = new Hotkey(Key.E, false, true, true);
if (hk.WasPressed())
{
// do stuff
}
You just check the input key every frame and then yield. But honestly, responding to input within a coroutine feels wrong to me. It would probably work but you should consider putting the input in Update and whatever coroutine that you need running can then while over some bool like didPlayerPressJump or whatever.
But generally speaking: coroutines are a terrible system for running game logic. They have their use as a simple kind of event that waits for a while and then does something. I practically never use them for anything but deferred execution. Once you find yourself calling StopCoroutine to StartCoroutine another, you should move away from coroutines altogether because in most cases this means trying to implement a statemachine with coroutines, and that’ll be terrible to manage and debug as you have no concrete “I’m in this state” variable to check for.