1
/* Mednafen - Multi-system Emulator
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "Joystick_DX5.h"
24
#define DIRECTINPUT_VERSION 0x0500
34
int32 minimum, maximum;
35
uint32 jd_logical_offset;
38
class Joystick_DX5 : public Joystick
42
Joystick_DX5(LPDIRECTINPUT dii, DIDEVICEINSTANCE *ddi);
43
virtual ~Joystick_DX5();
44
virtual unsigned HatToAxisCompat(unsigned hat);
45
virtual void SetRumble(uint8 weak_intensity, uint8 strong_intensity);
47
void UpdateInternal(void);
50
LPDIRECTINPUTDEVICE2 dev;
52
std::vector<di_axis_info> DIAxisInfo;
53
int have_exclusive_access;
54
void RequestExclusive(bool value);
57
#define REQUIRE_DI_CALL(code) { HRESULT hres = (code); if(hres != DI_OK) { throw MDFN_Error(0, "\"" #code "\"" "failed: %u", (unsigned)hres); } }
59
void Joystick_DX5::RequestExclusive(bool value)
61
if(value != have_exclusive_access)
63
if(value && SUCCEEDED(dev->SetCooperativeLevel(GetDesktopWindow(), DISCL_BACKGROUND | DISCL_EXCLUSIVE)) && SUCCEEDED(dev->Acquire()))
64
have_exclusive_access = true;
67
have_exclusive_access = false;
68
dev->SetCooperativeLevel(GetDesktopWindow(), DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
74
Joystick_DX5::Joystick_DX5(LPDIRECTINPUT dii, DIDEVICEINSTANCE *ddi) : dev(NULL), have_exclusive_access(-1)
76
LPDIRECTINPUTDEVICE tmp_dev = NULL;
80
REQUIRE_DI_CALL( dii->CreateDevice(ddi->guidInstance, &tmp_dev, NULL) );
81
REQUIRE_DI_CALL( tmp_dev->QueryInterface(IID_IDirectInputDevice2, (LPVOID *)&dev) );
82
REQUIRE_DI_CALL( dev->SetDataFormat(&c_dfDIJoystick2) );
83
DevCaps.dwSize = sizeof(DevCaps);
84
REQUIRE_DI_CALL( dev->GetCapabilities(&DevCaps) );
86
for(unsigned rax = 0; rax < 8; rax++)
91
diprg.diph.dwSize = sizeof(diprg);
92
diprg.diph.dwHeaderSize = sizeof(diprg.diph);
93
diprg.diph.dwObj = rax * sizeof(LONG);
94
diprg.diph.dwHow = DIPH_BYOFFSET;
96
// TODO: Handle DIPROPRANGE_NOMIN and DIPROPRANGE_NOMAX
97
hres = dev->GetProperty(DIPROP_RANGE, &diprg.diph);
100
if(diprg.lMin < diprg.lMax)
104
dai.jd_logical_offset = rax;
105
dai.minimum = diprg.lMin;
106
dai.maximum = diprg.lMax;
108
DIAxisInfo.push_back(dai);
111
//else if(hres != DIERR_OBJECTNOTFOUND)
115
num_axes = DIAxisInfo.size() + DevCaps.dwPOVs * 2;
116
num_buttons = DevCaps.dwButtons;
117
axis_state.resize(num_axes);
118
rel_axis_state.resize(num_rel_axes);
119
button_state.resize(num_buttons);
120
// id, guidinstance, etc.
127
DIEFFECTINFO eff_inf;
129
eff_inf.dwSize = sizeof(eff_inf);
130
if(dev->GetEffectInfo(&eff_inf, GUID_Square) == DI_OK || dev->GetEffectInfo(&eff_inf, GUID_Sine) == DI_OK)
136
RequestExclusive(false);
138
CalcOldStyleID(DIAxisInfo.size(), 0, DevCaps.dwPOVs, DevCaps.dwButtons);
139
snprintf(name, sizeof(name), "%s", ddi->tszProductName);
153
Joystick_DX5::~Joystick_DX5()
163
unsigned Joystick_DX5::HatToAxisCompat(unsigned hat)
165
return(DIAxisInfo.size() + (hat * 2));
168
// TODO: RequestExclusive(false) when SetRumble() hasn't been called for several seconds.
169
void Joystick_DX5::UpdateInternal(void)
174
if(DevCaps.dwFlags & (DIDC_POLLEDDEVICE | DIDC_POLLEDDATAFORMAT))
176
do { /* */ hres = dev->Poll(); /* */ } while((hres == DIERR_INPUTLOST) && ((hres = dev->Acquire()) == DI_OK));
181
do { /* */ hres = dev->GetDeviceState(sizeof(js), &js); /* */ } while((hres == DIERR_INPUTLOST) && ((hres = dev->Acquire()) == DI_OK));
185
for(unsigned button = 0; button < DevCaps.dwButtons; button++)
187
button_state[button] = (bool)(js.rgbButtons[button] & 0x80);
190
for(unsigned axis = 0; axis < DIAxisInfo.size(); axis++)
192
int64 rv = (&js.lX)[DIAxisInfo[axis].jd_logical_offset];
194
rv = (((rv - DIAxisInfo[axis].minimum) * 32767 * 2) / (DIAxisInfo[axis].maximum - DIAxisInfo[axis].minimum)) - 32767;
200
axis_state[axis] = rv;
203
for(unsigned hat = 0; hat < DevCaps.dwPOVs; hat++)
205
DWORD hat_val = js.rgdwPOV[hat];
207
//if((uint16)hat_val == 0xFFFF) // Reportedly some drivers report 0xFFFF instead of 0xFFFFFFFF? (comment from byuu)
210
axis_state[(DIAxisInfo.size() + hat * 2) + 0] = 0;
211
axis_state[(DIAxisInfo.size() + hat * 2) + 1] = 0;
217
//axis_state[(DIAxisInfo.size() + hat * 2) + 0] = 32767 * sin((double)M_PI * 2 * hat_val / 36000); // x
218
//axis_state[(DIAxisInfo.size() + hat * 2) + 1] = 32767 * -cos((double)M_PI * 2 * hat_val / 36000); // y
219
unsigned octant = (hat_val / 4500) & 0x7;
220
signed octant_doff = hat_val % 4500;
224
case 0: x = octant_doff * 32767 / 4500; y = -32767; break;
225
case 1: x = 32767; y = (-4500 + octant_doff) * 32767 / 4500; break;
227
case 2: x = 32767; y = octant_doff * 32767 / 4500; break;
228
case 3: x = (4500 - octant_doff) * 32767 / 4500; y = 32767; break;
230
case 4: x = (-octant_doff) * 32767 / 4500; y = 32767; break;
231
case 5: x = -32767; y = (4500 - octant_doff) * 32767 / 4500; break;
233
case 6: x = -32767; y = (-octant_doff) * 32767 / 4500; break;
234
case 7: x = (-4500 + octant_doff) * 32767 / 4500; y = -32767; break;
237
axis_state[(DIAxisInfo.size() + hat * 2) + 0] = x;
238
axis_state[(DIAxisInfo.size() + hat * 2) + 1] = y;
243
void Joystick_DX5::SetRumble(uint8 weak_intensity, uint8 strong_intensity)
245
//if((weak_intensity || strong_intensity) && rumble_supported)
246
// RequestExclusive(true);
249
class JoystickDriver_DX5 : public JoystickDriver
253
JoystickDriver_DX5(bool exclude_xinput);
254
virtual ~JoystickDriver_DX5();
256
virtual unsigned NumJoysticks(); // Cached internally on JoystickDriver instantiation.
257
virtual Joystick *GetJoystick(unsigned index);
258
virtual void UpdateJoysticks(void);
261
std::vector<Joystick_DX5 *> joys;
266
static INLINE std::set<uint32> GetXInputVidPid(void)
269
UINT WINAPI (*p_GetRawInputDeviceList)(PRAWINPUTDEVICELIST, PUINT, UINT) = NULL;
270
UINT WINAPI (*p_GetRawInputDeviceInfo)(HANDLE, UINT, LPVOID, PUINT) = NULL;
271
std::set<uint32> exclude_vps;
273
if((us32 = LoadLibrary("user32.dll")) == NULL)
276
p_GetRawInputDeviceList = (UINT WINAPI (*)(PRAWINPUTDEVICELIST, PUINT, UINT))GetProcAddress(us32, "GetRawInputDeviceList");
277
p_GetRawInputDeviceInfo = (UINT WINAPI (*)(HANDLE, UINT, LPVOID, PUINT))GetProcAddress(us32, "GetRawInputDeviceInfoA");
279
if(p_GetRawInputDeviceList && p_GetRawInputDeviceInfo)
281
std::vector<RAWINPUTDEVICELIST> ridl;
282
unsigned int alloc_num_devices = 0;
283
unsigned int num_devices = 0;
285
p_GetRawInputDeviceList(NULL, &alloc_num_devices, 0);
286
ridl.resize(alloc_num_devices);
288
if((num_devices = p_GetRawInputDeviceList(&ridl[0], &alloc_num_devices, sizeof(RAWINPUTDEVICELIST))) > 0)
290
for(unsigned i = 0; i < num_devices; i++)
292
if(ridl[i].dwType != RIM_TYPEHID)
295
RID_DEVICE_INFO devinfo;
296
std::vector<char> devname;
297
unsigned int sizepar;
299
memset(&devinfo, 0, sizeof(devinfo));
300
devinfo.cbSize = sizeof(RID_DEVICE_INFO);
301
sizepar = sizeof(RID_DEVICE_INFO);
302
if(p_GetRawInputDeviceInfo(ridl[i].hDevice, RIDI_DEVICEINFO, &devinfo, &sizepar) != sizeof(RID_DEVICE_INFO))
306
p_GetRawInputDeviceInfo(ridl[i].hDevice, RIDI_DEVICENAME, NULL, &sizepar);
307
devname.resize(sizepar + 1);
308
p_GetRawInputDeviceInfo(ridl[i].hDevice, RIDI_DEVICENAME, &devname[0], &sizepar);
310
//printf("MOOCOW: %s\n", devname);
311
if(!strncmp(&devname[0], "IG_", 3) || strstr(&devname[0], "&IG_") != NULL)
313
exclude_vps.insert(MAKELONG(devinfo.hid.dwVendorId, devinfo.hid.dwProductId));
325
struct enum_device_list
327
enum_device_list() : valid_count(0) { ddi.resize(max_count); }
328
static const unsigned max_count = 256;
329
std::vector<DIDEVICEINSTANCE> ddi;
330
unsigned valid_count;
333
static BOOL CALLBACK GLOB_EnumJoysticksProc(LPCDIDEVICEINSTANCE ddi, LPVOID private_data)
335
enum_device_list *edl = (enum_device_list*)private_data;
337
//printf("%08x\n", (unsigned int)ddi->guidInstance.Data1);
339
if((ddi->dwDevType & 0xFF) != DIDEVTYPE_JOYSTICK)
340
return DIENUM_CONTINUE;
342
if(edl->valid_count < edl->max_count)
344
memcpy(&edl->ddi[edl->valid_count], ddi, sizeof(DIDEVICEINSTANCE));
348
return DIENUM_CONTINUE;
351
JoystickDriver_DX5::JoystickDriver_DX5(bool exclude_xinput) : dii(NULL)
353
enum_device_list edl;
354
std::set<uint32> exclude_vps;
358
REQUIRE_DI_CALL( DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &dii, NULL) );
359
REQUIRE_DI_CALL( dii->EnumDevices(DIDEVTYPE_JOYSTICK, GLOB_EnumJoysticksProc, &edl, DIEDFL_ATTACHEDONLY) );
363
exclude_vps = GetXInputVidPid();
366
for(unsigned i = 0; i < edl.valid_count; i++)
368
Joystick_DX5 *jdx5 = NULL;
370
if(edl.ddi[i].guidProduct.Data1 && exclude_vps.count(edl.ddi[i].guidProduct.Data1))
375
jdx5 = new Joystick_DX5(dii, &edl.ddi[i]);
376
joys.push_back(jdx5);
378
catch(std::exception &e)
380
MDFND_PrintError(e.what());
389
catch(std::exception &e)
391
MDFND_PrintError(e.what());
395
JoystickDriver_DX5::~JoystickDriver_DX5()
397
for(unsigned int n = 0; n < joys.size(); n++)
409
unsigned JoystickDriver_DX5::NumJoysticks(void)
414
Joystick *JoystickDriver_DX5::GetJoystick(unsigned index)
419
void JoystickDriver_DX5::UpdateJoysticks(void)
421
for(unsigned int n = 0; n < joys.size(); n++)
423
joys[n]->UpdateInternal();
427
JoystickDriver *JoystickDriver_DX5_New(bool exclude_xinput)
429
return new JoystickDriver_DX5(exclude_xinput);