OK, here’s what I’ve figured out. The type of the action needs to be Value, not Button or Pass Through—this can be changed in the editor by selecting the action from the list; there’s a drop down available in its settings. (Don’t forget to save the asset and regenerate the C# code.)
Once this is done, the button behaves more like an axis, and invokes
.canceled on its release. For a hold action, you can use a coroutine; simply set a control boolean to true and call
StartCoroutine with it in your
.performed callback. When the button or control is released, it will trigger
.canceled, which can call another function that toggles the boolean back to false, and breaks the internal control loop in your coroutine allowing it to exit.
This allows for one action to be performed for a brief press, and another to be performed after a hold in continuum, until the button is released.