Line 6: |
Line 6: |
| ===Check button state=== | | ===Check button state=== |
| <dl> | | <dl> |
− | <dt><tt>IsDown</tt></dt> | + | <dt><samp>IsDown</samp></dt> |
| <dd> | | <dd> |
− | You can check if any [[#SButton|controller/keyboard/mouse button]] is currently pressed by calling the <tt>IsDown(button)</tt> method. For example: | + | You can check if any [[#SButton|controller/keyboard/mouse button]] is currently pressed by calling the <samp>IsDown(button)</samp> method. For example: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| bool isShiftPressed = this.Helper.Input.IsDown(SButton.LeftShift) || this.Helper.Input.IsDown(SButton.RightShift); | | bool isShiftPressed = this.Helper.Input.IsDown(SButton.LeftShift) || this.Helper.Input.IsDown(SButton.RightShift); |
− | </source> | + | </syntaxhighlight> |
| </dd> | | </dd> |
| | | |
− | <dt><tt>GetState</tt></dt> | + | <dt><samp>GetState</samp></dt> |
| <dd> | | <dd> |
| For more finetuned control, you can check the [[#SButton|button]] state relative to the previous game tick: | | For more finetuned control, you can check the [[#SButton|button]] state relative to the previous game tick: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| SButtonState state = this.Helper.Input.GetState(SButton.LeftShift); | | SButtonState state = this.Helper.Input.GetState(SButton.LeftShift); |
| bool isDown = (state == SButtonState.Pressed || state == SButtonState.Held); | | bool isDown = (state == SButtonState.Pressed || state == SButtonState.Held); |
− | </source> | + | </syntaxhighlight> |
| Available button states: | | Available button states: |
| {| class="wikitable" | | {| class="wikitable" |
Line 30: |
Line 30: |
| | up | | | up |
| | up | | | up |
− | | <tt>None</tt> | + | | <samp>None</samp> |
| |- | | |- |
| | up | | | up |
| | down | | | down |
− | | <tt>Pressed</tt> | + | | <samp>Pressed</samp> |
| |- | | |- |
| | down | | | down |
| | down | | | down |
− | | <tt>Held</tt> | + | | <samp>Held</samp> |
| |- | | |- |
| | down | | | down |
| | up | | | up |
− | | <tt>Released</tt> | + | | <samp>Released</samp> |
| |} | | |} |
| </dd> | | </dd> |
Line 48: |
Line 48: |
| | | |
| ===Check cursor position=== | | ===Check cursor position=== |
− | The <tt>GetCursorPosition()</tt> method provides the [[#ICursorPosition|cursor position in three coordinate systems|ICursorPosition]]. | + | The <samp>GetCursorPosition()</samp> method provides the [[#ICursorPosition|cursor position in three coordinate systems]]. |
| | | |
| For example: | | For example: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| // draw text at the cursor position | | // draw text at the cursor position |
| ICursorPosition cursorPos = this.Helper.Input.GetCursorPosition(); | | ICursorPosition cursorPos = this.Helper.Input.GetCursorPosition(); |
| Game1.spriteBatch.DrawString(Game1.smallFont, "some text", cursorPos.ScreenPixels, Color.Black); | | Game1.spriteBatch.DrawString(Game1.smallFont, "some text", cursorPos.ScreenPixels, Color.Black); |
− | </source> | + | </syntaxhighlight> |
| | | |
| ===Suppress input=== | | ===Suppress input=== |
| You can prevent the game from handling any [[#SButton|controller/keyboard/mouse button press]] (including clicks) by ''suppressing'' it. This suppression will remain in effect until the player releases the button. This won't prevent other mods from handling it. | | You can prevent the game from handling any [[#SButton|controller/keyboard/mouse button press]] (including clicks) by ''suppressing'' it. This suppression will remain in effect until the player releases the button. This won't prevent other mods from handling it. |
| + | |
| + | {| class="wikitable" |
| + | |- |
| + | ! method |
| + | ! effect |
| + | |- |
| + | | <code>Suppress</code> |
| + | | Suppress the specified [[#SButton|<samp>SButton</samp>]] value. |
| + | |- |
| + | | <code>SuppressActiveKeybinds</code> |
| + | | For the given [[#KeybindList|<samp>KeybindList</samp>]], suppress every button that's part of an activated keybind. |
| + | |- |
| + | | <code>IsSuppressed</code> |
| + | | Get whether the specified [[#SButton|<samp>SButton</samp>]] value is currently suppressed. |
| + | |} |
| | | |
| For example: | | For example: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| // prevent game from seeing that LeftShift is pressed | | // prevent game from seeing that LeftShift is pressed |
| this.Helper.Input.Suppress(SButton.LeftShift); | | this.Helper.Input.Suppress(SButton.LeftShift); |
Line 70: |
Line 85: |
| // check if a button is being suppressed: | | // check if a button is being suppressed: |
| bool suppressed = this.Helper.Input.IsSuppressed(SButton.LeftShift); | | bool suppressed = this.Helper.Input.IsSuppressed(SButton.LeftShift); |
− | </source> | + | </syntaxhighlight> |
| | | |
| Side-effects: | | Side-effects: |
| <ul> | | <ul> |
− | <li>The [[Modding:Modder Guide/APIs/Events#Input.ButtonReleased|<tt>ButtonReleased</tt> event]] will be raised on the next tick for the suppressed input.</li> | + | <li>The [[Modding:Modder Guide/APIs/Events#Input.ButtonReleased|<samp>ButtonReleased</samp> event]] will be raised on the next tick for the suppressed input.</li> |
− | <li>Methods like <tt>helper.Input.IsDown(button)</tt> and <tt>helper.Input.GetState(button)</tt> will show the button as released for the duration of the suppression, even if it's physically still pressed. You can use <tt>helper.Input.IsSuppressed(button)</tt> to check if that's the case (it will only be true until the button is physically released): | + | <li>Methods like <samp>helper.Input.IsDown(button)</samp> and <samp>helper.Input.GetState(button)</samp> will show the button as released for the duration of the suppression, even if it's physically still pressed. You can use <samp>helper.Input.IsSuppressed(button)</samp> to check if that's the case (it will only be true until the button is physically released): |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| bool isPhysicallyDown = helper.Input.IsDown(button) || helper.Input.IsSuppressed(button); | | bool isPhysicallyDown = helper.Input.IsDown(button) || helper.Input.IsSuppressed(button); |
− | </source></li> | + | </syntaxhighlight></li> |
| </ul> | | </ul> |
| | | |
| ==Data structures== | | ==Data structures== |
| ===SButton=== | | ===SButton=== |
− | SMAPI's <tt>SButton</tt> is a constant which includes every [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb975202(v%3dxnagamestudio.40) controller], [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb197781(v%3dxnagamestudio.40) keyboard], and [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb198097(v%3dxnagamestudio.40) mouse] button. SMAPI events use this to let you handle button presses without needing separate code for each. See [[Modding:Player Guide/Key Bindings]] for a list of values. | + | SMAPI's <samp>SButton</samp> is a constant which includes every [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb975202(v%3dxnagamestudio.40) controller], [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb197781(v%3dxnagamestudio.40) keyboard], and [https://docs.microsoft.com/en-us/previous-versions/windows/xna/bb198097(v%3dxnagamestudio.40) mouse] button. SMAPI events use this to let you handle button presses without needing separate code for each. See [[Modding:Player Guide/Key Bindings]] for a list of values. |
| | | |
− | SMAPI provides extensions to convert any of the other constants to <tt>SButton</tt>: | + | SMAPI provides extensions to convert any of the other constants to <samp>SButton</samp>: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| SButton key = Keys.A.ToSButton(); // SButton.A | | SButton key = Keys.A.ToSButton(); // SButton.A |
| SButton button = Buttons.A.ToSButton(); // SButton.ControllerA | | SButton button = Buttons.A.ToSButton(); // SButton.ControllerA |
| SButton input = new InputButton(true).ToSButton(); // SButton.MouseLeft | | SButton input = new InputButton(true).ToSButton(); // SButton.MouseLeft |
− | </source> | + | </syntaxhighlight> |
| | | |
− | You can also convert <tt>SButton</tt> to the other constants. This uses a <tt>TryGet</tt> approach since <tt>SButton</tt> is a superset of the others (e.g. you can't convert <tt>SButton.ControllerA</tt> to a keyboard value): | + | You can also convert <samp>SButton</samp> to the other constants. This uses a <samp>TryGet</samp> approach since <samp>SButton</samp> is a superset of the others (''e.g.,'' you can't convert <samp>SButton.ControllerA</samp> to a keyboard value): |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| SButton value = SButton.A; | | SButton value = SButton.A; |
| if (value.TryGetKeyboard(out Keys key)) | | if (value.TryGetKeyboard(out Keys key)) |
Line 101: |
Line 116: |
| if (value.TryGetStardewInput(out InputButton input)) | | if (value.TryGetStardewInput(out InputButton input)) |
| ...; | | ...; |
− | </source> | + | </syntaxhighlight> |
| | | |
| Two last extensions let you check how the button is mapped in the game: | | Two last extensions let you check how the button is mapped in the game: |
− | <source lang="c#"> | + | <syntaxhighlight lang="c#"> |
| SButton button = SButton.MouseLeft; | | SButton button = SButton.MouseLeft; |
| if (button.IsUseToolButton()) | | if (button.IsUseToolButton()) |
Line 110: |
Line 125: |
| else if (button.IsActionButton()) | | else if (button.IsActionButton()) |
| // perform action | | // perform action |
− | </source> | + | </syntaxhighlight> |
| + | |
| + | You can use <samp>SButton</samp> values directly in your [[../Config|config model]], but <samp>[[#KeybindList|KeybindList]]</samp> is recommended instead in most cases. |
| + | |
| + | ===KeybindList=== |
| + | SMAPI's <samp>KeybindList</samp> utility lets you manage an arbitrary set of keybindings. A ''keybind list'' has any number of ''keybinds'', each of which has any number of [[#SButton|button codes]]. For example, the keybind list <code>"F2, LeftShift + S"</code> would be pressed if (a) <samp>F2</samp> is pressed, ''or'' (b) both <samp>LeftShift</samp> and <samp>S</samp> are pressed. |
| + | |
| + | You can use a <samp>KeybindList</samp> directly in [[../Config|your <samp>config.json</samp> model]]: |
| | | |
− | You can use <tt>SButton</tt> values directly in your [[../Config|config model]], and they'll be represented by their names:
| |
| {| class="wikitable" | | {| class="wikitable" |
− | | <source lang="c#"> | + | |- |
− | internal class ModConfig
| + | ! C# model |
| + | ! |
| + | ! JSON file |
| + | |- |
| + | | <syntaxhighlight lang="c#"> |
| + | class ModConfig |
| { | | { |
− | public SButton DoThingButton { get; set; } = SButton.LeftControl; | + | public KeybindList ToggleKey { get; set; } = KeybindList.Parse("LeftShift + F2"); |
| } | | } |
− | </source> | + | </syntaxhighlight> |
| | → | | | → |
− | | <source lang="json"> | + | | <syntaxhighlight lang="json"> |
| { | | { |
− | "DoThingButton": "LeftControl" | + | "ToggleKey": "LeftShift + F2" |
| } | | } |
− | </source> | + | </syntaxhighlight> |
| |} | | |} |
| | | |
− | ===KeybindList===
| + | And you can then check whether it's pressed directly in your code. For example, in a [[../Events|<samp>ButtonsChanged</samp> event handler]]: |
− | {{SMAPI upcoming|3.9}}
| |
− | | |
− | SMAPI's <tt>KeybindList</tt> utility lets you manage an arbitrary set of keybindings. A ''keybind list'' has any number of ''keybinds'', each of which has any number of [[#SButton|button codes]]. For example, the keybind list <code>"F2, LeftShift + S"</code> would be pressed if (a) <tt>F2</tt> is pressed, ''or'' (b) both <tt>LeftShift</tt> and <tt>S</tt> are pressed.
| |
| | | |
− | You can use a <tt>KeybindList</tt> directly in [[../Config|your <tt>config.json</tt> model]]:
| + | <syntaxhighlight lang="c#"> |
− | | |
− | <source lang="c#">
| |
− | class ModConfig
| |
− | {
| |
− | public KeybindList ToggleKey { get; set; } = KeybindList.Parse("Shift + F2");
| |
− | }
| |
− | </source>
| |
− | | |
− | And you can then check whether it's pressed directly in your code. For example, in a [[../Events|<tt>ButtonsChanged</tt> event handler]]:
| |
− | | |
− | <source lang="c#">
| |
| private void OnButtonsChanged(object sender, ButtonsChangedEventArgs e) | | private void OnButtonsChanged(object sender, ButtonsChangedEventArgs e) |
| { | | { |
Line 152: |
Line 164: |
| } | | } |
| } | | } |
− | </source> | + | </syntaxhighlight> |
| | | |
− | The <tt>KeybindList</tt> provides a number of methods depending on your use case: | + | The <samp>KeybindList</samp> provides a number of methods depending on your use case: |
| | | |
| {| class="wikitable" | | {| class="wikitable" |
Line 171: |
Line 183: |
| |- | | |- |
| | <code>GetState()</code> | | | <code>GetState()</code> |
− | | Get the overall [[#Check button state|keybind state relative to the previous tick]]. This state is transitive across keybinds; e.g. if the player releases one keybind and immediately presses another within the list, the overall state is <tt>Held</tt>. | + | | Get the overall [[#Check button state|keybind state relative to the previous tick]]. This state is transitive across keybinds; ''e.g.,'' if the player releases one keybind and immediately presses another within the list, the overall state is <samp>Held</samp>. |
| |- | | |- |
| | <code>IsDown()</code> | | | <code>IsDown()</code> |
− | | Get whether any keybind in the list is currently down (i.e. the player pressed or is holding down the keys). | + | | Get whether any keybind in the list is currently down (''i.e.,'' the player pressed or is holding down the keys). |
| |- | | |- |
| | <code>JustPressed()</code> | | | <code>JustPressed()</code> |
− | | Get whether the player just activated the keybind during the current tick (i.e. <code>GetState()</code> returns <tt>Pressed</tt> instead of <tt>Held</tt>). | + | | Get whether the player just activated the keybind during the current tick (''i.e.,'' <code>GetState()</code> returns <samp>Pressed</samp> instead of <samp>Held</samp>). |
| |- | | |- |
| | <code>GetKeybindCurrentlyDown()</code> | | | <code>GetKeybindCurrentlyDown()</code> |
− | | Get the individual <tt>Keybind</tt> in the list which is currently down, if any. If there are multiple keybinds down, the first one is returned. | + | | Get the individual <samp>Keybind</samp> in the list which is currently down, if any. If there are multiple keybinds down, the first one is returned. |
| |- | | |- |
| | <code>ToString()</code> | | | <code>ToString()</code> |
− | | Get a string representation of the input binding (e.g. <code>"F2, LeftShift + S"</code>). | + | | Get a string representation of the input binding (''e.g.,'' <code>"F2, LeftShift + S"</code>). |
| |} | | |} |
| | | |
| Caveats: | | Caveats: |
− | * '''Don't use the <tt>ButtonPressed</tt> [[../Events|event]] to check keybinds''', since it's raised once for each button pressed. If the player presses two keys at once, your keybind would be activated twice. Use <tt>ButtonsChanged</tt> instead. | + | * '''Don't use the <samp>ButtonPressed</samp> [[../Events|event]] to check keybinds''', since it's raised once for each button pressed. If the player presses two keys at once, your keybind would be activated twice. Use <samp>ButtonsChanged</samp> instead. |
| | | |
| ===ICursorPosition=== | | ===ICursorPosition=== |
− | SMAPI's <tt>ICursorPosition</tt> provides the cursor position in four coordinate systems: | + | SMAPI's <samp>ICursorPosition</samp> provides the cursor position in four coordinate systems: |
− | * <tt>AbsolutePixels</tt> is the pixel position relative to the top-left corner of the in-game map, adjusted for [[Modding:Modder Guide/Game Fundamentals#Zoom level|zoom]] but not [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]. | + | * <samp>AbsolutePixels</samp> is the pixel position relative to the top-left corner of the in-game map, adjusted for [[Modding:Modder Guide/Game Fundamentals#Zoom level|zoom]] but not [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]. |
− | * <tt>ScreenPixels</tt> is the pixel position relative to the top-left corner of the visible screen, adjusted for [[Modding:Modder Guide/Game Fundamentals#Zoom level|zoom]] but not [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]. | + | * <samp>ScreenPixels</samp> is the pixel position relative to the top-left corner of the visible screen, adjusted for [[Modding:Modder Guide/Game Fundamentals#Zoom level|zoom]] but not [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]. |
− | * <tt>Tile</tt> is the [[Modding:Modder Guide/Game Fundamentals#Tiles|tile position]] under the cursor. | + | * <samp>Tile</samp> is the [[Modding:Modder Guide/Game Fundamentals#Tiles|tile position]] under the cursor. |
− | * <tt>GrabTile</tt> is the tile position that the game considers under the cursor for the purposes of clicking actions. This automatically accounts for controller mode. This may be different than <tt>Tile</tt> if that's too far from the player. | + | * <samp>GrabTile</samp> is the tile position that the game considers under the cursor for the purposes of clicking actions. This automatically accounts for controller mode. This may be different than <samp>Tile</samp> if that's too far from the player. |
| | | |
− | This is returned by the <tt>this.Helper.Input.GetCursorPosition()</tt> method and in the event args for some input events. | + | This is returned by the <samp>this.Helper.Input.GetCursorPosition()</samp> method and in the event args for some input events. |
| | | |
− | '''The pixel positions are ''not'' adjusted for [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]''' (i.e. they're non-UI mode). Whether you need UI or non-UI positions depends how you're using them, so you can use <tt>cursorPos.GetScaledAbsolutePixels()</tt> or <tt>cursorPos.GetScaledScreenPixels()</tt> to adjust them automatically for the current mode or <tt>Utility.ModifyCoordinatesForUIScale</tt> to always get UI mode coordinates. | + | '''The pixel positions are ''not'' adjusted for [[Modding:Modder Guide/Game Fundamentals#UI scaling|UI scaling]]''' (''i.e.,'' they're non-UI mode). Whether you need UI or non-UI positions depends how you're using them, so you can use <samp>cursorPos.GetScaledAbsolutePixels()</samp> or <samp>cursorPos.GetScaledScreenPixels()</samp> to adjust them automatically for the current mode or <samp>Utility.ModifyCoordinatesForUIScale</samp> to always get UI mode coordinates. |
| | | |
| ==See also== | | ==See also== |
| * [[../Events#Input|Input events]] | | * [[../Events#Input|Input events]] |
− | * [[Modding:Player Guide/Key Bindings]] for a list of valid <tt>SButton</tt> values | + | * [[Modding:Player Guide/Key Bindings]] for a list of valid <samp>SButton</samp> values |
| + | |
| + | [[zh:模组:制作指南/APIs/Input]] |