mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Add 'sdk/' from commit '18c67764ae7cc9827095eb4e70d75aa52ac8b392'
git-subtree-dir: sdk git-subtree-mainline:0dbf810ad0git-subtree-split:18c67764ae
This commit is contained in:
29
sdk/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
sdk/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior (example):
|
||||
1. Start program '...'
|
||||
2. Click on '....'
|
||||
3. Plug in device '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**System details (please complete the following information):**
|
||||
- OS: [e.g. Windows 10 1803]
|
||||
- Feeder software: [e.g. VDX, DS4Windows, ...]
|
||||
- Driver Version: [e.g. 1.14.3.0]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
17
sdk/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
sdk/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
7
sdk/.github/ISSUE_TEMPLATE/you-need-support.md
vendored
Normal file
7
sdk/.github/ISSUE_TEMPLATE/you-need-support.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: You need support
|
||||
about: This is the wrong place to ask for support
|
||||
|
||||
---
|
||||
|
||||
**Please don't abuse the issue tracker as a helpdesk!** We have a Discord server (linked in the README) where you can ask the lovely like-minded folks for assistance. Thank you for your compliance :smiley:
|
||||
1
sdk/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
1
sdk/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
# TBD :smiley:
|
||||
70
sdk/.gitignore
vendored
Normal file
70
sdk/.gitignore
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
|
||||
/.vs/ViGEmBus/v15
|
||||
/build/bin/Release
|
||||
/build/obj/Release
|
||||
/lib
|
||||
/packages
|
||||
/sys/x64/Release
|
||||
/x64/Release
|
||||
/x64/Release (dynamic)
|
||||
/x64/Release (static)
|
||||
/.tmp
|
||||
/lib/Release (static)
|
||||
/Release
|
||||
/sys/Release
|
||||
/Release (static)
|
||||
/build/bin/Debug
|
||||
/build/obj/Debug
|
||||
/bin
|
||||
/sys/x64
|
||||
/x64
|
||||
*.user
|
||||
/.vs/config
|
||||
/sys/RCa21300
|
||||
/sys/RCb21300
|
||||
/build/*.dotsettings
|
||||
/artifacts
|
||||
/.vs/ViGEmBus/DesignTimeBuild
|
||||
/build/obj
|
||||
/.vs/ViGEmClient
|
||||
/src/Release (static)
|
||||
/src/x64/Debug (static)
|
||||
/src/x64/Release (dynamic)
|
||||
/src/x64/Release (static)
|
||||
*.TMP
|
||||
/src/Debug_LIB
|
||||
/src/x64/Debug_LIB
|
||||
/x64/Debug_LIB
|
||||
/Debug_LIB
|
||||
*.aps
|
||||
/Release_LIB
|
||||
/src/Release_LIB
|
||||
/src/x64
|
||||
/src/Debug_DLL
|
||||
/src/Release_DLL
|
||||
/app/Tester/Debug
|
||||
/Debug
|
||||
/app/Tester/x64/Debug
|
||||
/app/Tester/x64/Release/Tester.tlog
|
||||
/app/Tester/x64/Release/Tester.log
|
||||
/app/Tester/x64/Release/Tester.obj
|
||||
/app/Tester/x64/Release/vc141.pdb
|
||||
/app/Tester/x64/Release/vcpkg.applocal.log
|
||||
/app/Tester/Release/Tester.tlog/CL.command.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/CL.read.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/CL.write.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/link.command.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/link.read.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/link.write.1.tlog
|
||||
/app/Tester/Release/Tester.tlog/Tester.lastbuildstate
|
||||
/app/Tester/Release/Tester.tlog/Tester.write.1u.tlog
|
||||
/app/Tester/Release/Tester.Build.CppClean.log
|
||||
/app/Tester/Release/Tester.log
|
||||
/app/Tester/Release/Tester.obj
|
||||
/app/Tester/Release/vc141.pdb
|
||||
/app/Tester/Release/vcpkg.applocal.log
|
||||
/app/Tester/x64/Release/Tester.Build.CppClean.log
|
||||
/app/Tester/x64/Release
|
||||
21
sdk/LICENSE
Normal file
21
sdk/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Benjamin Höglinger-Stelzer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
194
sdk/README.md
Normal file
194
sdk/README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# ViGEm Client Native SDK
|
||||
|
||||
C/C++ developer SDK for communication with [`ViGEmBus`](https://github.com/ViGEm/ViGEmBus).
|
||||
|
||||
[](https://ci.appveyor.com/project/nefarius/vigemclient) [](https://discord.vigem.org)
|
||||
|
||||
## 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`](https://github.com/ViGEm/ViGEmBus). The library takes care of discovering a compatible instance of the bus driver on the users 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](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=16) 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](../../issues)!
|
||||
|
||||
Have an idea for a new feature? Let's have a chat about your request on [Discord](https://discord.vigem.org) or the [community forums](https://forums.vigem.org).
|
||||
|
||||
### Questions & Support
|
||||
|
||||
Please respect that the GitHub issue tracker isn't a helpdesk. We offer a [Discord server](https://discord.vigem.org) and [forums](https://forums.vigem.org), 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`](https://github.com/microsoft/vcpkg) package manager integration [found here](https://github.com/ViGEm/ViGEmClient.vcpkg) (recommended, can be updates 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](./include/ViGEm/Client.h).
|
||||
|
||||
Now, onwards to a practical example 😉 First, include some basic headers:
|
||||
|
||||
```cpp
|
||||
//
|
||||
// Windows basic types 'n' fun
|
||||
//
|
||||
#define WIN32_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:
|
||||
|
||||
```cpp
|
||||
const auto client = vigem_alloc();
|
||||
|
||||
if (client == nullptr)
|
||||
{
|
||||
std::cerr << "Uh, not enough memory to do that?!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
Establish connection to the driver:
|
||||
|
||||
```cpp
|
||||
const auto 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:
|
||||
|
||||
```cpp
|
||||
//
|
||||
// Allocate handle to identify new pad
|
||||
//
|
||||
const auto pad = vigem_target_x360_alloc();
|
||||
|
||||
//
|
||||
// Add client to the bus, this equals a plug-in event
|
||||
//
|
||||
const auto pir = vigem_target_add(client, pad);
|
||||
|
||||
//
|
||||
// Error handling
|
||||
//
|
||||
if (!VIGEM_SUCCESS(pir))
|
||||
{
|
||||
std::cerr << "Target plugin failed with error code: 0x" << std::hex << retval << 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:
|
||||
|
||||
```cpp
|
||||
//
|
||||
// Define the callback function
|
||||
//
|
||||
VOID CALLBACK notification(
|
||||
PVIGEM_CLIENT Client,
|
||||
PVIGEM_TARGET Target,
|
||||
UCHAR LargeMotor,
|
||||
UCHAR SmallMotor,
|
||||
UCHAR LedNumber,
|
||||
LPVOID UserData
|
||||
)
|
||||
{
|
||||
static int 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:
|
||||
|
||||
```cpp
|
||||
const auto retval = vigem_target_x360_register_notification(client, pad, ¬ification, 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:
|
||||
|
||||
```cpp
|
||||
vigem_disconnect(client);
|
||||
vigem_free(client);
|
||||
```
|
||||
|
||||
After that the `client` handle will become invalid and must not be used again.
|
||||
55
sdk/ViGEmClient.sln
Normal file
55
sdk/ViGEmClient.sln
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29709.97
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ViGEmClient", "src\ViGEmClient.vcxproj", "{7DB06674-1F4F-464B-8E1C-172E9587F9DC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug_DLL|x64 = Debug_DLL|x64
|
||||
Debug_DLL|x86 = Debug_DLL|x86
|
||||
Debug_LIB|x64 = Debug_LIB|x64
|
||||
Debug_LIB|x86 = Debug_LIB|x86
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release_DLL|x64 = Release_DLL|x64
|
||||
Release_DLL|x86 = Release_DLL|x86
|
||||
Release_LIB|x64 = Release_LIB|x64
|
||||
Release_LIB|x86 = Release_LIB|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x86.ActiveCfg = Debug_DLL|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_DLL|x86.Build.0 = Debug_DLL|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x64.ActiveCfg = Debug_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x64.Build.0 = Debug_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x86.ActiveCfg = Debug_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug_LIB|x86.Build.0 = Debug_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x64.ActiveCfg = Debug_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x64.Build.0 = Debug_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x86.ActiveCfg = Debug_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Debug|x86.Build.0 = Debug_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x64.Build.0 = Release_DLL|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x86.ActiveCfg = Release_DLL|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_DLL|x86.Build.0 = Release_DLL|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x64.ActiveCfg = Release_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x64.Build.0 = Release_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x86.ActiveCfg = Release_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release_LIB|x86.Build.0 = Release_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x64.ActiveCfg = Release_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x64.Build.0 = Release_LIB|x64
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x86.ActiveCfg = Release_LIB|Win32
|
||||
{7DB06674-1F4F-464B-8E1C-172E9587F9DC}.Release|x86.Build.0 = Release_LIB|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D5CD61FD-80BB-4E0E-840C-BAF66ABB1CF0}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
24
sdk/appveyor.yml
Normal file
24
sdk/appveyor.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
version: 1.16.{build}.0
|
||||
image: Visual Studio 2019
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
configuration:
|
||||
- Release_DLL
|
||||
install:
|
||||
- cmd: git submodule -q update --init
|
||||
before_build:
|
||||
- ps: Invoke-WebRequest "https://downloads.vigem.org/other/nefarius/vpatch/vpatch.exe" -OutFile vpatch.exe
|
||||
- cmd: vpatch.exe --stamp-version "%APPVEYOR_BUILD_VERSION%" --target-file ".\src\%APPVEYOR_PROJECT_NAME%.vcxproj" --vcxproj.inf-time-stamp
|
||||
- cmd: vpatch.exe --stamp-version "%APPVEYOR_BUILD_VERSION%" --target-file ".\src\%APPVEYOR_PROJECT_NAME%.rc" --resource.file-version --resource.product-version
|
||||
build:
|
||||
project: $(APPVEYOR_BUILD_FOLDER)\$(APPVEYOR_PROJECT_NAME).sln
|
||||
artifacts:
|
||||
- path: 'bin**\*.lib'
|
||||
- path: 'bin**\*.dll'
|
||||
- path: 'bin**\*.pdb'
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: BUILDBOT
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
501
sdk/include/ViGEm/Client.h
Normal file
501
sdk/include/ViGEm/Client.h
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ViGEmClient_h__
|
||||
#define ViGEmClient_h__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ViGEm/Common.h"
|
||||
|
||||
#ifdef VIGEM_DYNAMIC
|
||||
#ifdef VIGEM_EXPORTS
|
||||
#define VIGEM_API __declspec(dllexport)
|
||||
#else
|
||||
#define VIGEM_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define VIGEM_API
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \typedef enum _VIGEM_ERRORS
|
||||
*
|
||||
* \brief Defines an alias representing the ViGEm errors.
|
||||
*/
|
||||
typedef enum _VIGEM_ERRORS
|
||||
{
|
||||
VIGEM_ERROR_NONE = 0x20000000,
|
||||
VIGEM_ERROR_BUS_NOT_FOUND = 0xE0000001,
|
||||
VIGEM_ERROR_NO_FREE_SLOT = 0xE0000002,
|
||||
VIGEM_ERROR_INVALID_TARGET = 0xE0000003,
|
||||
VIGEM_ERROR_REMOVAL_FAILED = 0xE0000004,
|
||||
VIGEM_ERROR_ALREADY_CONNECTED = 0xE0000005,
|
||||
VIGEM_ERROR_TARGET_UNINITIALIZED = 0xE0000006,
|
||||
VIGEM_ERROR_TARGET_NOT_PLUGGED_IN = 0xE0000007,
|
||||
VIGEM_ERROR_BUS_VERSION_MISMATCH = 0xE0000008,
|
||||
VIGEM_ERROR_BUS_ACCESS_FAILED = 0xE0000009,
|
||||
VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED = 0xE0000010,
|
||||
VIGEM_ERROR_CALLBACK_NOT_FOUND = 0xE0000011,
|
||||
VIGEM_ERROR_BUS_ALREADY_CONNECTED = 0xE0000012,
|
||||
VIGEM_ERROR_BUS_INVALID_HANDLE = 0xE0000013,
|
||||
VIGEM_ERROR_XUSB_USERINDEX_OUT_OF_RANGE = 0xE0000014,
|
||||
VIGEM_ERROR_INVALID_PARAMETER = 0xE0000015
|
||||
|
||||
} VIGEM_ERROR;
|
||||
|
||||
/**
|
||||
* \def VIGEM_SUCCESS(_val_) (_val_ == VIGEM_ERROR_NONE);
|
||||
*
|
||||
* \brief A macro that defines success.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param _val_ The VIGEM_ERROR value.
|
||||
*/
|
||||
#define VIGEM_SUCCESS(_val_) (_val_ == VIGEM_ERROR_NONE)
|
||||
|
||||
/**
|
||||
* \typedef struct _VIGEM_CLIENT_T *PVIGEM_CLIENT
|
||||
*
|
||||
* \brief Defines an alias representing a driver connection object.
|
||||
*/
|
||||
typedef struct _VIGEM_CLIENT_T *PVIGEM_CLIENT;
|
||||
|
||||
/**
|
||||
* \typedef struct _VIGEM_TARGET_T *PVIGEM_TARGET
|
||||
*
|
||||
* \brief Defines an alias representing a target device object.
|
||||
*/
|
||||
typedef struct _VIGEM_TARGET_T *PVIGEM_TARGET;
|
||||
|
||||
typedef
|
||||
_Function_class_(EVT_VIGEM_TARGET_ADD_RESULT)
|
||||
VOID CALLBACK
|
||||
EVT_VIGEM_TARGET_ADD_RESULT(
|
||||
PVIGEM_CLIENT Client,
|
||||
PVIGEM_TARGET Target,
|
||||
VIGEM_ERROR Result
|
||||
);
|
||||
|
||||
typedef EVT_VIGEM_TARGET_ADD_RESULT *PFN_VIGEM_TARGET_ADD_RESULT;
|
||||
|
||||
typedef
|
||||
_Function_class_(EVT_VIGEM_X360_NOTIFICATION)
|
||||
VOID CALLBACK
|
||||
EVT_VIGEM_X360_NOTIFICATION(
|
||||
PVIGEM_CLIENT Client,
|
||||
PVIGEM_TARGET Target,
|
||||
UCHAR LargeMotor,
|
||||
UCHAR SmallMotor,
|
||||
UCHAR LedNumber,
|
||||
LPVOID UserData
|
||||
);
|
||||
|
||||
typedef EVT_VIGEM_X360_NOTIFICATION *PFN_VIGEM_X360_NOTIFICATION;
|
||||
|
||||
typedef
|
||||
_Function_class_(EVT_VIGEM_DS4_NOTIFICATION)
|
||||
VOID CALLBACK
|
||||
EVT_VIGEM_DS4_NOTIFICATION(
|
||||
PVIGEM_CLIENT Client,
|
||||
PVIGEM_TARGET Target,
|
||||
UCHAR LargeMotor,
|
||||
UCHAR SmallMotor,
|
||||
DS4_LIGHTBAR_COLOR LightbarColor,
|
||||
LPVOID UserData
|
||||
);
|
||||
|
||||
typedef EVT_VIGEM_DS4_NOTIFICATION *PFN_VIGEM_DS4_NOTIFICATION;
|
||||
|
||||
/**
|
||||
* \fn PVIGEM_CLIENT vigem_alloc(void);
|
||||
*
|
||||
* \brief Allocates an object representing a driver connection.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \return A new driver connection object.
|
||||
*/
|
||||
VIGEM_API PVIGEM_CLIENT vigem_alloc(void);
|
||||
|
||||
/**
|
||||
* \fn void vigem_free(PVIGEM_CLIENT vigem);
|
||||
*
|
||||
* \brief Frees up memory used by the driver connection object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
*/
|
||||
VIGEM_API void vigem_free(PVIGEM_CLIENT vigem);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem);
|
||||
*
|
||||
* \brief Initializes the driver object and establishes a connection to the emulation bus
|
||||
* driver. Returns an error if no compatible bus device has been found.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem);
|
||||
|
||||
/**
|
||||
* \fn void vigem_disconnect(PVIGEM_CLIENT vigem);
|
||||
*
|
||||
* \brief Disconnects from the bus device and resets the driver object state. The driver object
|
||||
* may be reused again after calling this function. When called, all targets which may
|
||||
* still be connected will be destroyed automatically. Be aware, that allocated target
|
||||
* objects won't be automatically freed, this has to be taken care of by the caller.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
*/
|
||||
VIGEM_API void vigem_disconnect(PVIGEM_CLIENT vigem);
|
||||
|
||||
/**
|
||||
* \fn PVIGEM_TARGET vigem_target_x360_alloc(void);
|
||||
*
|
||||
* \brief Allocates an object representing an Xbox 360 Controller device.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \return A PVIGEM_TARGET representing an Xbox 360 Controller device.
|
||||
*/
|
||||
VIGEM_API PVIGEM_TARGET vigem_target_x360_alloc(void);
|
||||
|
||||
/**
|
||||
* \fn PVIGEM_TARGET vigem_target_ds4_alloc(void);
|
||||
*
|
||||
* \brief Allocates an object representing a DualShock 4 Controller device.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \return A PVIGEM_TARGET representing a DualShock 4 Controller device.
|
||||
*/
|
||||
VIGEM_API PVIGEM_TARGET vigem_target_ds4_alloc(void);
|
||||
|
||||
/**
|
||||
* \fn void vigem_target_free(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Frees up memory used by the target device object. This does not automatically remove
|
||||
* the associated device from the bus, if present. If the target device doesn't get
|
||||
* removed before this call, the device becomes orphaned until the owning process is
|
||||
* terminated.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*/
|
||||
VIGEM_API void vigem_target_free(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Adds a provided target device to the bus driver, which is equal to a device plug-in
|
||||
* event of a physical hardware device. This function blocks until the target device is
|
||||
* in full operational mode.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_add_async(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PVIGEM_TARGET_ADD_RESULT result);
|
||||
*
|
||||
* \brief Adds a provided target device to the bus driver, which is equal to a device plug-in
|
||||
* event of a physical hardware device. This function immediately returns. An optional
|
||||
* callback may be registered which gets called on error or if the target device has
|
||||
* become fully operational.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param result An optional function getting called when the target device becomes available.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_add_async(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PFN_VIGEM_TARGET_ADD_RESULT result);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Removes a provided target device from the bus driver, which is equal to a device
|
||||
* unplug event of a physical hardware device. The target device object may be reused
|
||||
* after this function is called. If this function is never called on target device
|
||||
* objects, they will be removed from the bus when the owning process terminates.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_x360_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PVIGEM_X360_NOTIFICATION notification);
|
||||
*
|
||||
* \brief Registers a function which gets called, when LED index or vibration state changes
|
||||
* occur on the provided target device. This function fails if the provided target
|
||||
* device isn't fully operational or in an erroneous state.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param notification The notification callback.
|
||||
* \param userData The user data passed to the notification callback.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_x360_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PFN_VIGEM_X360_NOTIFICATION notification, LPVOID userData);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_ds4_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PVIGEM_DS4_NOTIFICATION notification);
|
||||
*
|
||||
* \brief Registers a function which gets called, when LightBar or vibration state changes
|
||||
* occur on the provided target device. This function fails if the provided target
|
||||
* device isn't fully operational or in an erroneous state.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param notification The notification callback.
|
||||
* \param userData The user data passed to the notification callback.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_ds4_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PFN_VIGEM_DS4_NOTIFICATION notification, LPVOID userData);
|
||||
|
||||
/**
|
||||
* \fn void vigem_target_x360_unregister_notification(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Removes a previously registered callback function from the provided target object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*/
|
||||
VIGEM_API void vigem_target_x360_unregister_notification(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Removes a previously registered callback function from the provided target object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*/
|
||||
VIGEM_API void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn void vigem_target_set_vid(PVIGEM_TARGET target, USHORT vid);
|
||||
*
|
||||
* \brief Overrides the default Vendor ID value with the provided one.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
* \param vid The Vendor ID to set.
|
||||
*/
|
||||
VIGEM_API void vigem_target_set_vid(PVIGEM_TARGET target, USHORT vid);
|
||||
|
||||
/**
|
||||
* \fn void vigem_target_set_pid(PVIGEM_TARGET target, USHORT pid);
|
||||
*
|
||||
* \brief Overrides the default Product ID value with the provided one.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
* \param pid The Product ID to set.
|
||||
*/
|
||||
VIGEM_API void vigem_target_set_pid(PVIGEM_TARGET target, USHORT pid);
|
||||
|
||||
/**
|
||||
* \fn USHORT vigem_target_get_vid(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Returns the Vendor ID of the provided target device object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return The Vendor ID.
|
||||
*/
|
||||
VIGEM_API USHORT vigem_target_get_vid(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn USHORT vigem_target_get_pid(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Returns the Product ID of the provided target device object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return The Product ID.
|
||||
*/
|
||||
VIGEM_API USHORT vigem_target_get_pid(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_x360_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, XUSB_REPORT report);
|
||||
*
|
||||
* \brief Sends a state report to the provided target device.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param report The report to send to the target device.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_x360_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, XUSB_REPORT report);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_ERROR vigem_target_ds4_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, DS4_REPORT report);
|
||||
*
|
||||
* \brief Sends a state report to the provided target device.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param report The report to send to the target device.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_ds4_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, DS4_REPORT report);
|
||||
|
||||
/**
|
||||
* \fn ULONG vigem_target_get_index(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Returns the internal index (serial number) the bus driver assigned to the provided
|
||||
* target device object. Note that this value is specific to the inner workings of the
|
||||
* bus driver, it does not reflect related values like player index or device arrival
|
||||
* order experienced by other APIs. It may be used to identify the target device object
|
||||
* for its lifetime. This value becomes invalid once the target device is removed from
|
||||
* the bus and may change on the next addition of the device.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return The internally used index of the target device.
|
||||
*/
|
||||
VIGEM_API ULONG vigem_target_get_index(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Returns the type of the provided target device object.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 28.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return A VIGEM_TARGET_TYPE.
|
||||
*/
|
||||
VIGEM_API VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn BOOL vigem_target_is_attached(PVIGEM_TARGET target);
|
||||
*
|
||||
* \brief Returns TRUE if the provided target device object is currently attached to the bus,
|
||||
* FALSE otherwise.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 30.08.2017
|
||||
*
|
||||
* \param target The target device object.
|
||||
*
|
||||
* \return TRUE if device is attached to the bus, FALSE otherwise.
|
||||
*/
|
||||
VIGEM_API BOOL vigem_target_is_attached(PVIGEM_TARGET target);
|
||||
|
||||
/**
|
||||
* \fn VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index);
|
||||
*
|
||||
* \brief Returns the user index of the emulated Xenon device. This value correspondents to the
|
||||
* (zero-based) index number representing the player number via LED present on a
|
||||
* physical controller and is compatible to the dwUserIndex propery of the XInput* APIs.
|
||||
*
|
||||
* \author Benjamin "Nefarius" H<>glinger
|
||||
* \date 10.05.2018
|
||||
*
|
||||
* \param vigem The driver connection object.
|
||||
* \param target The target device object.
|
||||
* \param index The (zero-based) user index of the Xenon device.
|
||||
*
|
||||
* \return A VIGEM_ERROR.
|
||||
*/
|
||||
VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ViGEmClient_h__
|
||||
202
sdk/include/ViGEm/Common.h
Normal file
202
sdk/include/ViGEm/Common.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Represents the desired target type for the emulated device.
|
||||
//
|
||||
typedef enum _VIGEM_TARGET_TYPE
|
||||
{
|
||||
//
|
||||
// Microsoft Xbox 360 Controller (wired)
|
||||
//
|
||||
Xbox360Wired = 0,
|
||||
//
|
||||
// Sony DualShock 4 (wired)
|
||||
//
|
||||
DualShock4Wired = 2 // NOTE: 1 skipped on purpose to maintain compatibility
|
||||
|
||||
} VIGEM_TARGET_TYPE, *PVIGEM_TARGET_TYPE;
|
||||
|
||||
//
|
||||
// Possible XUSB report buttons.
|
||||
//
|
||||
typedef enum _XUSB_BUTTON
|
||||
{
|
||||
XUSB_GAMEPAD_DPAD_UP = 0x0001,
|
||||
XUSB_GAMEPAD_DPAD_DOWN = 0x0002,
|
||||
XUSB_GAMEPAD_DPAD_LEFT = 0x0004,
|
||||
XUSB_GAMEPAD_DPAD_RIGHT = 0x0008,
|
||||
XUSB_GAMEPAD_START = 0x0010,
|
||||
XUSB_GAMEPAD_BACK = 0x0020,
|
||||
XUSB_GAMEPAD_LEFT_THUMB = 0x0040,
|
||||
XUSB_GAMEPAD_RIGHT_THUMB = 0x0080,
|
||||
XUSB_GAMEPAD_LEFT_SHOULDER = 0x0100,
|
||||
XUSB_GAMEPAD_RIGHT_SHOULDER = 0x0200,
|
||||
XUSB_GAMEPAD_GUIDE = 0x0400,
|
||||
XUSB_GAMEPAD_A = 0x1000,
|
||||
XUSB_GAMEPAD_B = 0x2000,
|
||||
XUSB_GAMEPAD_X = 0x4000,
|
||||
XUSB_GAMEPAD_Y = 0x8000
|
||||
|
||||
} XUSB_BUTTON, *PXUSB_BUTTON;
|
||||
|
||||
//
|
||||
// Represents an XINPUT_GAMEPAD-compatible report structure.
|
||||
//
|
||||
typedef struct _XUSB_REPORT
|
||||
{
|
||||
USHORT wButtons;
|
||||
BYTE bLeftTrigger;
|
||||
BYTE bRightTrigger;
|
||||
SHORT sThumbLX;
|
||||
SHORT sThumbLY;
|
||||
SHORT sThumbRX;
|
||||
SHORT sThumbRY;
|
||||
|
||||
} XUSB_REPORT, *PXUSB_REPORT;
|
||||
|
||||
//
|
||||
// Initializes a _XUSB_REPORT structure.
|
||||
//
|
||||
VOID FORCEINLINE XUSB_REPORT_INIT(
|
||||
_Out_ PXUSB_REPORT Report
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Report, sizeof(XUSB_REPORT));
|
||||
}
|
||||
|
||||
//
|
||||
// The color value (RGB) of a DualShock 4 Lightbar
|
||||
//
|
||||
typedef struct _DS4_LIGHTBAR_COLOR
|
||||
{
|
||||
//
|
||||
// Red part of the Lightbar (0-255).
|
||||
//
|
||||
UCHAR Red;
|
||||
|
||||
//
|
||||
// Green part of the Lightbar (0-255).
|
||||
//
|
||||
UCHAR Green;
|
||||
|
||||
//
|
||||
// Blue part of the Lightbar (0-255).
|
||||
//
|
||||
UCHAR Blue;
|
||||
|
||||
} DS4_LIGHTBAR_COLOR, *PDS4_LIGHTBAR_COLOR;
|
||||
|
||||
//
|
||||
// DualShock 4 digital buttons
|
||||
//
|
||||
typedef enum _DS4_BUTTONS
|
||||
{
|
||||
DS4_BUTTON_THUMB_RIGHT = 1 << 15,
|
||||
DS4_BUTTON_THUMB_LEFT = 1 << 14,
|
||||
DS4_BUTTON_OPTIONS = 1 << 13,
|
||||
DS4_BUTTON_SHARE = 1 << 12,
|
||||
DS4_BUTTON_TRIGGER_RIGHT = 1 << 11,
|
||||
DS4_BUTTON_TRIGGER_LEFT = 1 << 10,
|
||||
DS4_BUTTON_SHOULDER_RIGHT = 1 << 9,
|
||||
DS4_BUTTON_SHOULDER_LEFT = 1 << 8,
|
||||
DS4_BUTTON_TRIANGLE = 1 << 7,
|
||||
DS4_BUTTON_CIRCLE = 1 << 6,
|
||||
DS4_BUTTON_CROSS = 1 << 5,
|
||||
DS4_BUTTON_SQUARE = 1 << 4
|
||||
|
||||
} DS4_BUTTONS, *PDS4_BUTTONS;
|
||||
|
||||
//
|
||||
// DualShock 4 special buttons
|
||||
//
|
||||
typedef enum _DS4_SPECIAL_BUTTONS
|
||||
{
|
||||
DS4_SPECIAL_BUTTON_PS = 1 << 0,
|
||||
DS4_SPECIAL_BUTTON_TOUCHPAD = 1 << 1
|
||||
|
||||
} DS4_SPECIAL_BUTTONS, *PDS4_SPECIAL_BUTTONS;
|
||||
|
||||
//
|
||||
// DualShock 4 directional pad (HAT) values
|
||||
//
|
||||
typedef enum _DS4_DPAD_DIRECTIONS
|
||||
{
|
||||
DS4_BUTTON_DPAD_NONE = 0x8,
|
||||
DS4_BUTTON_DPAD_NORTHWEST = 0x7,
|
||||
DS4_BUTTON_DPAD_WEST = 0x6,
|
||||
DS4_BUTTON_DPAD_SOUTHWEST = 0x5,
|
||||
DS4_BUTTON_DPAD_SOUTH = 0x4,
|
||||
DS4_BUTTON_DPAD_SOUTHEAST = 0x3,
|
||||
DS4_BUTTON_DPAD_EAST = 0x2,
|
||||
DS4_BUTTON_DPAD_NORTHEAST = 0x1,
|
||||
DS4_BUTTON_DPAD_NORTH = 0x0
|
||||
|
||||
} DS4_DPAD_DIRECTIONS, *PDS4_DPAD_DIRECTIONS;
|
||||
|
||||
//
|
||||
// DualShock 4 HID Input report
|
||||
//
|
||||
typedef struct _DS4_REPORT
|
||||
{
|
||||
BYTE bThumbLX;
|
||||
BYTE bThumbLY;
|
||||
BYTE bThumbRX;
|
||||
BYTE bThumbRY;
|
||||
USHORT wButtons;
|
||||
BYTE bSpecial;
|
||||
BYTE bTriggerL;
|
||||
BYTE bTriggerR;
|
||||
|
||||
} DS4_REPORT, *PDS4_REPORT;
|
||||
|
||||
//
|
||||
// Sets the current state of the D-PAD on a DualShock 4 report.
|
||||
//
|
||||
VOID FORCEINLINE DS4_SET_DPAD(
|
||||
_Out_ PDS4_REPORT Report,
|
||||
_In_ DS4_DPAD_DIRECTIONS Dpad
|
||||
)
|
||||
{
|
||||
Report->wButtons &= ~0xF;
|
||||
Report->wButtons |= (USHORT)Dpad;
|
||||
}
|
||||
|
||||
VOID FORCEINLINE DS4_REPORT_INIT(
|
||||
_Out_ PDS4_REPORT Report
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Report, sizeof(DS4_REPORT));
|
||||
|
||||
Report->bThumbLX = 0x80;
|
||||
Report->bThumbLY = 0x80;
|
||||
Report->bThumbRX = 0x80;
|
||||
Report->bThumbRY = 0x80;
|
||||
|
||||
DS4_SET_DPAD(Report, DS4_BUTTON_DPAD_NONE);
|
||||
}
|
||||
|
||||
50
sdk/include/ViGEm/Util.h
Normal file
50
sdk/include/ViGEm/Util.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "ViGEm/Common.h"
|
||||
#include <limits.h>
|
||||
|
||||
VOID FORCEINLINE XUSB_TO_DS4_REPORT(
|
||||
_Out_ PXUSB_REPORT Input,
|
||||
_Out_ PDS4_REPORT Output
|
||||
)
|
||||
{
|
||||
if (Input->wButtons & XUSB_GAMEPAD_BACK) Output->wButtons |= DS4_BUTTON_SHARE;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_START) Output->wButtons |= DS4_BUTTON_OPTIONS;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_LEFT_THUMB) Output->wButtons |= DS4_BUTTON_THUMB_LEFT;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_RIGHT_THUMB) Output->wButtons |= DS4_BUTTON_THUMB_RIGHT;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_LEFT_SHOULDER) Output->wButtons |= DS4_BUTTON_SHOULDER_LEFT;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_RIGHT_SHOULDER) Output->wButtons |= DS4_BUTTON_SHOULDER_RIGHT;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_GUIDE) Output->bSpecial |= DS4_SPECIAL_BUTTON_PS;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_A) Output->wButtons |= DS4_BUTTON_CROSS;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_B) Output->wButtons |= DS4_BUTTON_CIRCLE;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_X) Output->wButtons |= DS4_BUTTON_SQUARE;
|
||||
if (Input->wButtons & XUSB_GAMEPAD_Y) Output->wButtons |= DS4_BUTTON_TRIANGLE;
|
||||
|
||||
Output->bTriggerL = Input->bLeftTrigger;
|
||||
Output->bTriggerR = Input->bRightTrigger;
|
||||
|
||||
if (Input->bLeftTrigger > 0)Output->wButtons |= DS4_BUTTON_TRIGGER_LEFT;
|
||||
if (Input->bRightTrigger > 0)Output->wButtons |= DS4_BUTTON_TRIGGER_RIGHT;
|
||||
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_UP) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTH);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_EAST);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTH);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_WEST);
|
||||
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_UP
|
||||
&& Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTHEAST);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_RIGHT
|
||||
&& Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTHEAST);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_DOWN
|
||||
&& Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_SOUTHWEST);
|
||||
if (Input->wButtons & XUSB_GAMEPAD_DPAD_LEFT
|
||||
&& Input->wButtons & XUSB_GAMEPAD_DPAD_UP) DS4_SET_DPAD(Output, DS4_BUTTON_DPAD_NORTHWEST);
|
||||
|
||||
Output->bThumbLX = ((Input->sThumbLX + ((USHRT_MAX / 2) + 1)) / 257);
|
||||
Output->bThumbLY = (-(Input->sThumbLY + ((USHRT_MAX / 2) - 1)) / 257);
|
||||
Output->bThumbLY = (Output->bThumbLY == 0) ? 0xFF : Output->bThumbLY;
|
||||
Output->bThumbRX = ((Input->sThumbRX + ((USHRT_MAX / 2) + 1)) / 257);
|
||||
Output->bThumbRY = (-(Input->sThumbRY + ((USHRT_MAX / 2) + 1)) / 257);
|
||||
Output->bThumbRY = (Output->bThumbRY == 0) ? 0xFF : Output->bThumbRY;
|
||||
}
|
||||
|
||||
404
sdk/include/ViGEm/km/BusShared.h
Normal file
404
sdk/include/ViGEm/km/BusShared.h
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2019 Nefarius Software Solutions e.U. and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// GUID identifying the bus device. Used by client library to detect and communicate.
|
||||
//
|
||||
// IMPORTANT: make sure to change this value if you fork it or introduce
|
||||
// breaking changes!
|
||||
//
|
||||
// {96E42B22-F5E9-42F8-B043-ED0F932F014F}
|
||||
DEFINE_GUID(GUID_DEVINTERFACE_BUSENUM_VIGEM,
|
||||
0x96E42B22, 0xF5E9, 0x42F8, 0xB0, 0x43, 0xED, 0x0F, 0x93, 0x2F, 0x01, 0x4F);
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ViGEm/Common.h"
|
||||
|
||||
//
|
||||
// Common version for user-mode library and driver compatibility
|
||||
//
|
||||
// On initialization, the user-mode library has this number embedded
|
||||
// and sends it to the bus on its enumeration. The bus compares this
|
||||
// number to the one it was compiled with. If they match, the bus
|
||||
// access is permitted and success reported. If they mismatch, an
|
||||
// error is reported and the user-mode library skips this instance.
|
||||
//
|
||||
#define VIGEM_COMMON_VERSION 0x0001
|
||||
|
||||
#define FILE_DEVICE_BUSENUM FILE_DEVICE_BUS_EXTENDER
|
||||
#define BUSENUM_IOCTL(_index_) CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA)
|
||||
#define BUSENUM_W_IOCTL(_index_) CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define BUSENUM_R_IOCTL(_index_) CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA)
|
||||
#define BUSENUM_RW_IOCTL(_index_) CTL_CODE(FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_WRITE_DATA | FILE_READ_DATA)
|
||||
|
||||
#define IOCTL_VIGEM_BASE 0x801
|
||||
|
||||
//
|
||||
// IO control codes
|
||||
//
|
||||
#define IOCTL_VIGEM_PLUGIN_TARGET BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x000)
|
||||
#define IOCTL_VIGEM_UNPLUG_TARGET BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x001)
|
||||
#define IOCTL_VIGEM_CHECK_VERSION BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x002)
|
||||
|
||||
#define IOCTL_XUSB_REQUEST_NOTIFICATION BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x200)
|
||||
#define IOCTL_XUSB_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x201)
|
||||
#define IOCTL_DS4_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x202)
|
||||
#define IOCTL_DS4_REQUEST_NOTIFICATION BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x203)
|
||||
//#define IOCTL_XGIP_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x204)
|
||||
//#define IOCTL_XGIP_SUBMIT_INTERRUPT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x205)
|
||||
#define IOCTL_XUSB_GET_USER_INDEX BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x206)
|
||||
|
||||
|
||||
//
|
||||
// Data structure used in PlugIn and UnPlug ioctls
|
||||
//
|
||||
|
||||
#pragma region Plugin
|
||||
|
||||
//
|
||||
// Data structure used in IOCTL_VIGEM_PLUGIN_TARGET requests.
|
||||
//
|
||||
typedef struct _VIGEM_PLUGIN_TARGET
|
||||
{
|
||||
//
|
||||
// sizeof (struct _BUSENUM_HARDWARE)
|
||||
//
|
||||
IN ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
IN ULONG SerialNo;
|
||||
|
||||
//
|
||||
// Type of the target device to emulate.
|
||||
//
|
||||
VIGEM_TARGET_TYPE TargetType;
|
||||
|
||||
//
|
||||
// If set, the vendor ID the emulated device is reporting
|
||||
//
|
||||
USHORT VendorId;
|
||||
|
||||
//
|
||||
// If set, the product ID the emulated device is reporting
|
||||
//
|
||||
USHORT ProductId;
|
||||
|
||||
} VIGEM_PLUGIN_TARGET, *PVIGEM_PLUGIN_TARGET;
|
||||
|
||||
//
|
||||
// Initializes a VIGEM_PLUGIN_TARGET structure.
|
||||
//
|
||||
VOID FORCEINLINE VIGEM_PLUGIN_TARGET_INIT(
|
||||
_Out_ PVIGEM_PLUGIN_TARGET PlugIn,
|
||||
_In_ ULONG SerialNo,
|
||||
_In_ VIGEM_TARGET_TYPE TargetType
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(PlugIn, sizeof(VIGEM_PLUGIN_TARGET));
|
||||
|
||||
PlugIn->Size = sizeof(VIGEM_PLUGIN_TARGET);
|
||||
PlugIn->SerialNo = SerialNo;
|
||||
PlugIn->TargetType = TargetType;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Unplug
|
||||
|
||||
//
|
||||
// Data structure used in IOCTL_VIGEM_UNPLUG_TARGET requests.
|
||||
//
|
||||
typedef struct _VIGEM_UNPLUG_TARGET
|
||||
{
|
||||
//
|
||||
// sizeof (struct _REMOVE_HARDWARE)
|
||||
//
|
||||
IN ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
} VIGEM_UNPLUG_TARGET, *PVIGEM_UNPLUG_TARGET;
|
||||
|
||||
//
|
||||
// Initializes a VIGEM_UNPLUG_TARGET structure.
|
||||
//
|
||||
VOID FORCEINLINE VIGEM_UNPLUG_TARGET_INIT(
|
||||
_Out_ PVIGEM_UNPLUG_TARGET UnPlug,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(UnPlug, sizeof(VIGEM_UNPLUG_TARGET));
|
||||
|
||||
UnPlug->Size = sizeof(VIGEM_UNPLUG_TARGET);
|
||||
UnPlug->SerialNo = SerialNo;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Check version
|
||||
|
||||
typedef struct _VIGEM_CHECK_VERSION
|
||||
{
|
||||
IN ULONG Size;
|
||||
|
||||
IN ULONG Version;
|
||||
|
||||
} VIGEM_CHECK_VERSION, *PVIGEM_CHECK_VERSION;
|
||||
|
||||
VOID FORCEINLINE VIGEM_CHECK_VERSION_INIT(
|
||||
_Out_ PVIGEM_CHECK_VERSION CheckVersion,
|
||||
_In_ ULONG Version
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(CheckVersion, sizeof(VIGEM_CHECK_VERSION));
|
||||
|
||||
CheckVersion->Size = sizeof(VIGEM_CHECK_VERSION);
|
||||
CheckVersion->Version = Version;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region XUSB (aka Xbox 360 device) section
|
||||
|
||||
//
|
||||
// Data structure used in IOCTL_XUSB_REQUEST_NOTIFICATION requests.
|
||||
//
|
||||
typedef struct _XUSB_REQUEST_NOTIFICATION
|
||||
{
|
||||
//
|
||||
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// Vibration intensity value of the large motor (0-255).
|
||||
//
|
||||
UCHAR LargeMotor;
|
||||
|
||||
//
|
||||
// Vibration intensity value of the small motor (0-255).
|
||||
//
|
||||
UCHAR SmallMotor;
|
||||
|
||||
//
|
||||
// Index number of the slot/LED that XUSB.sys has assigned.
|
||||
//
|
||||
UCHAR LedNumber;
|
||||
|
||||
} XUSB_REQUEST_NOTIFICATION, *PXUSB_REQUEST_NOTIFICATION;
|
||||
|
||||
//
|
||||
// Initializes a XUSB_REQUEST_NOTIFICATION structure.
|
||||
//
|
||||
VOID FORCEINLINE XUSB_REQUEST_NOTIFICATION_INIT(
|
||||
_Out_ PXUSB_REQUEST_NOTIFICATION Request,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Request, sizeof(XUSB_REQUEST_NOTIFICATION));
|
||||
|
||||
Request->Size = sizeof(XUSB_REQUEST_NOTIFICATION);
|
||||
Request->SerialNo = SerialNo;
|
||||
}
|
||||
|
||||
//
|
||||
// Data structure used in IOCTL_XUSB_SUBMIT_REPORT requests.
|
||||
//
|
||||
typedef struct _XUSB_SUBMIT_REPORT
|
||||
{
|
||||
//
|
||||
// sizeof(struct _XUSB_SUBMIT_REPORT)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// Report to submit to the target device.
|
||||
//
|
||||
XUSB_REPORT Report;
|
||||
|
||||
} XUSB_SUBMIT_REPORT, *PXUSB_SUBMIT_REPORT;
|
||||
|
||||
//
|
||||
// Initializes an XUSB report.
|
||||
//
|
||||
VOID FORCEINLINE XUSB_SUBMIT_REPORT_INIT(
|
||||
_Out_ PXUSB_SUBMIT_REPORT Report,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Report, sizeof(XUSB_SUBMIT_REPORT));
|
||||
|
||||
Report->Size = sizeof(XUSB_SUBMIT_REPORT);
|
||||
Report->SerialNo = SerialNo;
|
||||
}
|
||||
|
||||
typedef struct _XUSB_GET_USER_INDEX
|
||||
{
|
||||
//
|
||||
// sizeof(struct _XUSB_GET_USER_INDEX)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// User index of target device.
|
||||
//
|
||||
OUT ULONG UserIndex;
|
||||
|
||||
} XUSB_GET_USER_INDEX, *PXUSB_GET_USER_INDEX;
|
||||
|
||||
//
|
||||
// Initializes XUSB_GET_USER_INDEX structure.
|
||||
//
|
||||
VOID FORCEINLINE XUSB_GET_USER_INDEX_INIT(
|
||||
_Out_ PXUSB_GET_USER_INDEX GetRequest,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(GetRequest, sizeof(XUSB_GET_USER_INDEX));
|
||||
|
||||
GetRequest->Size = sizeof(XUSB_GET_USER_INDEX);
|
||||
GetRequest->SerialNo = SerialNo;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region DualShock 4 section
|
||||
|
||||
typedef struct _DS4_OUTPUT_REPORT
|
||||
{
|
||||
//
|
||||
// Vibration intensity value of the small motor (0-255).
|
||||
//
|
||||
UCHAR SmallMotor;
|
||||
|
||||
//
|
||||
// Vibration intensity value of the large motor (0-255).
|
||||
//
|
||||
UCHAR LargeMotor;
|
||||
|
||||
//
|
||||
// Color values of the Lightbar.
|
||||
//
|
||||
DS4_LIGHTBAR_COLOR LightbarColor;
|
||||
|
||||
} DS4_OUTPUT_REPORT, *PDS4_OUTPUT_REPORT;
|
||||
|
||||
//
|
||||
// Data structure used in IOCTL_DS4_REQUEST_NOTIFICATION requests.
|
||||
//
|
||||
typedef struct _DS4_REQUEST_NOTIFICATION
|
||||
{
|
||||
//
|
||||
// sizeof(struct _XUSB_REQUEST_NOTIFICATION)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// The HID output report
|
||||
//
|
||||
DS4_OUTPUT_REPORT Report;
|
||||
|
||||
} DS4_REQUEST_NOTIFICATION, *PDS4_REQUEST_NOTIFICATION;
|
||||
|
||||
//
|
||||
// Initializes a DS4_REQUEST_NOTIFICATION structure.
|
||||
//
|
||||
VOID FORCEINLINE DS4_REQUEST_NOTIFICATION_INIT(
|
||||
_Out_ PDS4_REQUEST_NOTIFICATION Request,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Request, sizeof(DS4_REQUEST_NOTIFICATION));
|
||||
|
||||
Request->Size = sizeof(DS4_REQUEST_NOTIFICATION);
|
||||
Request->SerialNo = SerialNo;
|
||||
}
|
||||
|
||||
//
|
||||
// DualShock 4 request data
|
||||
//
|
||||
typedef struct _DS4_SUBMIT_REPORT
|
||||
{
|
||||
//
|
||||
// sizeof(struct _DS4_SUBMIT_REPORT)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Serial number of target device.
|
||||
//
|
||||
ULONG SerialNo;
|
||||
|
||||
//
|
||||
// HID Input report
|
||||
//
|
||||
DS4_REPORT Report;
|
||||
|
||||
} DS4_SUBMIT_REPORT, *PDS4_SUBMIT_REPORT;
|
||||
|
||||
//
|
||||
// Initializes a DualShock 4 report.
|
||||
//
|
||||
VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT(
|
||||
_Out_ PDS4_SUBMIT_REPORT Report,
|
||||
_In_ ULONG SerialNo
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT));
|
||||
|
||||
Report->Size = sizeof(DS4_SUBMIT_REPORT);
|
||||
Report->SerialNo = SerialNo;
|
||||
|
||||
DS4_REPORT_INIT(&Report->Report);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
73
sdk/src/Internal.h
Normal file
73
sdk/src/Internal.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// TODO: this is... not optimal. Improve in the future.
|
||||
//
|
||||
#define VIGEM_TARGETS_MAX USHRT_MAX
|
||||
|
||||
|
||||
//
|
||||
// Represents a driver connection object.
|
||||
//
|
||||
typedef struct _VIGEM_CLIENT_T
|
||||
{
|
||||
HANDLE hBusDevice;
|
||||
|
||||
} VIGEM_CLIENT;
|
||||
|
||||
//
|
||||
// Represents the (connection) state of a target device object.
|
||||
//
|
||||
typedef enum _VIGEM_TARGET_STATE
|
||||
{
|
||||
VIGEM_TARGET_NEW,
|
||||
VIGEM_TARGET_INITIALIZED,
|
||||
VIGEM_TARGET_CONNECTED,
|
||||
VIGEM_TARGET_DISCONNECTED
|
||||
} VIGEM_TARGET_STATE, *PVIGEM_TARGET_STATE;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Represents a virtual gamepad object.
|
||||
//
|
||||
typedef struct _VIGEM_TARGET_T
|
||||
{
|
||||
ULONG Size;
|
||||
ULONG SerialNo;
|
||||
VIGEM_TARGET_STATE State;
|
||||
USHORT VendorId;
|
||||
USHORT ProductId;
|
||||
VIGEM_TARGET_TYPE Type;
|
||||
FARPROC Notification;
|
||||
LPVOID NotificationUserData;
|
||||
|
||||
bool closingNotificationThreads;
|
||||
HANDLE cancelNotificationThreadEvent;
|
||||
std::unique_ptr<std::vector<std::thread>> notificationThreadList;
|
||||
} VIGEM_TARGET;
|
||||
8
sdk/src/README.md
Normal file
8
sdk/src/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# ViGEm user-mode client library
|
||||
This static library provides the gateway to the bus drivers functionalities. It offers:
|
||||
* Searching and connecting to a library-compatible bus device on the system
|
||||
* Attaching and removing a (artificially limited) number of virtual devices
|
||||
* Feeding the emulated devices (aka providing input state changes)
|
||||
|
||||
## Dependencies
|
||||
In addition to this library you'll need to link against `setupapi.lib`.
|
||||
984
sdk/src/ViGEmClient.cpp
Normal file
984
sdk/src/ViGEmClient.cpp
Normal file
@@ -0,0 +1,984 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Nefarius Software Solutions e.U. and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// WinAPI
|
||||
//
|
||||
#include <Windows.h>
|
||||
#include <SetupAPI.h>
|
||||
#include <initguid.h>
|
||||
#include <Dbghelp.h>
|
||||
|
||||
//
|
||||
// Driver shared
|
||||
//
|
||||
#include "ViGEm/km/BusShared.h"
|
||||
#include "ViGEm/Client.h"
|
||||
#include <winioctl.h>
|
||||
|
||||
//
|
||||
// STL
|
||||
//
|
||||
#include <cstdlib>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
//
|
||||
// Internal
|
||||
//
|
||||
#include "Internal.h"
|
||||
|
||||
|
||||
typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(
|
||||
HANDLE hProcess,
|
||||
DWORD dwPid,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
);
|
||||
|
||||
LONG WINAPI vigem_internal_exception_handler(struct _EXCEPTION_POINTERS* apExceptionInfo);
|
||||
|
||||
|
||||
//
|
||||
// DeviceIOControl request notification handler classes for X360 and DS4 controller types.
|
||||
// vigem_target_XXX_register_notification functions use x360 or DS4 derived class instances in a notification thread handlers.
|
||||
//
|
||||
class NotificationRequestPayload
|
||||
{
|
||||
public:
|
||||
LPVOID lpPayloadBuffer;
|
||||
DWORD payloadBufferSize;
|
||||
DWORD ioControlCode;
|
||||
|
||||
public:
|
||||
NotificationRequestPayload(DWORD _bufferSize, DWORD _ioControlCode)
|
||||
{
|
||||
lpPayloadBuffer = malloc(_bufferSize);
|
||||
payloadBufferSize = _bufferSize;
|
||||
ioControlCode = _ioControlCode;
|
||||
}
|
||||
|
||||
virtual ~NotificationRequestPayload()
|
||||
{
|
||||
free(lpPayloadBuffer);
|
||||
}
|
||||
|
||||
virtual void ProcessNotificationRequest(PVIGEM_CLIENT client, PVIGEM_TARGET target) = 0;
|
||||
};
|
||||
|
||||
class NotificationRequestPayloadX360 : public NotificationRequestPayload
|
||||
{
|
||||
public:
|
||||
NotificationRequestPayloadX360(ULONG _serialNo) : NotificationRequestPayload(sizeof(XUSB_REQUEST_NOTIFICATION), IOCTL_XUSB_REQUEST_NOTIFICATION)
|
||||
{
|
||||
// Let base class to allocate required buffer size, but initialize it here with a correct type of initialization function
|
||||
XUSB_REQUEST_NOTIFICATION_INIT((PXUSB_REQUEST_NOTIFICATION)lpPayloadBuffer, _serialNo);
|
||||
}
|
||||
|
||||
void ProcessNotificationRequest(PVIGEM_CLIENT client, PVIGEM_TARGET target) override
|
||||
{
|
||||
if(target->Notification != nullptr)
|
||||
PFN_VIGEM_X360_NOTIFICATION(target->Notification)(client, target,
|
||||
((PXUSB_REQUEST_NOTIFICATION)lpPayloadBuffer)->LargeMotor,
|
||||
((PXUSB_REQUEST_NOTIFICATION)lpPayloadBuffer)->SmallMotor,
|
||||
((PXUSB_REQUEST_NOTIFICATION)lpPayloadBuffer)->LedNumber,
|
||||
target->NotificationUserData
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class NotificationRequestPayloadDS4 : public NotificationRequestPayload
|
||||
{
|
||||
public:
|
||||
NotificationRequestPayloadDS4(ULONG _serialNo) : NotificationRequestPayload(sizeof(DS4_REQUEST_NOTIFICATION), IOCTL_DS4_REQUEST_NOTIFICATION)
|
||||
{
|
||||
// Let base class to allocate required buffer size, but initialize it here with a correct type of initialization function
|
||||
DS4_REQUEST_NOTIFICATION_INIT((PDS4_REQUEST_NOTIFICATION)lpPayloadBuffer, _serialNo);
|
||||
}
|
||||
|
||||
void ProcessNotificationRequest(PVIGEM_CLIENT client, PVIGEM_TARGET target) override
|
||||
{
|
||||
if (target->Notification != nullptr)
|
||||
PFN_VIGEM_DS4_NOTIFICATION(target->Notification)(client, target,
|
||||
((PDS4_REQUEST_NOTIFICATION)lpPayloadBuffer)->Report.LargeMotor,
|
||||
((PDS4_REQUEST_NOTIFICATION)lpPayloadBuffer)->Report.SmallMotor,
|
||||
((PDS4_REQUEST_NOTIFICATION)lpPayloadBuffer)->Report.LightbarColor,
|
||||
target->NotificationUserData
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Initializes a virtual gamepad object.
|
||||
//
|
||||
PVIGEM_TARGET FORCEINLINE VIGEM_TARGET_ALLOC_INIT(
|
||||
_In_ VIGEM_TARGET_TYPE Type
|
||||
)
|
||||
{
|
||||
auto target = static_cast<PVIGEM_TARGET>(malloc(sizeof(VIGEM_TARGET)));
|
||||
|
||||
if (!target)
|
||||
return nullptr;
|
||||
|
||||
memset(target, 0, sizeof(VIGEM_TARGET));
|
||||
|
||||
target->Size = sizeof(VIGEM_TARGET);
|
||||
target->State = VIGEM_TARGET_INITIALIZED;
|
||||
target->Type = Type;
|
||||
target->notificationThreadList = nullptr;
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI vigem_internal_exception_handler(struct _EXCEPTION_POINTERS* apExceptionInfo)
|
||||
{
|
||||
const auto mhLib = LoadLibrary(L"dbghelp.dll");
|
||||
const auto pDump = reinterpret_cast<MINIDUMPWRITEDUMP>(GetProcAddress(mhLib, "MiniDumpWriteDump"));
|
||||
|
||||
const auto hFile = CreateFile(
|
||||
L"ViGEmClient.dmp",
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
|
||||
const DWORD flags = MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules |
|
||||
MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData |
|
||||
MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo |
|
||||
MiniDumpWithFullAuxiliaryState | MiniDumpIgnoreInaccessibleMemory |
|
||||
MiniDumpWithTokenInformation;
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
|
||||
ExInfo.ThreadId = GetCurrentThreadId();
|
||||
ExInfo.ExceptionPointers = apExceptionInfo;
|
||||
ExInfo.ClientPointers = FALSE;
|
||||
|
||||
pDump(
|
||||
GetCurrentProcess(),
|
||||
GetCurrentProcessId(),
|
||||
hFile,
|
||||
(MINIDUMP_TYPE)flags,
|
||||
&ExInfo,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
PVIGEM_CLIENT vigem_alloc()
|
||||
{
|
||||
SetUnhandledExceptionFilter(vigem_internal_exception_handler);
|
||||
|
||||
const auto driver = static_cast<PVIGEM_CLIENT>(malloc(sizeof(VIGEM_CLIENT)));
|
||||
|
||||
if (!driver)
|
||||
return nullptr;
|
||||
|
||||
RtlZeroMemory(driver, sizeof(VIGEM_CLIENT));
|
||||
driver->hBusDevice = INVALID_HANDLE_VALUE;
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
void vigem_free(PVIGEM_CLIENT vigem)
|
||||
{
|
||||
if (vigem)
|
||||
free(vigem);
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
|
||||
deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
|
||||
DWORD memberIndex = 0;
|
||||
DWORD requiredSize = 0;
|
||||
auto error = VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
// check for already open handle as re-opening accidentally would destroy all live targets
|
||||
if (vigem->hBusDevice != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return VIGEM_ERROR_BUS_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
const auto deviceInfoSet = SetupDiGetClassDevs(
|
||||
&GUID_DEVINTERFACE_BUSENUM_VIGEM,
|
||||
nullptr,
|
||||
nullptr,
|
||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
|
||||
);
|
||||
|
||||
// enumerate device instances
|
||||
while (SetupDiEnumDeviceInterfaces(
|
||||
deviceInfoSet,
|
||||
nullptr,
|
||||
&GUID_DEVINTERFACE_BUSENUM_VIGEM,
|
||||
memberIndex++,
|
||||
&deviceInterfaceData
|
||||
))
|
||||
{
|
||||
// get required target buffer size
|
||||
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, nullptr, 0, &requiredSize, nullptr);
|
||||
|
||||
// allocate target buffer
|
||||
const auto detailDataBuffer = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(requiredSize));
|
||||
detailDataBuffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
|
||||
// get detail buffer
|
||||
if (!SetupDiGetDeviceInterfaceDetail(
|
||||
deviceInfoSet,
|
||||
&deviceInterfaceData,
|
||||
detailDataBuffer,
|
||||
requiredSize,
|
||||
&requiredSize,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||
free(detailDataBuffer);
|
||||
error = VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
continue;
|
||||
}
|
||||
|
||||
// bus found, open it
|
||||
vigem->hBusDevice = CreateFile(
|
||||
detailDataBuffer->DevicePath,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// check bus open result
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
error = VIGEM_ERROR_BUS_ACCESS_FAILED;
|
||||
free(detailDataBuffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD transferred = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
VIGEM_CHECK_VERSION version;
|
||||
VIGEM_CHECK_VERSION_INIT(&version, VIGEM_COMMON_VERSION);
|
||||
|
||||
// send compiled library version to driver to check compatibility
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_VIGEM_CHECK_VERSION,
|
||||
&version,
|
||||
version.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
// wait for result
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transferred, TRUE) != 0)
|
||||
{
|
||||
error = VIGEM_ERROR_NONE;
|
||||
free(detailDataBuffer);
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
error = VIGEM_ERROR_BUS_VERSION_MISMATCH;
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
free(detailDataBuffer);
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void vigem_disconnect(PVIGEM_CLIENT vigem)
|
||||
{
|
||||
if (!vigem)
|
||||
return;
|
||||
|
||||
if (vigem->hBusDevice != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(vigem->hBusDevice);
|
||||
|
||||
RtlZeroMemory(vigem, sizeof(VIGEM_CLIENT));
|
||||
vigem->hBusDevice = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
PVIGEM_TARGET vigem_target_x360_alloc(void)
|
||||
{
|
||||
const auto target = VIGEM_TARGET_ALLOC_INIT(Xbox360Wired);
|
||||
|
||||
if (!target)
|
||||
return nullptr;
|
||||
|
||||
target->VendorId = 0x045E;
|
||||
target->ProductId = 0x028E;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
PVIGEM_TARGET vigem_target_ds4_alloc(void)
|
||||
{
|
||||
const auto target = VIGEM_TARGET_ALLOC_INIT(DualShock4Wired);
|
||||
|
||||
if (!target)
|
||||
return nullptr;
|
||||
|
||||
target->VendorId = 0x054C;
|
||||
target->ProductId = 0x05C4;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
void vigem_target_free(PVIGEM_TARGET target)
|
||||
{
|
||||
if (target)
|
||||
free(target);
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->State == VIGEM_TARGET_NEW)
|
||||
return VIGEM_ERROR_TARGET_UNINITIALIZED;
|
||||
|
||||
if (target->State == VIGEM_TARGET_CONNECTED)
|
||||
return VIGEM_ERROR_ALREADY_CONNECTED;
|
||||
|
||||
DWORD transferred = 0;
|
||||
VIGEM_PLUGIN_TARGET plugin;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
for (target->SerialNo = 1; target->SerialNo <= VIGEM_TARGETS_MAX; target->SerialNo++)
|
||||
{
|
||||
VIGEM_PLUGIN_TARGET_INIT(&plugin, target->SerialNo, target->Type);
|
||||
|
||||
plugin.VendorId = target->VendorId;
|
||||
plugin.ProductId = target->ProductId;
|
||||
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_VIGEM_PLUGIN_TARGET,
|
||||
&plugin,
|
||||
plugin.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transferred, TRUE) != 0)
|
||||
{
|
||||
target->State = VIGEM_TARGET_CONNECTED;
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_NO_FREE_SLOT;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_add_async(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PFN_VIGEM_TARGET_ADD_RESULT result)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->State == VIGEM_TARGET_NEW)
|
||||
return VIGEM_ERROR_TARGET_UNINITIALIZED;
|
||||
|
||||
if (target->State == VIGEM_TARGET_CONNECTED)
|
||||
return VIGEM_ERROR_ALREADY_CONNECTED;
|
||||
|
||||
std::thread _async{ [](
|
||||
PVIGEM_TARGET _Target,
|
||||
PVIGEM_CLIENT _Client,
|
||||
PFN_VIGEM_TARGET_ADD_RESULT _Result)
|
||||
{
|
||||
DWORD transferred = 0;
|
||||
VIGEM_PLUGIN_TARGET plugin;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
for (_Target->SerialNo = 1; _Target->SerialNo <= VIGEM_TARGETS_MAX; _Target->SerialNo++)
|
||||
{
|
||||
VIGEM_PLUGIN_TARGET_INIT(&plugin, _Target->SerialNo, _Target->Type);
|
||||
|
||||
plugin.VendorId = _Target->VendorId;
|
||||
plugin.ProductId = _Target->ProductId;
|
||||
|
||||
DeviceIoControl(
|
||||
_Client->hBusDevice,
|
||||
IOCTL_VIGEM_PLUGIN_TARGET,
|
||||
&plugin,
|
||||
plugin.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(_Client->hBusDevice, &lOverlapped, &transferred, TRUE) != 0)
|
||||
{
|
||||
_Target->State = VIGEM_TARGET_CONNECTED;
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
if (_Result)
|
||||
_Result(_Client, _Target, VIGEM_ERROR_NONE);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
if (_Result)
|
||||
_Result(_Client, _Target, VIGEM_ERROR_NO_FREE_SLOT);
|
||||
|
||||
}, target, vigem, result };
|
||||
|
||||
_async.detach();
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->State == VIGEM_TARGET_NEW)
|
||||
return VIGEM_ERROR_TARGET_UNINITIALIZED;
|
||||
|
||||
if (target->State != VIGEM_TARGET_CONNECTED)
|
||||
return VIGEM_ERROR_TARGET_NOT_PLUGGED_IN;
|
||||
|
||||
DWORD transfered = 0;
|
||||
VIGEM_UNPLUG_TARGET unplug;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
VIGEM_UNPLUG_TARGET_INIT(&unplug, target->SerialNo);
|
||||
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_VIGEM_UNPLUG_TARGET,
|
||||
&unplug,
|
||||
unplug.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transfered,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, TRUE) != 0)
|
||||
{
|
||||
target->State = VIGEM_TARGET_DISCONNECTED;
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_REMOVAL_FAILED;
|
||||
}
|
||||
|
||||
// Num of items in Notification DeviceIOControl queue (at any time there should be at least one extra call waiting for the new events or there is danger that notification events are lost).
|
||||
// The size of this queue is based on "scientific" experimentals and estimations (few games seem to sometimes flood the FFB driver interface).
|
||||
#define NOTIFICATION_OVERLAPPED_QUEUE_SIZE 6
|
||||
|
||||
void vigem_notification_thread_worker(
|
||||
PVIGEM_CLIENT client,
|
||||
PVIGEM_TARGET target,
|
||||
std::unique_ptr <std::vector<std::unique_ptr<NotificationRequestPayload>>> pNotificationRequestPayload
|
||||
)
|
||||
{
|
||||
int idx;
|
||||
DWORD error;
|
||||
|
||||
HANDLE waitObjects[2];
|
||||
|
||||
BOOL devIoResult[NOTIFICATION_OVERLAPPED_QUEUE_SIZE];
|
||||
DWORD lastIoError[NOTIFICATION_OVERLAPPED_QUEUE_SIZE];
|
||||
DWORD transferred[NOTIFICATION_OVERLAPPED_QUEUE_SIZE];
|
||||
OVERLAPPED lOverlapped[NOTIFICATION_OVERLAPPED_QUEUE_SIZE];
|
||||
|
||||
int currentOverlappedIdx;
|
||||
int futureOverlappedIdx;
|
||||
|
||||
memset(lOverlapped, 0, sizeof(lOverlapped));
|
||||
for(idx = 0; idx < NOTIFICATION_OVERLAPPED_QUEUE_SIZE; idx++)
|
||||
lOverlapped[idx].hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
waitObjects[0] = target->cancelNotificationThreadEvent;
|
||||
|
||||
currentOverlappedIdx = 0;
|
||||
futureOverlappedIdx = NOTIFICATION_OVERLAPPED_QUEUE_SIZE - 1;
|
||||
|
||||
// Send out DeviceIOControl calls to wait for incoming feedback notifications. Use N pending requests to make sure that events are not lost even when application would flood FFB events.
|
||||
// The order of DeviceIoControl calls and GetOverlappedResult requests is important to ensure that feedback callback function is called in correct order (ie. FIFO buffer with FFB events).
|
||||
// Note! This loop doesn't call DevIo for the last lOverlapped item on purpose. The DO while loop does it as a first step (futureOverlappedIdx=NOTIFICATION_OVERLAPPED_QUEUE_SIZE-1 in the first loop round).
|
||||
for (idx = 0; idx < NOTIFICATION_OVERLAPPED_QUEUE_SIZE-1; idx++)
|
||||
{
|
||||
devIoResult[idx] = DeviceIoControl(client->hBusDevice,
|
||||
(*pNotificationRequestPayload)[idx]->ioControlCode,
|
||||
(*pNotificationRequestPayload)[idx]->lpPayloadBuffer,
|
||||
(*pNotificationRequestPayload)[idx]->payloadBufferSize,
|
||||
(*pNotificationRequestPayload)[idx]->lpPayloadBuffer,
|
||||
(*pNotificationRequestPayload)[idx]->payloadBufferSize,
|
||||
&transferred[idx],
|
||||
&lOverlapped[idx]);
|
||||
|
||||
lastIoError[idx] = GetLastError();
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Before reading data from "current overlapped request" then send a new DeviceIoControl request to wait for upcoming new FFB events (ring buffer of overlapped objects).
|
||||
devIoResult[futureOverlappedIdx] = DeviceIoControl(client->hBusDevice,
|
||||
(*pNotificationRequestPayload)[futureOverlappedIdx]->ioControlCode,
|
||||
(*pNotificationRequestPayload)[futureOverlappedIdx]->lpPayloadBuffer,
|
||||
(*pNotificationRequestPayload)[futureOverlappedIdx]->payloadBufferSize,
|
||||
(*pNotificationRequestPayload)[futureOverlappedIdx]->lpPayloadBuffer,
|
||||
(*pNotificationRequestPayload)[futureOverlappedIdx]->payloadBufferSize,
|
||||
&transferred[futureOverlappedIdx],
|
||||
&lOverlapped[futureOverlappedIdx]);
|
||||
|
||||
lastIoError[futureOverlappedIdx] = GetLastError();
|
||||
|
||||
// currentOverlappedIdx is an index to the "oldest" DeviceIOControl call, so it will receive the next FFB event in a FFB sequence (in case there are multiple FFB events coming in)
|
||||
if (!devIoResult[currentOverlappedIdx])
|
||||
{
|
||||
if (lastIoError[currentOverlappedIdx] == ERROR_IO_PENDING)
|
||||
{
|
||||
// DeviceIoControl is not yet completed to return all data. Wait for overlapped completion and thread cancellation events
|
||||
waitObjects[1] = lOverlapped[currentOverlappedIdx].hEvent;
|
||||
error = WaitForMultipleObjects(2, waitObjects, FALSE, INFINITE);
|
||||
if (error != (WAIT_OBJECT_0 + 1))
|
||||
break; // Cancel event signaled or error while waiting for events (maybe handles were closed?). Quit this thread worker
|
||||
|
||||
// At this point overlapped event was signaled by a device driver and data is ready and waiting for in a buffer. The next GetOverlappedResult call should return immediately.
|
||||
}
|
||||
else
|
||||
// Hmm... DeviceIoControl failed and is not just in async pending state. Quit the notification thread because the virtual controller may be in unknown state or device handles were closed
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetOverlappedResult(client->hBusDevice, &lOverlapped[currentOverlappedIdx], &transferred[currentOverlappedIdx], TRUE) != 0)
|
||||
(*pNotificationRequestPayload)[currentOverlappedIdx]->ProcessNotificationRequest(client, target);
|
||||
|
||||
if (currentOverlappedIdx >= NOTIFICATION_OVERLAPPED_QUEUE_SIZE-1)
|
||||
currentOverlappedIdx = 0;
|
||||
else
|
||||
currentOverlappedIdx++;
|
||||
|
||||
if (futureOverlappedIdx >= NOTIFICATION_OVERLAPPED_QUEUE_SIZE-1)
|
||||
futureOverlappedIdx = 0;
|
||||
else
|
||||
futureOverlappedIdx++;
|
||||
} while (target->closingNotificationThreads != TRUE && target->Notification != nullptr);
|
||||
|
||||
for (idx = 0; idx < NOTIFICATION_OVERLAPPED_QUEUE_SIZE; idx++)
|
||||
if(lOverlapped[idx].hEvent)
|
||||
CloseHandle(lOverlapped[idx].hEvent);
|
||||
|
||||
// Caller created the unique_ptr object, but this thread worker function should delete the object because it is no longer needed (thread specific object)
|
||||
pNotificationRequestPayload.reset();
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_x360_register_notification(
|
||||
PVIGEM_CLIENT vigem,
|
||||
PVIGEM_TARGET target,
|
||||
PFN_VIGEM_X360_NOTIFICATION notification,
|
||||
LPVOID userData
|
||||
)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->SerialNo == 0 || notification == nullptr)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (target->Notification == reinterpret_cast<FARPROC>(notification))
|
||||
return VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED;
|
||||
|
||||
target->Notification = reinterpret_cast<FARPROC>(notification);
|
||||
target->NotificationUserData = userData;
|
||||
|
||||
if (target->cancelNotificationThreadEvent == 0)
|
||||
target->cancelNotificationThreadEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
else
|
||||
ResetEvent(target->cancelNotificationThreadEvent);
|
||||
|
||||
if(target->notificationThreadList == nullptr)
|
||||
target->notificationThreadList = std::make_unique<std::vector<std::thread>>();
|
||||
|
||||
target->closingNotificationThreads = FALSE;
|
||||
|
||||
std::unique_ptr<std::vector<std::unique_ptr<NotificationRequestPayload>>> payloadVector = std::make_unique<std::vector<std::unique_ptr<NotificationRequestPayload>>>();
|
||||
payloadVector->reserve(NOTIFICATION_OVERLAPPED_QUEUE_SIZE);
|
||||
for (int idx = 0; idx < NOTIFICATION_OVERLAPPED_QUEUE_SIZE; idx++)
|
||||
payloadVector->push_back(std::make_unique<NotificationRequestPayloadX360>(target->SerialNo));
|
||||
|
||||
// Nowadays there is only one background thread listening for incoming FFB events, but there used to be more. This code still uses notificationThreadList vector even
|
||||
// when there is only one item in the vector. If it is someday find out that this logic needs more background threads then it is easy to do because the thread vector is already in place.
|
||||
//for (int i = 0; i < 1; i++)
|
||||
target->notificationThreadList->emplace_back(std::thread(&vigem_notification_thread_worker, vigem, target, std::move(payloadVector)));
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_ds4_register_notification(
|
||||
PVIGEM_CLIENT vigem,
|
||||
PVIGEM_TARGET target,
|
||||
PFN_VIGEM_DS4_NOTIFICATION notification,
|
||||
LPVOID userData
|
||||
)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->SerialNo == 0 || notification == nullptr)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (target->Notification == reinterpret_cast<FARPROC>(notification))
|
||||
return VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED;
|
||||
|
||||
target->Notification = reinterpret_cast<FARPROC>(notification);
|
||||
target->NotificationUserData = userData;
|
||||
|
||||
if (target->cancelNotificationThreadEvent == 0)
|
||||
target->cancelNotificationThreadEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
else
|
||||
ResetEvent(target->cancelNotificationThreadEvent);
|
||||
|
||||
if (target->notificationThreadList == nullptr)
|
||||
target->notificationThreadList = std::make_unique<std::vector<std::thread>>();
|
||||
|
||||
target->closingNotificationThreads = FALSE;
|
||||
|
||||
std::unique_ptr<std::vector<std::unique_ptr<NotificationRequestPayload>>> payloadVector = std::make_unique<std::vector<std::unique_ptr<NotificationRequestPayload>>>();
|
||||
payloadVector->reserve(NOTIFICATION_OVERLAPPED_QUEUE_SIZE);
|
||||
for (int idx = 0; idx < NOTIFICATION_OVERLAPPED_QUEUE_SIZE; idx++)
|
||||
payloadVector->push_back(std::make_unique<NotificationRequestPayloadDS4>(target->SerialNo));
|
||||
|
||||
//for (int i = 0; i < 1; i++)
|
||||
target->notificationThreadList->emplace_back(std::thread(&vigem_notification_thread_worker, vigem, target, std::move(payloadVector)));
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
void vigem_target_x360_unregister_notification(PVIGEM_TARGET target)
|
||||
{
|
||||
target->closingNotificationThreads = TRUE;
|
||||
|
||||
if (target->cancelNotificationThreadEvent != 0)
|
||||
SetEvent(target->cancelNotificationThreadEvent);
|
||||
|
||||
if (target->notificationThreadList != nullptr)
|
||||
{
|
||||
// Wait for completion of all notification threads before cleaning up target object and Notification function pointer (a thread may be in the middle of handling a notification request, so close it cleanly)
|
||||
std::for_each(target->notificationThreadList->begin(), target->notificationThreadList->end(), std::mem_fn(&std::thread::join));
|
||||
target->notificationThreadList.reset();
|
||||
target->notificationThreadList = nullptr;
|
||||
}
|
||||
|
||||
if (target->cancelNotificationThreadEvent != 0)
|
||||
{
|
||||
CloseHandle(target->cancelNotificationThreadEvent);
|
||||
target->cancelNotificationThreadEvent = 0;
|
||||
}
|
||||
|
||||
target->Notification = nullptr;
|
||||
target->NotificationUserData = nullptr;
|
||||
}
|
||||
|
||||
void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target)
|
||||
{
|
||||
vigem_target_x360_unregister_notification(target); // The same x360_unregister handler works for DS4_unregister also
|
||||
}
|
||||
|
||||
void vigem_target_set_vid(PVIGEM_TARGET target, USHORT vid)
|
||||
{
|
||||
target->VendorId = vid;
|
||||
}
|
||||
|
||||
void vigem_target_set_pid(PVIGEM_TARGET target, USHORT pid)
|
||||
{
|
||||
target->ProductId = pid;
|
||||
}
|
||||
|
||||
USHORT vigem_target_get_vid(PVIGEM_TARGET target)
|
||||
{
|
||||
return target->VendorId;
|
||||
}
|
||||
|
||||
USHORT vigem_target_get_pid(PVIGEM_TARGET target)
|
||||
{
|
||||
return target->ProductId;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_x360_update(
|
||||
PVIGEM_CLIENT vigem,
|
||||
PVIGEM_TARGET target,
|
||||
XUSB_REPORT report
|
||||
)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->SerialNo == 0)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
DWORD transferred = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
XUSB_SUBMIT_REPORT xsr;
|
||||
XUSB_SUBMIT_REPORT_INIT(&xsr, target->SerialNo);
|
||||
|
||||
xsr.Report = report;
|
||||
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_XUSB_SUBMIT_REPORT,
|
||||
&xsr,
|
||||
xsr.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transferred, TRUE) == 0)
|
||||
{
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_ds4_update(
|
||||
PVIGEM_CLIENT vigem,
|
||||
PVIGEM_TARGET target,
|
||||
DS4_REPORT report
|
||||
)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->SerialNo == 0)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
DWORD transferred = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
DS4_SUBMIT_REPORT dsr;
|
||||
DS4_SUBMIT_REPORT_INIT(&dsr, target->SerialNo);
|
||||
|
||||
dsr.Report = report;
|
||||
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_DS4_SUBMIT_REPORT,
|
||||
&dsr,
|
||||
dsr.Size,
|
||||
nullptr,
|
||||
0,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transferred, TRUE) == 0)
|
||||
{
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
ULONG vigem_target_get_index(PVIGEM_TARGET target)
|
||||
{
|
||||
return target->SerialNo;
|
||||
}
|
||||
|
||||
VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target)
|
||||
{
|
||||
return target->Type;
|
||||
}
|
||||
|
||||
BOOL vigem_target_is_attached(PVIGEM_TARGET target)
|
||||
{
|
||||
return (target->State == VIGEM_TARGET_CONNECTED);
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_x360_get_user_index(
|
||||
PVIGEM_CLIENT vigem,
|
||||
PVIGEM_TARGET target,
|
||||
PULONG index
|
||||
)
|
||||
{
|
||||
if (!vigem)
|
||||
return VIGEM_ERROR_BUS_INVALID_HANDLE;
|
||||
|
||||
if (!target)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
|
||||
if (target->SerialNo == 0 || target->Type != Xbox360Wired)
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
|
||||
if (!index)
|
||||
return VIGEM_ERROR_INVALID_PARAMETER;
|
||||
|
||||
DWORD transferred = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
XUSB_GET_USER_INDEX gui;
|
||||
XUSB_GET_USER_INDEX_INIT(&gui, target->SerialNo);
|
||||
|
||||
DeviceIoControl(
|
||||
vigem->hBusDevice,
|
||||
IOCTL_XUSB_GET_USER_INDEX,
|
||||
&gui,
|
||||
gui.Size,
|
||||
&gui,
|
||||
gui.Size,
|
||||
&transferred,
|
||||
&lOverlapped
|
||||
);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transferred, TRUE) == 0)
|
||||
{
|
||||
const auto error = GetLastError();
|
||||
|
||||
if (error == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
|
||||
if (error == ERROR_INVALID_DEVICE_OBJECT_PARAMETER)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return VIGEM_ERROR_XUSB_USERINDEX_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
*index = gui.UserIndex;
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
110
sdk/src/ViGEmClient.rc
Normal file
110
sdk/src/ViGEmClient.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Nefarius Software Solutions e.U."
|
||||
VALUE "FileDescription", "Virtual Gamepad Emulation Framework User-Mode Library"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "InternalName", "ViGEmClient.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2017-2020 Nefarius Software Solutions e.U."
|
||||
VALUE "OriginalFilename", "ViGEmClient.dll"
|
||||
VALUE "ProductName", "Virtual Gamepad Emulation Framework User-Mode Library"
|
||||
VALUE "ProductVersion", "1.0.0.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x809, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
318
sdk/src/ViGEmClient.vcxproj
Normal file
318
sdk/src/ViGEmClient.vcxproj
Normal file
@@ -0,0 +1,318 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug_DLL|Win32">
|
||||
<Configuration>Debug_DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug_DLL|x64">
|
||||
<Configuration>Debug_DLL</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug_LIB|Win32">
|
||||
<Configuration>Debug_LIB</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release_DLL|Win32">
|
||||
<Configuration>Release_DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release_DLL|x64">
|
||||
<Configuration>Release_DLL</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release_LIB|Win32">
|
||||
<Configuration>Release_LIB</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug_LIB|x64">
|
||||
<Configuration>Debug_LIB</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release_LIB|x64">
|
||||
<Configuration>Release_LIB</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7DB06674-1F4F-464B-8E1C-172E9587F9DC}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ViGEmClient</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'==''">
|
||||
<!-- Latest Target Version property -->
|
||||
<LatestTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</LatestTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0</WindowsTargetPlatformVersion>
|
||||
<TargetPlatformVersion>$(WindowsTargetPlatformVersion)</TargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release_LIB|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release_LIB|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|Win32'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\debug\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|Win32'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\debug\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|Win32'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\release\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|Win32'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\release\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|x64'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\debug\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|x64'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\debug\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|x64'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\release\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|x64'">
|
||||
<IncludePath>$(ProjectDir)../include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\release\$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;VIGEM_DYNAMIC;VIGEM_EXPORTS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalDependencies>setupapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_LIB|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DLL|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;VIGEM_DYNAMIC;VIGEM_EXPORTS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalDependencies>setupapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;VIGEM_DYNAMIC;VIGEM_EXPORTS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>setupapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_LIB|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_DLL|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;VIGEM_DYNAMIC;VIGEM_EXPORTS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>setupapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Client.h" />
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Common.h" />
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Util.h" />
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\km\BusShared.h" />
|
||||
<ClInclude Include="Internal.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ViGEmClient.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ViGEmClient.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
53
sdk/src/ViGEmClient.vcxproj.filters
Normal file
53
sdk/src/ViGEmClient.vcxproj.filters
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ViGEm">
|
||||
<UniqueIdentifier>{3355fb06-3745-4161-8c61-b8bca15ff8fa}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ViGEm\km">
|
||||
<UniqueIdentifier>{e0df94ae-e213-4f04-981d-02d6d321df28}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Util.h">
|
||||
<Filter>Header Files\ViGEm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Common.h">
|
||||
<Filter>Header Files\ViGEm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\Client.h">
|
||||
<Filter>Header Files\ViGEm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Internal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)\include\ViGEm\km\BusShared.h">
|
||||
<Filter>Header Files\ViGEm\km</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ViGEmClient.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ViGEmClient.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
14
sdk/src/resource.h
Normal file
14
sdk/src/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ViGEmClient.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user