Input: Windows: Initalize DirectInput in WorkerThreadPool task
This commit is contained in:
parent
533c616cb8
commit
7acfc50a34
2 changed files with 84 additions and 30 deletions
|
@ -63,22 +63,14 @@ JoypadWindows::JoypadWindows(HWND *hwnd) {
|
|||
for (int i = 0; i < JOYPADS_MAX; i++) {
|
||||
attached_joypads[i] = false;
|
||||
}
|
||||
|
||||
HRESULT result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr);
|
||||
if (result == DI_OK) {
|
||||
probe_joypads();
|
||||
} else {
|
||||
ERR_PRINT("Couldn't initialize DirectInput. Error: " + itos(result));
|
||||
if (result == DIERR_OUTOFMEMORY) {
|
||||
ERR_PRINT("The Windows DirectInput subsystem could not allocate sufficient memory.");
|
||||
ERR_PRINT("Rebooting your PC may solve this issue.");
|
||||
}
|
||||
// Ensure dinput is still a nullptr.
|
||||
dinput = nullptr;
|
||||
}
|
||||
probe_joypads();
|
||||
}
|
||||
|
||||
JoypadWindows::~JoypadWindows() {
|
||||
if (dinput_probe_task != WorkerThreadPool::INVALID_TASK_ID) {
|
||||
WorkerThreadPool::get_singleton()->wait_for_task_completion(dinput_probe_task);
|
||||
}
|
||||
|
||||
close_joypad();
|
||||
if (dinput) {
|
||||
dinput->Release();
|
||||
|
@ -97,7 +89,7 @@ bool JoypadWindows::have_device(const GUID &p_guid) {
|
|||
}
|
||||
|
||||
// adapted from SDL2, works a lot better than the MSDN version
|
||||
bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
|
||||
static bool is_xinput_device(const GUID *p_guid) {
|
||||
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
||||
static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
||||
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
||||
|
@ -268,11 +260,16 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
|
|||
}
|
||||
|
||||
BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) {
|
||||
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
|
||||
if (self->is_xinput_device(&p_instance->guidProduct)) {
|
||||
JoypadWindows::dinput_init_task_context *self = static_cast<JoypadWindows::dinput_init_task_context *>(p_context);
|
||||
if (self->xinput_enabled && is_xinput_device(&p_instance->guidProduct)) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
self->setup_dinput_joypad(p_instance);
|
||||
|
||||
if (self->instances_count < JOYPADS_MAX) {
|
||||
// Copy is needed because DIDEVICEINSTANCE* is invalidated after enumCallback is completed.
|
||||
memcpy(&self->instances[self->instances_count], p_instance, sizeof(DIDEVICEINSTANCE));
|
||||
self->instances_count += 1;
|
||||
}
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -283,6 +280,28 @@ BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *p_ins
|
|||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
void JoypadWindows::dinput_probe_joypads_task(void *p_context) {
|
||||
JoypadWindows::dinput_init_task_context *self = static_cast<JoypadWindows::dinput_init_task_context *>(p_context);
|
||||
|
||||
if (!self->dinput) {
|
||||
HRESULT result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&self->dinput, nullptr);
|
||||
if (result != DI_OK) {
|
||||
ERR_PRINT("Couldn't initialize DirectInput. Error: " + itos(result));
|
||||
if (result == DIERR_OUTOFMEMORY) {
|
||||
ERR_PRINT("The Windows DirectInput subsystem could not allocate sufficient memory.");
|
||||
ERR_PRINT("Rebooting your PC may solve this issue.");
|
||||
}
|
||||
// Ensure dinput is still a nullptr.
|
||||
self->dinput = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->dinput) {
|
||||
self->dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, self, DIEDFL_ATTACHEDONLY);
|
||||
}
|
||||
self->ready = true;
|
||||
}
|
||||
|
||||
void JoypadWindows::close_joypad(int id) {
|
||||
if (id == -1) {
|
||||
for (int i = 0; i < JOYPADS_MAX; i++) {
|
||||
|
@ -305,7 +324,6 @@ void JoypadWindows::close_joypad(int id) {
|
|||
}
|
||||
|
||||
void JoypadWindows::probe_joypads() {
|
||||
ERR_FAIL_NULL_MSG(dinput, "DirectInput not initialized. Rebooting your PC may solve this issue.");
|
||||
DWORD dwResult;
|
||||
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||
ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE));
|
||||
|
@ -331,21 +349,23 @@ void JoypadWindows::probe_joypads() {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < joypad_count; i++) {
|
||||
d_joypads[i].confirmed = false;
|
||||
if (dinput_probe_task != WorkerThreadPool::INVALID_TASK_ID) {
|
||||
WorkerThreadPool::get_singleton()->wait_for_task_completion(dinput_probe_task);
|
||||
dinput_probe_task = WorkerThreadPool::INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
|
||||
|
||||
for (int i = 0; i < joypad_count; i++) {
|
||||
if (!d_joypads[i].confirmed) {
|
||||
close_joypad(i);
|
||||
}
|
||||
}
|
||||
dinput_init_task_ctx.dinput = dinput;
|
||||
dinput_init_task_ctx.xinput_enabled = xinput_dll != nullptr;
|
||||
dinput_init_task_ctx.ready = false;
|
||||
dinput_init_task_ctx.instances_count = 0;
|
||||
dinput_probe_task = WorkerThreadPool::get_singleton()->add_native_task(&JoypadWindows::dinput_probe_joypads_task, &dinput_init_task_ctx);
|
||||
}
|
||||
|
||||
void JoypadWindows::process_joypads() {
|
||||
HRESULT hr;
|
||||
if (dinput_init_task_ctx.ready) {
|
||||
process_dinput_init_task_result(dinput_init_task_ctx);
|
||||
}
|
||||
|
||||
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||
xinput_gamepad &joy = x_joypads[i];
|
||||
|
@ -504,6 +524,26 @@ float JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool
|
|||
return value;
|
||||
}
|
||||
|
||||
void JoypadWindows::process_dinput_init_task_result(dinput_init_task_context &context) {
|
||||
dinput_probe_task = WorkerThreadPool::INVALID_TASK_ID;
|
||||
dinput_init_task_ctx.ready = false;
|
||||
|
||||
for (int i = 0; i < joypad_count; i++) {
|
||||
d_joypads[i].confirmed = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dinput_init_task_ctx.instances_count; ++i) {
|
||||
setup_dinput_joypad(&dinput_init_task_ctx.instances[i]);
|
||||
}
|
||||
dinput_init_task_ctx.instances_count = 0;
|
||||
|
||||
for (int i = 0; i < joypad_count; i++) {
|
||||
if (!d_joypads[i].confirmed) {
|
||||
close_joypad(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JoypadWindows::joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
|
||||
xinput_gamepad &joy = x_joypads[p_device];
|
||||
if (joy.attached) {
|
||||
|
@ -564,5 +604,6 @@ void JoypadWindows::load_xinput() {
|
|||
void JoypadWindows::unload_xinput() {
|
||||
if (xinput_dll) {
|
||||
FreeLibrary((HMODULE)xinput_dll);
|
||||
xinput_dll = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ private:
|
|||
attached = false;
|
||||
confirmed = false;
|
||||
di_joy = nullptr;
|
||||
guid = {};
|
||||
guid = GUID_NULL;
|
||||
|
||||
for (int i = 0; i < MAX_JOY_BUTTONS; i++) {
|
||||
last_buttons[i] = false;
|
||||
|
@ -104,12 +104,24 @@ private:
|
|||
uint64_t ff_end_timestamp = 0;
|
||||
};
|
||||
|
||||
struct dinput_init_task_context {
|
||||
bool xinput_enabled = false;
|
||||
LPDIRECTINPUT8 dinput = nullptr;
|
||||
DIDEVICEINSTANCE instances[JOYPADS_MAX];
|
||||
int instances_count = 0;
|
||||
std::atomic_bool ready = false;
|
||||
};
|
||||
|
||||
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
|
||||
typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
|
||||
|
||||
HWND *hWnd = nullptr;
|
||||
HANDLE xinput_dll;
|
||||
LPDIRECTINPUT8 dinput;
|
||||
|
||||
LPDIRECTINPUT8 dinput = nullptr;
|
||||
dinput_init_task_context dinput_init_task_ctx;
|
||||
WorkerThreadPool::TaskID dinput_probe_task = WorkerThreadPool::INVALID_TASK_ID;
|
||||
|
||||
Input *input = nullptr;
|
||||
|
||||
int id_to_change;
|
||||
|
@ -121,6 +133,7 @@ private:
|
|||
|
||||
static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context);
|
||||
static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context);
|
||||
static void dinput_probe_joypads_task(void *p_context);
|
||||
|
||||
void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
|
||||
void close_joypad(int id = -1);
|
||||
|
@ -130,7 +143,7 @@ private:
|
|||
void post_hat(int p_device, DWORD p_dpad);
|
||||
|
||||
bool have_device(const GUID &p_guid);
|
||||
bool is_xinput_device(const GUID *p_guid);
|
||||
void process_dinput_init_task_result(dinput_init_task_context &context);
|
||||
bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance);
|
||||
void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
|
||||
void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
|
||||
|
|
Loading…
Reference in a new issue