~ubuntu-branches/debian/experimental/mednafen/experimental

« back to all changes in this revision

Viewing changes to src/drivers/Joystick_DX5.cpp

  • Committer: Package Import Robot
  • Author(s): Stephen Kitt
  • Date: 2012-11-19 07:00:37 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20121119070037-jvknrm13zvim88oc
Tags: 0.9.26-1
* New upstream WIP version.
* Change priority to "extra" to match libvorbisidec1's.
* Drop "DM-Upload-Allowed" since it is no longer appropriate.
* Refresh patches, replacing MPC_STATUS_FAIL constant from older mpcdec
  versions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Mednafen - Multi-system Emulator
 
2
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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
 
16
 */
 
17
 
 
18
#include "main.h"
 
19
#include "input.h"
 
20
#include "Joystick.h"
 
21
#include "Joystick_DX5.h"
 
22
#include "../md5.h"
 
23
 
 
24
#define DIRECTINPUT_VERSION 0x0500
 
25
#include <windows.h>
 
26
#include <windowsx.h>
 
27
#include <dinput.h>
 
28
 
 
29
#include <math.h>
 
30
#include <set>
 
31
 
 
32
struct di_axis_info
 
33
{
 
34
 int32 minimum, maximum;
 
35
 uint32 jd_logical_offset;
 
36
};
 
37
 
 
38
class Joystick_DX5 : public Joystick
 
39
{
 
40
 public:
 
41
 
 
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);
 
46
 
 
47
 void UpdateInternal(void);
 
48
 
 
49
 private:
 
50
 LPDIRECTINPUTDEVICE2 dev;
 
51
 DIDEVCAPS DevCaps;
 
52
 std::vector<di_axis_info> DIAxisInfo;
 
53
 int have_exclusive_access;
 
54
 void RequestExclusive(bool value);
 
55
};
 
56
 
 
57
#define REQUIRE_DI_CALL(code) { HRESULT hres = (code); if(hres != DI_OK) { throw MDFN_Error(0, "\"" #code "\"" "failed: %u", (unsigned)hres); } }
 
58
 
 
59
void Joystick_DX5::RequestExclusive(bool value)
 
60
{
 
61
 if(value != have_exclusive_access)
 
62
 {
 
63
  if(value && SUCCEEDED(dev->SetCooperativeLevel(GetDesktopWindow(), DISCL_BACKGROUND | DISCL_EXCLUSIVE)) && SUCCEEDED(dev->Acquire()))
 
64
   have_exclusive_access = true;
 
65
  else
 
66
  {
 
67
   have_exclusive_access = false;
 
68
   dev->SetCooperativeLevel(GetDesktopWindow(), DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
 
69
   dev->Acquire();
 
70
  }
 
71
 }
 
72
}
 
73
 
 
74
Joystick_DX5::Joystick_DX5(LPDIRECTINPUT dii, DIDEVICEINSTANCE *ddi) : dev(NULL), have_exclusive_access(-1)
 
75
{
 
76
 LPDIRECTINPUTDEVICE tmp_dev = NULL;
 
77
 
 
78
 try
 
79
 {
 
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) );
 
85
 
 
86
  for(unsigned rax = 0; rax < 8; rax++)
 
87
  {
 
88
   DIPROPRANGE diprg;
 
89
   HRESULT hres;
 
90
 
 
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;
 
95
 
 
96
   // TODO: Handle DIPROPRANGE_NOMIN and DIPROPRANGE_NOMAX
 
97
   hres = dev->GetProperty(DIPROP_RANGE, &diprg.diph);
 
98
   if(hres == DI_OK)
 
99
   {
 
100
    if(diprg.lMin < diprg.lMax)
 
101
    {
 
102
     di_axis_info dai;
 
103
 
 
104
     dai.jd_logical_offset = rax;
 
105
     dai.minimum = diprg.lMin;
 
106
     dai.maximum = diprg.lMax;
 
107
 
 
108
     DIAxisInfo.push_back(dai);
 
109
    }
 
110
   }
 
111
   //else if(hres != DIERR_OBJECTNOTFOUND)
 
112
  }
 
113
 
 
114
  num_rel_axes = 0;
 
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.
 
121
 
 
122
  //
 
123
  //
 
124
  //
 
125
#if 0
 
126
  {
 
127
   DIEFFECTINFO eff_inf;
 
128
 
 
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)
 
131
   {
 
132
    
 
133
   }
 
134
  }
 
