mirror of
https://github.com/nefarius/ViGEmBus.git
synced 2025-08-10 00:52:17 +00:00
It appears to be working
This commit is contained in:
@@ -22,10 +22,14 @@ VOID CALLBACK notification(
|
||||
{
|
||||
m.lock();
|
||||
|
||||
//std::cout.width(3);
|
||||
//std::cout << (int)LargeMotor << " ";
|
||||
//std::cout.width(3);
|
||||
//std::cout << (int)SmallMotor << std::endl;
|
||||
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;
|
||||
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ typedef enum _VIGEM_TARGET_STATE
|
||||
VIGEM_TARGET_DISCONNECTED
|
||||
} VIGEM_TARGET_STATE, *PVIGEM_TARGET_STATE;
|
||||
|
||||
class NotificationRequestPool;
|
||||
|
||||
//
|
||||
// Represents a virtual gamepad object.
|
||||
//
|
||||
@@ -35,14 +37,6 @@ typedef struct _VIGEM_TARGET_T
|
||||
VIGEM_TARGET_TYPE Type;
|
||||
DWORD_PTR Notification;
|
||||
|
||||
boost::shared_ptr<boost::asio::io_service> io_svc;
|
||||
boost::shared_ptr<boost::asio::io_service::work> worker;
|
||||
boost::shared_ptr<boost::thread_group> worker_threads;
|
||||
boost::shared_ptr<boost::mutex> enqueue_lock;
|
||||
|
||||
std::shared_ptr<NotificationRequestPool> pool;
|
||||
|
||||
HANDLE WaitHandles[VIGEM_INVERTED_CALL_THREAD_COUNT];
|
||||
std::vector<XusbNotificationRequest*> notify_req;
|
||||
|
||||
} VIGEM_TARGET;
|
||||
|
||||
@@ -1,27 +1,48 @@
|
||||
#include "NotificationRequestPool.h"
|
||||
|
||||
void NotificationRequestPool::strand_dispatch_worker() const
|
||||
{
|
||||
io_svc_->run();
|
||||
}
|
||||
|
||||
NotificationRequestPool::NotificationRequestPool(
|
||||
HANDLE bus,
|
||||
const ULONG serial,
|
||||
PFN_VIGEM_X360_NOTIFICATION callback) :
|
||||
PVIGEM_CLIENT client,
|
||||
PVIGEM_TARGET target,
|
||||
PFN_VIGEM_X360_NOTIFICATION callback
|
||||
) :
|
||||
client_(client),
|
||||
target_(target),
|
||||
callback_(callback),
|
||||
stop_(false)
|
||||
{
|
||||
// prepare array of handles and request wrappers
|
||||
for (auto& wait_handle : wait_handles_)
|
||||
{
|
||||
// create auto-reset event
|
||||
wait_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
XusbNotificationRequest req(bus, serial, wait_handle);
|
||||
requests_.push_back(std::ref(req));
|
||||
// create async pending I/O request wrapper
|
||||
auto req = new XusbNotificationRequest(
|
||||
client_->hBusDevice,
|
||||
target_->SerialNo,
|
||||
wait_handle
|
||||
);
|
||||
requests_.push_back(req);
|
||||
}
|
||||
|
||||
// init ASIO
|
||||
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());
|
||||
|
||||
// launch notification completion thread
|
||||
thread_ = std::make_shared<boost::thread>(boost::ref(*this));
|
||||
|
||||
// launch boost I/O service dispatcher thread
|
||||
worker_thread_ = std::make_shared<boost::thread>(
|
||||
boost::bind(&NotificationRequestPool::strand_dispatch_worker, this));
|
||||
|
||||
// submit pending I/O to driver
|
||||
for (auto& request : requests_)
|
||||
request.get().request_async();
|
||||
request->request_async();
|
||||
}
|
||||
|
||||
NotificationRequestPool::~NotificationRequestPool()
|
||||
@@ -29,46 +50,64 @@ NotificationRequestPool::~NotificationRequestPool()
|
||||
for (auto& wait_handle : wait_handles_)
|
||||
CloseHandle(wait_handle);
|
||||
|
||||
io_svc_->stop();
|
||||
worker_thread_->join();
|
||||
|
||||
thread_->join();
|
||||
}
|
||||
|
||||
void NotificationRequestPool::operator()()
|
||||
{
|
||||
// used to dispatch notification callback
|
||||
boost::asio::io_service::strand strand(*io_svc_);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// wait for the first pending I/O to signal its event
|
||||
const auto ret = WaitForMultipleObjects(
|
||||
requests_.size(),
|
||||
wait_handles_,
|
||||
FALSE,
|
||||
INFINITE
|
||||
25
|
||||
);
|
||||
|
||||
// timeout has occurred...
|
||||
if (ret == WAIT_TIMEOUT)
|
||||
{
|
||||
// ...check for termination request
|
||||
boost::mutex::scoped_lock lock(m_);
|
||||
if (stop_)
|
||||
// exits function (terminates thread)
|
||||
break;
|
||||
|
||||
// go for another round
|
||||
continue;
|
||||
}
|
||||
|
||||
// index of the request which just got completed
|
||||
const auto index = ret - WAIT_OBJECT_0;
|
||||
auto& req = requests_[index].get();
|
||||
// grab associated request
|
||||
const auto req = requests_[index];
|
||||
|
||||
//const boost::function<void(
|
||||
// PVIGEM_CLIENT,
|
||||
// PVIGEM_TARGET,
|
||||
// UCHAR,
|
||||
// UCHAR,
|
||||
// UCHAR
|
||||
// )> pfn = callback_;
|
||||
// prepare queueing library caller notification callback
|
||||
const boost::function<void(
|
||||
PVIGEM_CLIENT,
|
||||
PVIGEM_TARGET,
|
||||
UCHAR,
|
||||
UCHAR,
|
||||
UCHAR)> pfn = callback_;
|
||||
|
||||
//strand.post(boost::bind(pfn,
|
||||
// client,
|
||||
// target,
|
||||
// notify.LargeMotor,
|
||||
// notify.SmallMotor,
|
||||
// notify.LedNumber
|
||||
//));
|
||||
// submit callback for async yet ordered invocation
|
||||
strand.post(boost::bind(pfn,
|
||||
client_,
|
||||
target_,
|
||||
req->get_large_motor(),
|
||||
req->get_small_motor(),
|
||||
req->get_led_number()
|
||||
));
|
||||
|
||||
req.request_async();
|
||||
|
||||
boost::mutex::scoped_lock lock(m_);
|
||||
if (stop_)
|
||||
break;
|
||||
// submit another pending I/O
|
||||
req->request_async();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
#include "XusbNotificationRequest.h"
|
||||
#include "ViGEm/Client.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#define VIGEM_INVERTED_CALL_THREAD_COUNT 20
|
||||
|
||||
@@ -14,8 +15,12 @@
|
||||
class NotificationRequestPool
|
||||
{
|
||||
HANDLE wait_handles_[VIGEM_INVERTED_CALL_THREAD_COUNT]{};
|
||||
|
||||
PVIGEM_CLIENT client_;
|
||||
PVIGEM_TARGET target_;
|
||||
PFN_VIGEM_X360_NOTIFICATION callback_;
|
||||
std::vector<std::reference_wrapper<XusbNotificationRequest>> requests_;
|
||||
|
||||
std::vector<XusbNotificationRequest*> requests_;
|
||||
std::shared_ptr<boost::thread> thread_;
|
||||
boost::mutex m_;
|
||||
boost::condition_variable cv_;
|
||||
@@ -23,10 +28,16 @@ class NotificationRequestPool
|
||||
|
||||
boost::shared_ptr<boost::asio::io_service> io_svc_;
|
||||
boost::shared_ptr<boost::asio::io_service::work> worker_;
|
||||
boost::shared_ptr<boost::thread_group> worker_threads_;
|
||||
std::shared_ptr<boost::thread> worker_thread_;
|
||||
|
||||
void strand_dispatch_worker() const;
|
||||
|
||||
public:
|
||||
NotificationRequestPool(HANDLE bus, ULONG serial, PFN_VIGEM_X360_NOTIFICATION callback);
|
||||
NotificationRequestPool(
|
||||
PVIGEM_CLIENT client,
|
||||
PVIGEM_TARGET target,
|
||||
PFN_VIGEM_X360_NOTIFICATION callback
|
||||
);
|
||||
~NotificationRequestPool();
|
||||
|
||||
void operator()();
|
||||
|
||||
@@ -98,14 +98,6 @@ PVIGEM_TARGET FORCEINLINE VIGEM_TARGET_ALLOC_INIT(
|
||||
target->State = VIGEM_TARGET_INITIALIZED;
|
||||
target->Type = Type;
|
||||
|
||||
target->io_svc.reset(new boost::asio::io_service());
|
||||
target->worker.reset(new boost::asio::io_service::work(*target->io_svc));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -139,81 +131,6 @@ LONG WINAPI vigem_internal_exception_handler(struct _EXCEPTION_POINTERS* apExcep
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void vigem_internal_x360_notification_worker(
|
||||
PVIGEM_TARGET target,
|
||||
PVIGEM_CLIENT client
|
||||
)
|
||||
{
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
DWORD transferred = 0;
|
||||
OVERLAPPED lOverlapped = { 0 };
|
||||
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
boost::asio::io_service::strand strand(*target->io_svc);
|
||||
|
||||
XUSB_REQUEST_NOTIFICATION notify;
|
||||
XUSB_REQUEST_NOTIFICATION_INIT(¬ify, target->SerialNo);
|
||||
|
||||
static std::mutex m;
|
||||
|
||||
do
|
||||
{
|
||||
DeviceIoControl(client->hBusDevice,
|
||||
IOCTL_XUSB_REQUEST_NOTIFICATION,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
¬ify,
|
||||
notify.Size,
|
||||
&transferred,
|
||||
&lOverlapped);
|
||||
|
||||
if (GetOverlappedResult(client->hBusDevice, &lOverlapped, &transferred, TRUE) != 0)
|
||||
{
|
||||
m.lock();
|
||||
auto timestamp = std::chrono::high_resolution_clock::now();
|
||||
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(timestamp.time_since_epoch()).count() << " ";
|
||||
std::cout.width(3);
|
||||
std::cout << (int)notify.LargeMotor << " ";
|
||||
std::cout.width(3);
|
||||
std::cout << (int)notify.SmallMotor << std::endl;
|
||||
m.unlock();
|
||||
|
||||
if (target->Notification == NULL)
|
||||
{
|
||||
if (lOverlapped.hEvent)
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
target->enqueue_lock->lock();
|
||||
const boost::function<void(
|
||||
PVIGEM_CLIENT,
|
||||
PVIGEM_TARGET,
|
||||
UCHAR,
|
||||
UCHAR,
|
||||
UCHAR
|
||||
)> pfn = PFN_VIGEM_X360_NOTIFICATION(target->Notification);
|
||||
|
||||
strand.post(boost::bind(pfn,
|
||||
client,
|
||||
target,
|
||||
notify.LargeMotor,
|
||||
notify.SmallMotor,
|
||||
notify.LedNumber
|
||||
));
|
||||
target->enqueue_lock->unlock();
|
||||
|
||||
target->io_svc->poll();
|
||||
}
|
||||
else
|
||||
{
|
||||
error = GetLastError();
|
||||
}
|
||||
} while (error != ERROR_OPERATION_ABORTED && error != ERROR_ACCESS_DENIED);
|
||||
|
||||
if (lOverlapped.hEvent)
|
||||
CloseHandle(lOverlapped.hEvent);
|
||||
}
|
||||
|
||||
PVIGEM_CLIENT vigem_alloc()
|
||||
{
|
||||
SetUnhandledExceptionFilter(vigem_internal_exception_handler);
|
||||
@@ -392,11 +309,7 @@ PVIGEM_TARGET vigem_target_ds4_alloc(void)
|
||||
void vigem_target_free(PVIGEM_TARGET target)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
target->io_svc->stop();
|
||||
|
||||
free(target);
|
||||
}
|
||||
}
|
||||
|
||||
VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
|
||||
@@ -605,8 +518,8 @@ VIGEM_ERROR vigem_target_x360_register_notification(
|
||||
//}
|
||||
|
||||
target->pool = std::make_shared<NotificationRequestPool>(
|
||||
vigem->hBusDevice,
|
||||
target->SerialNo,
|
||||
vigem,
|
||||
target,
|
||||
PFN_VIGEM_X360_NOTIFICATION(target->Notification)
|
||||
);
|
||||
|
||||
|
||||
@@ -5,41 +5,45 @@ XusbNotificationRequest::XusbNotificationRequest(
|
||||
HANDLE bus,
|
||||
ULONG serial,
|
||||
HANDLE notification
|
||||
) : parent_bus(bus),
|
||||
payload(), transferred(0),
|
||||
overlapped()
|
||||
) : parent_bus_(bus),
|
||||
payload_(),
|
||||
overlapped_()
|
||||
{
|
||||
overlapped.hEvent = notification;
|
||||
XUSB_REQUEST_NOTIFICATION_INIT(&payload, serial);
|
||||
memset(&overlapped_, 0, sizeof(OVERLAPPED));
|
||||
overlapped_.hEvent = notification;
|
||||
XUSB_REQUEST_NOTIFICATION_INIT(&payload_, serial);
|
||||
}
|
||||
|
||||
bool XusbNotificationRequest::request_async()
|
||||
{
|
||||
// queue request in driver
|
||||
const auto ret = DeviceIoControl(
|
||||
parent_bus,
|
||||
parent_bus_,
|
||||
IOCTL_XUSB_REQUEST_NOTIFICATION,
|
||||
&payload,
|
||||
payload.Size,
|
||||
&payload,
|
||||
payload.Size,
|
||||
&payload_,
|
||||
payload_.Size,
|
||||
&payload_,
|
||||
payload_.Size,
|
||||
nullptr,
|
||||
&overlapped
|
||||
&overlapped_
|
||||
);
|
||||
|
||||
return (!ret && GetLastError() == ERROR_IO_PENDING);
|
||||
const auto error = GetLastError();
|
||||
|
||||
return (!ret && error == ERROR_IO_PENDING);
|
||||
}
|
||||
|
||||
UCHAR XusbNotificationRequest::get_led_number() const
|
||||
{
|
||||
return payload.LedNumber;
|
||||
return payload_.LedNumber;
|
||||
}
|
||||
|
||||
UCHAR XusbNotificationRequest::get_large_motor() const
|
||||
{
|
||||
return payload.LargeMotor;
|
||||
return payload_.LargeMotor;
|
||||
}
|
||||
|
||||
UCHAR XusbNotificationRequest::get_small_motor() const
|
||||
{
|
||||
return payload.SmallMotor;
|
||||
return payload_.SmallMotor;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
class XusbNotificationRequest
|
||||
{
|
||||
HANDLE parent_bus;
|
||||
XUSB_REQUEST_NOTIFICATION payload;
|
||||
DWORD transferred;
|
||||
OVERLAPPED overlapped;
|
||||
HANDLE parent_bus_;
|
||||
XUSB_REQUEST_NOTIFICATION payload_;
|
||||
OVERLAPPED overlapped_;
|
||||
|
||||
public:
|
||||
XusbNotificationRequest(HANDLE bus, ULONG serial, HANDLE notification);
|
||||
|
||||
Reference in New Issue
Block a user