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

« back to all changes in this revision

Viewing changes to src/drivers/Joystick.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
 The joystick driver configuration priority system should be considered as last-resort protection for multiple-API platforms(such as DirectInput + XInput on Windows), in the
 
19
 event that all reasonable attempts at preventing the same physical device from being opened via multiple APIs fail.  (The configuration priority system generally should
 
20
 work ok as long as the user isn't extremely unlucky, doesn't try to configure too quickly(or too slowly ;)), and the controller is well-behaved; but it is still
 
21
 inherently race-conditiony).
 
22
*/
 
23
#include "main.h"
 
24
#include "input.h"
 
25
#include "../md5.h"
 
26
#include "../math_ops.h"
 
27
 
 
28
#include "Joystick.h"
 
29
 
 
30
#ifdef HAVE_SDL
 
31
 #include "Joystick_SDL.h"
 
32
#endif
 
33
 
 
34
#ifdef HAVE_LINUX_JOYSTICK
 
35
 #include "Joystick_Linux.h"
 
36
#endif
 
37
 
 
38
#ifdef WIN32
 
39
 #include "Joystick_DX5.h"
 
40
 #include "Joystick_XInput.h"
 
41
#endif
 
42
 
 
43
#ifdef DOS
 
44
 #include "Joystick_DOS_Standard.h"
 
45
 //#include "Joystick_DOS_SideWinder.h"
 
46
#endif
 
47
 
 
48
Joystick::Joystick() : num_axes(0), num_rel_axes(0), num_buttons(0), id(0)
 
49
{
 
50
 name[0] = 0;
 
51
}
 
52
 
 
53
Joystick::~Joystick()
 
54
{
 
55
 
 
56
}
 
57
 
 
58
void Joystick::CalcOldStyleID(unsigned arg_num_axes, unsigned arg_num_balls, unsigned arg_num_hats, unsigned arg_num_buttons)
 
59
{
 
60
 uint8 digest[16];
 
61
 int tohash[4];
 
62
 md5_context hashie;
 
63
 uint64 ret = 0;
 
64
 
 
65
 //printf("%u %u %u %u\n", arg_num_axes, arg_num_balls, arg_num_hats, arg_num_buttons);
 
66
 
 
67
 tohash[0] = arg_num_axes;
 
68
 tohash[1] = arg_num_balls;
 
69
 tohash[2] = arg_num_hats;
 
70
 tohash[3] = arg_num_buttons;
 
71
 
 
72
 hashie.starts();
 
73
 hashie.update((uint8 *)tohash, sizeof(tohash));
 
74
 hashie.finish(digest);
 
75
 
 
76
 for(int x = 0; x < 16; x++)
 
77
 {
 
78
  ret ^= (uint64)digest[x] << ((x & 7) * 8);
 
79
 }
 
80
 
 
81
 id = ret;
 
82
}
 
83
 
 
84
void Joystick::SetRumble(uint8 weak_intensity, uint8 strong_intensity)
 
85
{
 
86
 
 
87
 
 
88
}
 
89
 
 
90
bool Joystick::IsAxisButton(unsigned axis)
 
91
{
 
92
 return(false);
 
93
}
 
94
 
 
95
unsigned Joystick::HatToAxisCompat(unsigned hat)
 
96
{
 
97
 return(~0U);
 
98
}
 
99
 
 
100
unsigned Joystick::HatToButtonCompat(unsigned hat)
 
101
{
 
102
 return(~0U);
 
103
}
 
104
 
 
105
JoystickDriver::JoystickDriver()
 
106
{
 
107
 
 
108
}
 
109
 
 
110
JoystickDriver::~JoystickDriver()
 
111
{
 
112
 
 
113
}
 
114
 
 
115
unsigned JoystickDriver::NumJoysticks()
 
116
{
 
117
 return 0;
 
118
}
 
119
 
 
120
Joystick *JoystickDriver::GetJoystick(unsigned index)
 
121
{
 
122
 return NULL;
 
123
}
 
124
 
 
125
void JoystickDriver::UpdateJoysticks(void)
 
126
{
 
127
 
 
128
}
 
129
 
 
130
JoystickManager::JoystickManager()
 