135
#endif
 
136
  RequestExclusive(false);
 
137
 
 
138
  CalcOldStyleID(DIAxisInfo.size(), 0, DevCaps.dwPOVs, DevCaps.dwButtons);
 
139
  snprintf(name, sizeof(name), "%s", ddi->tszProductName);
 
140
 }
 
141
 catch(...)
 
142
 {
 
143
  if(tmp_dev != NULL)
 
144
   tmp_dev->Release();
 
145
 
 
146
  if(dev != NULL)
 
147
   dev->Release();
 
148
 
 
149
  throw;
 
150
 }
 
151
}
 
152
 
 
153
Joystick_DX5::~Joystick_DX5()
 
154
{
 
155
 if(dev != NULL)
 
156
 {
 
157
  dev->Unacquire();
 
158
  dev->Release();
 
159
  dev = NULL;
 
160
 }
 
161
}
 
162
 
 
163
unsigned Joystick_DX5::HatToAxisCompat(unsigned hat)
 
164
{
 
165
 return(DIAxisInfo.size() + (hat * 2));
 
166
}
 
167
 
 
168
// TODO: RequestExclusive(false) when SetRumble() hasn't been called for several seconds.
 
169
void Joystick_DX5::UpdateInternal(void)
 
170
{
 
171
 DIJOYSTATE2 js;
 
172
 HRESULT hres;
 
173
 
 
174
 if(DevCaps.dwFlags & (DIDC_POLLEDDEVICE | DIDC_POLLEDDATAFORMAT))
 
175
 {
 
176
  do { /* */ hres = dev->Poll(); /* */ } while((hres == DIERR_INPUTLOST) && ((hres = dev->Acquire()) == DI_OK));
 
177
  if(hres != DI_OK)
 
178
   return;
 
179
 }
 
180
 
 
181
 do { /* */ hres = dev->GetDeviceState(sizeof(js), &js); /* */ } while((hres == DIERR_INPUTLOST) && ((hres = dev->Acquire()) == DI_OK));
 
182
 if(hres != DI_OK)
 
183
  return;
 
184
 
 
185
 for(unsigned button = 0; button < DevCaps.dwButtons; button++)
 
186
 {
 
187
  button_state[button] = (bool)(js.rgbButtons[button] & 0x80);
 
188
 }
 
189
 
 
190
 for(unsigned axis = 0; axis < DIAxisInfo.size(); axis++)
 
191
 {
 
192
  int64 rv = (&js.lX)[DIAxisInfo[axis].jd_logical_offset];
 
193
 
 
194
  rv = (((rv - DIAxisInfo[axis].minimum) * 32767 * 2) / (DIAxisInfo[axis].maximum - DIAxisInfo[axis].minimum)) - 32767;
 
195
  if(rv < -32767)
 
196
   rv = -32767;
 
197
 
 
198
  if(rv > 32767)
 
199
   rv = 32767;
 
200
  axis_state[axis] = rv;
 
201
 }
 
202
 
 
203
 for(unsigned hat = 0; hat < DevCaps.dwPOVs; hat++)
 
204
 {
 
205
  DWORD hat_val = js.rgdwPOV[hat];
 
206
 
 
207
  //if((uint16)hat_val == 0xFFFF)       // Reportedly some drivers report 0xFFFF instead of 0xFFFFFFFF? (comment from byuu)
 
208
  if(hat_val >= 36000)
 
209
  {
 
210
   axis_state[(DIAxisInfo.size() + hat * 2) + 0] = 0;
 
211
   axis_state[(DIAxisInfo.size() + hat * 2) + 1] = 0;
 
212
  }
 
213
  else
 
214
  {
 
215
   int32 x, y;
 
216
 
 
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;
 
221
 
 
222
   switch(octant)
 
223
   {
 
224
    case 0: x = octant_doff * 32767 / 4500; y = -32767; break;
 
225
    case 1: x = 32767; y = (-4500 + octant_doff) * 32767 / 4500; break;
 
226
 
 
227
    case 2: x = 32767; y = octant_doff * 32767 / 4500; break;
 
228
    case 3: x = (4500 - octant_doff) * 32767 / 4500; y = 32767; break;
 
229
 
 
230
    case 4: x = (-octant_doff) * 32767 / 4500; y = 32767; break;
 
231
    case 5: x = -32767; y = (4500 - octant_doff) * 32767 / 4500; break;
 
232
    
 
233
    case 6: x = -32767; y = (-octant_doff) * 32767 / 4500; break;
 
234
    case 7: x = (-4500 + octant_doff) * 32767 / 4500; y = -32767; break;
 
235
   }
 
236
 
 
237
   axis_state[(DIAxisInfo.size() + hat * 2) + 0] = x;
 
238
   axis_state[(DIAxisInfo.size() + hat * 2) + 1] = y;
 
239
  }
 
240
 }
 
241
}
 
