You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
Get joypad's vendor ID, product ID, and name on Windows
This commit is contained in:
@@ -609,10 +609,9 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_
|
|||||||
for (int i = 0; i < map_db.size(); i++) {
|
for (int i = 0; i < map_db.size(); i++) {
|
||||||
if (js.uid == map_db[i].uid) {
|
if (js.uid == map_db[i].uid) {
|
||||||
mapping = i;
|
mapping = i;
|
||||||
js.name = map_db[i].name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
js.mapping = mapping;
|
_set_joypad_mapping(js, mapping);
|
||||||
} else {
|
} else {
|
||||||
js.connected = false;
|
js.connected = false;
|
||||||
for (int i = 0; i < (int)JoyButton::MAX; i++) {
|
for (int i = 0; i < (int)JoyButton::MAX; i++) {
|
||||||
@@ -1706,7 +1705,7 @@ void Input::add_joy_mapping(const String &p_mapping, bool p_update_existing) {
|
|||||||
for (KeyValue<int, Joypad> &E : joy_names) {
|
for (KeyValue<int, Joypad> &E : joy_names) {
|
||||||
Joypad &joy = E.value;
|
Joypad &joy = E.value;
|
||||||
if (joy.uid == uid) {
|
if (joy.uid == uid) {
|
||||||
joy.mapping = map_db.size() - 1;
|
_set_joypad_mapping(joy, map_db.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1721,11 +1720,22 @@ void Input::remove_joy_mapping(const String &p_guid) {
|
|||||||
for (KeyValue<int, Joypad> &E : joy_names) {
|
for (KeyValue<int, Joypad> &E : joy_names) {
|
||||||
Joypad &joy = E.value;
|
Joypad &joy = E.value;
|
||||||
if (joy.uid == p_guid) {
|
if (joy.uid == p_guid) {
|
||||||
joy.mapping = -1;
|
_set_joypad_mapping(joy, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Input::_set_joypad_mapping(Joypad &p_js, int p_map_index) {
|
||||||
|
if (p_map_index != fallback_mapping && p_map_index >= 0 && p_map_index < map_db.size() && p_js.uid != "__XINPUT_DEVICE__") {
|
||||||
|
// Prefer the joypad name defined in the mapping.
|
||||||
|
// Exceptions:
|
||||||
|
// * On Windows for XInput devices the mapping would change the joypad's name to a collective name.
|
||||||
|
// * A fallback mapping is not allowed to override the joypad's name.
|
||||||
|
p_js.name = map_db[p_map_index].name;
|
||||||
|
}
|
||||||
|
p_js.mapping = p_map_index;
|
||||||
|
}
|
||||||
|
|
||||||
void Input::set_fallback_mapping(const String &p_guid) {
|
void Input::set_fallback_mapping(const String &p_guid) {
|
||||||
for (int i = 0; i < map_db.size(); i++) {
|
for (int i = 0; i < map_db.size(); i++) {
|
||||||
if (map_db[i].uid == p_guid) {
|
if (map_db[i].uid == p_guid) {
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ private:
|
|||||||
|
|
||||||
Vector<JoyDeviceMapping> map_db;
|
Vector<JoyDeviceMapping> map_db;
|
||||||
|
|
||||||
|
void _set_joypad_mapping(Joypad &p_js, int p_map_index);
|
||||||
|
|
||||||
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
|
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
|
||||||
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
|
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
|
||||||
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
|
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
|
||||||
|
|||||||
@@ -118,7 +118,8 @@
|
|||||||
<return type="String" />
|
<return type="String" />
|
||||||
<param index="0" name="device" type="int" />
|
<param index="0" name="device" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns an SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID.
|
Returns an SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns an empty string if it cannot be found. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID.
|
||||||
|
On Windows, all XInput joypad GUIDs will be overridden by Godot to [code]__XINPUT_DEVICE__[/code], because their mappings are the same.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_joy_info" qualifiers="const">
|
<method name="get_joy_info" qualifiers="const">
|
||||||
@@ -126,8 +127,10 @@
|
|||||||
<param index="0" name="device" type="int" />
|
<param index="0" name="device" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns a dictionary with extra platform-specific information about the device, e.g. the raw gamepad name from the OS or the Steam Input index.
|
Returns a dictionary with extra platform-specific information about the device, e.g. the raw gamepad name from the OS or the Steam Input index.
|
||||||
On Windows the dictionary contains the following fields:
|
On Windows, the dictionary contains the following fields:
|
||||||
[code]xinput_index[/code]: The index of the controller in the XInput system.
|
[code]xinput_index[/code]: The index of the controller in the XInput system. Undefined for DirectInput devices.
|
||||||
|
[code]vendor_id[/code]: The USB vendor ID of the device.
|
||||||
|
[code]product_id[/code]: The USB product ID of the device.
|
||||||
On Linux:
|
On Linux:
|
||||||
[code]raw_name[/code]: The name of the controller as it came from the OS, before getting renamed by the godot controller database.
|
[code]raw_name[/code]: The name of the controller as it came from the OS, before getting renamed by the godot controller database.
|
||||||
[code]vendor_id[/code]: The USB vendor ID of the device.
|
[code]vendor_id[/code]: The USB vendor ID of the device.
|
||||||
|
|||||||
@@ -46,17 +46,23 @@ DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
|
|||||||
return ERROR_DEVICE_NOT_CONNECTED;
|
return ERROR_DEVICE_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMRESULT WINAPI _winmm_get_joycaps(UINT uJoyID, LPJOYCAPSW pjc, UINT cbjc) {
|
||||||
|
return MMSYSERR_NODRIVER;
|
||||||
|
}
|
||||||
|
|
||||||
JoypadWindows::JoypadWindows() {
|
JoypadWindows::JoypadWindows() {
|
||||||
}
|
}
|
||||||
|
|
||||||
JoypadWindows::JoypadWindows(HWND *hwnd) {
|
JoypadWindows::JoypadWindows(HWND *hwnd) {
|
||||||
input = Input::get_singleton();
|
input = Input::get_singleton();
|
||||||
hWnd = hwnd;
|
hWnd = hwnd;
|
||||||
joypad_count = 0;
|
x_joypad_probe_count = 0;
|
||||||
|
d_joypad_count = 0;
|
||||||
dinput = nullptr;
|
dinput = nullptr;
|
||||||
xinput_dll = nullptr;
|
xinput_dll = nullptr;
|
||||||
xinput_get_state = nullptr;
|
xinput_get_state = nullptr;
|
||||||
xinput_set_state = nullptr;
|
xinput_set_state = nullptr;
|
||||||
|
winmm_get_joycaps = nullptr;
|
||||||
|
|
||||||
load_xinput();
|
load_xinput();
|
||||||
|
|
||||||
@@ -79,14 +85,15 @@ JoypadWindows::JoypadWindows(HWND *hwnd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JoypadWindows::~JoypadWindows() {
|
JoypadWindows::~JoypadWindows() {
|
||||||
close_joypad();
|
close_d_joypad();
|
||||||
if (dinput) {
|
if (dinput) {
|
||||||
dinput->Release();
|
dinput->Release();
|
||||||
}
|
}
|
||||||
|
unload_winmm();
|
||||||
unload_xinput();
|
unload_xinput();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JoypadWindows::have_device(const GUID &p_guid) {
|
bool JoypadWindows::is_d_joypad_known(const GUID &p_guid) {
|
||||||
for (int i = 0; i < JOYPADS_MAX; i++) {
|
for (int i = 0; i < JOYPADS_MAX; i++) {
|
||||||
if (d_joypads[i].guid == p_guid) {
|
if (d_joypads[i].guid == p_guid) {
|
||||||
d_joypads[i].confirmed = true;
|
d_joypads[i].confirmed = true;
|
||||||
@@ -97,7 +104,7 @@ bool JoypadWindows::have_device(const GUID &p_guid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adapted from SDL2, works a lot better than the MSDN version
|
// adapted from SDL2, works a lot better than the MSDN version
|
||||||
bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
|
bool JoypadWindows::is_xinput_joypad(const GUID *p_guid) {
|
||||||
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
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_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 } };
|
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
|
||||||
@@ -159,12 +166,56 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JoypadWindows::probe_xinput_joypad(const String &name) {
|
||||||
|
if (x_joypad_probe_count >= XUSER_MAX_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i = x_joypad_probe_count;
|
||||||
|
x_joypad_probe_count++;
|
||||||
|
|
||||||
|
ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE));
|
||||||
|
|
||||||
|
DWORD dwResult = xinput_get_state(i, &x_joypads[i].state);
|
||||||
|
if (dwResult == ERROR_SUCCESS) {
|
||||||
|
int id = input->get_unused_joy_id();
|
||||||
|
if (id != -1 && !x_joypads[i].attached) {
|
||||||
|
x_joypads[i].attached = true;
|
||||||
|
x_joypads[i].id = id;
|
||||||
|
x_joypads[i].ff_timestamp = 0;
|
||||||
|
x_joypads[i].ff_end_timestamp = 0;
|
||||||
|
x_joypads[i].vibrating = false;
|
||||||
|
attached_joypads[id] = true;
|
||||||
|
Dictionary joypad_info;
|
||||||
|
String joypad_name;
|
||||||
|
|
||||||
|
joypad_info["xinput_index"] = (int)i;
|
||||||
|
|
||||||
|
JOYCAPSW jc;
|
||||||
|
memset(&jc, 0, sizeof(JOYCAPSW));
|
||||||
|
MMRESULT jcResult = winmm_get_joycaps((UINT)id, &jc, sizeof(JOYCAPSW));
|
||||||
|
if (jcResult == JOYERR_NOERROR) {
|
||||||
|
joypad_info["vendor_id"] = itos(jc.wMid);
|
||||||
|
joypad_info["product_id"] = itos(jc.wPid);
|
||||||
|
if (!name.is_empty()) {
|
||||||
|
joypad_name = name.trim_prefix("Controller (").trim_suffix(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input->joy_connection_changed(id, true, joypad_name, "__XINPUT_DEVICE__", joypad_info);
|
||||||
|
}
|
||||||
|
} else if (x_joypads[i].attached) {
|
||||||
|
x_joypads[i].attached = false;
|
||||||
|
attached_joypads[x_joypads[i].id] = false;
|
||||||
|
input->joy_connection_changed(x_joypads[i].id, false, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
|
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.");
|
ERR_FAIL_NULL_V_MSG(dinput, false, "DirectInput not initialized. Rebooting your PC may solve this issue.");
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
int num = input->get_unused_joy_id();
|
int num = input->get_unused_joy_id();
|
||||||
|
|
||||||
if (have_device(instance->guidInstance) || num == -1) {
|
if (is_d_joypad_known(instance->guidInstance) || num == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +244,10 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
|
|||||||
WORD version = 0;
|
WORD version = 0;
|
||||||
sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0);
|
sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0);
|
||||||
|
|
||||||
|
Dictionary joypad_info;
|
||||||
|
joypad_info["vendor_id"] = itos(vendor);
|
||||||
|
joypad_info["product_id"] = itos(product);
|
||||||
|
|
||||||
id_to_change = num;
|
id_to_change = num;
|
||||||
slider_count = 0;
|
slider_count = 0;
|
||||||
|
|
||||||
@@ -202,16 +257,17 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
|
|||||||
joy->joy_axis.sort();
|
joy->joy_axis.sort();
|
||||||
|
|
||||||
joy->guid = instance->guidInstance;
|
joy->guid = instance->guidInstance;
|
||||||
input->joy_connection_changed(num, true, instance->tszProductName, uid);
|
const String &name = String(instance->tszProductName).trim_prefix("Controller (").trim_suffix(")");
|
||||||
|
input->joy_connection_changed(num, true, name, uid, joypad_info);
|
||||||
joy->attached = true;
|
joy->attached = true;
|
||||||
joy->id = num;
|
joy->id = num;
|
||||||
attached_joypads[num] = true;
|
attached_joypads[num] = true;
|
||||||
joy->confirmed = true;
|
joy->confirmed = true;
|
||||||
joypad_count++;
|
d_joypad_count++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
|
void JoypadWindows::setup_d_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
|
||||||
if (ob->dwType & DIDFT_AXIS) {
|
if (ob->dwType & DIDFT_AXIS) {
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
DIPROPRANGE prop_range;
|
DIPROPRANGE prop_range;
|
||||||
@@ -270,7 +326,8 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
|
|||||||
|
|
||||||
BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) {
|
BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) {
|
||||||
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
|
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
|
||||||
if (self->is_xinput_device(&p_instance->guidProduct)) {
|
if (self->is_xinput_joypad(&p_instance->guidProduct)) {
|
||||||
|
self->probe_xinput_joypad(p_instance->tszProductName);
|
||||||
return DIENUM_CONTINUE;
|
return DIENUM_CONTINUE;
|
||||||
}
|
}
|
||||||
self->setup_dinput_joypad(p_instance);
|
self->setup_dinput_joypad(p_instance);
|
||||||
@@ -279,15 +336,15 @@ BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, vo
|
|||||||
|
|
||||||
BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *p_instance, void *p_context) {
|
BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *p_instance, void *p_context) {
|
||||||
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
|
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
|
||||||
self->setup_joypad_object(p_instance, self->id_to_change);
|
self->setup_d_joypad_object(p_instance, self->id_to_change);
|
||||||
|
|
||||||
return DIENUM_CONTINUE;
|
return DIENUM_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoypadWindows::close_joypad(int id) {
|
void JoypadWindows::close_d_joypad(int id) {
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
for (int i = 0; i < JOYPADS_MAX; i++) {
|
for (int i = 0; i < JOYPADS_MAX; i++) {
|
||||||
close_joypad(i);
|
close_d_joypad(i);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -302,45 +359,29 @@ void JoypadWindows::close_joypad(int id) {
|
|||||||
attached_joypads[d_joypads[id].id] = false;
|
attached_joypads[d_joypads[id].id] = false;
|
||||||
d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0;
|
d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0;
|
||||||
input->joy_connection_changed(d_joypads[id].id, false, "");
|
input->joy_connection_changed(d_joypads[id].id, false, "");
|
||||||
joypad_count--;
|
d_joypad_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoypadWindows::probe_joypads() {
|
void JoypadWindows::probe_joypads() {
|
||||||
ERR_FAIL_NULL_MSG(dinput, "DirectInput not initialized. Rebooting your PC may solve this issue.");
|
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));
|
|
||||||
|
|
||||||
dwResult = xinput_get_state(i, &x_joypads[i].state);
|
for (int i = 0; i < d_joypad_count; i++) {
|
||||||
if (dwResult == ERROR_SUCCESS) {
|
d_joypads[i].confirmed = false; // Flag DirectInput devices for re-checking their availability.
|
||||||
int id = input->get_unused_joy_id();
|
|
||||||
if (id != -1 && !x_joypads[i].attached) {
|
|
||||||
x_joypads[i].attached = true;
|
|
||||||
x_joypads[i].id = id;
|
|
||||||
x_joypads[i].ff_timestamp = 0;
|
|
||||||
x_joypads[i].ff_end_timestamp = 0;
|
|
||||||
x_joypads[i].vibrating = false;
|
|
||||||
attached_joypads[id] = true;
|
|
||||||
Dictionary joypad_info;
|
|
||||||
joypad_info["xinput_index"] = (int)i;
|
|
||||||
input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__", joypad_info);
|
|
||||||
}
|
|
||||||
} else if (x_joypads[i].attached) {
|
|
||||||
x_joypads[i].attached = false;
|
|
||||||
attached_joypads[x_joypads[i].id] = false;
|
|
||||||
input->joy_connection_changed(x_joypads[i].id, false, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < joypad_count; i++) {
|
|
||||||
d_joypads[i].confirmed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x_joypad_probe_count = 0;
|
||||||
|
// Probe _all attached_ joypad devices.
|
||||||
dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
|
dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
|
||||||
|
|
||||||
for (int i = 0; i < joypad_count; i++) {
|
for (int i = x_joypad_probe_count; i < XUSER_MAX_COUNT; i++) {
|
||||||
|
// Handle disconnect of XInput devices.
|
||||||
|
// And act as a fallback, just in case DirectInput could not find the device.
|
||||||
|
probe_xinput_joypad();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < d_joypad_count; i++) {
|
||||||
if (!d_joypads[i].confirmed) {
|
if (!d_joypads[i].confirmed) {
|
||||||
close_joypad(i);
|
close_d_joypad(i); // Any DirectInput device not found during probing is considered as disconnected.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,6 +389,7 @@ void JoypadWindows::probe_joypads() {
|
|||||||
void JoypadWindows::process_joypads() {
|
void JoypadWindows::process_joypads() {
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
// Handle XInput joypads.
|
||||||
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
|
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||||
xinput_gamepad &joy = x_joypads[i];
|
xinput_gamepad &joy = x_joypads[i];
|
||||||
if (!joy.attached) {
|
if (!joy.attached) {
|
||||||
@@ -388,6 +430,7 @@ void JoypadWindows::process_joypads() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle DirectIndput joypads.
|
||||||
for (int i = 0; i < JOYPADS_MAX; i++) {
|
for (int i = 0; i < JOYPADS_MAX; i++) {
|
||||||
dinput_gamepad *joy = &d_joypads[i];
|
dinput_gamepad *joy = &d_joypads[i];
|
||||||
|
|
||||||
@@ -535,7 +578,9 @@ void JoypadWindows::joypad_vibration_stop_xinput(int p_device, uint64_t p_timest
|
|||||||
void JoypadWindows::load_xinput() {
|
void JoypadWindows::load_xinput() {
|
||||||
xinput_get_state = &_xinput_get_state;
|
xinput_get_state = &_xinput_get_state;
|
||||||
xinput_set_state = &_xinput_set_state;
|
xinput_set_state = &_xinput_set_state;
|
||||||
|
winmm_get_joycaps = &_winmm_get_joycaps;
|
||||||
bool legacy_xinput = false;
|
bool legacy_xinput = false;
|
||||||
|
|
||||||
xinput_dll = LoadLibrary("XInput1_4.dll");
|
xinput_dll = LoadLibrary("XInput1_4.dll");
|
||||||
if (!xinput_dll) {
|
if (!xinput_dll) {
|
||||||
xinput_dll = LoadLibrary("XInput1_3.dll");
|
xinput_dll = LoadLibrary("XInput1_3.dll");
|
||||||
@@ -560,6 +605,16 @@ void JoypadWindows::load_xinput() {
|
|||||||
}
|
}
|
||||||
xinput_get_state = func;
|
xinput_get_state = func;
|
||||||
xinput_set_state = set_func;
|
xinput_set_state = set_func;
|
||||||
|
|
||||||
|
winmm_dll = LoadLibrary("Winmm.dll");
|
||||||
|
if (winmm_dll) {
|
||||||
|
joyGetDevCaps_t caps_func = (joyGetDevCaps_t)GetProcAddress((HMODULE)winmm_dll, "joyGetDevCapsW");
|
||||||
|
if (caps_func) {
|
||||||
|
winmm_get_joycaps = caps_func;
|
||||||
|
} else {
|
||||||
|
unload_winmm();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoypadWindows::unload_xinput() {
|
void JoypadWindows::unload_xinput() {
|
||||||
@@ -567,3 +622,9 @@ void JoypadWindows::unload_xinput() {
|
|||||||
FreeLibrary((HMODULE)xinput_dll);
|
FreeLibrary((HMODULE)xinput_dll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JoypadWindows::unload_winmm() {
|
||||||
|
if (winmm_dll) {
|
||||||
|
FreeLibrary((HMODULE)winmm_dll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#include <dinput.h>
|
#include <dinput.h>
|
||||||
#include <xinput.h>
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <mmsystem.h>
|
||||||
|
|
||||||
#ifndef SAFE_RELEASE // when Windows Media Device M? is not present
|
#ifndef SAFE_RELEASE // when Windows Media Device M? is not present
|
||||||
#define SAFE_RELEASE(x) \
|
#define SAFE_RELEASE(x) \
|
||||||
if (x != nullptr) { \
|
if (x != nullptr) { \
|
||||||
@@ -107,14 +109,18 @@ private:
|
|||||||
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
|
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
|
||||||
typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
|
typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
|
||||||
|
|
||||||
|
typedef MMRESULT(WINAPI *joyGetDevCaps_t)(UINT uJoyID, LPJOYCAPSW pjc, UINT cbjc);
|
||||||
|
|
||||||
HWND *hWnd = nullptr;
|
HWND *hWnd = nullptr;
|
||||||
HANDLE xinput_dll;
|
HANDLE xinput_dll;
|
||||||
|
HANDLE winmm_dll;
|
||||||
LPDIRECTINPUT8 dinput;
|
LPDIRECTINPUT8 dinput;
|
||||||
Input *input = nullptr;
|
Input *input = nullptr;
|
||||||
|
|
||||||
int id_to_change;
|
int id_to_change;
|
||||||
int slider_count;
|
int slider_count;
|
||||||
int joypad_count;
|
int x_joypad_probe_count; // XInput equivalent to dinput_gamepad.confirmed.
|
||||||
|
int d_joypad_count;
|
||||||
bool attached_joypads[JOYPADS_MAX];
|
bool attached_joypads[JOYPADS_MAX];
|
||||||
dinput_gamepad d_joypads[JOYPADS_MAX];
|
dinput_gamepad d_joypads[JOYPADS_MAX];
|
||||||
xinput_gamepad x_joypads[XUSER_MAX_COUNT];
|
xinput_gamepad x_joypads[XUSER_MAX_COUNT];
|
||||||
@@ -122,22 +128,25 @@ private:
|
|||||||
static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context);
|
static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context);
|
||||||
static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context);
|
static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context);
|
||||||
|
|
||||||
void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
|
void setup_d_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
|
||||||
void close_joypad(int id = -1);
|
void close_d_joypad(int id = -1);
|
||||||
void load_xinput();
|
void load_xinput();
|
||||||
void unload_xinput();
|
void unload_xinput();
|
||||||
|
void unload_winmm();
|
||||||
|
|
||||||
void post_hat(int p_device, DWORD p_dpad);
|
void post_hat(int p_device, DWORD p_dpad);
|
||||||
|
|
||||||
bool have_device(const GUID &p_guid);
|
bool is_d_joypad_known(const GUID &p_guid);
|
||||||
bool is_xinput_device(const GUID *p_guid);
|
bool is_xinput_joypad(const GUID *p_guid);
|
||||||
bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance);
|
bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance);
|
||||||
|
void probe_xinput_joypad(const String &name = ""); // Handles connect, disconnect & re-connect for XInput joypads.
|
||||||
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_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);
|
void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
|
||||||
|
|
||||||
float axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
|
float axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
|
||||||
XInputGetState_t xinput_get_state;
|
XInputGetState_t xinput_get_state;
|
||||||
XInputSetState_t xinput_set_state;
|
XInputSetState_t xinput_set_state;
|
||||||
|
joyGetDevCaps_t winmm_get_joycaps; // Only for reading info on XInput joypads.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // JOYPAD_WINDOWS_H
|
#endif // JOYPAD_WINDOWS_H
|
||||||
|
|||||||
Reference in New Issue
Block a user