131
{
 
132
 JoystickDriver *main_driver = NULL;
 
133
 JoystickDriver *hicp_driver = NULL;
 
134
 
 
135
 MDFNI_printf(_("Initializing joysticks...\n"));
 
136
 MDFN_indent(1);
 
137
 
 
138
 try
 
139
 {
 
140
  #ifdef HAVE_LINUX_JOYSTICK
 
141
  main_driver = JoystickDriver_Linux_New();
 
142
  #elif defined(WIN32)
 
143
  {
 
144
   hicp_driver = JoystickDriver_XInput_New();
 
145
   main_driver = JoystickDriver_DX5_New(hicp_driver != NULL && hicp_driver->NumJoysticks() > 0);
 
146
  }
 
147
  #elif defined(HAVE_SDL)
 
148
  main_driver = JoystickDriver_SDL_New();
 
149
  #endif
 
150
 
 
151
  if(hicp_driver != NULL)
 
152
  {
 
153
   JoystickDrivers.push_back(hicp_driver);
 
154
  }
 
155
 
 
156
  if(main_driver != NULL)
 
157
  {
 
158
   JoystickDrivers.push_back(main_driver);
 
159
  }
 
160
 
 
161
  for(unsigned jd = 0; jd < JoystickDrivers.size(); jd++)
 
162
  {
 
163
   for(unsigned i = 0; i < JoystickDrivers[jd]->NumJoysticks(); i++)
 
164
   {
 
165
    JoystickManager_Cache ce;
 
166
 
 
167
    ce.joystick = JoystickDrivers[jd]->GetJoystick(i);
 
168
    ce.UniqueID = ce.joystick->ID();
 
169
    ce.config_prio = (JoystickDrivers[jd] == hicp_driver) ? 1 : 0;
 
170
 
 
171
    TryAgain:
 
172
    for(unsigned nji = 0; nji < JoystickCache.size(); nji++)
 
173
    {
 
174
     if(JoystickCache[nji].UniqueID == ce.UniqueID)
 
175
     {
 
176
      ce.UniqueID++;
 
177
      goto TryAgain;
 
178
     }
 
179
    }
 
180
 
 
181
    MDFN_printf(_("Joystick %u - %s - Unique ID: %016llx\n"), (unsigned)JoystickCache.size(), ce.joystick->Name(), (unsigned long long)ce.UniqueID);
 
182
 
 
183
    ce.axis_config_type.resize(ce.joystick->NumAxes());
 
184
    ce.prev_state_valid = false;
 
185
    ce.prev_axis_state.resize(ce.joystick->NumAxes());
 
186
    ce.axis_hysterical_ax_murderer.resize(ce.joystick->NumAxes());
 
187
    ce.prev_button_state.resize(ce.joystick->NumButtons());
 
188
    ce.rel_axis_accum_state.resize(ce.joystick->NumRelAxes());
 
189
 
 
190
    JoystickCache.push_back(ce);
 
191
   }
 
192
  }
 
193
 
 
194
 }
 
195
 catch(std::exception &e)
 
196
 {
 
197
  MDFND_PrintError(e.what());
 
198
  if(main_driver != NULL)
 
199
  {
 
200
   delete main_driver;
 
201
   main_driver = NULL;
 
202
  }
 
203
  if(hicp_driver != NULL)
 
204
  {
 
205
   delete hicp_driver;
 
206
   hicp_driver = NULL;
 
207
  }
 
208
 }
 
209
 MDFN_indent(-1);
 
210
}
 
211
 
 
212
void JoystickManager::SetAnalogThreshold(double thresh)
 
213
{
 
214
 AnalogThreshold = thresh * 32767;
 
215
}
 
216
 
 
217
JoystickManager::~JoystickManager()
 
218
{
 
219
 for(unsigned i = 0; i < JoystickDrivers.size(); i++)
 
220
  delete JoystickDrivers[i];
 
221
}
 
222
 
 
223
unsigned JoystickManager::DetectAnalogButtonsForChangeCheck(void)
 
224
{
 
225
 unsigned ret = 0;
 
226
 
 
227
 for(unsigned i = 0; i < JoystickCache.size(); i++)
 
228
 {
 
229
  for(unsigned axis = 0; axis < JoystickCache[i].joystick->NumAxes(); axis++)
 
230
  {
 
231
   JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_GENERIC;
 
232
 
 
233
   if(JoystickCache[i].joystick->IsAxisButton(axis))
 
234
    ret++;
 
235
   else
 
236
   {
 
237
    int pos = JoystickCache[i].joystick->GetAxis(axis);
 
238
 
 
239
    if(abs(pos) >= 31000)
 
240
    {
 
241
     if(pos < 0)
 
242
      JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS;
 
243
     else
 
244
      JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS;
 
245
 
 
246
     printf("SPOON -- joystick=%u, axis=%u, type=%u\n", i, axis, JoystickCache[i].axis_config_type[axis]);
 
247
     ret++;
 
248
    }
 
249
   }
 
250
  }
 
251
 }
 
252
 return ret;
 
253
}
 