242
 
 
243
void Joystick_DX5::SetRumble(uint8 weak_intensity, uint8 strong_intensity)
 
244
{
 
245
 //if((weak_intensity || strong_intensity) && rumble_supported)
 
246
 // RequestExclusive(true);
 
247
}
 
248
 
 
249
class JoystickDriver_DX5 : public JoystickDriver
 
250
{
 
251
 public:
 
252
 
 
253
 JoystickDriver_DX5(bool exclude_xinput);
 
254
 virtual ~JoystickDriver_DX5();
 
255
 
 
256
 virtual unsigned NumJoysticks();                       // Cached internally on JoystickDriver instantiation.
 
257
 virtual Joystick *GetJoystick(unsigned index);
 
258
 virtual void UpdateJoysticks(void);
 
259
 
 
260
 private:
 
261
 std::vector<Joystick_DX5 *> joys;
 
262
 LPDIRECTINPUT dii;
 
263
};
 
264
 
 
265
 
 
266
static INLINE std::set<uint32> GetXInputVidPid(void)
 
267
{
 
268
 HMODULE us32 = NULL;
 
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;
 
272
 
 
273
 if((us32 = LoadLibrary("user32.dll")) == NULL)
 
274
  return exclude_vps;
 
275
 
 
276
 p_GetRawInputDeviceList = (UINT WINAPI (*)(PRAWINPUTDEVICELIST, PUINT, UINT))GetProcAddress(us32, "GetRawInputDeviceList");
 
277
 p_GetRawInputDeviceInfo = (UINT WINAPI (*)(HANDLE, UINT, LPVOID, PUINT))GetProcAddress(us32, "GetRawInputDeviceInfoA");
 
278
 
 
279
 if(p_GetRawInputDeviceList && p_GetRawInputDeviceInfo)
 
280
 {
 
281
  std::vector<RAWINPUTDEVICELIST> ridl;
 
282
  unsigned int alloc_num_devices = 0;
 
283
  unsigned int num_devices = 0;
 
284
 
 
285
  p_GetRawInputDeviceList(NULL, &alloc_num_devices, 0);
 
286
  ridl.resize(alloc_num_devices);
 
287
 
 
288
  if((num_devices = p_GetRawInputDeviceList(&ridl[0], &alloc_num_devices, sizeof(RAWINPUTDEVICELIST))) > 0)
 
289
  {
 
290
   for(unsigned i = 0; i < num_devices; i++)
 
291
   {
 
292
    if(ridl[i].dwType != RIM_TYPEHID)
 
293
     continue;
 
294
 
 
295
    RID_DEVICE_INFO devinfo;
 
296
    std::vector<char> devname;
 
297
    unsigned int sizepar;
 
298
 
 
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))
 
303
     continue;
 
304
    
 
305
    sizepar = 0;
 
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);
 
309
 
 
310
    //printf("MOOCOW: %s\n", devname);
 
311
    if(!strncmp(&devname[0], "IG_", 3) || strstr(&devname[0], "&IG_") != NULL)
 
312
    {
 
313
     exclude_vps.insert(MAKELONG(devinfo.hid.dwVendorId, devinfo.hid.dwProductId));
 
314
    }
 
315
   }
 
