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