254
 
 
255
void JoystickManager::Reset_BC_ChangeCheck(void)
 
256
{
 
257
 for(unsigned i = 0; i < JoystickCache.size(); i++)
 
258
  JoystickCache[i].prev_state_valid = false;
 
259
 
 
260
 BCPending.ButtType = BUTTC_NONE;
 
261
 BCPending_Prio = -1;
 
262
 BCPending_CCCC = 0;
 
263
}
 
264
 
 
265
bool JoystickManager::Do_BC_ChangeCheck(ButtConfig *bc) //, bool hint_analog)
 
266
{
 
267
 if(BCPending.ButtType != BUTTC_NONE)
 
268
 {
 
269
  if((BCPending_Time + 150) <= MDFND_GetTime() && BCPending_CCCC >= 5) //(int32)(MDFND_GetTime() - BCPending_Time) >= 150)
 
270
  {
 
271
   *bc = BCPending;
 
272
   BCPending.ButtType = BUTTC_NONE;
 
273
   BCPending_Prio = -1;
 
274
   BCPending_CCCC = 0;
 
275
   return(true);
 
276
  }
 
277
 
 
278
  int SaveAT = AnalogThreshold; // Begin Kludge
 
279
  AnalogThreshold = ((JoystickCache[BCPending.DeviceNum].config_prio > 0) ? 25000 : 26000);
 
280
  if(!TestButton(BCPending))
 
281
  {
 
282
   BCPending.ButtType = BUTTC_NONE;
 
283
   BCPending_Prio = -1;
 
284
   BCPending_CCCC = 0;
 
285
  }
 
286
  else
 
287
   BCPending_CCCC++;
 
288
  AnalogThreshold = SaveAT;     // End Kludge.
 
289
 }
 
290
 
 
291
  for(unsigned i = 0; i < JoystickCache.size(); i++)
 
292
  {
 
293
   JoystickManager_Cache *const jsc = &JoystickCache[i];
 
294
   Joystick *const js = jsc->joystick;
 
295
   const int ana_low_thresh = ((jsc->config_prio > 0) ? 6000 : 5000);
 
296
   const int ana_high_thresh = ((jsc->config_prio > 0) ? 25000 : 26000);
 
297
 
 
298
   // Search buttons first, then axes?
 
299
   for(unsigned button = 0; button < js->NumButtons(); button++)
 
300
   {
 
301
    bool button_state = js->GetButton(button);
 
302
 
 
303
    if(jsc->prev_state_valid && (button_state != jsc->prev_button_state[button]) && button_state)
 
304
    {
 
305
     ButtConfig bctmp;
 
306
 
 
307
     bctmp.ButtType = BUTTC_JOYSTICK;
 
308
     bctmp.DeviceNum = i;
 
309
     bctmp.ButtonNum = button;
 
310
     bctmp.DeviceID = jsc->UniqueID;
 
311
 
 
312
     if(jsc->config_prio >= 0 && (jsc->config_prio > BCPending_Prio || 0))      // TODO: add axis/button priority logic(replace || 0) for gamepads that send axis and button events for analog button presses.
 
313
     {
 
314
      BCPending = bctmp;
 
315
      BCPending_Prio = jsc->config_prio;
 
316
      BCPending_Time = MDFND_GetTime();
 
317
      BCPending_CCCC = 0;
 
318
     }
 
319
    }
 
320
    jsc->prev_button_state[button] = button_state;
 
321
   }
 
322
 
 
323
   for(unsigned axis = 0; axis < js->NumAxes(); axis++)
 
324
   {
 
325
    int16 axis_state = js->GetAxis(axis);
 
326
 
 
327
    if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS)
 
328
    {
 
329
     if(axis_state < -32767)
 
330
      axis_state = -32767;
 
331
 
 
332
     axis_state = (axis_state + 32767) >> 1;
 
333
     //printf("%u: %u\n", axis, axis_state);
 
334
    }
 
335
    else if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS)
 
336
    {
 
337
     if(axis_state < -32767)
 
338
      axis_state = -32767;
 
339
 
 
340
     axis_state = -axis_state;
 
341
 
 
342
     axis_state = (axis_state + 32767) >> 1;
 
343
     //printf("%u: %u\n", axis, axis_state);
 
344
    }
 
345
 
 
346
    if(jsc->prev_state_valid)
 
347
    {
 
348
     if(jsc->axis_hysterical_ax_murderer[axis] && abs(axis_state) >= ana_high_thresh)
 
349
     {
 
350
      ButtConfig bctmp;
 
351
 
 
352
      bctmp.ButtType = BUTTC_JOYSTICK;
 
353
      bctmp.DeviceNum = i;
 
354
 
 
355
      if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS)
 
356
       bctmp.ButtonNum = (1 << 16) | axis;
 
357
      else if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS)
 
358
       bctmp.ButtonNum = (1 << 16) | (1 << 17) | axis;
 
359
      else
 
360
       bctmp.ButtonNum = 0x8000 | axis | ((axis_state < 0) ? 0x4000 : 0);
 
361
 
 
362
      bctmp.DeviceID = jsc->UniqueID;
 
363
 
 
364
      if(jsc->config_prio >= 0 && (jsc->config_prio > BCPending_Prio || 0))     // TODO: add axis/button priority logic(replace || 0) for gamepads that send axis and button events for analog button presses.
 
365
      {
 
366
       BCPending = bctmp;
 
367
       BCPending_Prio = jsc->config_prio;
 
368
       BCPending_Time = MDFND_GetTime();
 
369
       BCPending_CCCC = 0;
 
370
      }
 
371
     }
 
