-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
343 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using Promete.Example.Kernel; | ||
using Promete.Input; | ||
using Silk.NET.Input; | ||
|
||
namespace Promete.Example.examples.experimental; | ||
|
||
[Demo("input/gamepad.demo", "ゲームパッドの入力確認")] | ||
public class GamepadExampleScene(ConsoleLayer console, Keyboard keyboard, Gamepads pads) : Scene | ||
{ | ||
private Gamepad? CurrentPad => pads[0]; | ||
|
||
public override void OnUpdate() | ||
{ | ||
console.Clear(); | ||
if (CurrentPad is null || !CurrentPad.IsConnected) | ||
{ | ||
console.Print("Connect a gamepad!"); | ||
return; | ||
} | ||
|
||
console.Print($"Name: {CurrentPad.Name}"); | ||
console.Print($"Supports Motor: {(CurrentPad.IsVibrationSupported ? "Yes" : "No")}"); | ||
console.Print($"Left Stick: {CurrentPad.LeftStick}"); | ||
console.Print($"Right Stick: {CurrentPad.RightStick}"); | ||
|
||
|
||
console.Print($"\n{"Button Type",-12} Pressed Down Up"); | ||
foreach (var btn in CurrentPad.AllButtons) | ||
{ | ||
console.Print($"{btn.Type.ToString(),-12} {btn.IsPressed,-7} {btn.IsButtonDown,-5} {btn.IsButtonUp,-5}"); | ||
} | ||
|
||
if (keyboard.Escape.IsKeyDown) App.LoadScene<MainScene>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Promete.Input.Internal; | ||
using Promete.Windowing; | ||
using Silk.NET.Input; | ||
|
||
namespace Promete.Input; | ||
|
||
public sealed class Gamepad : IDisposable | ||
{ | ||
public bool IsConnected => pad.IsConnected; | ||
|
||
public string Name => pad.Name; | ||
public bool IsVibrationSupported => pad.VibrationMotors.Any(); | ||
|
||
public Vector LeftStick => pad.Thumbsticks.Count >= 1 ? (pad.Thumbsticks[0].X, pad.Thumbsticks[0].Y) : (0, 0); | ||
|
||
public Vector RightStick => pad.Thumbsticks.Count >= 2 ? (pad.Thumbsticks[1].X, pad.Thumbsticks[1].Y) : (0, 0); | ||
|
||
public GamepadButton this[int index] => buttons[index]; | ||
|
||
public GamepadButton this[GamepadButtonType type] => buttonMap[type]; | ||
|
||
public IEnumerable<GamepadButton> AllButtons => buttons.AsEnumerable(); | ||
|
||
/// <summary> | ||
/// 現在押されている全てのボタンを列挙します。 | ||
/// </summary> | ||
public IEnumerable<GamepadButton> AllPressedButtons => buttons.Where(c => c.IsPressed); | ||
|
||
/// <summary> | ||
/// このフレームで押された全てのボタンを列挙します。 | ||
/// </summary> | ||
public IEnumerable<GamepadButton> AllDownButtons => buttons.Where(c => c.IsButtonDown); | ||
|
||
/// <summary> | ||
/// このフレームで離された全てのボタンを列挙します。 | ||
/// </summary> | ||
public IEnumerable<GamepadButton> AllUpButtons => buttons.Where(c => c.IsButtonUp); | ||
|
||
private readonly GamepadButton[] buttons; | ||
private readonly Dictionary<GamepadButtonType, GamepadButton> buttonMap = new(); | ||
private readonly IWindow window; | ||
private readonly IGamepad pad; | ||
|
||
private const int TriggerCount = 2; | ||
|
||
public Gamepad(IGamepad pad, IWindow window) | ||
{ | ||
this.pad = pad; | ||
this.window = window; | ||
buttons = new GamepadButton[pad.Buttons.Count + TriggerCount]; | ||
for (var i = 0; i < pad.Buttons.Count; i++) | ||
{ | ||
buttons[i] = new GamepadButton(pad.Buttons[i].Name.ToPromete()); | ||
buttonMap[buttons[i].Type] = buttons[i]; | ||
} | ||
|
||
// Note: XInputの仕様に従い、Prometeでは最大2つのトリガーをL2, R2として解釈する | ||
buttonMap[GamepadButtonType.L2] = buttons[pad.Buttons.Count + 0] = new GamepadButton(GamepadButtonType.L2); | ||
buttonMap[GamepadButtonType.R2] = buttons[pad.Buttons.Count + 1] = new GamepadButton(GamepadButtonType.R2); | ||
|
||
pad.ButtonDown += OnButtonDown; | ||
pad.ButtonUp += OnButtonUp; | ||
pad.TriggerMoved += OnTriggerMove; | ||
|
||
window.PreUpdate += OnPreUpdate; | ||
window.PostUpdate += OnPostUpdate; | ||
} | ||
|
||
public void Vibrate(float value) | ||
{ | ||
if (!IsVibrationSupported) return; | ||
|
||
foreach (var motor in pad.VibrationMotors) | ||
{ | ||
motor.Speed = value; | ||
} | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
ReleaseUnmanagedResources(); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
private void OnPreUpdate() | ||
{ | ||
for (var i = 0; i < buttons.Length; i++) | ||
{ | ||
var isPressed = i < buttons.Length - 2 | ||
? pad.Buttons[i].Pressed | ||
: pad.Triggers[i - buttons.Length + 2].Position >= 1; | ||
buttons[i].IsPressed = isPressed; | ||
buttons[i].ElapsedFrameCount = isPressed ? buttons[i].ElapsedFrameCount + 1 : 0; | ||
buttons[i].ElapsedTime = isPressed ? buttons[i].ElapsedTime + window.DeltaTime : 0; | ||
} | ||
} | ||
|
||
private void OnPostUpdate() | ||
{ | ||
foreach (var t in buttons) | ||
{ | ||
t.IsButtonDown = false; | ||
t.IsButtonUp = false; | ||
} | ||
} | ||
|
||
private void OnButtonDown(IGamepad pad, Button button) | ||
{ | ||
buttons[button.Index].IsButtonDown = true; | ||
} | ||
|
||
private void OnButtonUp(IGamepad pad, Button button) | ||
{ | ||
buttons[button.Index].IsButtonUp = true; | ||
} | ||
|
||
private void OnTriggerMove(IGamepad pad, Trigger trigger) | ||
{ | ||
var button = buttons[buttons.Length - 2 + trigger.Index]; | ||
if (trigger.Position >= 1) | ||
{ | ||
button.IsButtonDown = true; | ||
} | ||
else | ||
{ | ||
button.IsButtonUp = true; | ||
} | ||
} | ||
|
||
private void ReleaseUnmanagedResources() | ||
{ | ||
foreach (var motor in pad.VibrationMotors) | ||
{ | ||
motor.Speed = 0; | ||
} | ||
pad.ButtonDown -= OnButtonDown; | ||
pad.ButtonUp -= OnButtonUp; | ||
pad.TriggerMoved -= OnTriggerMove; | ||
window.PreUpdate -= OnPreUpdate; | ||
window.PostUpdate -= OnPostUpdate; | ||
} | ||
|
||
~Gamepad() | ||
{ | ||
ReleaseUnmanagedResources(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using Silk.NET.Input; | ||
|
||
namespace Promete.Input; | ||
|
||
public class GamepadButton | ||
{ | ||
public GamepadButtonType Type { get; } | ||
|
||
/// <summary> | ||
/// このボタンが押されているかどうかを取得します。 | ||
/// </summary> | ||
public bool IsPressed { get; internal set; } | ||
|
||
/// <summary> | ||
/// このボタンが押されてからの経過フレーム数を取得します。 | ||
/// </summary> | ||
/// <value></value> | ||
public int ElapsedFrameCount { get; internal set; } | ||
|
||
/// <summary> | ||
/// このボタンが押されてからの経過時間を取得します。 | ||
/// </summary> | ||
/// <value></value> | ||
public float ElapsedTime { get; internal set; } | ||
|
||
/// <summary> | ||
/// このボタンがこのフレームで押されたかどうかを取得します。 | ||
/// </summary> | ||
public bool IsButtonDown { get; internal set; } | ||
|
||
/// <summary> | ||
/// このボタンがこのフレームで離されたかどうかを取得します。 | ||
/// </summary> | ||
public bool IsButtonUp { get; internal set; } | ||
|
||
internal GamepadButton(GamepadButtonType type) | ||
{ | ||
Type = type; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
namespace Promete.Input; | ||
|
||
public enum GamepadButtonType | ||
{ | ||
DpadUp, | ||
DpadDown, | ||
DpadLeft, | ||
DpadRight, | ||
A, | ||
B, | ||
X, | ||
Y, | ||
L1, | ||
R1, | ||
L2, | ||
R2, | ||
Plus, | ||
Minus, | ||
LeftStick, | ||
RightStick, | ||
Home, | ||
Unknown, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System.Collections.Generic; | ||
using Promete.Windowing; | ||
using Silk.NET.Input; | ||
|
||
namespace Promete.Input; | ||
|
||
/// <summary> | ||
/// 接続されたゲームパッドの入力を取得する Promete プラグインです。このクラスは継承できません。 | ||
/// </summary> | ||
public sealed class Gamepads | ||
{ | ||
private IInputContext input; | ||
private List<Gamepad> pads = []; | ||
|
||
private readonly IWindow window; | ||
|
||
public Gamepad? this[int index] => index < pads.Count ? pads[index] : null; | ||
|
||
public Gamepads(IWindow window) | ||
{ | ||
this.window = window; | ||
input = window._RawInputContext!; | ||
UpdateGamepads(); | ||
|
||
input.ConnectionChanged += OnConnectionChanged; | ||
} | ||
|
||
private void OnConnectionChanged(IInputDevice device, bool isConnected) | ||
{ | ||
if (device is IGamepad) UpdateGamepads(); | ||
} | ||
|
||
private void UpdateGamepads() | ||
{ | ||
pads.ForEach(p => p.Dispose()); | ||
pads.Clear(); | ||
foreach (var silkGamepad in input.Gamepads) | ||
{ | ||
pads.Add(new Gamepad(silkGamepad, window)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using System; | ||
using Silk.NET.Input; | ||
|
||
namespace Promete.Input.Internal; | ||
|
||
internal static class GamepadButtonTypeEnumConverter | ||
{ | ||
public static ButtonName ToSilk(this GamepadButtonType type) => | ||
type switch | ||
{ | ||
GamepadButtonType.DpadUp => ButtonName.DPadUp, | ||
GamepadButtonType.DpadDown => ButtonName.DPadDown, | ||
GamepadButtonType.DpadLeft => ButtonName.DPadLeft, | ||
GamepadButtonType.DpadRight => ButtonName.DPadRight, | ||
GamepadButtonType.A => ButtonName.A, | ||
GamepadButtonType.B => ButtonName.B, | ||
GamepadButtonType.X => ButtonName.X, | ||
GamepadButtonType.Y => ButtonName.Y, | ||
GamepadButtonType.L1 => ButtonName.LeftBumper, | ||
GamepadButtonType.R1 => ButtonName.RightBumper, | ||
GamepadButtonType.L2 => throw new NotSupportedException("L2 is not a button in Silk.NET"), | ||
GamepadButtonType.R2 => throw new NotSupportedException("R2 is not a button in Silk.NET"), | ||
GamepadButtonType.Plus => ButtonName.Start, | ||
GamepadButtonType.Minus => ButtonName.Back, | ||
GamepadButtonType.LeftStick => ButtonName.LeftStick, | ||
GamepadButtonType.RightStick => ButtonName.RightStick, | ||
GamepadButtonType.Home => ButtonName.Home, | ||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null) | ||
}; | ||
|
||
public static GamepadButtonType ToPromete(this ButtonName type) => | ||
type switch | ||
{ | ||
ButtonName.DPadUp => GamepadButtonType.DpadUp, | ||
ButtonName.DPadDown => GamepadButtonType.DpadDown, | ||
ButtonName.DPadLeft => GamepadButtonType.DpadLeft, | ||
ButtonName.DPadRight => GamepadButtonType.DpadRight, | ||
ButtonName.A => GamepadButtonType.A, | ||
ButtonName.B => GamepadButtonType.B, | ||
ButtonName.X => GamepadButtonType.X, | ||
ButtonName.Y => GamepadButtonType.Y, | ||
ButtonName.LeftBumper => GamepadButtonType.L1, | ||
ButtonName.RightBumper => GamepadButtonType.R1, | ||
ButtonName.Start => GamepadButtonType.Plus, | ||
ButtonName.Back => GamepadButtonType.Minus, | ||
ButtonName.LeftStick => GamepadButtonType.LeftStick, | ||
ButtonName.RightStick => GamepadButtonType.RightStick, | ||
ButtonName.Home => GamepadButtonType.Home, | ||
_ => GamepadButtonType.Unknown, | ||
}; | ||
} |