summaryrefslogtreecommitdiffstats
path: root/platform/windows/joypad_windows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/joypad_windows.cpp')
-rw-r--r--platform/windows/joypad_windows.cpp112
1 files changed, 63 insertions, 49 deletions
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 0cff12ca8c..94da63e49d 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,10 +33,6 @@
#include <oleauto.h>
#include <wbemidl.h>
-#ifndef __GNUC__
-#define __builtin_bswap32 _byteswap_ulong
-#endif
-
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
#define GetProcAddress (void *)GetProcAddress
@@ -67,17 +63,25 @@ JoypadWindows::JoypadWindows(HWND *hwnd) {
for (int i = 0; i < JOYPADS_MAX; i++)
attached_joypads[i] = false;
- HRESULT result;
- result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr);
- if (FAILED(result)) {
- printf("failed init DINPUT: %ld\n", result);
+ 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() {
close_joypad();
- dinput->Release();
+ if (dinput) {
+ dinput->Release();
+ }
unload_xinput();
}
@@ -106,12 +110,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
return false;
}
- dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
- if (!dev_list)
- return false;
+ dev_list = (PRAWINPUTDEVICELIST)memalloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
+ ERR_FAIL_NULL_V_MSG(dev_list, false, "Out of memory.");
if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
- free(dev_list);
+ memfree(dev_list);
return false;
}
for (unsigned int i = 0; i < dev_list_count; i++) {
@@ -126,27 +129,28 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) &&
(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) &&
(strstr(dev_name, "IG_") != nullptr)) {
- free(dev_list);
+ memfree(dev_list);
return true;
}
}
- free(dev_list);
+ memfree(dev_list);
return false;
}
bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
+ ERR_FAIL_NULL_V_MSG(dinput, false, "DirectInput not initialized. Rebooting your PC may solve this issue.");
HRESULT hr;
int num = input->get_unused_joy_id();
if (have_device(instance->guidInstance) || num == -1)
return false;
- d_joypads[joypad_count] = dinput_gamepad();
- dinput_gamepad *joy = &d_joypads[joypad_count];
+ d_joypads[num] = dinput_gamepad();
+ dinput_gamepad *joy = &d_joypads[num];
const DWORD devtype = (instance->dwDevType & 0xFF);
- if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) {
+ if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON) && (devtype != DI8DEVTYPE_DRIVING)) {
return false;
}
@@ -158,12 +162,16 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
const GUID &guid = instance->guidProduct;
char uid[128];
- sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
- __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
- guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
- guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
- id_to_change = joypad_count;
+ ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognised.");
+ WORD type = BSWAP16(0x03);
+ WORD vendor = BSWAP16(LOWORD(guid.Data1));
+ WORD product = BSWAP16(HIWORD(guid.Data1));
+ WORD version = 0;
+ sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0);
+
+ id_to_change = num;
+ slider_count = 0;
joy->di_joy->SetDataFormat(&c_dfDIJoystick2);
joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND);
@@ -185,7 +193,7 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
HRESULT res;
DIPROPRANGE prop_range;
DIPROPDWORD dilong;
- DWORD ofs;
+ LONG ofs;
if (ob->guidType == GUID_XAxis)
ofs = DIJOFS_X;
else if (ob->guidType == GUID_YAxis)
@@ -198,9 +206,14 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
ofs = DIJOFS_RY;
else if (ob->guidType == GUID_RzAxis)
ofs = DIJOFS_RZ;
- else if (ob->guidType == GUID_Slider)
- ofs = DIJOFS_SLIDER(0);
- else
+ else if (ob->guidType == GUID_Slider) {
+ if (slider_count < 2) {
+ ofs = DIJOFS_SLIDER(slider_count);
+ slider_count++;
+ } else {
+ return;
+ }
+ } else
return;
prop_range.diph.dwSize = sizeof(DIPROPRANGE);
prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
@@ -266,6 +279,7 @@ 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));
@@ -316,7 +330,7 @@ void JoypadWindows::process_joypads() {
if (joy.state.dwPacketNumber != joy.last_packet) {
int button_mask = XINPUT_GAMEPAD_DPAD_UP;
for (int j = 0; j <= 16; j++) {
- input->joy_button(joy.id, j, joy.state.Gamepad.wButtons & button_mask);
+ input->joy_button(joy.id, (JoyButton)j, joy.state.Gamepad.wButtons & button_mask);
button_mask = button_mask * 2;
}
@@ -367,26 +381,26 @@ void JoypadWindows::process_joypads() {
for (int j = 0; j < 128; j++) {
if (js.rgbButtons[j] & 0x80) {
if (!joy->last_buttons[j]) {
- input->joy_button(joy->id, j, true);
+ input->joy_button(joy->id, (JoyButton)j, true);
joy->last_buttons[j] = true;
}
} else {
if (joy->last_buttons[j]) {
- input->joy_button(joy->id, j, false);
+ input->joy_button(joy->id, (JoyButton)j, false);
joy->last_buttons[j] = false;
}
}
}
// on mingw, these constants are not constants
- int count = 6;
- unsigned int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ };
- int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz };
+ int count = 8;
+ LONG axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, (LONG)DIJOFS_SLIDER(0), (LONG)DIJOFS_SLIDER(1) };
+ int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz, js.rglSlider[0], js.rglSlider[1] };
for (int j = 0; j < joy->joy_axis.size(); j++) {
for (int k = 0; k < count; k++) {
if (joy->joy_axis[j] == axes[k]) {
- input->joy_axis(joy->id, j, axis_correct(values[k]));
+ input->joy_axis(joy->id, (JoyAxis)j, axis_correct(values[k]));
break;
};
};
@@ -396,44 +410,44 @@ void JoypadWindows::process_joypads() {
}
void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
- int dpad_val = 0;
+ HatMask dpad_val = (HatMask)0;
// Should be -1 when centered, but according to docs:
// "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows:
// BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);"
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks
if (LOWORD(p_dpad) == 0xFFFF) {
- dpad_val = Input::HAT_MASK_CENTER;
+ dpad_val = (HatMask)HatMask::HAT_MASK_CENTER;
}
if (p_dpad == 0) {
- dpad_val = Input::HAT_MASK_UP;
+ dpad_val = (HatMask)HatMask::HAT_MASK_UP;
} else if (p_dpad == 4500) {
- dpad_val = (Input::HAT_MASK_UP | Input::HAT_MASK_RIGHT);
+ dpad_val = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT);
} else if (p_dpad == 9000) {
- dpad_val = Input::HAT_MASK_RIGHT;
+ dpad_val = (HatMask)HatMask::HAT_MASK_RIGHT;
} else if (p_dpad == 13500) {
- dpad_val = (Input::HAT_MASK_RIGHT | Input::HAT_MASK_DOWN);
+ dpad_val = (HatMask)(HatMask::HAT_MASK_RIGHT | HatMask::HAT_MASK_DOWN);
} else if (p_dpad == 18000) {
- dpad_val = Input::HAT_MASK_DOWN;
+ dpad_val = (HatMask)HatMask::HAT_MASK_DOWN;
} else if (p_dpad == 22500) {
- dpad_val = (Input::HAT_MASK_DOWN | Input::HAT_MASK_LEFT);
+ dpad_val = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT);
} else if (p_dpad == 27000) {
- dpad_val = Input::HAT_MASK_LEFT;
+ dpad_val = (HatMask)HatMask::HAT_MASK_LEFT;
} else if (p_dpad == 31500) {
- dpad_val = (Input::HAT_MASK_LEFT | Input::HAT_MASK_UP);
+ dpad_val = (HatMask)(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_UP);
}
input->joy_hat(p_device, dpad_val);
};
-Input::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
- Input::JoyAxis jx;
+Input::JoyAxisValue JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+ Input::JoyAxisValue jx;
if (Math::abs(p_val) < MIN_JOY_AXIS) {
jx.min = p_trigger ? 0 : -1;
jx.value = 0.0f;