372
     else if(!jsc->axis_hysterical_ax_murderer[axis] && abs(axis_state) < ana_low_thresh)
 
373
     {
 
374
      jsc->axis_hysterical_ax_murderer[axis] = 1;
 
375
     }
 
376
    }
 
377
    else
 
378
    {
 
379
     if(abs(axis_state) >= ana_low_thresh)
 
380
      jsc->axis_hysterical_ax_murderer[axis] = 0;
 
381
     else
 
382
      jsc->axis_hysterical_ax_murderer[axis] = 1;
 
383
    }
 
384
 
 
385
    jsc->prev_axis_state[axis] = axis_state;
 
386
   }
 
387
   //
 
388
   //
 
389
   jsc->prev_state_valid = true;
 
390
  }
 
391
 
 
392
 return(false);
 
393
}
 
394
 
 
395
void JoystickManager::SetRumble(const std::vector<ButtConfig> &bc, uint8 weak_intensity, uint8 strong_intensity)
 
396
{
 
397
 for(unsigned i = 0; i < bc.size(); i++)
 
398
 {
 
399
  if(bc[i].ButtType != BUTTC_JOYSTICK)
 
400
   continue;
 
401
 
 
402
  if(bc[i].DeviceNum >= JoystickCache.size())
 
403
   continue;
 
404
 
 
405
  Joystick *joy = JoystickCache[bc[i].DeviceNum].joystick;
 
406
  joy->SetRumble(weak_intensity, strong_intensity);
 
407
 }
 
408
}
 
409
 
 
410
void JoystickManager::TestRumble(void)
 
411
{
 
412
 uint8 weak, strong;
 
413
 //uint32 cur_time = MDFND_GetTime();
 
414
 
 
415
 strong = 255;
 
416
 weak = 0;
 
417
 for(unsigned i = 0; i < JoystickCache.size(); i++)
 
418
 {
 
419
  Joystick *joy = JoystickCache[i].joystick; 
 
420
  joy->SetRumble(weak, strong);
 
421
 }
 
422
}
 
423
 
 
424
void JoystickManager::UpdateJoysticks(void)
 
425
{
 
426
 //TestRumble();
 
427
 for(unsigned i = 0; i < JoystickDrivers.size(); i++)
 
428
 {
 
429
  JoystickDrivers[i]->UpdateJoysticks();
 
430
 }
 
431
}
 
432
 
 
433
bool JoystickManager::TestButton(const ButtConfig &bc)
 