316
  }
 
317
 }
 
318
 
 
319
 FreeLibrary(us32);
 
320
 
 
321
 return exclude_vps;
 
322
}
 
323
 
 
324
 
 
325
struct enum_device_list
 
326
{
 
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;
 
331
};
 
332
 
 
333
static BOOL CALLBACK GLOB_EnumJoysticksProc(LPCDIDEVICEINSTANCE ddi, LPVOID private_data)
 
334
{
 
335
 enum_device_list *edl = (enum_device_list*)private_data;
 
336
 
 
337
 //printf("%08x\n", (unsigned int)ddi->guidInstance.Data1);
 
338
 
 
339
 if((ddi->dwDevType & 0xFF) != DIDEVTYPE_JOYSTICK)
 
340
  return DIENUM_CONTINUE;
 
341
 
 
342
 if(edl->valid_count < edl->max_count)
 
343
 {
 
344
  memcpy(&edl->ddi[edl->valid_count], ddi, sizeof(DIDEVICEINSTANCE));
 
345
  edl->valid_count++;
 
346
 }
 
347
 
 
348
 return DIENUM_CONTINUE;
 
349
}
 
350
 
 
351
JoystickDriver_DX5::JoystickDriver_DX5(bool exclude_xinput) : dii(NULL)
 
352
{
 
353
 enum_device_list edl;
 
354
 std::set<uint32> exclude_vps;
 
355
 
 
356
 try
 
357
 {
 
358
  REQUIRE_DI_CALL( DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &dii, NULL) );
 
359
  REQUIRE_DI_CALL( dii->EnumDevices(DIDEVTYPE_JOYSTICK, GLOB_EnumJoysticksProc, &edl, DIEDFL_ATTACHEDONLY) );
 
360
 
 
361
  if(exclude_xinput)
 
362
  {
 
363
   exclude_vps = GetXInputVidPid();
 
364
  }
 
365
 
 
366
  for(unsigned i = 0; i < edl.valid_count; i++)
 
367
  {
 
368
   Joystick_DX5 *jdx5 = NULL;
 
369
 
 
370
   if(edl.ddi[i].guidProduct.Data1 && exclude_vps.count(edl.ddi[i].guidProduct.Data1))
 
371
    continue;
 
372
 
 
373
   try
 
374
   {
 
375
    jdx5 = new Joystick_DX5(dii, &edl.ddi[i]);
 
376
    joys.push_back(jdx5);
 
377
   }
 
378
   catch(std::exception &e)
 
379
   {
 
380
    MDFND_PrintError(e.what());
 
381
    if(jdx5 != NULL)
 
382
    {
 
383
     delete jdx5;
 
384
     jdx5 = NULL;
 
385
    }
 
386
   }
 
387
  }
 
388
 }
 
389
 catch(std::exception &e)
 
390
 {
 
391
  MDFND_PrintError(e.what());
 
392
 }
 
393
}
 
394
 
 
395
JoystickDriver_DX5::~JoystickDriver_DX5()
 
396
{
 
397
 for(unsigned int n = 0; n < joys.size(); n++)
 
398
 {
 
399
  delete joys[n];
 
400
 }
 
401
 
 
402
 if(dii != NULL)
 
403
 {
 
404
  dii->Release();
 
405
  dii = NULL;
 
406
 }
 
407
}
 
408
 
 
409
unsigned JoystickDriver_DX5::NumJoysticks(void)
 
410
{
 
411
 return joys.size();
 
412
}
 
413
 
 
414
Joystick *JoystickDriver_DX5::GetJoystick(unsigned index)
 
415
{
 
416
 return joys[index];
 
417
}
 
418
 
 
419
void JoystickDriver_DX5::UpdateJoysticks(void)
 
420
{
 
421
 for(unsigned int n = 0; n < joys.size(); n++)
 
422
 {
 
423
  joys[n]->UpdateInternal();
 
424
 }
 
425
}
 
426
 
 
427
JoystickDriver *JoystickDriver_DX5_New(bool exclude_xinput)
 
428
{
 
429
 return new JoystickDriver_DX5(exclude_xinput);
 
430
}
 
431