{"id":20526536,"url":"https://github.com/nikvoronin/xinput.wrapper","last_synced_at":"2025-09-21T06:42:07.821Z","repository":{"id":144197570,"uuid":"60783000","full_name":"nikvoronin/XInput.Wrapper","owner":"nikvoronin","description":"XInput wrapper in a single and monolithic C# class that can be embedded as source code in any project.","archived":false,"fork":false,"pushed_at":"2022-01-07T20:19:34.000Z","size":79,"stargazers_count":31,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"part","last_synced_at":"2025-08-30T01:54:13.415Z","etag":null,"topics":["csharp","game-controller","game-development","gamepad","windows","wrapper","xinput"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikvoronin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-06-09T14:56:00.000Z","updated_at":"2023-12-20T20:03:56.000Z","dependencies_parsed_at":"2023-06-16T07:30:53.380Z","dependency_job_id":null,"html_url":"https://github.com/nikvoronin/XInput.Wrapper","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/nikvoronin/XInput.Wrapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikvoronin%2FXInput.Wrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikvoronin%2FXInput.Wrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikvoronin%2FXInput.Wrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikvoronin%2FXInput.Wrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikvoronin","download_url":"https://codeload.github.com/nikvoronin/XInput.Wrapper/tar.gz/refs/heads/part","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikvoronin%2FXInput.Wrapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276204825,"owners_count":25602738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-21T02:00:07.055Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","game-controller","game-development","gamepad","windows","wrapper","xinput"],"created_at":"2024-11-15T23:14:36.754Z","updated_at":"2025-09-21T06:42:07.816Z","avatar_url":"https://github.com/nikvoronin.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XInput.Wrapper\r\n\r\n- It is a short and monolithic C# class that can be embedded as source code in any project (1 source file).\r\n- 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.\r\n- 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.\r\n\r\n\u003e 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/).\r\n\r\n# TODO\r\n\r\n- **Native** - DONE / untested\r\n- **Battery** - DONE / untested\r\n- **Button** - partial ready / untested\r\n\t- is this button **Supported** field\r\n\t- readme part about using of events\r\n- **Axis** - in develope\r\n\t- Update\r\n- **Gamepad** - in design\r\n\t- Force Feedback\r\n\t- Battery update period\r\n\t- Get buttons by number\r\n\t- yield Buttons.List\r\n\t- supported buttons only\r\n- **X** - in design\r\n\t\r\n# First steps\r\n\r\n- [Getting Started With XInput](https://msdn.microsoft.com/ru-ru/library/windows/desktop/ee417001(v=vs.85).aspx)\r\n- [Functions](https://msdn.microsoft.com/ru-ru/library/windows/desktop/ee417007(v=vs.85).aspx)\r\n\r\n# Class Structure\r\n\r\n- **X**: threading, availability of the XInput_1.4 subsystem, polling loop\r\n\t- **Gamepad**\r\n\t\t- **Button**: gamepad buttons like A, B, X, Y, LT, RT, ...\r\n\t\t- **Axis**: sticks and triggers.\r\n\t\t- **Battery**: suddenly, wireless gamepads and headsets includes batteries.\r\n\t- **Native** - interop to xinput1_4.dll\r\n\r\n# How to...\r\n\r\n## Initialization\r\n\r\n```c#\r\nusing XInput.Wrapper;\r\n\r\n// for ease of later using\r\nX.Gamepad gamepad = null;\r\n```\r\n\r\n\r\nTest of availability of XInput 1.4 (xinput1_4.dll). This one should not call often! It is not cached.\r\n\r\n```c#\r\nif (X.IsAvailable)\r\n{\r\n    [...]\r\n```\r\n\r\n\u003e 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.\u003cbr/\u003e\r\n[MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).aspx#getting_controller_state)\r\n\r\n\r\nGot Gamepad of the first user\r\n\r\n```c#\r\nif (X.IsAvailable)\r\n{\r\n    gamepad = X.Gamepad_1;\r\n    [...]\r\n```\r\n\r\n\r\nCheck gamepad's capabilites and test ForceFeedBack support\r\n\r\n```c#\r\nif (X.IsAvailable)\r\n{\r\n    gamepad = X.Gamepad_1;\r\n    X.Gamepad.Capability caps = gamepad.Capabilities;\r\n\r\n    if (gamepad.FFB_Supported)\r\n    {\r\n        // can play with ~~vibrations~~ FFB\r\n    }\r\n\r\n    [...]\r\n```\r\n\r\n\r\nYou can subscribe on events then start polling thread. X.StartPolling() supports up to four controllers.\r\n\r\n```c#\r\nif (X.IsAvailable)\r\n{\r\n    gamepad = X.Gamepad_1;\r\n\r\n    ...\r\n    \r\n    gamepad.KeyDown           += Gamepad_KeyDown;\r\n    gamepad.StateChanged      += Gamepad_StateChanged;\r\n    gamepad.ConnectionChanged += Gamepad_ConnectionChanged;\r\n\r\n    X.StartPolling(gamepad);\r\n}\r\n```\r\n\r\n\r\nDo not forget to stop polling\r\n\r\n```c#\r\nprivate void GameForm_FormClosing(object sender, FormClosingEventArgs e)\r\n{\r\n    if (gamepad != null)\r\n        X.StopPolling();\r\n        \r\n    [...]\r\n```\r\n\r\n\r\n## Events\r\n\r\n### ConnectionChanged\r\n\r\nOccurs when state of connection is changed: controller connects or disconnects. Use X.GamePad.IsConnected() to retrieve state of connection.\r\n\r\n\r\n### StateChanged\r\n\r\nOccurs 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. \r\n\r\n\r\n### KeyDown\r\n\r\nWhen button pressed for a long time your app can regularly receive messages about this.\r\n\r\nStateChanged event called once when button pressed. Use KeyDown event handler if you want to receive regularly messages about this.\r\n\r\n\r\n## Update gamepad state \r\n\r\nIf 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.\r\n\r\n```c#\r\nwhile (true)\r\n{\r\n    ProcessInput();\r\n    Update();\r\n    Render();\r\n}\r\n\r\n...\r\n\r\nvoid ProcessInput()\r\n{\r\n    if (gamepad == null)\r\n        return;\r\n\r\n    if (gamepad.Update())\r\n    {\r\n        // something happened: button pressed, stick turned or trigger was triggered\r\n    }\r\n    [...]\r\n```\r\n\r\n\r\nIf Update() returns TRUE you should check connection state, state of buttons, sticks, triggers, bumpers,...\r\n\r\n```c#\r\nif (gamepad.Update())\r\n{\r\n    // Check connection status and if connected then check battery state\r\n    if (gamepad.IsConnected)\r\n        gamepad.UpdateBattery();\r\n\r\n    // KeyUp is an event that happens once\r\n    // Try to stop vibrations\r\n    if (gamepad.X_up)\r\n        gamepad.FFB_Stop();\r\n\r\n    // You can process here but this will called once\r\n    if (gamepad.A_down)\r\n        gamepad.FFB_Vibrate(1, .5f, 100);\r\n\r\n    // Processing of analog inputs\r\n    [...]\r\n}\r\n\r\n// Will called again and again and again while button is pressed\r\nif (gamepad.Buttons != 0)\r\n{\r\n    if (gamepad.X_down)\r\n        gamepad.FFB_Vibrate(.2f, .5f, 100);\r\n    \r\n    [...]\r\n}\r\n```\r\n\r\n\r\n## Processing of analog inputs\r\n\r\nThere 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}.\r\n\r\n```\r\n     0    \u003c= LTrigger.X   \u003c=   255        // absolute\r\n     0.0f \u003c= LTrigger_N.X \u003c=     1.0f    // normalized\r\n\r\n-32767    \u003c= LStick.X     \u003c= 32767        // absolute\r\n    -1.0f \u003c= LStick_N.X   \u003c=     1.0f    // normalized\r\n\r\n```\r\n\r\n\r\n### Dead zones\r\n\r\nTo adjust dead zones sensitivity\r\n\r\n```c#\r\nint LStick_DeadZone    = 7849;\r\nint RStick_DeadZone    = 8689;\r\nint LTrigger_Threshold = 30;\r\nint RTrigger_Threshold = 30;\r\n```\r\n\r\n_N methods return 0.0f when axis in a dead zone.\r\n\r\n\r\n## Force feedback\r\n\r\nCheck presence of FFB\r\n\r\n```c#\r\nif (gamepad.FFB_Supported)\r\n{\r\n    // Already here\r\n}\r\n```\r\n\r\nor\r\n\r\n```c#\r\nX.Gamepad.Capability caps = gamepad.Capabilities;\r\n\r\nif ((caps.Flags \u0026 X.Gamepad.CapabilityFlags.FFB_Supported) == X.Gamepad.CapabilityFlags.FFB_Supported)\r\n{\r\n    // Already here\r\n}\r\n```\r\n\r\n\r\nStop vabrations\r\n\r\n```c#\r\ngamepad.FFB_Stop();\r\n```\r\n\r\n\r\nAnd starts again at left and right with strength lying beetwen 0.0f and 1.0f up to 100ms\r\n\r\n```c#\r\ngamepad.FFB_Vibrate(0.5f, 1.0f, 100);\r\n```\r\n\r\n\r\nLeft motor only (low-frequency motor)\r\n\r\n```c#\r\ngamepad.FFB_LeftMotor(0.5f, 100);\r\n```\r\n\r\n\r\nRight side only (hi-frequency motor)\r\n\r\n```c#\r\ngamepad.FFB_RightMotor(0.5f, 100);\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikvoronin%2Fxinput.wrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikvoronin%2Fxinput.wrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikvoronin%2Fxinput.wrapper/lists"}