434
{
 
435
 if(bc.DeviceNum >= JoystickCache.size())
 
436
  return(0);
 
437
 
 
438
 //printf("%u\n", AnalogThreshold);
 
439
 
 
440
 Joystick *joy = JoystickCache[bc.DeviceNum].joystick;
 
441
 
 
442
 if(bc.ButtonNum & (0x8000 | 0x2000))      /* Axis "button" (| 0x2000 for backwards-compat hat translation)*/
 
443
 {
 
444
  bool neg_req = (bool)(bc.ButtonNum & 0x4000);
 
445
  unsigned axis = bc.ButtonNum & 0x3FFF;
 
446
  int pos;
 
447
 
 
448
  if(bc.ButtonNum & 0x2000)
 
449
  {
 
450
   axis = joy->HatToAxisCompat((bc.ButtonNum >> 8) & 0x1F);
 
451
   if(axis == ~0U)      // Not-implemented case.  See if implemented for buttons.
 
452
   {
 
453
    unsigned button = joy->HatToButtonCompat((bc.ButtonNum >> 8) & 0x1F);
 
454
 
 
455
    if(button != ~0U)
 
456
    {
 
457
     button += uilog2(bc.ButtonNum & 0xF);
 
458
 
 
459
     if(button >= joy->NumButtons())
 
460
      return(0);
 
461
 
 
462
     return joy->GetButton(button);
 
463
    }
 
464
    return(0);
 
465
   }
 
466
 
 
467
   if(bc.ButtonNum & 0x05)
 
468
    axis++;
 
469
 
 
470
   neg_req = bc.ButtonNum & 0x09;
 
471
  }
 
472
 
 
473
  if(axis >= joy->NumAxes())
 
474
   return(0);
 
475
 
 
476
  pos = joy->GetAxis(axis);
 
477
 
 
478
  if(neg_req && (pos <= -AnalogThreshold))
 
479
   return(1);
 
480
  else if(!neg_req && (pos >= AnalogThreshold))
 
481
   return(1);
 
482
 }
 
483
 else if(bc.ButtonNum & (1 << 16))      // Analog button axis.
 
484
 {
 
485
  unsigned axis = bc.ButtonNum & 0x3FFF;
 
486
  int pos;
 
487
 
 
488
  if(axis >= joy->NumAxes())
 
489
   return(0);
 
490
 
 
491
  pos = joy->GetAxis(axis);
 
492
  if(pos < -32767)
 
493
   pos = -32767;
 
494
 
 
495
  if(bc.ButtonNum & (1 << 17))
 
496
   pos = -pos;
 
497
 
 
498
  pos += 32767;
 
499
  pos >>= 1;
 
500
 
 
501
  if(pos >= AnalogThreshold)
 
502
   return(1);
 
503
 }
 
504
 else
 
505
 {
 
506
  unsigned button = bc.ButtonNum;
 
507
 
 
508
  if(button >= joy->NumButtons())
 
509
   return(0);
 
510
 
 
511
  return joy->GetButton(button);
 
512
 }
 
513
 
 
514
 return(0);
 
515
}
 
516
 
 
517
int JoystickManager::TestAnalogButton(const ButtConfig &bc)
 
518
{
 
519
 if(bc.DeviceNum >= JoystickCache.size())
 
520
  return(0);
 
521
 
 
522
 Joystick *joy = JoystickCache[bc.DeviceNum].joystick;
 
523
 
 
524
 if(bc.ButtonNum & 0x8000)      /* Axis "button" */
 
525
 {
 
526
  unsigned axis = bc.ButtonNum & 0x3FFF;
 
527
  int pos;
 
528
 
 
529
  if(axis >= joy->NumAxes())
 
530
   return(0);
 
531
  pos = joy->GetAxis(axis);
 
532
 
 
533
  if((bc.ButtonNum & 0x4000) && pos < 0)
 
534
   return(std::min<int>(-pos, 32767));
 
535
  else if (!(bc.ButtonNum & 0x4000) && pos > 0)
 
536
   return(pos);
 
537
 }
 
538
 else if(bc.ButtonNum & (1 << 16))      // Analog button axis.
 
539
 {
 
540
  unsigned axis = bc.ButtonNum & 0x3FFF;
 
541
  int pos;
 
542
 
 
543
  if(axis >= joy->NumAxes())
 
544
   return(0);
 
545
 
 
546
  pos = joy->GetAxis(axis);
 
547
  if(pos < -32767)
 
548
   pos = -32767;
 
549
 
 
550
  if(bc.ButtonNum & (1 << 17))
 
551
   pos = -pos;
 
552
 
 
553
  pos += 32767;
 
554
  pos >>= 1;
 
555
 
 
556
  return(pos);
 
557
 }
 
558
 else
 
559
 {
 
560
  return(TestButton(bc) ? 32767 : 0);
 
561
 }
 
562
 
 
563
 return(0);
 
564
}
 
565
 
 
566
unsigned JoystickManager::GetIndexByUniqueID(uint64 unique_id)
 
567
{
 
568
 for(unsigned i = 0; i < JoystickCache.size(); i++)
 
569
 {
 
570
  if(JoystickCache[i].UniqueID == unique_id)
 
571
  {
 
572
   //printf("%16llx %u\n", unique_id, i);
 
573
   return(i);
 
574
  }
 
575
 }
 
576
 
 
577
 return(~0U);
 
578
}
 
579
 
 
580
unsigned JoystickManager::GetUniqueIDByIndex(unsigned index)
 
581
{
 
582
 return JoystickCache[index].UniqueID;
 
583
}