diff --git a/src/Internal.h b/src/Internal.h new file mode 100644 index 0000000..3c3076a --- /dev/null +++ b/src/Internal.h @@ -0,0 +1,48 @@ +#pragma once +#include "XusbNotificationRequest.h" +#include "NotificationRequestPool.h" + +// +// 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; + + boost::shared_ptr io_svc; + boost::shared_ptr worker; + boost::shared_ptr worker_threads; + boost::shared_ptr enqueue_lock; + + std::shared_ptr pool; + + HANDLE WaitHandles[VIGEM_INVERTED_CALL_THREAD_COUNT]; + std::vector notify_req; + +} VIGEM_TARGET; diff --git a/src/NotificationRequestPool.cpp b/src/NotificationRequestPool.cpp new file mode 100644 index 0000000..d9eda03 --- /dev/null +++ b/src/NotificationRequestPool.cpp @@ -0,0 +1,79 @@ +#include "NotificationRequestPool.h" + +NotificationRequestPool::NotificationRequestPool( + HANDLE bus, + const ULONG serial, + PFN_VIGEM_X360_NOTIFICATION callback) : + callback_(callback), + stop_(false) +{ + for (auto& wait_handle : wait_handles_) + { + wait_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr); + XusbNotificationRequest req(bus, serial, wait_handle); + requests_.push_back(std::ref(req)); + } + + io_svc_.reset(new boost::asio::io_service()); + worker_.reset(new boost::asio::io_service::work(*io_svc_)); + worker_threads_.reset(new boost::thread_group()); + + thread_ = std::make_shared(boost::ref(*this)); + + for (auto& request : requests_) + request.get().request_async(); +} + +NotificationRequestPool::~NotificationRequestPool() +{ + for (auto& wait_handle : wait_handles_) + CloseHandle(wait_handle); + + thread_->join(); +} + +void NotificationRequestPool::operator()() +{ + boost::asio::io_service::strand strand(*io_svc_); + + while (true) + { + const auto ret = WaitForMultipleObjects( + requests_.size(), + wait_handles_, + FALSE, + INFINITE + ); + + const auto index = ret - WAIT_OBJECT_0; + auto& req = requests_[index].get(); + + //const boost::function pfn = callback_; + + //strand.post(boost::bind(pfn, + // client, + // target, + // notify.LargeMotor, + // notify.SmallMotor, + // notify.LedNumber + //)); + + req.request_async(); + + boost::mutex::scoped_lock lock(m_); + if (stop_) + break; + } +} + +void NotificationRequestPool::terminate() +{ + boost::mutex::scoped_lock lock(m_); + stop_ = true; +} diff --git a/src/NotificationRequestPool.h b/src/NotificationRequestPool.h new file mode 100644 index 0000000..238692d --- /dev/null +++ b/src/NotificationRequestPool.h @@ -0,0 +1,34 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include "XusbNotificationRequest.h" +#include "ViGEm/Client.h" + +#define VIGEM_INVERTED_CALL_THREAD_COUNT 20 + + +class NotificationRequestPool +{ + HANDLE wait_handles_[VIGEM_INVERTED_CALL_THREAD_COUNT]{}; + PFN_VIGEM_X360_NOTIFICATION callback_; + std::vector> requests_; + std::shared_ptr thread_; + boost::mutex m_; + boost::condition_variable cv_; + bool stop_; + + boost::shared_ptr io_svc_; + boost::shared_ptr worker_; + boost::shared_ptr worker_threads_; + +public: + NotificationRequestPool(HANDLE bus, ULONG serial, PFN_VIGEM_X360_NOTIFICATION callback); + ~NotificationRequestPool(); + + void operator()(); + void terminate(); +}; diff --git a/src/ViGEmClient.cpp b/src/ViGEmClient.cpp index e1a9ece..017af7f 100644 --- a/src/ViGEmClient.cpp +++ b/src/ViGEmClient.cpp @@ -55,12 +55,15 @@ SOFTWARE. #include #include +#include "Internal.h" + +#include "NotificationRequestPool.h" + // // TODO: this is... not optimal. Improve in the future. // #define VIGEM_TARGETS_MAX USHRT_MAX -#define VIGEM_INVERTED_CALL_THREAD_COUNT 20 typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)( @@ -75,45 +78,7 @@ typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)( LONG WINAPI vigem_internal_exception_handler(struct _EXCEPTION_POINTERS* apExceptionInfo); -// -// 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; - - boost::shared_ptr io_svc; - boost::shared_ptr worker; - boost::shared_ptr worker_threads; - boost::shared_ptr enqueue_lock; - -} VIGEM_TARGET; // // Initializes a virtual gamepad object. @@ -138,6 +103,9 @@ PVIGEM_TARGET FORCEINLINE VIGEM_TARGET_ALLOC_INIT( target->worker_threads.reset(new boost::thread_group()); target->enqueue_lock.reset(new boost::mutex()); + for (auto& WaitHandle : target->WaitHandles) + WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); + return target; } @@ -625,8 +593,26 @@ VIGEM_ERROR vigem_target_x360_register_notification( target->Notification = reinterpret_cast(notification); - for (int i = 1; i <= VIGEM_INVERTED_CALL_THREAD_COUNT; i++) - target->worker_threads->create_thread(boost::bind(&vigem_internal_x360_notification_worker, target, vigem)); + //for (auto i = 0; i < /* VIGEM_INVERTED_CALL_THREAD_COUNT */ 1; i++) + //{ + // auto req = new XusbNotificationRequest( + // vigem->hBusDevice, + // target->SerialNo, + // target->WaitHandles[i] + // ); + // target->notify_req.emplace_back(req); + // //target->worker_threads->create_thread(*req); + //} + + target->pool = std::make_shared( + vigem->hBusDevice, + target->SerialNo, + PFN_VIGEM_X360_NOTIFICATION(target->Notification) + ); + + + //for (int i = 1; i <= VIGEM_INVERTED_CALL_THREAD_COUNT; i++) + // target->worker_threads->create_thread(boost::bind(&vigem_internal_x360_notification_worker, target, vigem)); return VIGEM_ERROR_NONE; } diff --git a/src/ViGEmClient.vcxproj b/src/ViGEmClient.vcxproj index c06afea..5683040 100644 --- a/src/ViGEmClient.vcxproj +++ b/src/ViGEmClient.vcxproj @@ -305,9 +305,12 @@ + + + diff --git a/src/ViGEmClient.vcxproj.filters b/src/ViGEmClient.vcxproj.filters index 5f0b4b3..ed9f98d 100644 --- a/src/ViGEmClient.vcxproj.filters +++ b/src/ViGEmClient.vcxproj.filters @@ -36,6 +36,12 @@ Header Files + + Header Files + + + Header Files + @@ -44,5 +50,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/XusbNotificationRequest.cpp b/src/XusbNotificationRequest.cpp index 3fbd4e7..9944bcd 100644 --- a/src/XusbNotificationRequest.cpp +++ b/src/XusbNotificationRequest.cpp @@ -4,25 +4,42 @@ XusbNotificationRequest::XusbNotificationRequest( HANDLE bus, ULONG serial, - HANDLE wait + HANDLE notification ) : parent_bus(bus), payload(), transferred(0), overlapped() { - overlapped.hEvent = wait; + overlapped.hEvent = notification; XUSB_REQUEST_NOTIFICATION_INIT(&payload, serial); } -void XusbNotificationRequest::requestAsync() +bool XusbNotificationRequest::request_async() { - DeviceIoControl( + const auto ret = DeviceIoControl( parent_bus, IOCTL_XUSB_REQUEST_NOTIFICATION, &payload, payload.Size, &payload, payload.Size, - &transferred, + nullptr, &overlapped ); + + return (!ret && GetLastError() == ERROR_IO_PENDING); +} + +UCHAR XusbNotificationRequest::get_led_number() const +{ + return payload.LedNumber; +} + +UCHAR XusbNotificationRequest::get_large_motor() const +{ + return payload.LargeMotor; +} + +UCHAR XusbNotificationRequest::get_small_motor() const +{ + return payload.SmallMotor; } diff --git a/src/XusbNotificationRequest.h b/src/XusbNotificationRequest.h index d12df3c..0aa3f8f 100644 --- a/src/XusbNotificationRequest.h +++ b/src/XusbNotificationRequest.h @@ -5,14 +5,16 @@ class XusbNotificationRequest { -private: HANDLE parent_bus; XUSB_REQUEST_NOTIFICATION payload; DWORD transferred; OVERLAPPED overlapped; public: - XusbNotificationRequest(HANDLE bus, ULONG serial, HANDLE wait); + XusbNotificationRequest(HANDLE bus, ULONG serial, HANDLE notification); + bool request_async(); - void requestAsync(); + UCHAR get_led_number() const; + UCHAR get_large_motor() const; + UCHAR get_small_motor() const; };