SMAPI - Stardew Modding API

SMAPI - Stardew Modding API

971k Downloads

Add multi-key binding API

Pathoschild opened this issue ยท 4 comments

commented

Add a multi-key binding utility to SMAPI, which mods could optionally use in their config files. That would let players set both keyboard and controller keys for split-screen mode.

Design goals

  • Keybind functionality:
    • An action can have multiple bindings (e.g. both P and ControllerA).
    • A binding can consist of multiple keys (e.g. press both Ctrl and S at once).
    • Multi-key bindings are commutative (i.e. Ctrl + S and S + Ctrl have the same effect).
  • Config support:
    • Key bindings can be used directly in config.json models.
    • An SButton value in a pre-existing config.json file can be mapped to a Keybind field (i.e. SButton fields are forward-compatible with Keybind).
  • Limitations:
    • Overlapping bindings aren't resolved automatically (similar to existing single-key bindings). For example, if you register both CTRL + S and S as separate bindings, both would be triggered when you press both CTRL and S. It's up to the mod(s) to determine the priority by which they check bindings.

See #630 for a proposed larger keybind registration API.

commented

Proposed design

Let's say a mod's menu should open when you press P, or press both LeftShoulder and ControllerA.

SMAPI mods could use a KeybindList class in their config model and specify a default value directly:

public class ModConfig
{
    public KeybindList OpenMenuKey { get; set; } = new KeybindList("P, LeftShoulder + ControllerA");
}

This would be (de)serialized to a string value automatically for user readability:

{
   "OpenMenuKey": "P, LeftShoulder + ControllerA"
}

Usually mods would call a JustPressed method to check whether it was activated this tick (i.e. not held from a previous tick):

if (config.OpenMenuKey.JustPressed())
   this.OpenMenu();

But the class would provide other methods to use as needed:

bool isDown = keybind.IsDown();
SButtonState state = keybind.GetState(); // e.g. Pressed, Held, Released, or None
string readableForm = keybind.ToString();

KeybindList would support multiple keybindings, but mods could access the individual keybinds if needed:

if (openKey.JustPressed())
{
    this.OpenMenu();
    this.Monitor.Log($"Press {openKey.Bindings.First(p => p.JustPressed())} again to disable the menu.", LogLevel.Info);
}
commented

Would it be possible to make it backwards compatible with SButton (so changing the ModConfig.OpenMenuKey type from SButton to KeybindList would read the old value correctly)?

I wonder how I'm supposed to support this in GMCM. :P

commented

Yep, SButton (de)serializes to string too so your existing config.json files would get parsed as a keybind with one button. I'll add that as an explicit design goal though.

commented

Done in develop for the upcoming SMAPI 3.9. See documentation on the wiki for details.