前言
这是我的第一篇技术博客,希望能为大家提供些有用信息。
概述
前段时间有一项工作是通过游戏手柄控制云台,通过google和msdn搞定了,在这吧就总结一下吧。
问题
对于手柄控制主要有以下几个问题
- 在合适的时机获取游戏手柄的输入?
- 一般游戏手柄都是有n个方向键和n个功能键控制的,要确认各个键的状态?
解决方案
- 通过windows API 中与游戏手柄相关的函数进行控制,主要是joystick系统函数,这一问题的关键点是P/Invoke调用。优点是不需要directx 支持,缺点是调用如果要想让多个窗口接受手柄输入有点麻烦(后边会详细描述)。
- 通过directx的directx input,Microsoft.DirectX.DirectInput命名空间下的类对joystick进行了很好的封装,在.net中用时很方便。优点使用方便,缺点需要directx支持不过这点应该不用担心,现在大部分系统安装完后应该都安装了directx
在本篇中将先介绍通过directxinput进行控制,这篇文章有些地方借鉴了codepoject上的文章点击这里可以看到
程序最终运行效果

1.获取系统中已经连接成功的游戏手柄列表,代码如下
public static string[] FindJoysticks(IntPtr hWnd)
{
string[] systemJoysticks = null;
try
{
// 查找连接成功的游戏设备
DeviceList gameControllerList = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
// 遍历列表并获取设备名称
if (gameControllerList.Count > 0)
{
systemJoysticks = new string[gameControllerList.Count];
int i = 0;
foreach (DeviceInstance deviceInstance in gameControllerList)
{
// 创建一个Device对像并获取
Device joystickDevice = new Device(deviceInstance.InstanceGuid);
joystickDevice.SetCooperativeLevel(hWnd,
CooperativeLevelFlags.Background |
CooperativeLevelFlags.NonExclusive);
systemJoysticks[i] = joystickDevice.DeviceInformation.InstanceName;
i++;
}
}
}
catch (Exception err)
{
Debug.WriteLine("FindJoysticks()");
Debug.WriteLine(err.Message);
Debug.WriteLine(err.StackTrace);
}
return systemJoysticks;
}
2.连接到手柄设备开始获取手柄输入
public bool AcquireJoystick(string name)
{
try
{
DeviceList gameControllerList = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
int i = 0;
bool found = false;
// 查找指定名称的设备并连接到指定的窗口
foreach (DeviceInstance deviceInstance in gameControllerList)
{
if (deviceInstance.InstanceName == name)
{
found = true;
// 创建一个Device对象用来管理一个joystick
joystickDevice = new Device(deviceInstance.InstanceGuid);
joystickDevice.SetCooperativeLevel(hWnd,
CooperativeLevelFlags.Background |
CooperativeLevelFlags.NonExclusive);
break;
}
i++;
}
if (!found)
return false;
//告诉directx要控制的是一个Joystick
joystickDevice.SetDataFormat(DeviceDataFormat.Joystick);
joystickDevice.Acquire();
DeviceCaps cps = joystickDevice.Caps;
Debug.WriteLine("Joystick Axis: " + cps.NumberAxes);
Debug.WriteLine("Joystick Buttons: " + cps.NumberButtons);
UpdateStatus();
}
catch (Exception err)
{
Debug.WriteLine("FindJoysticks()");
Debug.WriteLine(err.Message);
Debug.WriteLine(err.StackTrace);
return false;
}
return true;
}
3.获取手柄状态并管理按键的状态上放开还是按下等信息,由于从手柄获取到的信息只含方向和那个键是按下的所以要想获取某个键是否按下或弹起要进行一些处理,下面的程序逻缉大家看下应该会懂的。
public void UpdateStatus()
{
Poll();
int[] extraAxis = state.GetSlider();
//获取方向键的状态,并区分左右上下以及按键的按下与放开
if (state.X == 0)
{
m_joyMove.Direction = JoyDirection.LEFT;
m_joyMove.Event = JoyEvent.WM_DOWN;
}
else if (state.Y == 0)
{
m_joyMove.Direction = JoyDirection.UP;
m_joyMove.Event = JoyEvent.WM_DOWN;
}
else if (state.X == 65535)
{
m_joyMove.Direction = JoyDirection.RIGHT;
m_joyMove.Event = JoyEvent.WM_DOWN;
}
else if (state.Y == 65535)
{
m_joyMove.Direction = JoyDirection.DOWN;
m_joyMove.Event = JoyEvent.WM_DOWN;
}
else if (state.X == 32511 && (m_joyMove.Direction == JoyDirection.LEFT || m_joyMove.Direction == JoyDirection.RIGHT)
&& m_joyMove.Event == JoyEvent.WM_DOWN)
{
m_joyMove.Event = JoyEvent.WM_UP;
}
else if (state.Y == 32511 && (m_joyMove.Direction == JoyDirection.UP || m_joyMove.Direction == JoyDirection.DOWN)
&& m_joyMove.Event == JoyEvent.WM_DOWN)
{
m_joyMove.Event = JoyEvent.WM_UP;
}
else
{
m_joyMove.Direction = JoyDirection.NONE;
m_joyMove.Event = JoyEvent.NONE;
}
// 获取按键的状态
byte[] jsButtons = state.GetButtons();
if (jsButtons != null)
{
if (m_JoyButtons == null)
m_JoyButtons = new JoyEvent[jsButtons.Length];
for (int i = 0; i < jsButtons.Length; i++)
{
if (jsButtons[i] >= 128)
{
m_JoyButtons[i] = JoyEvent.WM_DOWN;
}
else
{
if (m_JoyButtons[i] == JoyEvent.WM_DOWN)
m_JoyButtons[i] = JoyEvent.WM_UP;
else
m_JoyButtons[i] = JoyEvent.NONE;
}
}
}
}
最后我想上传整个工程但找不到从哪儿上传的.
本文介绍了如何使用C#通过DirectX Input来控制游戏手柄,包括获取手柄输入、处理按键状态,并提供了获取系统已连接手柄列表的代码示例。文章还提及了使用Windows API的joystick系统函数作为替代方案,但指出该方法在多窗口接收手柄输入时存在挑战。
1240





