https://github.com/nikvoronin/xinput.wrapper
XInput wrapper in a single and monolithic C# class that can be embedded as source code in any project.
https://github.com/nikvoronin/xinput.wrapper
csharp game-controller game-development gamepad windows wrapper xinput
Last synced: 9 months ago
JSON representation
XInput wrapper in a single and monolithic C# class that can be embedded as source code in any project.
- Host: GitHub
- URL: https://github.com/nikvoronin/xinput.wrapper
- Owner: nikvoronin
- License: mit
- Created: 2016-06-09T14:56:00.000Z (about 10 years ago)
- Default Branch: part
- Last Pushed: 2022-01-07T20:19:34.000Z (over 4 years ago)
- Last Synced: 2025-08-30T01:54:13.415Z (10 months ago)
- Topics: csharp, game-controller, game-development, gamepad, windows, wrapper, xinput
- Language: C#
- Homepage:
- Size: 77.1 KB
- Stars: 31
- Watchers: 2
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# XInput.Wrapper
- It is a short and monolithic C# class that can be embedded as source code in any project (1 source file).
- No external libraries, except XInput1_4.DLL but it ships today as a system component in Windows 8/8.1/10. It is available "inbox" and does not require redistribution with an application.
- To implement this class into your own project, just add the "X.cs" class file and start using it without any restriction. Anyway you can download [latest release](https://github.com/nikvoronin/xinput.wrapper/releases/latest) and add a reference to XInput.Wrapper.dll.
> There are an unstable `develop` or splitted `part` branches are selected by default. If you want to use this wrapper in production you should go to a stable `master` branch or download assembly via `release` section or should use NuGet package [XInput.Wrapper](https://www.nuget.org/packages/XInput.Wrapper/).
# TODO
- **Native** - DONE / untested
- **Battery** - DONE / untested
- **Button** - partial ready / untested
- is this button **Supported** field
- readme part about using of events
- **Axis** - in develope
- Update
- **Gamepad** - in design
- Force Feedback
- Battery update period
- Get buttons by number
- yield Buttons.List
- supported buttons only
- **X** - in design
# First steps
- [Getting Started With XInput](https://msdn.microsoft.com/ru-ru/library/windows/desktop/ee417001(v=vs.85).aspx)
- [Functions](https://msdn.microsoft.com/ru-ru/library/windows/desktop/ee417007(v=vs.85).aspx)
# Class Structure
- **X**: threading, availability of the XInput_1.4 subsystem, polling loop
- **Gamepad**
- **Button**: gamepad buttons like A, B, X, Y, LT, RT, ...
- **Axis**: sticks and triggers.
- **Battery**: suddenly, wireless gamepads and headsets includes batteries.
- **Native** - interop to xinput1_4.dll
# How to...
## Initialization
```c#
using XInput.Wrapper;
// for ease of later using
X.Gamepad gamepad = null;
```
Test of availability of XInput 1.4 (xinput1_4.dll). This one should not call often! It is not cached.
```c#
if (X.IsAvailable)
{
[...]
```
> For performance reasons, don't call XInputGetState for an 'empty' user slot every frame. We recommend that you space out checks for new controllers every few seconds instead.
[MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).aspx#getting_controller_state)
Got Gamepad of the first user
```c#
if (X.IsAvailable)
{
gamepad = X.Gamepad_1;
[...]
```
Check gamepad's capabilites and test ForceFeedBack support
```c#
if (X.IsAvailable)
{
gamepad = X.Gamepad_1;
X.Gamepad.Capability caps = gamepad.Capabilities;
if (gamepad.FFB_Supported)
{
// can play with ~~vibrations~~ FFB
}
[...]
```
You can subscribe on events then start polling thread. X.StartPolling() supports up to four controllers.
```c#
if (X.IsAvailable)
{
gamepad = X.Gamepad_1;
...
gamepad.KeyDown += Gamepad_KeyDown;
gamepad.StateChanged += Gamepad_StateChanged;
gamepad.ConnectionChanged += Gamepad_ConnectionChanged;
X.StartPolling(gamepad);
}
```
Do not forget to stop polling
```c#
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (gamepad != null)
X.StopPolling();
[...]
```
## Events
### ConnectionChanged
Occurs when state of connection is changed: controller connects or disconnects. Use X.GamePad.IsConnected() to retrieve state of connection.
### StateChanged
Occurs when controller sends new data packet for application. Something changed and you should do something with new data. You can spot that some of buttons were pressed (up or down), thumb was rotated or trigger was pressed.
### KeyDown
When button pressed for a long time your app can regularly receive messages about this.
StateChanged event called once when button pressed. Use KeyDown event handler if you want to receive regularly messages about this.
## Update gamepad state
If you are playing with an event driven application (such as WinForms, WPF, etc) you can use X.Start|StopPolling. Apps with custom main loop should call X.Gamepad.Update() method.
```c#
while (true)
{
ProcessInput();
Update();
Render();
}
...
void ProcessInput()
{
if (gamepad == null)
return;
if (gamepad.Update())
{
// something happened: button pressed, stick turned or trigger was triggered
}
[...]
```
If Update() returns TRUE you should check connection state, state of buttons, sticks, triggers, bumpers,...
```c#
if (gamepad.Update())
{
// Check connection status and if connected then check battery state
if (gamepad.IsConnected)
gamepad.UpdateBattery();
// KeyUp is an event that happens once
// Try to stop vibrations
if (gamepad.X_up)
gamepad.FFB_Stop();
// You can process here but this will called once
if (gamepad.A_down)
gamepad.FFB_Vibrate(1, .5f, 100);
// Processing of analog inputs
[...]
}
// Will called again and again and again while button is pressed
if (gamepad.Buttons != 0)
{
if (gamepad.X_down)
gamepad.FFB_Vibrate(.2f, .5f, 100);
[...]
}
```
## Processing of analog inputs
There are two kinds of analog methods: absolute and normalized. Normalized are with the _N postfix. Absolute methods returns X.Point {int X, int Y} objects, normalized returns X.PointF {float X, float Y}.
```
0 <= LTrigger.X <= 255 // absolute
0.0f <= LTrigger_N.X <= 1.0f // normalized
-32767 <= LStick.X <= 32767 // absolute
-1.0f <= LStick_N.X <= 1.0f // normalized
```
### Dead zones
To adjust dead zones sensitivity
```c#
int LStick_DeadZone = 7849;
int RStick_DeadZone = 8689;
int LTrigger_Threshold = 30;
int RTrigger_Threshold = 30;
```
_N methods return 0.0f when axis in a dead zone.
## Force feedback
Check presence of FFB
```c#
if (gamepad.FFB_Supported)
{
// Already here
}
```
or
```c#
X.Gamepad.Capability caps = gamepad.Capabilities;
if ((caps.Flags & X.Gamepad.CapabilityFlags.FFB_Supported) == X.Gamepad.CapabilityFlags.FFB_Supported)
{
// Already here
}
```
Stop vabrations
```c#
gamepad.FFB_Stop();
```
And starts again at left and right with strength lying beetwen 0.0f and 1.0f up to 100ms
```c#
gamepad.FFB_Vibrate(0.5f, 1.0f, 100);
```
Left motor only (low-frequency motor)
```c#
gamepad.FFB_LeftMotor(0.5f, 100);
```
Right side only (hi-frequency motor)
```c#
gamepad.FFB_RightMotor(0.5f, 100);
```