Skip to content

Instantly share code, notes, and snippets.

@mfakane
Created August 28, 2011 11:15
Show Gist options
  • Save mfakane/1176549 to your computer and use it in GitHub Desktop.
Save mfakane/1176549 to your computer and use it in GitHub Desktop.
ゲームパッドの取り扱い
// GamePad.GetAvailableGamePads() してインスタンスを取得してから
// Update() を呼び出してフレームごとに状態を更新しましょう。
// 状態を更新後 IsDown や IsUp でボタンとかを調べられます。前フレームとの取得結果を比較することで押した瞬間や離した瞬間と比較できるでしょう。
// ボタン指定とかが適当で使いづらいので要改善
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
namespace Coredivider.Framework
{
public class GamePad
{
#region P/Invoke
[SuppressUnmanagedCodeSecurity, DllImport("winmm")]
static extern int joyGetNumDevs();
[SuppressUnmanagedCodeSecurity, DllImport("winmm")]
static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji);
[SuppressUnmanagedCodeSecurity, DllImport("winmm")]
static extern int joyGetDevCaps(int uJoyID, ref JOYCAPS pjc, int cbjc);
[Flags]
enum ReturnType : uint
{
None = 0,
X = 1 << 0,
Y = 1 << 1,
Z = 1 << 2,
R = 1 << 3,
U = 1 << 4,
V = 1 << 5,
POV = 1 << 6,
Buttons = 1 << 7,
RawData = 1 << 8,
POVContinuous = 1 << 9,
Centered = 1 << 10,
UseDeadZone = 1 << 11,
All = X | Y | Z | R | U | V | POV | Buttons,
}
enum POV : uint
{
None = 65535,
Up = 0,
UpRight = 4500,
Right = 9000,
DownRight = 13500,
Down = 18000,
DownLeft = 22500,
Left = 27000,
UpLeft = 31500,
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct JOYINFOEX
{
public uint dwSize;
public ReturnType dwFlags;
public uint dwXpos;
public uint dwYpos;
public uint dwZpos;
public uint dwRpos;
public uint dwUpos;
public uint dwVpos;
public uint dwButtons;
public uint dwButtonNumber;
public POV dwPOV;
public uint dwReserved1;
public uint dwReserved2;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct JOYCAPS
{
public ushort wMid;
public ushort wPid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szPname;
public uint wXmin;
public uint wXmax;
public uint wYmin;
public uint wYmax;
public uint wZmin;
public uint wZmax;
public uint wNumButtons;
public uint wPeriodMin;
public uint wPeriodMax;
public uint wRmin;
public uint wRmax;
public uint wUmin;
public uint wUmax;
public uint wVmin;
public uint wVmax;
public uint wCaps;
public uint wMaxAxes;
public uint wNumAxes;
public uint wMaxButtons;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szRegKey;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szOEMVxD;
}
#endregion
JOYINFOEX info;
JOYCAPS caps;
readonly Dictionary<PadKey, bool> isDown = new Dictionary<PadKey, bool>();
public int ID
{
get;
private set;
}
public double X
{
get
{
return Math.Round((double)(info.dwXpos - caps.wXmin) / (caps.wXmax - caps.wXmin), 3);
}
}
public double Y
{
get
{
return Math.Round((double)(info.dwYpos - caps.wYmin) / (caps.wYmax - caps.wYmin), 3);
}
}
public double SpinX
{
get
{
return Math.Round((double)(info.dwVpos - caps.wVmin) / (caps.wVmax - caps.wVmin), 3);
}
}
public double SpinY
{
get
{
return Math.Round((double)(info.dwUpos - caps.wUmin) / (caps.wUmax - caps.wUmin), 3);
}
}
public bool Available
{
get;
private set;
}
GamePad(int id)
{
caps = new JOYCAPS();
info = new JOYINFOEX
{
dwSize = (uint)Marshal.SizeOf(typeof(JOYINFOEX)),
dwFlags = ReturnType.All,
};
this.ID = id;
this.Available = Update();
if (id != -1)
joyGetDevCaps(id, ref caps, Marshal.SizeOf(typeof(JOYCAPS)));
}
public bool Update()
{
if (this.ID == -1)
return false;
else
if (joyGetPosEx(this.ID, ref info) == 0)
{
foreach (PadKey i in Enum.GetValues(typeof(PadKey)))
isDown[i] = CheckIsDown(i);
return true;
}
else
return false;
}
bool CheckIsDown(PadKey key)
{
const double stickThreshold = 0.2;
const double stickReverseThreshold = 1 - stickThreshold;
switch (key)
{
case PadKey.None:
return false;
case PadKey.StickUp:
return this.Y < stickThreshold;
case PadKey.StickDown:
return this.Y > stickReverseThreshold;
case PadKey.StickLeft:
return this.X < stickThreshold;
case PadKey.StickRight:
return this.X > stickReverseThreshold;
case PadKey.POVUp:
return info.dwPOV == POV.Up
|| info.dwPOV == POV.UpLeft
|| info.dwPOV == POV.UpRight;
case PadKey.POVDown:
return info.dwPOV == POV.Down
|| info.dwPOV == POV.DownLeft
|| info.dwPOV == POV.DownRight;
case PadKey.POVLeft:
return info.dwPOV == POV.Left
|| info.dwPOV == POV.UpLeft
|| info.dwPOV == POV.DownLeft;
case PadKey.POVRight:
return info.dwPOV == POV.Right
|| info.dwPOV == POV.UpRight
|| info.dwPOV == POV.DownRight;
//case PadKey.SpinUp:
// return this.SpinY < stickThreshold;
//case PadKey.SpinDown:
// return this.SpinY > stickReverseThreshold;
//case PadKey.SpinLeft:
// return this.SpinX < stickThreshold;
//case PadKey.SpinRight:
// return this.SpinX > stickReverseThreshold;
default:
return (info.dwButtons & (uint)Math.Pow(2, (int)key - 1)) != 0;
}
}
public bool IsDown(IEnumerable<PadKey> all)
{
return all.All(IsDown);
}
public bool IsDown(params PadKey[] all)
{
return all.All(IsDown);
}
public bool IsDown(PadKey key)
{
return isDown[key];
}
public bool IsUp(IEnumerable<PadKey> all)
{
return all.All(IsUp);
}
public bool IsUp(params PadKey[] all)
{
return all.All(IsUp);
}
public bool IsUp(PadKey key)
{
return !isDown[key];
}
public static IEnumerable<GamePad> GetAvailableGamePads()
{
var max = joyGetNumDevs();
for (int i = 0; i < max; i++)
{
var rt = new GamePad(i);
if (rt.Available)
yield return rt;
}
}
public enum PadKey : byte
{
None,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
Button10,
Button11,
Button12,
Button13,
Button14,
Button15,
Button16,
Button17,
Button18,
Button19,
Button20,
Button21,
Button22,
Button23,
Button24,
Button25,
Button26,
Button27,
Button28,
Button29,
Button30,
StickUp,
StickDown,
StickLeft,
StickRight,
POVUp,
POVDown,
POVLeft,
POVRight,
SpinUp,
SpinDown,
SpinLeft,
SpinRight,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment