Created
November 8, 2013 09:06
-
-
Save kb10uy/7368358 to your computer and use it in GitHub Desktop.
C#でXinputを汎用的に使うためにさらっと書いてみた。車輪のうんたららは気にしない。
今回知ったのはC#でもenumの型指定が使えるということ。
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
using System; | |
using System.Runtime.InteropServices; | |
namespace XInput | |
{ | |
/// <summary> | |
/// Xinput方式によるコントローラーの操作を提供します。 | |
/// </summary> | |
public class XInput | |
{ | |
#region DllImport宣言 | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static uint XInputGetCapabilities(uint num, uint flag, out XInputCapabilities pxic); | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static uint XInputGetDSoundAudioDeviceGuids(uint num, out Guid render, out Guid capture); | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static uint XInputGetKeystroke(uint num, uint fetch, out XInputState stroke); | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static uint XInputSetState(uint num, ref XInputVibrationState vib); | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static uint XInputGetState(uint num, out XInputState state); | |
[DllImport("xinput1_3.dll", CallingConvention = CallingConvention.Winapi)] | |
extern static void XInputEnable([MarshalAs(UnmanagedType.Bool)]bool enable); | |
#endregion | |
/// <summary> | |
/// コントローラーの性能を取得します。 | |
/// </summary> | |
public XInputCapabilities Capabilities { get; protected set; } | |
/// <summary> | |
/// ヘッドセットが接続されている場合、レンダリングデバイスのGUIDを取得します。 | |
/// 接続されていない場合、Guid.Emptyが返されると思われます。 | |
/// </summary> | |
public Guid DSoundRenderDeviceGuid { get; protected set; } | |
/// <summary> | |
/// ヘッドセットが接続されている場合、キャプチャデバイスのGUIDを取得します。 | |
/// 接続されていない場合、Guid.Emptyが返されると思われます。 | |
/// </summary> | |
public Guid DSoundCaptureDeviceGuid { get; protected set; } | |
/// <summary> | |
/// コントローラーの番号を取得します。 | |
/// </summary> | |
public uint Number { get; protected set; } | |
uint packetnum = 0; | |
/// <summary> | |
/// 指定されたコントローラー番号を使用して初期化します。 | |
/// </summary> | |
/// <param name="number">コントローラー番号(0~3)</param> | |
public XInput(uint number) | |
{ | |
Number = number; | |
if (Number >= 4) throw new ArgumentOutOfRangeException("コントローラー番号に4以上は指定できません。"); | |
if (!IsConected(Number)) throw new NotSupportedException("指定された番号のコントローラーは存在しません。"); | |
var c = new XInputCapabilities(); | |
XInputGetCapabilities(Number, 0, out c); | |
Capabilities = c; | |
var cd = new Guid(); | |
var rd = new Guid(); | |
XInputGetDSoundAudioDeviceGuids(Number, out rd, out cd); | |
DSoundCaptureDeviceGuid = cd; | |
DSoundRenderDeviceGuid = rd; | |
} | |
/// <summary> | |
/// コントローラーの現在の状態を取得します。 | |
/// </summary> | |
/// <returns>現在の状態</returns> | |
public XInputState GetState() | |
{ | |
if (!IsConected(Number)) throw new NotSupportedException("接続が切れた可能性があります"); | |
var i = new XInputState(); | |
XInputGetState(Number, out i); | |
packetnum = i.PacketNumber; | |
return i; | |
} | |
/// <summary> | |
/// コントローラーの現在の状態を取得して、 | |
/// 前回GetStateかTryGetStateを呼び出した時と同じ状態だった場合は、 | |
/// falseを返します。変化があった場合は、trueを返します。 | |
/// </summary> | |
/// <param name="state">現在の状態</param> | |
/// <returns>変化があった場合true</returns> | |
public bool TryGetState(out XInputGamepadState state) | |
{ | |
var i = GetState(); | |
state = i.Gamepad; | |
if (packetnum == i.PacketNumber) | |
{ | |
return false; | |
} | |
else | |
{ | |
packetnum = i.PacketNumber; | |
return true; | |
} | |
} | |
/// <summary> | |
/// 指定されたコントローラー番号は接続されているかチェックします。 | |
/// </summary> | |
/// <param name="num">コントローラー番号</param> | |
/// <returns>接続されている場合はtrue</returns> | |
public static bool IsConected(uint num) | |
{ | |
var s = new XInputState(); | |
if (num >= 4) throw new ArgumentOutOfRangeException("コントローラー番号に4以上は指定できません。"); | |
//0x48FはERROR_DEVICE_NOT_CONNECTED | |
if (XInputGetState(num, out s) == 0x48F) | |
{ | |
return false; | |
} | |
else | |
{ | |
return true; | |
} | |
} | |
/// <summary> | |
/// 振動機能の状態を送信します。 | |
/// </summary> | |
/// <param name="state">設定する状態</param> | |
public void SetVibration(XInputVibrationState state) | |
{ | |
XInputSetState(Number, ref state); | |
} | |
} | |
/// <summary> | |
/// Xinput対応コントローラーの性能を記述します。 | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct XInputCapabilities | |
{ | |
/// <summary> | |
/// タイプ。現状XINPUT_DEVTYPE_GAMEPAD(0x01)のみ。 | |
/// </summary> | |
public byte Type; | |
/// <summary> | |
/// サブタイプ。詳しい種類が指定されます。 | |
/// </summary> | |
[MarshalAs(UnmanagedType.U1)] | |
public XInputSubTypeKind SubType; | |
/// <summary> | |
/// コントローラーの機能。現状XINPUT_CAPS_VOICE_SUPPORTED(0x04)のみ。 | |
/// </summary> | |
public ushort Flags; | |
/// <summary> | |
/// コントローラーの状態。 | |
/// </summary> | |
[MarshalAs(UnmanagedType.Struct)] | |
public XInputGamepadState Gamepad; | |
/// <summary> | |
/// コントローラーの振動の状態。 | |
/// </summary> | |
[MarshalAs(UnmanagedType.Struct)] | |
public XInputVibrationState Vibration; | |
} | |
/// <summary> | |
/// コントローラーの状態を表します。 | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct XInputState | |
{ | |
/// <summary> | |
/// 状態パケット番号。この番号が連続して一致している場合、コントローラーに変化はない。 | |
/// </summary> | |
public uint PacketNumber; | |
/// <summary> | |
/// コントローラーの状態。 | |
/// </summary> | |
[MarshalAs(UnmanagedType.Struct)] | |
public XInputGamepadState Gamepad; | |
} | |
/// <summary> | |
/// Xinput対応コントローラーの操作状態を記述します。 | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct XInputGamepadState | |
{ | |
/// <summary> | |
/// 各ボタン。それぞれビットマスク指定。 | |
/// </summary> | |
[MarshalAs(UnmanagedType.U2)] | |
public XInputButtonKind Buttons; | |
/// <summary> | |
/// 左トリガー。0で無押下、255で完全押下。 | |
/// </summary> | |
public byte LeftTrigger; | |
/// <summary> | |
/// 右トリガー。0で無押下、255で完全押下。 | |
/// </summary> | |
public byte RightTrigger; | |
/// <summary> | |
/// 左スティックX軸。-32768で最も左、0で中央、32767で最も右。 | |
/// </summary> | |
public short ThumbLeftX; | |
/// <summary> | |
/// 左スティックY軸。-32768で最も下、、0で中央、32767で最も上。 | |
/// </summary> | |
public short ThumbLeftY; | |
/// <summary> | |
/// 右スティックX軸。-32768で最も左、0で中央、32767で最も右。 | |
/// </summary> | |
public short ThumbRightX; | |
/// <summary> | |
/// 左スティックY軸。-32768で最も下、、0で中央、32767で最も上。 | |
/// </summary> | |
public short ThumbRightY; | |
} | |
/// <summary> | |
/// Xinput対応コントローラーの振動機能の状態を指定します。 | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct XInputVibrationState | |
{ | |
/// <summary> | |
/// 左モーターの速度。0は全く振動せず、65535では | |
/// 完全に振動する。大きく動く方。 | |
/// </summary> | |
public ushort LeftMotorSpeed; | |
/// <summary> | |
/// 右モーターの速度。0は全く振動せず、65535では | |
/// 完全に振動する。小さく動く方。 | |
/// </summary> | |
public ushort RightMotorSpeed; | |
} | |
/// <summary> | |
/// Xinput対応コントローラーの種類を表します。 | |
/// </summary> | |
public enum XInputSubTypeKind : byte | |
{ | |
/// <summary> | |
/// 通常のゲームパッド | |
/// </summary> | |
Gamepad = 0x01, | |
/// <summary> | |
/// ステアリング型 | |
/// </summary> | |
Wheel = 0x02, | |
/// <summary> | |
/// アーケードスティック | |
/// </summary> | |
ArcadeStick = 0x03, | |
/// <summary> | |
/// フライトスティック | |
/// </summary> | |
FlightStick = 0x04, | |
/// <summary> | |
/// ダンスパッド(おそらくDDR用) | |
/// </summary> | |
DancePad = 0x05, | |
/// <summary> | |
/// ギター(おそらくギタフリ用) | |
/// </summary> | |
Guitar = 0x06, | |
/// <summary> | |
/// ドラムキット(おそらくドラマニ用) | |
/// </summary> | |
DrumKit = 0x07 | |
} | |
/// <summary> | |
/// Xinput対応コントローラーのボタンの種類を表します。 | |
/// </summary> | |
[Flags] | |
public enum XInputButtonKind : ushort | |
{ | |
/// <summary> | |
/// デジタルパッド上 | |
/// </summary> | |
DigitalPadUp = 0x0001, | |
/// <summary> | |
/// デジタルパッド下 | |
/// </summary> | |
DigitalPadDown = 0x0002, | |
/// <summary> | |
/// デジタルパッド左 | |
/// </summary> | |
DigitalPadLeft = 0x0004, | |
/// <summary> | |
/// デジタルパッド右 | |
/// </summary> | |
DigitalPadRight = 0x0008, | |
/// <summary> | |
/// スタート | |
/// </summary> | |
Start = 0x0010, | |
/// <summary> | |
/// バック | |
/// </summary> | |
Back = 0x0020, | |
/// <summary> | |
/// 左スティックボタン | |
/// </summary> | |
LeftThumb = 0x0040, | |
/// <summary> | |
/// 右スティックボタン | |
/// </summary> | |
RightThumb = 0x0080, | |
/// <summary> | |
/// 左ショルダー(左トリガーの上) | |
/// </summary> | |
LeftShoulder = 0x0100, | |
/// <summary> | |
/// 左ショルダー(左トリガーの上) | |
/// </summary> | |
RightShoulder = 0x0200, | |
/// <summary> | |
/// Aボタン | |
/// </summary> | |
A = 0x1000, | |
/// <summary> | |
/// Bボタン | |
/// </summary> | |
B = 0x2000, | |
/// <summary> | |
/// Xボタン | |
/// </summary> | |
X = 0x4000, | |
/// <summary> | |
/// Yボタン | |
/// </summary> | |
Y = 0x8000, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment