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 <trio/trio.h>
26 #include <mednafen/hash/md5.h>
27 #include <mednafen/math_ops.h>
28 
29 #include "Joystick.h"
30 
31 #ifdef HAVE_SDL
32  #include "Joystick_SDL.h"
33 #endif
34 
35 #if defined(HAVE_LINUX_JOYSTICK) && !defined(__FreeBSD__)
36  #include "Joystick_Linux.h"
37 #endif
38 
39 #ifdef WIN32
40  #include "Joystick_DX5.h"
41  #include "Joystick_XInput.h"
42 #endif
43 
44 #ifdef DOS
45  #include "Joystick_DOS_Standard.h"
46  //#include "Joystick_DOS_SideWinder.h"
47 #endif
48 
Joystick()49 Joystick::Joystick() : id_09x(0), id{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, num_axes(0), num_rel_axes(0), num_buttons(0)
50 {
51 
52 }
53 
~Joystick()54 Joystick::~Joystick()
55 {
56 
57 }
58 
Calc09xID(unsigned arg_num_axes,unsigned arg_num_balls,unsigned arg_num_hats,unsigned arg_num_buttons)59 void Joystick::Calc09xID(unsigned arg_num_axes, unsigned arg_num_balls, unsigned arg_num_hats, unsigned arg_num_buttons)
60 {
61  uint8 digest[16];
62  int tohash[4];
63  md5_context hashie;
64  uint64 ret = 0;
65 
66  //printf("%u %u %u %u\n", arg_num_axes, arg_num_balls, arg_num_hats, arg_num_buttons);
67 
68  tohash[0] = arg_num_axes;
69  tohash[1] = arg_num_balls;
70  tohash[2] = arg_num_hats;
71  tohash[3] = arg_num_buttons;
72 
73  hashie.starts();
74  hashie.update((uint8 *)tohash, sizeof(tohash));
75  hashie.finish(digest);
76 
77  for(int x = 0; x < 16; x++)
78  {
79   ret ^= (uint64)digest[x] << ((x & 7) * 8);
80  }
81 
82  id_09x = ret;
83 }
84 
SetRumble(uint8 weak_intensity,uint8 strong_intensity)85 void Joystick::SetRumble(uint8 weak_intensity, uint8 strong_intensity)
86 {
87 
88 
89 }
90 
IsAxisButton(unsigned axis)91 bool Joystick::IsAxisButton(unsigned axis)
92 {
93  return(false);
94 }
95 
HatToAxisCompat(unsigned hat)96 unsigned Joystick::HatToAxisCompat(unsigned hat)
97 {
98  return(~0U);
99 }
100 
HatToButtonCompat(unsigned hat)101 unsigned Joystick::HatToButtonCompat(unsigned hat)
102 {
103  return(~0U);
104 }
105 
JoystickDriver()106 JoystickDriver::JoystickDriver()
107 {
108 
109 }
110 
~JoystickDriver()111 JoystickDriver::~JoystickDriver()
112 {
113 
114 }
115 
NumJoysticks()116 unsigned JoystickDriver::NumJoysticks()
117 {
118  return 0;
119 }
120 
GetJoystick(unsigned index)121 Joystick *JoystickDriver::GetJoystick(unsigned index)
122 {
123  return NULL;
124 }
125 
UpdateJoysticks(void)126 void JoystickDriver::UpdateJoysticks(void)
127 {
128 
129 }
130 
131 namespace JoystickManager
132 {
133 
134 struct JoystickManager_Cache
135 {
136  Joystick *joystick;
137  std::array<uint8, 16> UniqueID;
138  uint64 UniqueID_09x;
139 
140  enum
141  {
142   AXIS_CONFIG_TYPE_GENERIC = 0,
143   AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS,
144   AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS
145  };
146 
147  // Helpers for input configuration(may have semantics that differ from what the names would suggest)!
148  int config_prio;	// Set to -1 to exclude this joystick instance from configuration, 0 is normal, 1 is SPECIALSAUCEWITHBACON.
149  std::vector<int16> axis_config_type;
150  bool prev_state_valid;
151  std::vector<int16> prev_axis_state;
152  std::vector<int> axis_hysterical_ax_murderer;
153  std::vector<bool> prev_button_state;
154  std::vector<int32> rel_axis_accum_state;
155 };
156 
157 static INLINE int TestAnalogUnscaled(const ButtConfig& bc);
158 
159 static int AnalogThreshold;	// 15.12
160 
161 static std::vector<JoystickDriver *> JoystickDrivers;
162 static std::vector<JoystickManager_Cache> JoystickCache;
163 static ButtConfig BCPending;
164 static int BCPending_Prio;
165 static uint32 BCPending_Time;
166 static uint32 BCPending_CCCC;
167 
Init(void)168 void Init(void)
169 {
170  JoystickDriver *main_driver = NULL;
171  JoystickDriver *hicp_driver = NULL;
172 
173  MDFNI_printf(_("Initializing joysticks...\n"));
174  MDFN_indent(1);
175 
176  try
177  {
178   #if defined(HAVE_LINUX_JOYSTICK) && !defined(__FreeBSD__)
179   main_driver = JoystickDriver_Linux_New();
180   #elif defined(WIN32)
181   {
182    hicp_driver = JoystickDriver_XInput_New();
183    main_driver = JoystickDriver_DX5_New(hicp_driver != NULL && hicp_driver->NumJoysticks() > 0);
184   }
185   #elif defined(HAVE_SDL)
186   main_driver = JoystickDriver_SDL_New();
187   #endif
188 
189   if(hicp_driver != NULL)
190   {
191    JoystickDrivers.push_back(hicp_driver);
192   }
193 
194   if(main_driver != NULL)
195   {
196    JoystickDrivers.push_back(main_driver);
197   }
198 
199   for(unsigned jd = 0; jd < JoystickDrivers.size(); jd++)
200   {
201    for(unsigned i = 0; i < JoystickDrivers[jd]->NumJoysticks(); i++)
202    {
203     JoystickManager_Cache ce;
204 
205     ce.joystick = JoystickDrivers[jd]->GetJoystick(i);
206     ce.UniqueID = ce.joystick->ID();
207     ce.UniqueID_09x = ce.joystick->ID_09x();
208 
209     ce.config_prio = (JoystickDrivers[jd] == hicp_driver) ? 1 : 0;
210 
211     TryAgain:
212     for(unsigned nji = 0; nji < JoystickCache.size(); nji++)
213     {
214      if(JoystickCache[nji].UniqueID == ce.UniqueID)
215      {
216       MDFN_en64msb(&ce.UniqueID[8], MDFN_de64msb(&ce.UniqueID[8]) + 1);
217       goto TryAgain;
218      }
219     }
220 
221     TryAgain_09x:
222     for(unsigned nji = 0; nji < JoystickCache.size(); nji++)
223     {
224      if(JoystickCache[nji].UniqueID_09x == ce.UniqueID_09x)
225      {
226       ce.UniqueID_09x++;
227       goto TryAgain_09x;
228      }
229     }
230 
231     MDFN_printf(_("ID: 0x%016llx%016llx - %s\n"), (unsigned long long)MDFN_de64msb(&ce.UniqueID[0]), (unsigned long long)MDFN_de64msb(&ce.UniqueID[8]), ce.joystick->Name());
232 
233     ce.axis_config_type.resize(ce.joystick->NumAxes());
234     ce.prev_state_valid = false;
235     ce.prev_axis_state.resize(ce.joystick->NumAxes());
236     ce.axis_hysterical_ax_murderer.resize(ce.joystick->NumAxes());
237     ce.prev_button_state.resize(ce.joystick->NumButtons());
238     ce.rel_axis_accum_state.resize(ce.joystick->NumRelAxes());
239 
240     JoystickCache.push_back(ce);
241    }
242   }
243 
244  }
245  catch(std::exception &e)
246  {
247   MDFND_OutputNotice(MDFN_NOTICE_ERROR, e.what());
248   if(main_driver != NULL)
249   {
250    delete main_driver;
251    main_driver = NULL;
252   }
253   if(hicp_driver != NULL)
254   {
255    delete hicp_driver;
256    hicp_driver = NULL;
257   }
258 
259   JoystickDrivers.clear();
260   JoystickCache.clear();
261  }
262  MDFN_indent(-1);
263 }
264 
SetAnalogThreshold(double thresh)265 void SetAnalogThreshold(double thresh)
266 {
267  AnalogThreshold = std::max<int32>(1, std::min<int32>(32767 * 4096, thresh * 32767 * 4096));
268 }
269 
Kill(void)270 void Kill(void)
271 {
272  for(unsigned i = 0; i < JoystickDrivers.size(); i++)
273   delete JoystickDrivers[i];
274 
275  JoystickDrivers.clear();
276  JoystickCache.clear();
277 }
278 
DetectAnalogButtonsForChangeCheck(void)279 unsigned DetectAnalogButtonsForChangeCheck(void)
280 {
281  unsigned ret = 0;
282 
283  for(unsigned i = 0; i < JoystickCache.size(); i++)
284  {
285   for(unsigned axis = 0; axis < JoystickCache[i].joystick->NumAxes(); axis++)
286   {
287    JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_GENERIC;
288 
289    if(JoystickCache[i].joystick->IsAxisButton(axis))
290     ret++;
291    else
292    {
293     int pos = JoystickCache[i].joystick->GetAxis(axis);
294 
295     if(abs(pos) >= 31000)
296     {
297      if(pos < 0)
298       JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS;
299      else
300       JoystickCache[i].axis_config_type[axis] = JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS;
301 
302      printf("SPOON -- joystick=%u, axis=%u, type=%u\n", i, axis, JoystickCache[i].axis_config_type[axis]);
303      ret++;
304     }
305    }
306   }
307  }
308  return ret;
309 }
310 
Reset_BC_ChangeCheck(void)311 void Reset_BC_ChangeCheck(void)
312 {
313  for(unsigned i = 0; i < JoystickCache.size(); i++)
314   JoystickCache[i].prev_state_valid = false;
315 
316  memset(&BCPending, 0, sizeof(BCPending));
317  BCPending.DeviceType = BUTTC_NONE;
318  BCPending_Prio = -1;
319  BCPending_CCCC = 0;
320 }
321 
Do_BC_ChangeCheck(ButtConfig * bc)322 bool Do_BC_ChangeCheck(ButtConfig *bc) //, bool hint_analog)
323 {
324  const uint32 curtime = Time::MonoMS();
325 
326  if(BCPending.DeviceType != BUTTC_NONE)
327  {
328   if((BCPending_Time + 150) <= curtime && BCPending_CCCC >= 5)
329   {
330    *bc = BCPending;
331    BCPending.DeviceType = BUTTC_NONE;
332    BCPending_Prio = -1;
333    BCPending_CCCC = 0;
334    return(true);
335   }
336 
337   if(TestAnalogUnscaled(BCPending) < ((JoystickCache[BCPending.DeviceNum].config_prio > 0) ? 25000 : 26000))
338   {
339    BCPending.DeviceType = BUTTC_NONE;
340    BCPending_Prio = -1;
341    BCPending_CCCC = 0;
342   }
343   else
344    BCPending_CCCC++;
345  }
346 
347   for(unsigned i = 0; i < JoystickCache.size(); i++)
348   {
349    JoystickManager_Cache *const jsc = &JoystickCache[i];
350    Joystick *const js = jsc->joystick;
351    const int ana_low_thresh = ((jsc->config_prio > 0) ? 6000 : 5000);
352    const int ana_high_thresh = ((jsc->config_prio > 0) ? 25000 : 26000);
353 
354    // Search buttons first, then axes?
355    for(unsigned button = 0; button < js->NumButtons(); button++)
356    {
357     bool button_state = js->GetButton(button);
358 
359     if(jsc->prev_state_valid && (button_state != jsc->prev_button_state[button]) && button_state)
360     {
361      ButtConfig bctmp;
362 
363      bctmp.DeviceType = BUTTC_JOYSTICK;
364      bctmp.DeviceNum = i;
365      bctmp.ButtonNum = button;
366      bctmp.DeviceID = jsc->UniqueID;
367 
368      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.
369      {
370       BCPending = bctmp;
371       BCPending_Prio = jsc->config_prio;
372       BCPending_Time = curtime;
373       BCPending_CCCC = 0;
374      }
375     }
376     jsc->prev_button_state[button] = button_state;
377    }
378 
379    for(unsigned axis = 0; axis < js->NumAxes(); axis++)
380    {
381     int16 axis_state = js->GetAxis(axis);
382 
383     if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS)
384     {
385      if(axis_state < -32767)
386       axis_state = -32767;
387 
388      axis_state = (axis_state + 32767) >> 1;
389      //printf("%u: %u\n", axis, axis_state);
390     }
391     else if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS)
392     {
393      if(axis_state < -32767)
394       axis_state = -32767;
395 
396      axis_state = -axis_state;
397 
398      axis_state = (axis_state + 32767) >> 1;
399      //printf("%u: %u\n", axis, axis_state);
400     }
401 
402     if(jsc->prev_state_valid)
403     {
404      if(jsc->axis_hysterical_ax_murderer[axis] && abs(axis_state) >= ana_high_thresh)
405      {
406       ButtConfig bctmp;
407 
408       bctmp.DeviceType = BUTTC_JOYSTICK;
409       bctmp.DeviceNum = i;
410 
411       if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_POSPRESS)
412        bctmp.ButtonNum = JOY_BN_TYPE_ABS_AXIS | axis;
413       else if(jsc->axis_config_type[axis] == JoystickManager_Cache::AXIS_CONFIG_TYPE_ANABUTTON_NEGPRESS)
414        bctmp.ButtonNum = JOY_BN_TYPE_ABS_AXIS | JOY_BN_NEGATE | axis;
415       else
416        bctmp.ButtonNum = JOY_BN_TYPE_ABS_AXIS | JOY_BN_HALFAXIS | ((axis_state < 0) ? JOY_BN_NEGATE : 0) | axis;
417 
418       bctmp.DeviceID = jsc->UniqueID;
419 
420       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.
421       {
422        BCPending = bctmp;
423        BCPending_Prio = jsc->config_prio;
424        BCPending_Time = curtime;
425        BCPending_CCCC = 0;
426       }
427      }
428      else if(!jsc->axis_hysterical_ax_murderer[axis] && abs(axis_state) < ana_low_thresh)
429      {
430       jsc->axis_hysterical_ax_murderer[axis] = 1;
431      }
432     }
433     else
434     {
435      if(abs(axis_state) >= ana_low_thresh)
436       jsc->axis_hysterical_ax_murderer[axis] = 0;
437      else
438       jsc->axis_hysterical_ax_murderer[axis] = 1;
439     }
440 
441     jsc->prev_axis_state[axis] = axis_state;
442    }
443    //
444    //
445    jsc->prev_state_valid = true;
446   }
447 
448  return(false);
449 }
450 
SetRumble(const std::vector<ButtConfig> & bc,uint8 weak_intensity,uint8 strong_intensity)451 void SetRumble(const std::vector<ButtConfig> &bc, uint8 weak_intensity, uint8 strong_intensity)
452 {
453  for(unsigned i = 0; i < bc.size(); i++)
454  {
455   if(bc[i].DeviceType != BUTTC_JOYSTICK)
456    continue;
457 
458   if(bc[i].DeviceNum >= JoystickCache.size())
459    continue;
460 
461   Joystick *joy = JoystickCache[bc[i].DeviceNum].joystick;
462   joy->SetRumble(weak_intensity, strong_intensity);
463  }
464 }
465 
UpdateJoysticks(void)466 void UpdateJoysticks(void)
467 {
468  //TestRumble();
469  for(unsigned i = 0; i < JoystickDrivers.size(); i++)
470  {
471   JoystickDrivers[i]->UpdateJoysticks();
472  }
473 }
474 
TestAnalogUnscaled(const ButtConfig & bc)475 static INLINE int TestAnalogUnscaled(const ButtConfig& bc)
476 {
477  if(bc.DeviceNum >= JoystickCache.size())
478   return false;
479 
480  Joystick *joy = JoystickCache[bc.DeviceNum].joystick;
481  unsigned type = bc.ButtonNum & JOY_BN_TYPE_MASK;
482  unsigned index = bc.ButtonNum & JOY_BN_INDEX_MASK;
483  bool negate = (bool)(bc.ButtonNum & JOY_BN_NEGATE);
484  bool halfaxis = (bool)(bc.ButtonNum & JOY_BN_HALFAXIS);
485  int32 pos;
486 
487  //
488  //
489  if(type == JOY_BN_TYPE_HATCOMPAT)
490  {
491   const unsigned old_index = index;
492 
493   index = joy->HatToAxisCompat((old_index >> 4) & 0x1F);
494   if(index == ~0U)	// Not-implemented case.  See if implemented for buttons.
495   {
496    index = joy->HatToButtonCompat((old_index >> 4) & 0x1F);
497 
498    if(index != ~0U)
499    {
500     type = JOY_BN_TYPE_BUTTON;
501     index += MDFN_log2(old_index & 0xF);
502    }
503    else
504     return 0;
505   }
506   else
507   {
508    type = JOY_BN_TYPE_ABS_AXIS;
509    halfaxis = true;
510 
511    if(old_index & 0x05)
512     index++;
513 
514    negate = (bool)(old_index & 0x09);
515   }
516  }
517  //
518  //
519 
520  switch(bc.ButtonNum & JOY_BN_TYPE_MASK)
521  {
522   case JOY_BN_TYPE_BUTTON:
523 	if(index >= joy->NumButtons())
524 	 return 0;
525 
526 	return joy->GetButton(index) ? 32767 : 0;
527   //
528   //
529   //
530   case JOY_BN_TYPE_ABS_AXIS:
531 	if(index >= joy->NumAxes())
532 	 return 0;
533 
534 	pos = joy->GetAxis(index);
535 	if(pos < -32767)
536 	 pos = -32767;
537 
538 	if(negate)
539 	 pos = -pos;
540 
541 	if(halfaxis)
542 	 pos = std::max<int>(0, pos);
543 	else
544 	 pos = (pos + 32767) >> 1;
545 
546 	return pos;
547  }
548 
549  return 0;
550 }
551 
TestAnalogButton(const ButtConfig & bc)552 int TestAnalogButton(const ButtConfig &bc)
553 {
554  return std::min<int>(32767, (TestAnalogUnscaled(bc) * bc.Scale) >> 12);
555 }
556 
TestButton(const ButtConfig & bc)557 bool TestButton(const ButtConfig &bc)
558 {
559  return (TestAnalogUnscaled(bc) * bc.Scale) >= AnalogThreshold;
560 }
561 
TestAxisRel(const ButtConfig & bc)562 int64 TestAxisRel(const ButtConfig &bc)
563 {
564  if((bc.ButtonNum & JOY_BN_TYPE_MASK) == JOY_BN_TYPE_REL_AXIS)
565  {
566   if(bc.DeviceNum >= JoystickCache.size())
567    return 0;
568 
569   Joystick *joy = JoystickCache[bc.DeviceNum].joystick;
570 
571   const unsigned index = bc.ButtonNum & JOY_BN_INDEX_MASK;
572   const bool negate = (bool)(bc.ButtonNum & JOY_BN_NEGATE);
573   const bool halfaxis = (bool)(bc.ButtonNum & JOY_BN_HALFAXIS);
574 
575   if(index >= joy->NumRelAxes())
576    return 0;
577 
578   int32 ret = joy->GetRelAxis(index);
579 
580   if(negate)
581    ret = -ret;
582 
583   if(halfaxis)
584    ret = std::max<int32>(0, ret);
585 
586   return (int64)ret * bc.Scale;
587  }
588  else
589   return (TestAnalogUnscaled(bc) * bc.Scale) >> 10;
590 }
591 
BNToString(const uint32 bn)592 std::string BNToString(const uint32 bn)
593 {
594  char tmp[256] = { 0 };
595  const unsigned type = bn & JOY_BN_TYPE_MASK;
596 
597  switch(type)
598  {
599   case JOY_BN_TYPE_BUTTON:
600 	trio_snprintf(tmp, sizeof(tmp), "button_%u", bn & JOY_BN_INDEX_MASK);
601 	break;
602 
603   case JOY_BN_TYPE_ABS_AXIS:
604   case JOY_BN_TYPE_REL_AXIS:
605 	trio_snprintf(tmp, sizeof(tmp), "%s_%u%s%s",
606 		(type == JOY_BN_TYPE_REL_AXIS) ? "rel" : "abs",
607 		bn & JOY_BN_INDEX_MASK,
608 		(bn & JOY_BN_HALFAXIS) ? ((bn & JOY_BN_NEGATE) ? "-" : "+") : ((bn & JOY_BN_NEGATE) ? "+-" : "-+"),
609 		(bn & JOY_BN_GUN_TRANSLATE) ? "g" : "");
610 	break;
611 
612   case JOY_BN_TYPE_HATCOMPAT:
613 	trio_snprintf(tmp, sizeof(tmp), "hatcompat_%04x", bn & JOY_BN_INDEX_MASK);
614 	break;
615  }
616 
617  return tmp;
618 }
619 
StringToBN(const char * s,uint16 * bn)620 bool StringToBN(const char* s, uint16* bn)
621 {
622  char type_str[32];
623  unsigned index;
624  char pol_str[3] = { 0 };
625  char flags_str[2] = { 0 };
626 
627  if(trio_sscanf(s, "%31[^_]_%u%2[-+]%1s", type_str, &index, pol_str, flags_str) >= 2 && (index <= JOY_BN_INDEX_MASK))
628  {
629   unsigned type;
630 
631   if(!strcmp(type_str, "abs"))
632    type = JOY_BN_TYPE_ABS_AXIS;
633   else if(!strcmp(type_str, "rel"))
634    type = JOY_BN_TYPE_REL_AXIS;
635   else if(!strcmp(type_str, "button"))
636    type = JOY_BN_TYPE_BUTTON;
637   else
638    return false;
639 
640   if(type == JOY_BN_TYPE_BUTTON)
641   {
642    *bn = type | index;
643    return true;
644   }
645   else
646   {
647    unsigned flags = 0;
648 
649    if(pol_str[0] == '-' && pol_str[1] == '+')
650    { }
651    else if(pol_str[0] == '+' && pol_str[1] == '-')
652     flags |= JOY_BN_NEGATE;
653    else if(pol_str[0] == '+' && pol_str[1] == 0)
654     flags |= JOY_BN_HALFAXIS;
655    else if(pol_str[0] == '-' && pol_str[1] == 0)
656     flags |= JOY_BN_HALFAXIS | JOY_BN_NEGATE;
657    else
658     return false;
659 
660    if(flags_str[0] == 'g')
661     flags |= JOY_BN_GUN_TRANSLATE;
662 
663    *bn = type | flags | index;
664    return true;
665   }
666  }
667 
668  return false;
669 }
670 
Translate09xBN(unsigned bn09x,uint16 * bn,bool abs_pointer_axis_thing)671 bool Translate09xBN(unsigned bn09x, uint16* bn, bool abs_pointer_axis_thing)
672 {
673  unsigned type;
674  unsigned index;
675  unsigned flags = 0;
676 
677  if(bn09x & 0x2000)
678  {
679   type = JOY_BN_TYPE_HATCOMPAT;
680   index = (bn09x & 0xF) | ((bn09x >> 4) & 0x1F0);
681  }
682  else if(bn09x & 0x18000)
683  {
684   type = JOY_BN_TYPE_ABS_AXIS;
685   index = bn09x & 0x1FFF;
686 
687   if(abs_pointer_axis_thing)
688   {
689    if(bn09x & 0x4000)
690     flags |= JOY_BN_NEGATE;
691 
692    if(bn09x & (1U << 18))
693     flags |= JOY_BN_GUN_TRANSLATE;
694   }
695   else
696   {
697    if(bn09x & (1U << 16))
698    {
699     if(bn09x & (1U << 17))
700      flags |= JOY_BN_NEGATE;
701    }
702    else
703    {
704     flags |= JOY_BN_HALFAXIS;
705 
706     if(bn09x & 0x4000)
707      flags |= JOY_BN_NEGATE;
708    }
709   }
710  }
711  else
712  {
713   type = JOY_BN_TYPE_BUTTON;
714   index = bn09x & 0x1FFF;
715  }
716 
717  if(index > JOY_BN_INDEX_MASK)
718   return false;
719 
720  *bn = type | flags | index;
721 
722  return true;
723 }
724 
725 
GetIndexByUniqueID(const std::array<uint8,16> & unique_id)726 unsigned GetIndexByUniqueID(const std::array<uint8, 16>& unique_id)
727 {
728  for(unsigned i = 0; i < JoystickCache.size(); i++)
729  {
730   if(JoystickCache[i].UniqueID == unique_id)
731    return i;
732  }
733 
734  return ~0U;
735 }
736 
GetIndexByUniqueID_09x(uint64 unique_id)737 unsigned GetIndexByUniqueID_09x(uint64 unique_id)
738 {
739  for(unsigned i = 0; i < JoystickCache.size(); i++)
740  {
741   if(JoystickCache[i].UniqueID_09x == unique_id)
742   {
743    //printf("%16llx %u\n", unique_id, i);
744    return(i);
745   }
746  }
747 
748  return(~0U);
749 }
750 
GetUniqueIDByIndex(unsigned index)751 std::array<uint8, 16> GetUniqueIDByIndex(unsigned index)
752 {
753  if(index >= JoystickCache.size())
754   return { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
755 
756  return JoystickCache[index].UniqueID;
757 }
758 
759 }
760