mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
Moved client library project to new folder structure
This commit is contained in:
636
ViGEmClient.cpp
Normal file
636
ViGEmClient.cpp
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Benjamin "Nefarius" H<>glinger
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <SetupAPI.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#include "ViGEmBusShared.h"
|
||||
#include "ViGEmClient.h"
|
||||
#include <winioctl.h>
|
||||
#include <limits.h>
|
||||
#include <mutex>
|
||||
|
||||
#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;
|
||||
DWORD_PTR Notification;
|
||||
|
||||
} VIGEM_TARGET;
|
||||
|
||||
//
|
||||
// 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)));
|
||||
RtlZeroMemory(target, sizeof(VIGEM_TARGET));
|
||||
|
||||
target->Size = sizeof(VIGEM_TARGET);
|
||||
target->State = VIGEM_TARGET_INITIALIZED;
|
||||
target->Type = Type;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
PVIGEM_CLIENT vigem_alloc()
|
||||
{
|
||||
auto driver = static_cast<PVIGEM_CLIENT>(malloc(sizeof(VIGEM_CLIENT)));
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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_OVERLAPPED,
|
||||
nullptr);
|
||||
|
||||
// check bus open result
|
||||
if (vigem->hBusDevice == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
error = VIGEM_ERROR_BUS_ACCESS_FAILED;
|
||||
free(detailDataBuffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD transfered = 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, &transfered, &lOverlapped);
|
||||
|
||||
// wait for result
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, 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->hBusDevice != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(vigem->hBusDevice);
|
||||
|
||||
RtlZeroMemory(vigem, sizeof(VIGEM_CLIENT));
|
||||
vigem->hBusDevice = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
PVIGEM_TARGET vigem_target_x360_alloc(void)
|
||||
{
|
||||
auto target = VIGEM_TARGET_ALLOC_INIT(Xbox360Wired);
|
||||
|
||||
target->VendorId = 0x045E;
|
||||
target->ProductId = 0x028E;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
PVIGEM_TARGET vigem_target_ds4_alloc(void)
|
||||
{
|
||||
auto target = VIGEM_TARGET_ALLOC_INIT(DualShock4Wired);
|
||||
|
||||
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->hBusDevice == nullptr)
|
||||
{
|
||||
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 transfered = 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, &transfered, &lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, 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, PVIGEM_TARGET_ADD_RESULT result)
|
||||
{
|
||||
if (vigem->hBusDevice == nullptr)
|
||||
{
|
||||
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,
|
||||
PVIGEM_TARGET_ADD_RESULT _Result)
|
||||
{
|
||||
DWORD transfered = 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, &transfered, &lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(_Client->hBusDevice, &lOverlapped, &transfered, 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->hBusDevice == nullptr)
|
||||
{
|
||||
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);
|
||||
|
||||
//g_xusbCallbacks.erase(Target->SerialNo);
|
||||
//g_ds4Callbacks.erase(Target->SerialNo);
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
return VIGEM_ERROR_REMOVAL_FAILED;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_x360_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PVIGEM_X360_NOTIFICATION notification)
|
||||
{
|
||||
if (vigem->hBusDevice == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (target->SerialNo == 0 || notification == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
|
||||
if (target->Notification == reinterpret_cast<DWORD_PTR>(notification))
|
||||
{
|
||||
return VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
target->Notification = reinterpret_cast<DWORD_PTR>(notification);
|
||||
|
||||
std::thread _async{ [](
|
||||
PVIGEM_TARGET _Target,
|
||||
PVIGEM_CLIENT _Client)
|
||||
{
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
DWORD transfered = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
XUSB_REQUEST_NOTIFICATION notify;
|
||||
XUSB_REQUEST_NOTIFICATION_INIT(¬ify, _Target->SerialNo);
|
||||
|
||||
do
|
||||
{
|
||||
DeviceIoControl(_Client->hBusDevice,
|
||||
IOCTL_XUSB_REQUEST_NOTIFICATION,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
&transfered,
|
||||
&lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(_Client->hBusDevice, &lOverlapped, &transfered, TRUE) != 0)
|
||||
{
|
||||
if (_Target->Notification == NULL)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
reinterpret_cast<PVIGEM_X360_NOTIFICATION>(_Target->Notification)(
|
||||
_Client,
|
||||
_Target,
|
||||
notify.LargeMotor,
|
||||
notify.SmallMotor,
|
||||
notify.LedNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = GetLastError();
|
||||
}
|
||||
} while (error != ERROR_OPERATION_ABORTED && error != ERROR_ACCESS_DENIED);
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
}, target, vigem };
|
||||
|
||||
_async.detach();
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_ds4_register_notification(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PVIGEM_DS4_NOTIFICATION notification)
|
||||
{
|
||||
if (vigem->hBusDevice == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (target->SerialNo == 0 || notification == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
|
||||
if (target->Notification == reinterpret_cast<DWORD_PTR>(notification))
|
||||
{
|
||||
return VIGEM_ERROR_CALLBACK_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
target->Notification = reinterpret_cast<DWORD_PTR>(notification);
|
||||
|
||||
std::thread _async{ [](
|
||||
PVIGEM_TARGET _Target,
|
||||
PVIGEM_CLIENT _Client)
|
||||
{
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
DWORD transfered = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
DS4_REQUEST_NOTIFICATION notify;
|
||||
DS4_REQUEST_NOTIFICATION_INIT(¬ify, _Target->SerialNo);
|
||||
|
||||
do
|
||||
{
|
||||
DeviceIoControl(_Client->hBusDevice,
|
||||
IOCTL_DS4_REQUEST_NOTIFICATION,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
&transfered,
|
||||
&lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(_Client->hBusDevice, &lOverlapped, &transfered, TRUE) != 0)
|
||||
{
|
||||
if (_Target->Notification == NULL)
|
||||
{
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
reinterpret_cast<PVIGEM_DS4_NOTIFICATION>(_Target->Notification)(
|
||||
_Client,
|
||||
_Target,
|
||||
notify.Report.LargeMotor,
|
||||
notify.Report.SmallMotor,
|
||||
notify.Report.LightbarColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = GetLastError();
|
||||
}
|
||||
} while (error != ERROR_OPERATION_ABORTED && error != ERROR_ACCESS_DENIED);
|
||||
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
|
||||
}, target, vigem };
|
||||
|
||||
_async.detach();
|
||||
|
||||
return VIGEM_ERROR_NONE;
|
||||
}
|
||||
|
||||
void vigem_target_x360_unregister_notification(PVIGEM_TARGET target)
|
||||
{
|
||||
target->Notification = NULL;
|
||||
}
|
||||
|
||||
void vigem_target_ds4_unregister_notification(PVIGEM_TARGET target)
|
||||
{
|
||||
target->Notification = NULL;
|
||||
}
|
||||
|
||||
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->hBusDevice == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (target->SerialNo == 0)
|
||||
{
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
|
||||
DWORD transfered = 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, &transfered, &lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, 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->hBusDevice == nullptr)
|
||||
{
|
||||
return VIGEM_ERROR_BUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (target->SerialNo == 0)
|
||||
{
|
||||
return VIGEM_ERROR_INVALID_TARGET;
|
||||
}
|
||||
|
||||
DWORD transfered = 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, &transfered, &lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, 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);
|
||||
}
|
||||
99
ViGEmClient.rc
Normal file
99
ViGEmClient.rc
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// German (Austria) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA)
|
||||
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN
|
||||
|
||||
#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
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,12,1,0
|
||||
PRODUCTVERSION 1,12,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x7L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "0c0704b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Benjamin H<>glinger-Stelzer"
|
||||
VALUE "FileDescription", "Virtual Gamepad Emulation User-Mode Library"
|
||||
VALUE "FileVersion", "1.12.1.0"
|
||||
VALUE "InternalName", "Virtual Gamepad Emulation User-Mode Library"
|
||||
VALUE "LegalCopyright", "Copyright (C) Benjamin H<>glinger-Stelzer 2017"
|
||||
VALUE "OriginalFilename", "ViGEmCli.lib"
|
||||
VALUE "ProductName", "Virtual Gamepad Emulation User-Mode Library"
|
||||
VALUE "ProductVersion", "1.12.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0xc07, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // German (Austria) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
160
ViGEmClient.vcxproj
Normal file
160
ViGEmClient.vcxproj
Normal file
@@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7DB06674-1F4F-464B-8E1C-172E9587F9DC}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ViGEmClient</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</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|Win32'">
|
||||
<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|Win32'">
|
||||
<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|x64'">
|
||||
<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|x64'">
|
||||
<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|Win32'">
|
||||
<IncludePath>$(SolutionDir)Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IncludePath>$(SolutionDir)Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>$(SolutionDir)Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>$(SolutionDir)Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Include\ViGEmBusShared.h" />
|
||||
<ClInclude Include="..\Include\ViGEmClient.h" />
|
||||
<ClInclude Include="..\Include\ViGEmCommon.h" />
|
||||
<ClInclude Include="..\Include\ViGEmUtil.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>
|
||||
44
ViGEmClient.vcxproj.filters
Normal file
44
ViGEmClient.vcxproj.filters
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Include\ViGEmClient.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ViGEmBusShared.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ViGEmCommon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ViGEmUtil.h">
|
||||
<Filter>Header Files</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
resource.h
Normal file
14
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