This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Sep 8, 2023. It is now read-only.

Repository files navigation

ViGEm Client Native SDK

C/C++ developer SDK for communication with ViGEmBus.

Build statusDiscord


🧟 THIS PROJECT HAS BEEN RETIRED 🧟

Users of this software are encouraged to read the end-of-life statement. So long, cheers 🖖


About

TL;DR: use this if you want to create virtual game controllers from your C/C++ application 😊

The ViGEmClient provides a small library exposing a simple API for creating and "feeding" (periodically updating it with new input data) virtual game controllers through ViGEmBus. The library takes care of discovering a compatible instance of the bus driver on the user's system and abstracting away the inner workings of the emulation framework. You can use and distribute it with your project as either a static component (recommended) or a dynamic library (DLL). This library is not thread-safe, ensure proper synchronization in a multi-threaded environment.

How to build

Prerequisites

  • Visual Studio 2019 (Community Edition is just fine)
    • When linking statically, make sure to also link against setupapi.lib

Contribute

Bugs & Features

Found a bug and want it fixed? Open a detailed issue on the GitHub issue tracker!

Have an idea for a new feature? Let's have a chat about your request on our support channels.

Questions & Support

Please respect that the GitHub issue tracker isn't a helpdesk. We offer support resources, where you're welcome to check out and engage in discussions!

How to use

Integration

Integrating this library into your project is pretty straight-forward, there are no additional 3rd party dependencies. You can either git submodule or git subtree this repository directly into your source tree or use the provided vcpkg package manager integration found here (recommended, can be updated with ease). The library tries to handle driver compatibility internally so static linking is recommended to avoid DLL hell 😊

API usage

For a general overview of the provided types and functions take a look at the main include file.

Now, onwards to a practical example 😉 First, include some basic headers:

//// Windows basic types 'n' fun//
#defineWIN32_LEAN_AND_MEAN
#include<windows.h>//// Optional depending on your use case//
#include<Xinput.h>//// The ViGEm API//
#include<ViGEm/Client.h>//// Link against SetupAPI//
#pragma comment(lib, "setupapi.lib")

To initialize the API call vigem_alloc which gives you an opaque handle to the underlying driver:

constauto client = vigem_alloc();
if (client == nullptr)
{
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
return -1;
}

Establish connection to the driver:

constauto retval = vigem_connect(client);
if (!VIGEM_SUCCESS(retval))
{
std::cerr << "ViGEm Bus connection failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

👉 Note: this is an "expensive" operation, it's recommended you do this once in your project, not every frame for performance benefits.


With this handle we're prepared to spawn (connect) and feed (supply with periodic input updates) one or many emulated controller devices. So let's spawn an Xbox 360 controller:

//// Allocate handle to identify new pad//constauto pad = vigem_target_x360_alloc();
//// Add client to the bus, this equals a plug-in event//constauto pir = vigem_target_add(client, pad);
//// Error handling//if (!VIGEM_SUCCESS(pir))
{
std::cerr << "Target plugin failed with error code: 0x" << std::hex << pir << std::endl;
return -1;
}
XINPUT_STATE state;
//// Grab the input from a physical X36ß pad in this example//XInputGetState(0, &state);
//// The XINPUT_GAMEPAD structure is identical to the XUSB_REPORT structure// so we can simply take it "as-is" and cast it.//// Call this function on every input state change e.g. in a loop polling// another joystick or network device or thermometer or... you get the idea.//vigem_target_x360_update(client, pad, *reinterpret_cast<XUSB_REPORT*>(&state.Gamepad));
//// We're done with this pad, free resources (this disconnects the virtual device)//vigem_target_remove(client, pad);
vigem_target_free(pad);

Alright, so we got the feeding side of things done, but what about the other direction? After all, the virtual device can receive some state changes as well (for the Xbox 360 device the LED ring can change and rumble/vibration requests can arrive) and this information is of interest for us. This is achieved by defining a notification callback like so:

//// Define the callback function//VOIDCALLBACKnotification(
PVIGEM_CLIENT Client,
PVIGEM_TARGET Target,
UCHAR LargeMotor,
UCHAR SmallMotor,
UCHAR LedNumber,
LPVOID UserData
)
{
staticint count = 1;
std::cout.width(3);
std::cout << count++ << "";
std::cout.width(3);
std::cout << (int)LargeMotor << "";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
}

Register it:

constauto retval = vigem_target_x360_register_notification(client, pad, &notification, nullptr);
//// Error handling//if (!VIGEM_SUCCESS(retval))
{
std::cerr << "Registering for notification failed with error code: 0x" << std::hex << retval << std::endl;
return -1;
}

The function notification will now get invoked every time a rumble request was sent to the virtual controller and can get handled accordingly. This is a blocking call and the invocation will take place in the order the underlying requests arrived.


Once ViGEm interaction is no longer required (e.g. the application is about to end) the acquired resources need to be freed properly:

vigem_disconnect(client);
vigem_free(client);

After that the client handle will become invalid and must not be used again.

About

ViGEm Client SDK for feeder development.

Resources

Stars

191 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages