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 
20 #include <trio/trio.h>
21 #include <map>
22 
23 #include "input.h"
24 #include "sound.h"
25 #include "video.h"
26 #include "Joystick.h"
27 #include "mouse.h"
28 #include "keyboard.h"
29 #include "netplay.h"
30 #include "cheat.h"
31 #include "fps.h"
32 #include "debugger.h"
33 #include "help.h"
34 #include "rmdui.h"
35 
36 int NoWaiting = 0;
37 
38 static bool ViewDIPSwitches = false;
39 static bool InputGrab = false;
40 static bool EmuKeyboardKeysGrabbed = false;
41 static bool NPCheatDebugKeysGrabbed = false;
42 
43 static bool inff = 0;
44 static bool insf = 0;
45 
46 bool RewindState = true;
47 bool DNeedRewind = false;
48 
49 static unsigned int autofirefreq;
50 static unsigned int ckdelay;
51 
52 static bool fftoggle_setting;
53 static bool sftoggle_setting;
54 
55 static int ConfigDevice(int arg);
56 static void ConfigDeviceBegin(void);
57 
58 static void subcon_begin(void);
59 static bool subcon(const char *text, std::vector<ButtConfig> &bc, const bool commandkey, const bool AND_Mode);
60 
61 static void ResyncGameInputSettings(unsigned port);
62 static void CalcWMInputBehavior(void);
63 
DTestButton(const std::vector<ButtConfig> & bc,const bool bypass_key_masking)64 static bool DTestButton(const std::vector<ButtConfig>& bc, const bool bypass_key_masking)
65 {
66  size_t match_count = 0;
67  bool invert = false;
68 
69  for(size_t i = 0; i < bc.size(); i++)
70  {
71   auto const& bce = bc[i];
72 
73   switch(bce.DeviceType)
74   {
75    case BUTTC_KEYBOARD:
76 	match_count += invert ^ (bool)KBMan::TestButton(bce, bypass_key_masking);
77 	break;
78 
79    case BUTTC_JOYSTICK:
80 	match_count += invert ^ (bool)JoystickManager::TestButton(bce);
81 	break;
82 
83    case BUTTC_MOUSE:
84 	match_count += invert ^ (bool)MouseMan::TestButton(bce);
85 	break;
86   }
87   invert = (bce.ANDGroupCont < 0);
88 
89   if(!bce.ANDGroupCont)
90   {
91    if(match_count > i)
92     return true;
93 
94    match_count = i + 1;
95   }
96  }
97 
98  return false;
99 }
100 
DTestAnalogButton(const std::vector<ButtConfig> & bc,const bool bypass_key_masking)101 static INLINE int32 DTestAnalogButton(const std::vector<ButtConfig>& bc, const bool bypass_key_masking)
102 {
103  int32 accum = 0;
104 
105  for(auto const& bce : bc)
106  {
107   switch(bce.DeviceType)
108   {
109    case BUTTC_KEYBOARD:	accum += KBMan::TestAnalogButton(bce, bypass_key_masking); break;
110    case BUTTC_JOYSTICK:	accum += JoystickManager::TestAnalogButton(bce); break;
111    case BUTTC_MOUSE:	accum += MouseMan::TestAnalogButton(bce); break;
112   }
113  }
114 
115  return std::min<int32>(32767, accum);
116 }
117 
DTestAxis(const std::vector<ButtConfig> & neg_bc,const std::vector<ButtConfig> & pos_bc,const bool bypass_key_masking,const float dev_axis_scale)118 static INLINE uint32 DTestAxis(const std::vector<ButtConfig>& neg_bc, const std::vector<ButtConfig>& pos_bc, const bool bypass_key_masking, const float dev_axis_scale)
119 {
120  int32 accum = 0;
121 
122  for(auto const& bce : neg_bc)
123  {
124   switch(bce.DeviceType)
125   {
126    case BUTTC_KEYBOARD:	accum -= KBMan::TestAnalogButton(bce, bypass_key_masking); break;
127    case BUTTC_JOYSTICK:	accum -= JoystickManager::TestAnalogButton(bce); break;
128    case BUTTC_MOUSE:	accum -= MouseMan::TestAnalogButton(bce); break;
129   }
130  }
131 
132  for(auto const& bce : pos_bc)
133  {
134   switch(bce.DeviceType)
135   {
136    case BUTTC_KEYBOARD:	accum += KBMan::TestAnalogButton(bce, bypass_key_masking); break;
137    case BUTTC_JOYSTICK:	accum += JoystickManager::TestAnalogButton(bce); break;
138    case BUTTC_MOUSE:	accum += MouseMan::TestAnalogButton(bce); break;
139   }
140  }
141 
142  return 32768 + std::max<int32>(-32768, std::min<int32>(32767, floor(0.5 + accum * dev_axis_scale)));
143 }
144 
145 // Returns 1.51.12 value
DTestAxisRel(const std::vector<ButtConfig> & neg_bc,const std::vector<ButtConfig> & pos_bc,const bool bypass_key_masking)146 static int64 DTestAxisRel(const std::vector<ButtConfig>& neg_bc, const std::vector<ButtConfig>& pos_bc, const bool bypass_key_masking)
147 {
148  int64 accum = 0;
149 
150  for(auto const& bce : neg_bc)
151  {
152   switch(bce.DeviceType)
153   {
154    case BUTTC_KEYBOARD:	accum -= KBMan::TestAxisRel(bce, bypass_key_masking); break;
155    case BUTTC_JOYSTICK: accum -= JoystickManager::TestAxisRel(bce); break;
156    case BUTTC_MOUSE:	accum -= MouseMan::TestAxisRel(bce); break;
157   }
158  }
159 
160  for(auto const& bce : pos_bc)
161  {
162   switch(bce.DeviceType)
163   {
164    case BUTTC_KEYBOARD:	accum += KBMan::TestAxisRel(bce, bypass_key_masking); break;
165    case BUTTC_JOYSTICK: accum += JoystickManager::TestAxisRel(bce); break;
166    case BUTTC_MOUSE:	accum += MouseMan::TestAxisRel(bce); break;
167   }
168  }
169 
170  return accum;
171 }
172 
DTestPointer(const std::vector<ButtConfig> & bc,const bool bypass_key_masking,const bool axis_hint)173 static float DTestPointer(const std::vector<ButtConfig>& bc, const bool bypass_key_masking, const bool axis_hint)
174 {
175  if(MDFN_LIKELY(bc.size()))
176  {
177   const ButtConfig& bce = bc[0];
178 
179   switch(bce.DeviceType)
180   {
181    case BUTTC_JOYSTICK:
182 	printf("%d %d %f\n", axis_hint, JoystickManager::TestAnalogButton(bce), Video_PtoV_J(JoystickManager::TestAnalogButton(bce), axis_hint, bce.ButtonNum & JoystickManager::JOY_BN_GUN_TRANSLATE));
183 	return Video_PtoV_J(JoystickManager::TestAnalogButton(bce), axis_hint, bce.ButtonNum & JoystickManager::JOY_BN_GUN_TRANSLATE);
184 
185    case BUTTC_MOUSE:
186 	return MouseMan::TestPointer(bce);
187   }
188  }
189 
190  return 0;
191 }
192 
193 /* Used for command keys */
DTestButtonCombo(std::vector<ButtConfig> & bc,const bool bypass_key_masking,const bool ignore_ralt)194 static bool DTestButtonCombo(std::vector<ButtConfig> &bc, const bool bypass_key_masking, const bool ignore_ralt)
195 {
196  size_t match_count = 0;
197  bool invert = false;
198 
199  for(size_t i = 0; i < bc.size(); i++)
200  {
201   auto const& bce = bc[i];
202 
203   switch(bce.DeviceType)
204   {
205    case BUTTC_KEYBOARD:
206 	match_count += invert ^ (bool)KBMan::TestButtonWithMods(bce, bypass_key_masking, ignore_ralt);
207 	break;
208 
209    case BUTTC_JOYSTICK:
210 	match_count += invert ^ (bool)JoystickManager::TestButton(bce);
211 	break;
212 
213    case BUTTC_MOUSE:
214 	match_count += invert ^ (bool)MouseMan::TestButton(bce);
215 	break;
216   }
217   invert = (bce.ANDGroupCont < 0);
218 
219   if(!bce.ANDGroupCont)
220   {
221    if(match_count > i)
222     return true;
223 
224    match_count = i + 1;
225   }
226  }
227 
228  return false;
229 }
230 
231 
232 //
233 //
234 //
BCGToString(const std::vector<ButtConfig> & bcg)235 static std::string BCGToString(const std::vector<ButtConfig>& bcg)
236 {
237  std::string ret;
238 
239  for(size_t i = 0; i < bcg.size(); i++)
240  {
241   char tmp[256] = { 0 };
242   char devidstr[2 + 32 + 1];
243   const ButtConfig& bc = bcg[i];
244   char scalestr[32];
245 
246   if(!MDFN_de64msb(&bc.DeviceID[0]) && !MDFN_de64msb(&bc.DeviceID[8]))
247    trio_snprintf(devidstr, sizeof(devidstr), "0x0");
248   else
249    trio_snprintf(devidstr, sizeof(devidstr), "0x%016llx%016llx", (unsigned long long)MDFN_de64msb(&bc.DeviceID[0]), (unsigned long long)MDFN_de64msb(&bc.DeviceID[8]));
250 
251   if(bc.Scale == 4096)
252    scalestr[0] = 0;
253   else
254    trio_snprintf(scalestr, sizeof(scalestr), " %u", bc.Scale);
255 
256   if(bc.DeviceType == BUTTC_KEYBOARD)
257    trio_snprintf(tmp, sizeof(tmp), "keyboard %s %s%s", devidstr, KBMan::BNToString(bc.ButtonNum).c_str(), scalestr);
258   else if(bc.DeviceType == BUTTC_JOYSTICK)
259    trio_snprintf(tmp, sizeof(tmp), "joystick %s %s%s", devidstr, JoystickManager::BNToString(bc.ButtonNum).c_str(), scalestr);
260   else if(bc.DeviceType == BUTTC_MOUSE)
261    trio_snprintf(tmp, sizeof(tmp), "mouse %s %s%s", devidstr, MouseMan::BNToString(bc.ButtonNum).c_str(), scalestr);
262 
263   if(tmp[0])
264   {
265    if(i)
266    {
267     const int agc = bcg[i - 1].ANDGroupCont;
268 
269     if(agc < 0)
270      ret += " &! ";
271     else if(agc > 0)
272      ret += " && ";
273     else
274      ret += " || ";
275    }
276 
277    ret += tmp;
278   }
279  }
280 
281  return ret;
282 }
283 
StringToDeviceID(const char * s,size_t len,std::array<uint8,16> * device_id)284 static bool StringToDeviceID(const char* s, size_t len, std::array<uint8, 16>* device_id)
285 {
286  uint64 a = 0, b = 0;
287 
288  while(len--)
289  {
290   int nyb;
291 
292   if(*s >= '0' && *s <= '9')
293    nyb = *s - '0';
294   else if(*s >= 'A' && *s <= 'F')
295    nyb = 0xA + (*s - 'A');
296   else if(*s >= 'a' && *s <= 'f')
297    nyb = 0xA + (*s - 'a');
298   else
299    return false;
300 
301   a <<= 4;
302   a |= b >> 60;
303   b <<= 4;
304   b |= nyb;
305 
306   s++;
307  }
308 
309  //printf("HOW: %016llx%016llx\n", a, b);
310 
311  MDFN_en64msb(&(*device_id)[0], a);
312  MDFN_en64msb(&(*device_id)[8], b);
313 
314  return true;
315 }
316 
317 //
318 //
319 //
StringToBCG(std::vector<ButtConfig> * bcg,const char * s,const char * defs="",const bool abs_pointer_axis_thing=false)320 static bool StringToBCG(std::vector<ButtConfig>* bcg, const char* s, const char* defs = "", const bool abs_pointer_axis_thing = false)
321 {
322  if(bcg)
323   bcg->clear();
324 
325 #if 1
326  if(strstr(s, "0x") == NULL)
327  {
328   //
329   // Backwards-compat for 0.9.x joystick mappings
330   //
331   bool AND_Mode = false;
332   char device_name[64];
333   char extra[256];
334   bool any_kb = false;
335   bool any_mouse = false;
336   bool any_joy = false;
337 
338   s = MDFN_strskipspace(s);
339 
340   if(!strncmp(s, "/&&\\", 4))
341   {
342    AND_Mode = true;
343    s += 4;
344   }
345 
346   s = MDFN_strskipspace(s);
347 
348   do
349   {
350    if(trio_sscanf(s, "%63s %255[^~]", device_name, extra) == 2)
351    {
352     if(!MDFN_strazicmp(device_name, "keyboard"))
353      any_kb = true;
354     else
355     {
356      ButtConfig bc;
357 
358      bc.ANDGroupCont = AND_Mode;
359      bc.Scale = 4096;
360 
361      if(!MDFN_strazicmp(device_name, "joystick"))
362      {
363       any_joy = true;
364       //
365       unsigned long long devid = 0;
366       unsigned bn = 0;
367 
368       if(trio_sscanf(extra, "%016llx %08x", &devid, &bn) == 2)
369       {
370        bc.DeviceType = BUTTC_JOYSTICK;
371        bc.DeviceNum = JoystickManager::GetIndexByUniqueID_09x(devid);
372        bc.DeviceID = JoystickManager::GetUniqueIDByIndex(bc.DeviceNum);	// Not perfect, but eh...
373 
374        if(!JoystickManager::Translate09xBN(bn, &bc.ButtonNum, abs_pointer_axis_thing))
375         return false;
376       }
377       else
378        return false;
379      }
380      else if(!MDFN_strazicmp(device_name, "mouse"))
381      {
382       any_mouse = true;
383       //
384       unsigned long long dummy_devid = 0;
385       unsigned bn = 0;
386 
387       if(trio_sscanf(extra, "%016llx %08x", &dummy_devid, &bn) == 2 || trio_sscanf(extra, "%d", &bn) == 1)
388       {
389        bc.DeviceID = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
390        bc.DeviceType = BUTTC_MOUSE;
391        bc.DeviceNum = 0;
392 
393        if(!MouseMan::Translate09xBN(bn, &bc.ButtonNum))
394         return false;
395       }
396       else
397        return false;
398      }
399      else
400       return false;
401 
402      if(bcg)
403       bcg->push_back(bc);
404     }
405    }
406    s = strchr(s, '~');
407    if(s) s++;
408   } while(s);
409 
410   if(bcg)
411   {
412    if(bcg->size())
413     bcg->back().ANDGroupCont = false;
414    //
415    //
416    //
417    if(any_kb)
418    {
419     bool need_mouse_defaults = false;
420 
421     if(AND_Mode && (any_mouse || any_joy))
422     {
423      need_mouse_defaults = any_mouse;
424      bcg->clear();
425     }
426 
427     std::vector<ButtConfig> defbc;
428 
429     if(!StringToBCG(&defbc, defs))
430     {
431      assert(0);
432     }
433 
434     for(auto const& bc : defbc)
435     {
436      assert(!bc.ANDGroupCont);
437      if(bc.DeviceType == BUTTC_KEYBOARD || (bc.DeviceType == BUTTC_MOUSE && need_mouse_defaults))
438      {
439       bcg->push_back(bc);
440      }
441     }
442    }
443   }
444 
445   //printf("\"%s\" ---> \"%s\"\n", s.c_str(), BCGToString(ret).c_str());
446 
447   return true;
448  }
449 #endif
450  //
451  //
452  //
453  unsigned which_part = 0;
454  ButtConfig bc;
455  size_t len;
456 
457  do
458  {
459   const char* start_s;
460   int agc = INT_MAX;
461 
462   s = MDFN_strskipspace(s);
463   start_s = s;
464 
465   s = MDFN_strskipnonspace(s);
466   len = s - start_s;
467 
468   if(len == 2)
469   {
470    if(start_s[0] == '&' && start_s[1] == '&')
471     agc = true;
472    else if(start_s[0] == '|' && start_s[1] == '|')
473     agc = false;
474    else if(start_s[0] == '&' && start_s[1] == '!')
475     agc = -1;
476   }
477   else if(!len)
478    agc = false;
479 
480   if(agc != INT_MAX)
481   {
482    if(which_part < 3)
483    {
484     printf("Incomplete?\n");
485     return false;
486    }
487    else if(which_part < 4)
488     bc.Scale = 4096;
489 
490    bc.ANDGroupCont = agc;
491 
492    if(bcg)
493     bcg->push_back(bc);
494 
495    which_part = 0;
496   }
497   else if(which_part == 0)
498   {
499    if(len == 8 && !MDFN_memazicmp(start_s, "keyboard", 8))
500     bc.DeviceType = BUTTC_KEYBOARD;
501    else if(len == 8 && !MDFN_memazicmp(start_s, "joystick", 8))
502     bc.DeviceType = BUTTC_JOYSTICK;
503    else if(len == 5 && !MDFN_memazicmp(start_s, "mouse", 5))
504     bc.DeviceType = BUTTC_MOUSE;
505    else
506    {
507     printf("Unknown device type\n");
508     return false;
509    }
510 
511    which_part++;
512   }
513   else if(which_part == 1)
514   {
515    if(len < (2 + 1) || start_s[0] != '0' || start_s[1] != 'x' || !StringToDeviceID(start_s + 2, len - 2, &bc.DeviceID))
516    {
517     printf("Bad device id\n");
518     return false;
519    }
520 
521    which_part++;
522   }
523   else if(which_part == 2)
524   {
525    char bnstr[256];
526 
527    if((len + 1) > sizeof(bnstr))
528    {
529     printf("bn string too long.");
530     return false;
531    }
532 
533    memcpy(bnstr, start_s, len);
534    bnstr[len] = 0;
535 
536    if(bc.DeviceType == BUTTC_KEYBOARD)
537    {
538     if(!KBMan::StringToBN(bnstr, &bc.ButtonNum))
539     {
540      printf("Bad keyboard bn string\n");
541      return false;
542     }
543 
544     bc.DeviceNum = 0;	// TODO
545    }
546    else if(bc.DeviceType == BUTTC_JOYSTICK)
547    {
548     if(!JoystickManager::StringToBN(bnstr, &bc.ButtonNum))
549     {
550      printf("Bad joystick bn string\n");
551      return false;
552     }
553 
554     bc.DeviceNum = JoystickManager::GetIndexByUniqueID(bc.DeviceID);
555    }
556    else if(bc.DeviceType == BUTTC_MOUSE)
557    {
558     if(!MouseMan::StringToBN(bnstr, &bc.ButtonNum))
559     {
560      printf("Bad mouse bn string\n");
561      return false;
562     }
563 
564     bc.DeviceNum = 0;	// TODO
565    }
566    which_part++;
567   }
568   else if(which_part == 3)
569   {
570    unsigned scale = 0;
571 
572    for(const char* sls = start_s; sls != (start_s + len); sls++)
573    {
574     if(*sls >= '0' && *sls <= '9')
575     {
576      scale = (scale * 10) + (*sls - '0');
577      if(scale > 0xFFFF)
578      {
579       printf("Scale overflow\n");
580       return false;
581      }
582     }
583     else
584     {
585      printf("Bad scale value\n");
586      return false;
587     }
588    }
589 
590    bc.Scale = scale;
591    which_part++;
592   }
593   else if(which_part == 4)
594   {
595    printf("Junk at end of input mapping?\n");
596    return false;
597   }
598  } while(len);
599 
600  if(bcg && bcg->size() > 0)
601   bcg->back().ANDGroupCont = false;
602 
603  return true;
604 }
605 
ValidateIMSetting(const char * name,const char * value)606 static bool ValidateIMSetting(const char* name, const char* value)
607 {
608 #if 0
609  {
610   std::vector<ButtConfig> m;
611   StringToBCG(&m, value, MDFNI_GetSettingDefault(name).c_str());
612 
613   std::string tmp = BCGToString(m);
614   printf("%s -------- %s\n", value, tmp.c_str());
615   assert(tmp == value);
616  }
617 #endif
618 
619  return StringToBCG(nullptr, value);
620 }
621 
622 
CleanSettingName(char * string)623 static char *CleanSettingName(char *string)
624 {
625  size_t x = 0;
626 
627  while(string[x])
628  {
629   if(string[x] == ' ')
630    string[x] = '_';
631   else if(string[x] >= 'A' && string[x] <= 'Z')
632    string[x] = 'a' + string[x] - 'A';
633   x++;
634  }
635  return string;
636 }
637 
638 enum InputMappingType : unsigned
639 {
640  IMTYPE_UNKNOWN = 0,
641  IMTYPE_BUTTON,
642  IMTYPE_BUTTON_RAPID,
643  IMTYPE_BUTTON_ANALOG,
644  IMTYPE_AXIS_NEG,
645  IMTYPE_AXIS_POS,
646  IMTYPE_AXIS_REL_POS,
647  IMTYPE_AXIS_REL_NEG,
648  IMTYPE_POINTER_X,
649  IMTYPE_POINTER_Y,
650  IMTYPE_SWITCH,
651  //IMTYPE_STATUS
652 };
653 
654 struct ButtonInfoCache
655 {
656  char* SettingName = nullptr;
657  char* CPName = nullptr;
658  const InputDeviceInputInfoStruct* IDII = nullptr;
659  InputMappingType IMType = IMTYPE_UNKNOWN;
660  uint16 BitOffset = 0;
661  uint16 ExclusionBitOffset = 0xFFFF;
662  std::vector<ButtConfig> BC;
663 
664  struct
665  {
666   uint8 NumPos = 0;
667   uint8 LastPos = 0;
668   uint8 BitSize = 0;
669   bool LastPress = false;
670  } Switch;
671 
672  struct
673  {
674   int64 AccumError = 0;
675  } AxisRel;
676 };
677 
678 //static_assert(sizeof(ButtonInfoCache) == 64, "hm");
679 
680 struct StatusInfoCache
681 {
682  const InputDeviceInputInfoStruct* IDII = NULL;
683  uint32 BitOffset = 0;
684 
685  uint32 StatusNumStates = 0;
686  uint32 StatusLastState = 0;
687  uint32 StatusBitSize = 0;
688 };
689 
690 struct RumbleInfoCache
691 {
692  const InputDeviceInputInfoStruct* IDII = NULL;
693  uint32 BitOffset = 0;
694  uint32 AssocBICIndex = 0;
695 };
696 
697 struct PortInfoCache
698 {
699  unsigned int CurrentDeviceIndex = 0; // index into [SOMETHING HERE]
700  uint8 *Data = NULL;
701  const InputDeviceInfoStruct* Device = NULL;
702 
703  std::vector<ButtonInfoCache> BIC;
704  std::vector<StatusInfoCache> SIC;
705  std::vector<RumbleInfoCache> RIC;
706  std::vector<unsigned> BCC; // Button config cache
707 
708  float AxisScale = 0;
709 };
710 
711 static PortInfoCache PIDC[16];
712 
KillPortInfo(unsigned int port)713 static void KillPortInfo(unsigned int port)
714 {
715  PIDC[port].Data = NULL;
716  PIDC[port].Device = NULL;
717 
718  for(unsigned int x = 0; x < PIDC[port].BIC.size(); x++)
719  {
720   free(PIDC[port].BIC[x].CPName);
721   free(PIDC[port].BIC[x].SettingName);
722  }
723 
724  PIDC[port].BIC.clear();
725  PIDC[port].SIC.clear();
726  PIDC[port].RIC.clear();
727  PIDC[port].BCC.clear();
728 }
729 
730 
731 //
732 // trio_aprintf() was taking too long when building all the input mapping settings we have now from Saturn keyboards...
733 //
build_string(const char * s0,const char * s1,const char * s2="",const char * s3="",const char * s4="",const char * s5="",const char * s6="",const char * s7="",const char * s8="")734 static char* build_string(const char *s0, const char* s1, const char* s2 = "", const char* s3 = "", const char* s4 = "", const char* s5 = "", const char *s6 = "", const char* s7 = "", const char* s8 = "")
735 {
736  const size_t s0_len = strlen(s0);
737  const size_t s1_len = strlen(s1);
738  const size_t s2_len = strlen(s2);
739  const size_t s3_len = strlen(s3);
740  const size_t s4_len = strlen(s4);
741  const size_t s5_len = strlen(s5);
742  const size_t s6_len = strlen(s6);
743  const size_t s7_len = strlen(s7);
744  const size_t s8_len = strlen(s8);
745 
746  char* ret = (char*)malloc(s0_len + s1_len + s2_len + s3_len + s4_len + s5_len + s6_len + s7_len + s8_len + 1);
747  char* t = ret;
748 
749  t = (char*)memcpy(t, s0, s0_len) + s0_len;
750  t = (char*)memcpy(t, s1, s1_len) + s1_len;
751  t = (char*)memcpy(t, s2, s2_len) + s2_len;
752  t = (char*)memcpy(t, s3, s3_len) + s3_len;
753  t = (char*)memcpy(t, s4, s4_len) + s4_len;
754  t = (char*)memcpy(t, s5, s5_len) + s5_len;
755  t = (char*)memcpy(t, s6, s6_len) + s6_len;
756  t = (char*)memcpy(t, s7, s7_len) + s7_len;
757  t = (char*)memcpy(t, s8, s8_len) + s8_len;
758  *t = 0;
759 
760  return ret;
761 }
762 
763 
764 //
765 // Only call on init, or when the device on a port changes.
766 //
BuildPortInfo(MDFNGI * gi,const unsigned int port)767 static void BuildPortInfo(MDFNGI *gi, const unsigned int port)
768 {
769  const InputDeviceInfoStruct *zedevice = NULL;
770  char *port_device_name;
771  unsigned int device;
772  const std::map<std::string, uint32>* switches_defov = nullptr;
773 
774  std::vector<std::pair<uint64, size_t>> bcc_stmp;
775 
776  PIDC[port].AxisScale = 1.0;
777 
778   if(gi->PortInfo[port].DeviceInfo.size() > 1)
779   {
780    if(CurGame->DesiredInput.size() > port && CurGame->DesiredInput[port].device_name)
781    {
782     port_device_name = strdup(CurGame->DesiredInput[port].device_name);
783     switches_defov = &CurGame->DesiredInput[port].switches;
784    }
785    else
786    {
787     char tmp_setting_name[512];
788     trio_snprintf(tmp_setting_name, 512, "%s.input.%s", gi->shortname, gi->PortInfo[port].ShortName);
789     port_device_name = strdup(MDFN_GetSettingS(tmp_setting_name).c_str());
790    }
791   }
792   else
793   {
794    port_device_name = strdup(gi->PortInfo[port].DeviceInfo[0].ShortName);
795   }
796 
797   for(device = 0; device < gi->PortInfo[port].DeviceInfo.size(); device++)
798   {
799    if(!MDFN_strazicmp(gi->PortInfo[port].DeviceInfo[device].ShortName, port_device_name))
800    {
801     zedevice = &gi->PortInfo[port].DeviceInfo[device];
802     break;
803    }
804   }
805   free(port_device_name); port_device_name = NULL;
806 
807   PIDC[port].CurrentDeviceIndex = device;
808 
809   assert(zedevice);
810 
811   PIDC[port].Device = zedevice;
812 
813   // Figure out how much data should be allocated for each port
814   bool analog_axis_scale_grabbed = false;
815 
816   for(auto const& idii : zedevice->IDII)
817   {
818    // Handle dummy/padding button entries(the setting name will be NULL in such cases)
819    if(idii.SettingName == NULL)
820     continue;
821    //
822    char sname_pdpfx[384];
823 
824    trio_snprintf(sname_pdpfx, sizeof(sname_pdpfx), "%s.input.%s.%s", gi->shortname, gi->PortInfo[port].ShortName, zedevice->ShortName);
825 
826    if(idii.Type == IDIT_AXIS && (idii.Flags & IDIT_AXIS_FLAG_SQLR) && !analog_axis_scale_grabbed)
827    {
828     char tmpsn[512];
829 
830     trio_snprintf(tmpsn, sizeof(tmpsn), "%s.axis_scale", sname_pdpfx);
831     PIDC[port].AxisScale = MDFN_GetSettingF(tmpsn);
832     analog_axis_scale_grabbed = true;
833    }
834 
835    if(idii.Type == IDIT_BUTTON || idii.Type == IDIT_BUTTON_CAN_RAPID ||
836 	 idii.Type == IDIT_BUTTON_ANALOG ||
837 	 idii.Type == IDIT_AXIS ||
838 	 idii.Type == IDIT_POINTER_X || idii.Type == IDIT_POINTER_Y ||
839 	 idii.Type == IDIT_AXIS_REL ||
840 	 idii.Type == IDIT_SWITCH)
841    {
842     for(unsigned part = 0; part < ((idii.Type == IDIT_BUTTON_CAN_RAPID || idii.Type == IDIT_AXIS || idii.Type == IDIT_AXIS_REL) ? 2 : 1); part++)
843     {
844      ButtonInfoCache bic;
845 
846      bic.IDII = &idii;
847 
848      switch(idii.Type)
849      {
850       default:
851 	break;
852 
853       case IDIT_BUTTON:
854 	bic.IMType = IMTYPE_BUTTON;
855 	break;
856 
857       case IDIT_BUTTON_CAN_RAPID:
858 	bic.IMType = part ? IMTYPE_BUTTON_RAPID : IMTYPE_BUTTON;
859 	break;
860 
861       case IDIT_BUTTON_ANALOG:
862 	bic.IMType = IMTYPE_BUTTON_ANALOG;
863 	break;
864 
865       case IDIT_AXIS:
866 	bic.IMType = part ? IMTYPE_AXIS_POS : IMTYPE_AXIS_NEG;
867 	break;
868 
869       case IDIT_AXIS_REL:
870 	bic.IMType = part ? IMTYPE_AXIS_REL_POS : IMTYPE_AXIS_REL_NEG;
871 	break;
872 
873       case IDIT_POINTER_X:
874 	bic.IMType = IMTYPE_POINTER_X;
875 	break;
876 
877       case IDIT_POINTER_Y:
878 	bic.IMType = IMTYPE_POINTER_Y;
879 	break;
880 
881       case IDIT_SWITCH:
882 	bic.IMType = IMTYPE_SWITCH;
883 	bic.Switch.NumPos = idii.Switch.NumPos;
884 	bic.Switch.LastPos = 0;
885 	bic.Switch.BitSize = idii.BitSize;
886 	bic.Switch.LastPress = false;
887 	break;
888      }
889      //
890      //
891      //
892      if(idii.Type == IDIT_AXIS_REL)
893      {
894       bic.SettingName = build_string(sname_pdpfx, ".", idii.SettingName, idii.SettingName[0] ? "_" : "", idii.AxisRel.sname_dir[part]);
895       bic.CPName = build_string(idii.Name, " ", idii.AxisRel.name_dir[part]);
896      }
897      else if(idii.Type == IDIT_AXIS)
898      {
899       bic.SettingName = build_string(sname_pdpfx, ".", idii.SettingName, idii.SettingName[0] ? "_" : "", idii.Axis.sname_dir[part]);
900       bic.CPName = build_string(idii.Name, " ", idii.Axis.name_dir[part]);
901      }
902      else
903      {
904       bic.SettingName = build_string(sname_pdpfx, ".", bic.IMType == IMTYPE_BUTTON_RAPID ? "rapid_" : "", idii.SettingName);
905       bic.CPName = trio_aprintf(_("%s%s%s"), (bic.IMType == IMTYPE_BUTTON_RAPID ? _("Rapid ") : ""), idii.Name, (bic.IMType == IMTYPE_SWITCH) ? _(" Select") : "");
906      }
907      CleanSettingName(bic.SettingName);
908      if(!StringToBCG(&bic.BC, MDFN_GetSettingS(bic.SettingName).c_str(), MDFNI_GetSettingDefault(bic.SettingName).c_str(), (idii.Type == IDIT_POINTER_X || idii.Type == IDIT_POINTER_Y)))
909       abort();
910      bic.BitOffset = idii.BitOffset;
911 
912      if(idii.ConfigOrder >= 0 && idii.Type != IDIT_AXIS_REL)
913      {
914       std::pair<uint64, size_t> pot;
915 
916       pot.first = ((uint64)idii.ConfigOrder << 32) + (part ^ (idii.Type == IDIT_AXIS && (idii.Flags & IDIT_AXIS_FLAG_INVERT_CO)) ^ (idii.Type == IDIT_AXIS_REL && (idii.Flags & IDIT_AXIS_REL_FLAG_INVERT_CO)));
917       pot.second = PIDC[port].BIC.size();
918 
919       bcc_stmp.push_back(pot);
920      }
921      //
922      PIDC[port].BIC.push_back(bic);
923     }
924    }
925    else if(idii.Type == IDIT_STATUS)
926    {
927     StatusInfoCache sic;
928 
929     sic.IDII = &idii;
930     sic.StatusLastState = 0;
931 
932     sic.StatusNumStates = idii.Status.NumStates;
933     sic.StatusBitSize = idii.BitSize;
934     sic.BitOffset = idii.BitOffset;
935 
936     PIDC[port].SIC.push_back(sic);
937    }
938    else if(idii.Type == IDIT_RUMBLE)
939    {
940     RumbleInfoCache ric;
941     ric.IDII = &idii;
942     ric.BitOffset = idii.BitOffset;
943     ric.AssocBICIndex = PIDC[port].BIC.size() - 1;
944     PIDC[port].RIC.push_back(ric);
945    }
946   }
947 
948 
949  //
950  // Calculate configuration order.
951  //
952  std::sort(bcc_stmp.begin(), bcc_stmp.end(),
953 	[](const std::pair<uint64, size_t>& a, const std::pair<uint64, size_t>& b) { return a.first < b.first || (a.first == b.first && a.second < b.second); });
954 
955  for(const auto& p : bcc_stmp)
956   PIDC[port].BCC.push_back(p.second);
957 
958  //
959  // Now, search for exclusion buttons.
960  //
961  for(auto& bic : PIDC[port].BIC)
962  {
963   if((bic.IDII->Type == IDIT_BUTTON || bic.IDII->Type == IDIT_BUTTON_CAN_RAPID) && bic.IDII->Button.ExcludeName)
964   {
965    bool found = false;
966 
967    for(auto const& sub_bic : PIDC[port].BIC)
968    {
969     if(!MDFN_strazicmp(bic.IDII->Button.ExcludeName, sub_bic.IDII->SettingName))
970     {
971      assert(sub_bic.IDII->Type == IDIT_BUTTON || sub_bic.IDII->Type == IDIT_BUTTON_CAN_RAPID);
972      bic.ExclusionBitOffset = sub_bic.BitOffset;
973      found = true;
974      break;
975     }
976    }
977    assert(found);
978   }
979  }
980 
981  PIDC[port].Data = MDFNI_SetInput(port, device);
982 
983  //
984  // Set default switch positions.
985  //
986  size_t switches_defov_found = 0;
987 
988  for(auto& bic : PIDC[port].BIC)
989  {
990   if(bic.IMType == IMTYPE_SWITCH)
991   {
992    char tmpsn[512];
993    trio_snprintf(tmpsn, sizeof(tmpsn), "%s.defpos", bic.SettingName);
994    bic.Switch.LastPos = MDFN_GetSettingUI(tmpsn);
995    //
996    //
997    if(switches_defov)
998    {
999     std::map<std::string, uint32>::const_iterator sdov_it = switches_defov->find(bic.IDII->SettingName);
1000 
1001     if(sdov_it != switches_defov->end())
1002     {
1003      bic.Switch.LastPos = sdov_it->second;
1004      switches_defov_found++;
1005     }
1006    }
1007    //
1008    //
1009    BitsIntract(PIDC[port].Data, bic.BitOffset, bic.Switch.BitSize, bic.Switch.LastPos);
1010   }
1011  }
1012  assert(switches_defov_found == (switches_defov ? switches_defov->size() : 0));
1013 }
1014 
IncSelectedDevice(unsigned int port)1015 static void IncSelectedDevice(unsigned int port)
1016 {
1017  if(MDFNDnetplay)
1018  {
1019   MDFN_Notify(MDFN_NOTICE_STATUS, _("Cannot change input device during netplay."));
1020  }
1021  else if(RewindState)
1022  {
1023   MDFN_Notify(MDFN_NOTICE_STATUS, _("Cannot change input device while state rewinding is active."));
1024  }
1025  else if(port >= CurGame->PortInfo.size())
1026   MDFN_Notify(MDFN_NOTICE_STATUS, _("Port %u does not exist."), port + 1);
1027  else if(CurGame->PortInfo[port].DeviceInfo.size() <= 1)
1028   MDFN_Notify(MDFN_NOTICE_STATUS, _("Port %u device not selectable."), port + 1);
1029  else
1030  {
1031   char tmp_setting_name[512];
1032 
1033   if(CurGame->DesiredInput.size() > port)
1034    CurGame->DesiredInput[port] = NULL;
1035 
1036   trio_snprintf(tmp_setting_name, 512, "%s.input.%s", CurGame->shortname, CurGame->PortInfo[port].ShortName);
1037 
1038   PIDC[port].CurrentDeviceIndex = (PIDC[port].CurrentDeviceIndex + 1) % CurGame->PortInfo[port].DeviceInfo.size();
1039 
1040   const char *devname = CurGame->PortInfo[port].DeviceInfo[PIDC[port].CurrentDeviceIndex].ShortName;
1041 
1042   KillPortInfo(port);
1043   MDFNI_SetSetting(tmp_setting_name, devname);
1044   BuildPortInfo(CurGame, port);
1045   CalcWMInputBehavior();
1046 
1047   MDFN_Notify(MDFN_NOTICE_STATUS, _("%s selected on port %d"), CurGame->PortInfo[port].DeviceInfo[PIDC[port].CurrentDeviceIndex].FullName, port + 1);
1048  }
1049 }
1050 
1051 //
1052 // Don't use CTRL+ALT modifier for any defaults(due to AltGr on Windows, and usage as WM/OS-level hotkeys).
1053 //
1054 #define MK(x)			"keyboard 0x0 " KBD_SCANCODE_STRING(x)
1055 
1056 #define MK_CK_(x)		MK(x)
1057 #define MK_CK_ALT_(x)		MK(x) "+alt"
1058 #define MK_CK_SHIFT_(x)		MK(x) "+shift"
1059 #define MK_CK_CTRL_(x)		MK(x) "+ctrl"
1060 #define MK_CK_ALT_SHIFT_(x)	MK(x) "+alt+shift"
1061 #define MK_CK_CTRL_SHIFT_(x)	MK(x) "+ctrl+shift"
1062 //
1063 #define MK_CK(x)		MK_CK_(x)
1064 #define MK_CK_SHIFT(x)		MK_CK_SHIFT_(x)
1065 #define MK_CK_ALT(x)		MK_CK_ALT_(x)
1066 #define MK_CK_ALT_SHIFT(x)	MK_CK_ALT_SHIFT_(x)
1067 #define MK_CK_CTRL(x)		MK_CK_CTRL_(x)
1068 #define MK_CK_CTRL_SHIFT(x)	MK_CK_CTRL_SHIFT_(x)
1069 //
1070 #define MK_CK2(x,y)		MK_CK_(x) " || " MK_CK_(y)
1071 #define MK_CK_ALT2(x,y)		MK_CK_ALT_(x) " || " MK_CK_ALT_(y)
1072 
1073 enum CommandKey
1074 {
1075 	_CK_FIRST = 0,
1076         CK_SAVE_STATE = 0,
1077 	CK_LOAD_STATE,
1078 	CK_SAVE_MOVIE,
1079 	CK_LOAD_MOVIE,
1080 	CK_STATE_REWIND_TOGGLE,
1081 	CK_0,CK_1,CK_2,CK_3,CK_4,CK_5,CK_6,CK_7,CK_8,CK_9,
1082 	CK_M0,CK_M1,CK_M2,CK_M3,CK_M4,CK_M5,CK_M6,CK_M7,CK_M8,CK_M9,
1083 	CK_TL1, CK_TL2, CK_TL3, CK_TL4, CK_TL5, CK_TL6, CK_TL7, CK_TL8, CK_TL9,
1084 	CK_TAKE_SNAPSHOT,
1085 	CK_TAKE_SCALED_SNAPSHOT,
1086 	CK_TOGGLE_FS,
1087 	CK_FAST_FORWARD,
1088 	CK_SLOW_FORWARD,
1089 
1090 	CK_SELECT_DISK,
1091 	CK_SELECT_DRIVE,
1092 	CK_TOGGLE_DIPVIEW,
1093 	CK_INSERT_COIN,
1094 	CK_INSERTEJECT_DISK,
1095 	CK_ACTIVATE_BARCODE,
1096 
1097         CK_TOGGLE_GRAB,
1098 	CK_INPUT_CONFIG1,
1099 	CK_INPUT_CONFIG2,
1100         CK_INPUT_CONFIG3,
1101         CK_INPUT_CONFIG4,
1102 	CK_INPUT_CONFIG5,
1103         CK_INPUT_CONFIG6,
1104         CK_INPUT_CONFIG7,
1105         CK_INPUT_CONFIG8,
1106         CK_INPUT_CONFIG9,
1107         CK_INPUT_CONFIG10,
1108         CK_INPUT_CONFIG11,
1109         CK_INPUT_CONFIG12,
1110         CK_INPUT_CONFIGC,
1111 	CK_INPUT_CONFIGC_AM,
1112 	CK_INPUT_CONFIG_ABD,
1113 
1114 	CK_RESET,
1115 	CK_POWER,
1116 	CK_EXIT,
1117 	CK_STATE_REWIND,
1118 	CK_ROTATESCREEN,
1119 	CK_TOGGLENETVIEW,
1120 	CK_ADVANCE_FRAME,
1121 	CK_RUN_NORMAL,
1122 	CK_PAUSE,
1123 	CK_TOGGLECHEATVIEW,
1124 	CK_TOGGLE_CHEAT_ACTIVE,
1125 	CK_TOGGLE_FPS_VIEW,
1126 	CK_TOGGLE_DEBUGGER,
1127 	CK_STATE_SLOT_DEC,
1128         CK_STATE_SLOT_INC,
1129 	CK_TOGGLE_HELP,
1130 	CK_DEVICE_SELECT1,
1131         CK_DEVICE_SELECT2,
1132         CK_DEVICE_SELECT3,
1133         CK_DEVICE_SELECT4,
1134         CK_DEVICE_SELECT5,
1135         CK_DEVICE_SELECT6,
1136         CK_DEVICE_SELECT7,
1137         CK_DEVICE_SELECT8,
1138         CK_DEVICE_SELECT9,
1139         CK_DEVICE_SELECT10,
1140         CK_DEVICE_SELECT11,
1141         CK_DEVICE_SELECT12,
1142 
1143 	_CK_COUNT
1144 };
1145 
1146 struct COKE
1147 {
1148  const char* text;
1149  const char* description;
1150  const char* setting_name;
1151  const char* setting_default;
1152 
1153  bool BypassKeyZeroing;
1154  bool SkipCKDelay;
1155  bool TextInputExit;
1156 };
1157 
1158 #define CKEYDEF_BYPASSKEYZEROING 1
1159 #define CKEYDEF_DANGEROUS	 2	// For CK delay
1160 #define CKEYDEF_TEXTINPUTEXIT	 4	// Set with with cheat interface and debugger; for AltGr madness.
1161 
1162 #define CKEYDEF(n, d, f, c)	{ n, gettext_noop(d), "command." n, c, (bool)((f) & CKEYDEF_BYPASSKEYZEROING), (bool)!((f) & CKEYDEF_DANGEROUS), (bool)((f) & CKEYDEF_TEXTINPUTEXIT) }
1163 
1164 static const COKE CKeys[_CK_COUNT]	=
1165 {
1166 	CKEYDEF( "save_state", "Save state", 0, 		MK_CK(F5) ),
1167 	CKEYDEF( "load_state", "Load state", CKEYDEF_DANGEROUS, MK_CK(F7) ),
1168 	CKEYDEF( "save_movie", "Save movie", 0, 		MK_CK_SHIFT(F5) ),
1169 	CKEYDEF( "load_movie", "Load movie", CKEYDEF_DANGEROUS, MK_CK_SHIFT(F7) ),
1170 	CKEYDEF( "toggle_state_rewind", "Toggle state rewind functionality", 0, MK_CK_ALT(S) ),
1171 
1172 	CKEYDEF( "0", "Save state 0 select", 0, MK_CK(0) ),
1173         CKEYDEF( "1", "Save state 1 select", 0, MK_CK(1) ),
1174         CKEYDEF( "2", "Save state 2 select", 0, MK_CK(2) ),
1175         CKEYDEF( "3", "Save state 3 select", 0, MK_CK(3) ),
1176         CKEYDEF( "4", "Save state 4 select", 0, MK_CK(4) ),
1177         CKEYDEF( "5", "Save state 5 select", 0, MK_CK(5) ),
1178         CKEYDEF( "6", "Save state 6 select", 0, MK_CK(6) ),
1179         CKEYDEF( "7", "Save state 7 select", 0, MK_CK(7) ),
1180         CKEYDEF( "8", "Save state 8 select", 0, MK_CK(8) ),
1181         CKEYDEF( "9", "Save state 9 select", 0, MK_CK(9) ),
1182 
1183 	CKEYDEF( "m0", "Movie 0 select", 0, MK_CK_SHIFT(0) ),
1184         CKEYDEF( "m1", "Movie 1 select", 0, MK_CK_SHIFT(1) ),
1185         CKEYDEF( "m2", "Movie 2 select", 0, MK_CK_SHIFT(2) ),
1186         CKEYDEF( "m3", "Movie 3 select", 0, MK_CK_SHIFT(3) ),
1187         CKEYDEF( "m4", "Movie 4 select", 0, MK_CK_SHIFT(4) ),
1188         CKEYDEF( "m5", "Movie 5 select", 0, MK_CK_SHIFT(5) ),
1189         CKEYDEF( "m6", "Movie 6 select", 0, MK_CK_SHIFT(6) ),
1190         CKEYDEF( "m7", "Movie 7 select", 0, MK_CK_SHIFT(7) ),
1191         CKEYDEF( "m8", "Movie 8 select", 0, MK_CK_SHIFT(8) ),
1192         CKEYDEF( "m9", "Movie 9 select", 0, MK_CK_SHIFT(9) ),
1193 
1194         CKEYDEF( "tl1", "Toggle graphics layer 1", 0, MK_CK_CTRL(1) ),
1195         CKEYDEF( "tl2", "Toggle graphics layer 2", 0, MK_CK_CTRL(2) ),
1196         CKEYDEF( "tl3", "Toggle graphics layer 3", 0, MK_CK_CTRL(3) ),
1197         CKEYDEF( "tl4", "Toggle graphics layer 4", 0, MK_CK_CTRL(4) ),
1198         CKEYDEF( "tl5", "Toggle graphics layer 5", 0, MK_CK_CTRL(5) ),
1199         CKEYDEF( "tl6", "Toggle graphics layer 6", 0, MK_CK_CTRL(6) ),
1200         CKEYDEF( "tl7", "Toggle graphics layer 7", 0, MK_CK_CTRL(7) ),
1201         CKEYDEF( "tl8", "Toggle graphics layer 8", 0, MK_CK_CTRL(8) ),
1202         CKEYDEF( "tl9", "Toggle graphics layer 9", 0, MK_CK_CTRL(9) ),
1203 
1204 	CKEYDEF( "take_snapshot", 	 "Take screen snapshot", 0, MK_CK(F9) ),
1205 	CKEYDEF( "take_scaled_snapshot", "Take scaled(and filtered) screen snapshot", 0, MK_CK_SHIFT(F9) ),
1206 
1207 	CKEYDEF( "toggle_fs", "Toggle fullscreen mode", 0, MK_CK_ALT(RETURN) ),
1208 	CKEYDEF( "fast_forward", "Fast-forward", 0, 	   MK_CK(GRAVE) ),
1209         CKEYDEF( "slow_forward", "Slow-forward", 0, 	   MK_CK(BACKSLASH) ),
1210 
1211 	CKEYDEF( "select_disk", "Select disk/disc", 0, 		MK_CK(F6) ),
1212 	CKEYDEF( "select_drive", "Select drive", 0, MK_CK_SHIFT(F6) ),
1213 	CKEYDEF( "toggle_dipview", "Toggle DIP switch view", 0, MK_CK(F6) ),
1214 	CKEYDEF( "insert_coin", "Insert coin", 0, 		MK_CK(F8) ),
1215 	CKEYDEF( "insert_eject_disk", "Insert/Eject disk/disc", CKEYDEF_DANGEROUS, MK_CK(F8) ),
1216 	CKEYDEF( "activate_barcode", "Activate barcode(for Famicom)", 0, 	   MK_CK(F8) ),
1217 	CKEYDEF( "toggle_grab", "Grab input", CKEYDEF_BYPASSKEYZEROING, MK_CK_CTRL_SHIFT(APPLICATION) ),
1218 
1219 	CKEYDEF( "input_config1",  "Configure buttons on virtual port 1",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(1) ),
1220 	CKEYDEF( "input_config2",  "Configure buttons on virtual port 2",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(2) ),
1221         CKEYDEF( "input_config3",  "Configure buttons on virtual port 3",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(3) ),
1222         CKEYDEF( "input_config4",  "Configure buttons on virtual port 4",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(4) ),
1223 	CKEYDEF( "input_config5",  "Configure buttons on virtual port 5",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(5) ),
1224         CKEYDEF( "input_config6",  "Configure buttons on virtual port 6",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(6) ),
1225         CKEYDEF( "input_config7",  "Configure buttons on virtual port 7",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(7) ),
1226         CKEYDEF( "input_config8",  "Configure buttons on virtual port 8",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(8) ),
1227         CKEYDEF( "input_config9",  "Configure buttons on virtual port 9",  CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(9) ),
1228         CKEYDEF( "input_config10", "Configure buttons on virtual port 10", CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(0) ),
1229         CKEYDEF( "input_config11", "Configure buttons on virtual port 11", CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(KP_1) ),
1230         CKEYDEF( "input_config12", "Configure buttons on virtual port 12", CKEYDEF_DANGEROUS, MK_CK_ALT_SHIFT(KP_2) ),
1231 
1232         CKEYDEF( "input_configc", "Configure command key", 				       CKEYDEF_DANGEROUS, MK_CK(F2) ),
1233         CKEYDEF( "input_configc_am", "Configure command key, for all-pressed-to-trigger mode", CKEYDEF_DANGEROUS, MK_CK_SHIFT(F2) ),
1234 
1235 	CKEYDEF( "input_config_abd", "Detect analog buttons on physical joysticks/gamepads(for use with the input configuration process).", CKEYDEF_DANGEROUS, MK_CK(F3) ),
1236 
1237 	CKEYDEF( "reset", "Reset", CKEYDEF_DANGEROUS, MK_CK(F10) ),
1238 	CKEYDEF( "power", "Power toggle", CKEYDEF_DANGEROUS, MK_CK(F11) ),
1239 	CKEYDEF( "exit", "Exit", CKEYDEF_BYPASSKEYZEROING | CKEYDEF_DANGEROUS, MK_CK2(F12, ESCAPE) ),
1240 	CKEYDEF( "state_rewind", "Rewind", 0, MK_CK(BACKSPACE) ),
1241 	CKEYDEF( "rotate_screen", "Rotate screen", 0, MK_CK_ALT(O) ),
1242 
1243 	CKEYDEF( "togglenetview", "Toggle netplay console", 0, MK_CK(T) ),
1244 	CKEYDEF( "advance_frame", "Advance frame", 0, MK_CK_ALT(A) ),
1245 	CKEYDEF( "run_normal", "Return to normal mode after advancing frames", 0, MK_CK_ALT(R) ),
1246 	CKEYDEF( "pause", "Pause/Unpause", 0, MK_CK(PAUSE) ),
1247 	CKEYDEF( "togglecheatview", "Toggle cheat console", CKEYDEF_BYPASSKEYZEROING | CKEYDEF_TEXTINPUTEXIT, MK_CK_ALT(C) ),
1248 	CKEYDEF( "togglecheatactive", "Enable/Disable cheats", 0, MK_CK_ALT(T) ),
1249         CKEYDEF( "toggle_fps_view", "Toggle frames-per-second display", 0, MK_CK_SHIFT(F1) ),
1250 	CKEYDEF( "toggle_debugger", "Toggle debugger", CKEYDEF_BYPASSKEYZEROING | CKEYDEF_TEXTINPUTEXIT, MK_CK_ALT(D) ),
1251 	CKEYDEF( "state_slot_dec", "Decrease selected save state slot by 1", 0, MK_CK(MINUS) ),
1252 	CKEYDEF( "state_slot_inc", "Increase selected save state slot by 1", 0, MK_CK(EQUALS) ),
1253 	CKEYDEF( "toggle_help", "Toggle help screen", CKEYDEF_BYPASSKEYZEROING, MK_CK(F1) ),
1254 
1255 	CKEYDEF( "device_select1",  "Select virtual device on virtual input port 1",  0, MK_CK_CTRL_SHIFT(1) ),
1256         CKEYDEF( "device_select2",  "Select virtual device on virtual input port 2",  0, MK_CK_CTRL_SHIFT(2) ),
1257         CKEYDEF( "device_select3",  "Select virtual device on virtual input port 3",  0, MK_CK_CTRL_SHIFT(3) ),
1258         CKEYDEF( "device_select4",  "Select virtual device on virtual input port 4",  0, MK_CK_CTRL_SHIFT(4) ),
1259         CKEYDEF( "device_select5",  "Select virtual device on virtual input port 5",  0, MK_CK_CTRL_SHIFT(5) ),
1260         CKEYDEF( "device_select6",  "Select virtual device on virtual input port 6",  0, MK_CK_CTRL_SHIFT(6) ),
1261         CKEYDEF( "device_select7",  "Select virtual device on virtual input port 7",  0, MK_CK_CTRL_SHIFT(7) ),
1262         CKEYDEF( "device_select8",  "Select virtual device on virtual input port 8",  0, MK_CK_CTRL_SHIFT(8) ),
1263         CKEYDEF( "device_select9",  "Select virtual device on virtual input port 9",  0, MK_CK_CTRL_SHIFT(9) ),
1264         CKEYDEF( "device_select10", "Select virtual device on virtual input port 10", 0, MK_CK_CTRL_SHIFT(0) ),
1265         CKEYDEF( "device_select11", "Select virtual device on virtual input port 11", 0, MK_CK_CTRL_SHIFT(KP_1) ),
1266         CKEYDEF( "device_select12", "Select virtual device on virtual input port 12", 0, MK_CK_CTRL_SHIFT(KP_2) ),
1267 };
1268 #undef CKEYDEF_BYPASSKEYZEROING
1269 #undef CKEYDEF_DANGEROUS
1270 #undef CKEYDEF_TEXTINPUTEXIT
1271 #undef CKEYDEF
1272 
1273 static std::vector<ButtConfig> CKeysConfig[_CK_COUNT];
1274 static uint32 CKeysPressTime[_CK_COUNT];
1275 static bool CKeysActive[_CK_COUNT];
1276 static bool CKeysTrigger[_CK_COUNT];
1277 static uint32 CurTicks = 0;	// Optimization, Time::MonoMS() might be slow on some platforms?
1278 
CK_Init(void)1279 static void CK_Init(void)
1280 {
1281  ckdelay = MDFN_GetSettingUI("ckdelay");
1282 
1283  for(CommandKey i = _CK_FIRST; i < _CK_COUNT; i = (CommandKey)((unsigned)i + 1))
1284  {
1285   CKeysPressTime[i] = 0xFFFFFFFF;
1286   CKeysActive[i] = true;	// To prevent triggering when a button/key is held from before startup.
1287   CKeysTrigger[i] = false;
1288  }
1289 }
1290 
CK_PostRemapUpdate(CommandKey which)1291 static void CK_PostRemapUpdate(CommandKey which)
1292 {
1293  CKeysActive[which] = DTestButtonCombo(CKeysConfig[which], (CKeys[which].BypassKeyZeroing && (!EmuKeyboardKeysGrabbed || which == CK_TOGGLE_GRAB)), CKeys[which].TextInputExit);
1294  CKeysTrigger[which] = false;
1295  CKeysPressTime[which] = 0xFFFFFFFF;
1296 }
1297 
CK_ClearTriggers(void)1298 static void CK_ClearTriggers(void)
1299 {
1300  memset(CKeysTrigger, 0, sizeof(CKeysTrigger));
1301 }
1302 
CK_UpdateState(bool skipckd_tc)1303 static void CK_UpdateState(bool skipckd_tc)
1304 {
1305  for(CommandKey i = _CK_FIRST; i < _CK_COUNT; i = (CommandKey)((unsigned)i + 1))
1306  {
1307   const bool prev_state = CKeysActive[i];
1308   const bool cur_state = DTestButtonCombo(CKeysConfig[i], (CKeys[i].BypassKeyZeroing && (!EmuKeyboardKeysGrabbed || i == CK_TOGGLE_GRAB)), CKeys[i].TextInputExit);
1309   unsigned tmp_ckdelay = ckdelay;
1310 
1311   if(CKeys[i].SkipCKDelay || skipckd_tc)
1312    tmp_ckdelay = 0;
1313 
1314   if(cur_state)
1315   {
1316    if(!prev_state)
1317     CKeysPressTime[i] = CurTicks;
1318   }
1319   else
1320    CKeysPressTime[i] = 0xFFFFFFFF;
1321 
1322   if(CurTicks >= ((uint64)CKeysPressTime[i] + tmp_ckdelay))
1323   {
1324    CKeysTrigger[i] = true;
1325    CKeysPressTime[i] = 0xFFFFFFFF;
1326   }
1327 
1328   CKeysActive[i] = cur_state;
1329  }
1330 }
1331 
CK_Check(CommandKey which)1332 static INLINE bool CK_Check(CommandKey which)
1333 {
1334  return CKeysTrigger[which];
1335 }
1336 
CK_CheckActive(CommandKey which)1337 static INLINE bool CK_CheckActive(CommandKey which)
1338 {
1339  return CKeysActive[which];
1340 }
1341 
1342 typedef enum
1343 {
1344 	none,
1345 	Port1,
1346 	Port2,
1347 	Port3,
1348 	Port4,
1349 	Port5,
1350 	Port6,
1351 	Port7,
1352 	Port8,
1353 	Port9,
1354 	Port10,
1355 	Port11,
1356 	Port12,
1357 	Command,
1358 	CommandAM
1359 } ICType;
1360 
1361 static ICType IConfig = none;
1362 static int ICLatch;
1363 static uint32 ICDeadDelay = 0;
1364 
1365 //#include "InputConfigurator.inc"
1366 //static InputConfigurator *IConfigurator = NULL;
1367 
1368 // Can be called from MDFND_MidSync(), so be careful.
Input_Event(const SDL_Event * event)1369 void Input_Event(const SDL_Event *event)
1370 {
1371  switch(event->type)
1372  {
1373   case SDL_KEYDOWN:
1374   case SDL_KEYUP:
1375 	KBMan::Event(event);
1376 	break;
1377 
1378   case SDL_MOUSEBUTTONDOWN:
1379   case SDL_MOUSEBUTTONUP:
1380   case SDL_MOUSEMOTION:
1381   case SDL_MOUSEWHEEL:
1382 	MouseMan::Event(event);
1383 	break;
1384  }
1385 }
1386 
1387 /*
1388  Note: Don't call this function frivolously or any more than needed, or else the logic to prevent lost key and mouse button
1389  presses won't work properly in regards to emulated input devices(has particular significance with the "Pause" key and the emulated
1390  Saturn keyboard).
1391 */
UpdatePhysicalDeviceState(void)1392 static void UpdatePhysicalDeviceState(void)
1393 {
1394  MouseMan::UpdateMice();
1395  KBMan::UpdateKeyboards();
1396 
1397  if(MDFNDHaveFocus || MDFN_GetSettingB("input.joystick.global_focus"))
1398   JoystickManager::UpdateJoysticks();
1399 
1400  CurTicks = Time::MonoMS();
1401 }
1402 
RedoFFSF(void)1403 static void RedoFFSF(void)
1404 {
1405  if(inff)
1406   RefreshThrottleFPS(MDFN_GetSettingF("ffspeed"));
1407  else if(insf)
1408   RefreshThrottleFPS(MDFN_GetSettingF("sfspeed"));
1409  else
1410   RefreshThrottleFPS(1);
1411 }
1412 
1413 
ToggleLayer(int which)1414 static void ToggleLayer(int which)
1415 {
1416  static uint64 le_mask = ~0ULL; // FIXME/TODO: Init to ~0ULL on game load.
1417 
1418  if(CurGame && CurGame->LayerNames)
1419  {
1420   const char *goodies = CurGame->LayerNames;
1421   int x = 0;
1422 
1423   while(x != which)
1424   {
1425    while(*goodies)
1426     goodies++;
1427    goodies++;
1428    if(!*goodies) return; // ack, this layer doesn't exist.
1429    x++;
1430   }
1431 
1432   le_mask ^= (1ULL << which);
1433   MDFNI_SetLayerEnableMask(le_mask);
1434 
1435   if(le_mask & (1ULL << which))
1436    MDFN_Notify(MDFN_NOTICE_STATUS, _("%s enabled."), _(goodies));
1437   else
1438    MDFN_Notify(MDFN_NOTICE_STATUS, _("%s disabled."), _(goodies));
1439  }
1440 }
1441 
1442 
1443 // TODO: Remove this in the future when digit-string input devices are better abstracted.
1444 static uint8 BarcodeWorldData[1 + 13];
1445 
DoKeyStateZeroing(void)1446 static void DoKeyStateZeroing(void)
1447 {
1448  EmuKeyboardKeysGrabbed = false;
1449  NPCheatDebugKeysGrabbed = false;
1450 
1451  if(IConfig == none)
1452  {
1453   if(Debugger_IsActive())
1454   {
1455    static const unsigned sc_um[] =
1456    {
1457     SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5, SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8,
1458     SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_F11, SDL_SCANCODE_F12, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_F16,
1459     SDL_SCANCODE_F17, SDL_SCANCODE_F18, SDL_SCANCODE_F19, SDL_SCANCODE_F20, SDL_SCANCODE_F21, SDL_SCANCODE_F22, SDL_SCANCODE_F23, SDL_SCANCODE_F24
1460    };
1461 
1462    KBMan::MaskSysKBKeys();
1463    NPCheatDebugKeysGrabbed = true;
1464    KBMan::UnmaskSysKBKeys(sc_um, sizeof(sc_um) / sizeof(sc_um[0]));
1465   }
1466   else if(Netplay_IsTextInput() || CheatIF_Active())
1467   {
1468    // This effectively disables keyboard input, but still
1469    // allows physical joystick input when in the chat mode
1470    KBMan::MaskSysKBKeys();
1471    NPCheatDebugKeysGrabbed = true;
1472   }
1473   else if(InputGrab)
1474   {
1475    for(unsigned int x = 0; x < CurGame->PortInfo.size(); x++)
1476    {
1477     if(!(PIDC[x].Device->Flags & InputDeviceInfoStruct::FLAG_KEYBOARD))
1478      continue;
1479 
1480     for(auto& bic : PIDC[x].BIC)
1481     {
1482      for(auto& b : bic.BC)
1483      {
1484       if(b.DeviceType != BUTTC_KEYBOARD)
1485        continue;
1486 
1487       EmuKeyboardKeysGrabbed = true;
1488 
1489       KBMan::MaskSysKBKeys();
1490       goto IGrabEnd;
1491      }
1492     }
1493    }
1494    IGrabEnd:;
1495   }
1496  }
1497 }
1498 
CheckCommandKeys(void)1499 static void CheckCommandKeys(void)
1500 {
1501   for(unsigned i = 0; i < 12; i++)
1502   {
1503    if(IConfig == Port1 + i)
1504    {
1505     if(CK_Check((CommandKey)(CK_INPUT_CONFIG1 + i)))
1506     {
1507      CK_PostRemapUpdate((CommandKey)(CK_INPUT_CONFIG1 + i));	// Kind of abusing that function if going by its name, but meh.
1508 
1509      ResyncGameInputSettings(i);
1510      CalcWMInputBehavior();
1511      IConfig = none;
1512 
1513      MDFN_Notify(MDFN_NOTICE_STATUS, _("Configuration interrupted."));
1514     }
1515     else if(ConfigDevice(i))
1516     {
1517      ResyncGameInputSettings(i);
1518      CalcWMInputBehavior();
1519      ICDeadDelay = CurTicks + 300;
1520      IConfig = none;
1521     }
1522     break;
1523    }
1524   }
1525 
1526   if(IConfig == Command || IConfig == CommandAM)
1527   {
1528    if(ICLatch != -1)
1529    {
1530     if(subcon(CKeys[ICLatch].text, CKeysConfig[ICLatch], true, IConfig == CommandAM))
1531     {
1532      MDFN_Notify(MDFN_NOTICE_STATUS, _("Configuration finished."));
1533 
1534      MDFNI_SetSetting(CKeys[ICLatch].setting_name, BCGToString(CKeysConfig[ICLatch]));
1535      ICDeadDelay = CurTicks + 300;
1536      IConfig = none;
1537 
1538      // Prevent accidentally triggering the command
1539      CK_PostRemapUpdate((CommandKey)ICLatch);
1540      CalcWMInputBehavior();
1541     }
1542    }
1543    else
1544    {
1545     MDFN_Notify(MDFN_NOTICE_STATUS, _("Press command key to remap now%s..."), (IConfig == CommandAM) ? _("(AND Mode)") : "");
1546 
1547     for(CommandKey x = _CK_FIRST; x < _CK_COUNT; x = (CommandKey)((unsigned)x + 1))
1548     {
1549      if(CK_Check((CommandKey)x))
1550      {
1551       ICLatch = x;
1552       subcon_begin();
1553       break;
1554      }
1555     }
1556    }
1557   }
1558 
1559   if(IConfig != none)
1560    return;
1561 
1562   if(CK_Check(CK_TOGGLE_GRAB))
1563   {
1564    InputGrab = !InputGrab;
1565    CalcWMInputBehavior();
1566 
1567    MDFN_Notify(MDFN_NOTICE_STATUS, _("Input grabbing: %s"), InputGrab ? _("On") : _("Off"));
1568   }
1569 
1570   if(!MDFNDnetplay && !Netplay_IsTextInput())
1571   {
1572    if(!CheatIF_Active())
1573    {
1574     if(CK_Check(CK_TOGGLE_DEBUGGER))
1575     {
1576      Debugger_GT_Toggle();
1577      CalcWMInputBehavior();
1578     }
1579    }
1580 
1581    if(!Debugger_IsActive() && !MDFNDnetplay)
1582    {
1583     if(CK_Check(CK_TOGGLECHEATVIEW))
1584     {
1585      CheatIF_GT_Show(!CheatIF_Active());
1586     }
1587    }
1588   }
1589 
1590   if(CK_Check(CK_EXIT))
1591   {
1592    SendCEvent(CEVT_WANT_EXIT, NULL, NULL);
1593   }
1594 
1595   if(CK_Check(CK_TOGGLE_HELP))
1596    Help_Toggle();
1597 
1598   if(!CheatIF_Active() && !Debugger_IsActive())
1599   {
1600    if(CK_Check(CK_TOGGLENETVIEW))
1601    {
1602     Netplay_ToggleTextView();
1603    }
1604   }
1605 
1606   if(CK_Check(CK_TOGGLE_CHEAT_ACTIVE))
1607   {
1608    bool isactive = MDFN_GetSettingB("cheats");
1609 
1610    isactive = !isactive;
1611 
1612    MDFNI_SetSettingB("cheats", isactive);
1613 
1614    if(isactive)
1615     MDFN_Notify(MDFN_NOTICE_STATUS, _("Application of cheats enabled."));
1616    else
1617     MDFN_Notify(MDFN_NOTICE_STATUS, _("Application of cheats disabled."));
1618   }
1619 
1620   if(CK_Check(CK_TOGGLE_FPS_VIEW))
1621    FPS_ToggleView();
1622 
1623   if(CK_Check(CK_TOGGLE_FS))
1624   {
1625    GT_ToggleFS();
1626   }
1627 
1628   if(!CurGame)
1629 	return;
1630 
1631   if(!MDFNDnetplay)
1632   {
1633    if(CK_Check(CK_PAUSE))
1634    {
1635     if(IsInFrameAdvance())
1636      DoRunNormal();
1637     else
1638      DoFrameAdvance();
1639    }
1640    else
1641    {
1642     bool ck_af = CK_Check(CK_ADVANCE_FRAME);
1643     bool ck_rn = CK_Check(CK_RUN_NORMAL);
1644     bool iifa = IsInFrameAdvance();
1645 
1646     //
1647     // Change the order of processing based on being in frame advance mode to allow for the derivation of single-key (un)pause functionality.
1648     //
1649 
1650     if(ck_af & iifa)
1651      DoFrameAdvance();
1652 
1653     if(ck_rn)
1654      DoRunNormal();
1655 
1656     if(ck_af & !iifa)
1657      DoFrameAdvance();
1658    }
1659   }
1660 
1661   if(!Debugger_IsActive()) // We don't want to start button configuration when the debugger is active!
1662   {
1663    for(unsigned i = 0; i < 12; i++)
1664    {
1665     if(CK_Check((CommandKey)(CK_INPUT_CONFIG1 + i)))
1666     {
1667      if(i >= CurGame->PortInfo.size())
1668       MDFN_Notify(MDFN_NOTICE_STATUS, _("Port %u does not exist."), i + 1);
1669      else if(!PIDC[i].BIC.size())
1670      {
1671       MDFN_Notify(MDFN_NOTICE_STATUS, _("No buttons to configure on port %u device \"%s\"!"), i + 1, PIDC[i].Device->FullName);
1672      }
1673      else
1674      {
1675       //SetJoyReadMode(0);
1676       ConfigDeviceBegin();
1677       IConfig = (ICType)(Port1 + i);
1678      }
1679      break;
1680     }
1681    }
1682 
1683    if(CK_Check(CK_INPUT_CONFIGC))
1684    {
1685     //SetJoyReadMode(0);
1686     ConfigDeviceBegin();
1687     ICLatch = -1;
1688     IConfig = Command;
1689    }
1690 
1691    if(CK_Check(CK_INPUT_CONFIGC_AM))
1692    {
1693     //SetJoyReadMode(0);
1694     ConfigDeviceBegin();
1695     ICLatch = -1;
1696     IConfig = CommandAM;
1697    }
1698 
1699    if(CK_Check(CK_INPUT_CONFIG_ABD))
1700    {
1701     MDFN_Notify(MDFN_NOTICE_STATUS, "%u joystick/gamepad analog button(s) detected.", JoystickManager::DetectAnalogButtonsForChangeCheck());
1702    }
1703   }
1704 
1705   if(CK_Check(CK_ROTATESCREEN))
1706   {
1707    if(CurGame->rotated == MDFN_ROTATE0)
1708     CurGame->rotated = MDFN_ROTATE90;
1709    else if(CurGame->rotated == MDFN_ROTATE90)
1710     CurGame->rotated = MDFN_ROTATE270;
1711    else if(CurGame->rotated == MDFN_ROTATE270)
1712     CurGame->rotated = MDFN_ROTATE0;
1713   }
1714 
1715   if(CK_CheckActive(CK_STATE_REWIND))
1716 	DNeedRewind = true;
1717   else
1718 	DNeedRewind = false;
1719 
1720   if(CK_Check(CK_STATE_REWIND_TOGGLE))
1721   {
1722    RewindState = !RewindState;
1723    MDFNI_EnableStateRewind(RewindState);
1724 
1725    MDFN_Notify(MDFN_NOTICE_STATUS, RewindState ? _("State rewinding functionality enabled.") : _("State rewinding functionality disabled."));
1726   }
1727 
1728   {
1729    bool previous_ff = inff;
1730    bool previous_sf = insf;
1731 
1732    if(fftoggle_setting)
1733     inff ^= CK_Check(CK_FAST_FORWARD);
1734    else
1735     inff = CK_CheckActive(CK_FAST_FORWARD);
1736 
1737    if(sftoggle_setting)
1738     insf ^= CK_Check(CK_SLOW_FORWARD);
1739    else
1740     insf = CK_CheckActive(CK_SLOW_FORWARD);
1741 
1742    if(previous_ff != inff || previous_sf != insf)
1743     RedoFFSF();
1744   }
1745 
1746   if(CurGame->RMD->Drives.size())
1747   {
1748    if(CK_Check(CK_SELECT_DISK))
1749    {
1750     RMDUI_SelectDisk();
1751    }
1752 
1753    if(CK_Check(CK_SELECT_DRIVE))
1754    {
1755     RMDUI_SelectDrive();
1756    }
1757 
1758    if(CK_Check(CK_INSERTEJECT_DISK))
1759    {
1760     RMDUI_Toggle_InsertEject();
1761    }
1762   }
1763 
1764   if(CurGame->GameType != GMT_PLAYER)
1765   {
1766    for(int i = 0; i < 12; i++)
1767    {
1768     if(CK_Check((CommandKey)(CK_DEVICE_SELECT1 + i)))
1769      IncSelectedDevice(i);
1770    }
1771   }
1772 
1773   if(CK_Check(CK_TAKE_SNAPSHOT))
1774 	pending_snapshot = 1;
1775 
1776   if(CK_Check(CK_TAKE_SCALED_SNAPSHOT))
1777 	pending_ssnapshot = 1;
1778 
1779   if(CK_Check(CK_SAVE_STATE))
1780 	pending_save_state = 1;
1781 
1782   if(CK_Check(CK_SAVE_MOVIE))
1783 	pending_save_movie = 1;
1784 
1785   if(CK_Check(CK_LOAD_STATE))
1786   {
1787 	MDFNI_LoadState(NULL, NULL);
1788 	Debugger_GT_SyncDisToPC();
1789   }
1790 
1791   if(CK_Check(CK_LOAD_MOVIE))
1792   {
1793 	MDFNI_LoadMovie(NULL);
1794 	Debugger_GT_SyncDisToPC();
1795   }
1796 
1797   if(CK_Check(CK_TL1))
1798     ToggleLayer(0);
1799   if(CK_Check(CK_TL2))
1800     ToggleLayer(1);
1801   if(CK_Check(CK_TL3))
1802     ToggleLayer(2);
1803   if(CK_Check(CK_TL4))
1804     ToggleLayer(3);
1805   if(CK_Check(CK_TL5))
1806     ToggleLayer(4);
1807   if(CK_Check(CK_TL6))
1808     ToggleLayer(5);
1809   if(CK_Check(CK_TL7))
1810     ToggleLayer(6);
1811   if(CK_Check(CK_TL8))
1812     ToggleLayer(7);
1813   if(CK_Check(CK_TL9))
1814     ToggleLayer(8);
1815 
1816   if(CK_Check(CK_STATE_SLOT_INC))
1817   {
1818    MDFNI_SelectState(666 + 1);
1819   }
1820 
1821   if(CK_Check(CK_STATE_SLOT_DEC))
1822   {
1823    MDFNI_SelectState(666 - 1);
1824   }
1825 
1826   if(CK_Check(CK_RESET))
1827   {
1828 	MDFNI_Reset();
1829 	Debugger_GT_ForceStepIfStepping();
1830   }
1831 
1832   if(CK_Check(CK_POWER))
1833   {
1834 	MDFNI_Power();
1835 	Debugger_GT_ForceStepIfStepping();
1836   }
1837 
1838   if(CurGame->GameType == GMT_ARCADE)
1839   {
1840 	if(CK_Check(CK_INSERT_COIN))
1841 		MDFNI_InsertCoin();
1842 
1843 	if(CK_Check(CK_TOGGLE_DIPVIEW))
1844         {
1845 	 ViewDIPSwitches = !ViewDIPSwitches;
1846 	 MDFNI_ToggleDIPView();
1847 	}
1848 
1849 	if(!ViewDIPSwitches)
1850 	 goto DIPSless;
1851 
1852 	if(CK_Check(CK_1)) MDFNI_ToggleDIP(0);
1853 	if(CK_Check(CK_2)) MDFNI_ToggleDIP(1);
1854 	if(CK_Check(CK_3)) MDFNI_ToggleDIP(2);
1855 	if(CK_Check(CK_4)) MDFNI_ToggleDIP(3);
1856 	if(CK_Check(CK_5)) MDFNI_ToggleDIP(4);
1857 	if(CK_Check(CK_6)) MDFNI_ToggleDIP(5);
1858 	if(CK_Check(CK_7)) MDFNI_ToggleDIP(6);
1859 	if(CK_Check(CK_8)) MDFNI_ToggleDIP(7);
1860   }
1861   else
1862   {
1863    #ifdef WANT_NES_EMU
1864    static uint8 bbuf[32];
1865    static int bbuft;
1866    static int barcoder = 0;
1867 
1868    if(!strcmp(CurGame->shortname, "nes") && (!strcmp(PIDC[4].Device->ShortName, "bworld") || (CurGame->cspecial && !MDFN_strazicmp(CurGame->cspecial, "datach"))))
1869    {
1870     if(CK_Check(CK_ACTIVATE_BARCODE))
1871     {
1872      barcoder ^= 1;
1873      if(!barcoder)
1874      {
1875       if(!strcmp(PIDC[4].Device->ShortName, "bworld"))
1876       {
1877        BarcodeWorldData[0] = 1;
1878        memset(BarcodeWorldData + 1, 0, 13);
1879 
1880        strncpy((char *)BarcodeWorldData + 1, (char *)bbuf, 13);
1881       }
1882       else
1883        MDFNI_DatachSet(bbuf);
1884       MDFN_Notify(MDFN_NOTICE_STATUS, _("Barcode Entered"));
1885      }
1886      else { bbuft = 0; MDFN_Notify(MDFN_NOTICE_STATUS, _("Enter Barcode"));}
1887     }
1888    }
1889    else
1890     barcoder = 0;
1891 
1892    #define SSM(x) { if(bbuft < 13) {bbuf[bbuft++] = '0' + x; bbuf[bbuft] = 0;} MDFN_Notify(MDFN_NOTICE_STATUS, _("Barcode: %s"),bbuf); }
1893 
1894    DIPSless:
1895 
1896    if(barcoder)
1897    {
1898     for(unsigned i = 0; i < 10; i++)
1899      if(CK_Check((CommandKey)(CK_0 + i)))
1900       SSM(i);
1901    }
1902    else
1903    #else
1904    DIPSless: ;
1905    #endif
1906    {
1907     for(unsigned i = 0; i < 10; i++)
1908     {
1909      if(CK_Check((CommandKey)(CK_0 + i)))
1910       MDFNI_SelectState(i);
1911 
1912      if(CK_Check((CommandKey)(CK_M0 + i)))
1913       MDFNI_SelectMovie(i);
1914     }
1915    }
1916    #undef SSM
1917  }
1918 }
1919 
Input_Update(bool VirtualDevicesOnly,bool UpdateRapidFire)1920 void Input_Update(bool VirtualDevicesOnly, bool UpdateRapidFire)
1921 {
1922  static unsigned int rapid=0;
1923 
1924  UpdatePhysicalDeviceState();
1925 
1926  DoKeyStateZeroing();	// Call before CheckCommandKeys()
1927 
1928  //
1929  // CheckCommandKeys(), specifically MDFNI_LoadState(), should be called *before* we update the emulated device input data, as that data is
1930  // stored/restored from save states(related: ALT+A frame advance, switch state).
1931  //
1932  CK_UpdateState((IConfig == Command || IConfig == CommandAM) && ICLatch == -1);
1933  if(!VirtualDevicesOnly)
1934  {
1935   CheckCommandKeys();
1936   CK_ClearTriggers();
1937  }
1938 
1939  if(UpdateRapidFire)
1940   rapid = (rapid + 1) % (autofirefreq + 1);
1941 
1942  // Do stuff here
1943  for(unsigned int x = 0; x < CurGame->PortInfo.size(); x++)
1944  {
1945   bool bypass_key_masking = false;
1946 
1947   if(!PIDC[x].Data)
1948    continue;
1949 
1950   if(PIDC[x].Device->Flags & InputDeviceInfoStruct::FLAG_KEYBOARD)
1951   {
1952    if(!InputGrab || NPCheatDebugKeysGrabbed)
1953     continue;
1954    else
1955     bypass_key_masking = true;
1956   }
1957 
1958   //
1959   // Handle rumble(FIXME: Do we want rumble to work in frame advance mode too?)
1960   //
1961   for(auto const& ric : PIDC[x].RIC)
1962   {
1963    const uint16 rumble_data = MDFN_de16lsb(PIDC[x].Data + ric.BitOffset / 8);
1964    const uint8 weak = (rumble_data >> 0) & 0xFF;
1965    const uint8 strong = (rumble_data >> 8) & 0xFF;
1966 
1967    JoystickManager::SetRumble(PIDC[x].BIC[ric.AssocBICIndex].BC, weak, strong);
1968    //printf("Rumble: %04x --- Weak: %02x, Strong: %02x\n", rumble_data, weak, strong);
1969   }
1970 
1971   if(IConfig != none)
1972    continue;
1973 
1974   if(ICDeadDelay > CurTicks)
1975    continue;
1976   else
1977    ICDeadDelay = 0;
1978 
1979   //
1980   // Handle configurable inputs/buttons.
1981   //
1982   for(size_t bic_i = 0; bic_i < PIDC[x].BIC.size(); bic_i++)
1983   {
1984    auto& bic = PIDC[x].BIC[bic_i];
1985    uint8* tptr = PIDC[x].Data;
1986    const uint32 bo = bic.BitOffset;
1987    uint8* const btptr = &tptr[bo >> 3];
1988 
1989    switch(bic.IMType)
1990    {
1991     default:
1992 	break;
1993 
1994     case IMTYPE_BUTTON:
1995 	*btptr &= ~(1 << (bo & 7));
1996 	*btptr |= DTestButton(bic.BC, bypass_key_masking) << (bo & 7);
1997 	break;
1998 
1999     case IMTYPE_BUTTON_RAPID:
2000 	*btptr |= (DTestButton(bic.BC, bypass_key_masking) & (rapid >= ((autofirefreq + 1) >> 1))) << (bo & 7);
2001 	break;
2002 
2003     case IMTYPE_AXIS_NEG:
2004 	break;
2005 
2006     case IMTYPE_AXIS_POS:
2007 	//assert(PIDC[x].BIC[bic_i - 1].IMType == IMTYPE_AXIS_NEG);
2008 	MDFN_en16lsb(btptr, DTestAxis(PIDC[x].BIC[bic_i - 1].BC, bic.BC, bypass_key_masking, PIDC[x].AxisScale));
2009 	break;
2010 
2011     case IMTYPE_BUTTON_ANALOG:
2012 	MDFN_en16lsb(btptr, DTestAnalogButton(bic.BC, bypass_key_masking) << 1);
2013 	break;
2014 
2015     // Ordered before IMTYPE_AXIS_REL_POS
2016     case IMTYPE_AXIS_REL_NEG:
2017 	break;
2018 
2019     // Ordered after IMPTYPE_AXIS_REL_NEG
2020     case IMTYPE_AXIS_REL_POS:
2021 	//assert(PIDC[x].BIC[bic_i - 1].IMType == IMTYPE_AXIS_REL_NEG);
2022 	bic.AxisRel.AccumError += (int64)DTestAxisRel(PIDC[x].BIC[bic_i - 1].BC, bic.BC, bypass_key_masking) * (int64)floor(0.5 + CurGame->mouse_sensitivity * (1 << 20));
2023 	{
2024 	 int32 tosend = bic.AxisRel.AccumError / ((int64)1 << 32);	// Division, not simple right arithmetic shift.
2025 	 //printf("%lld, %d\n", tosend, bic.AxisRel.AccumError >> 32);
2026 	 MDFN_en16lsb(btptr, std::max<int32>(-32768, std::min<int32>(32767, tosend)));	// don't assign result of min/max to tosend
2027 	 bic.AxisRel.AccumError -= tosend * ((int64)1 << 32);
2028 	}
2029 	break;
2030 
2031     //
2032     // Mice axes aren't buttons!  Oh well...
2033     //
2034     case IMTYPE_POINTER_X:
2035     case IMTYPE_POINTER_Y:
2036 	{
2037 	 float tv = DTestPointer(bic.BC, bypass_key_masking, (bic.IMType == IMTYPE_POINTER_Y));
2038 
2039 	 if(bic.IMType == IMTYPE_POINTER_Y)
2040 	  tv = floor(0.5 + (tv * CurGame->mouse_scale_y) + CurGame->mouse_offs_y);
2041 	 else
2042 	  tv = floor(0.5 + (tv * CurGame->mouse_scale_x) + CurGame->mouse_offs_x);
2043 
2044 	 //printf("msx: %f, msy: %f --- %f\n", CurGame->mouse_scale_x, CurGame->mouse_scale_y, tv);
2045 
2046 	 MDFN_en16lsb(btptr, (int16)std::max<float>(-32768, std::min<float>(tv, 32767)));
2047 	}
2048 	break;
2049 
2050     case IMTYPE_SWITCH:
2051 	{
2052 	 const bool nps = DTestButton(bic.BC, bypass_key_masking);
2053 	 uint8 cv = BitsExtract(tptr, bo, bic.Switch.BitSize);
2054 
2055 	 if(MDFN_UNLIKELY(!bic.Switch.LastPress && nps))
2056 	 {
2057 	  cv = (cv + 1) % bic.Switch.NumPos;
2058 	  BitsIntract(tptr, bo, bic.Switch.BitSize, cv);
2059 	 }
2060 
2061 	 if(MDFN_UNLIKELY(cv >= bic.Switch.NumPos))	// Can also be triggered intentionally by a bad save state/netplay.
2062 	  fprintf(stderr, "[BUG] cv(%u) >= bic.Switch.NumPos(%u)\n", cv, bic.Switch.NumPos);
2063 	 else if(MDFN_UNLIKELY(cv != bic.Switch.LastPos))
2064 	 {
2065 	  MDFN_Notify(MDFN_NOTICE_STATUS, _("%s %u: %s: %s selected."), PIDC[x].Device->FullName, x + 1, bic.IDII->Name, bic.IDII->Switch.Pos[cv].Name);
2066 	  bic.Switch.LastPos = cv;
2067 	 }
2068 
2069 	 bic.Switch.LastPress = nps;
2070 	}
2071 	break;
2072    }
2073   }
2074 
2075   //
2076   // Handle button exclusion!
2077   //
2078   for(auto& bic : PIDC[x].BIC)
2079   {
2080    if(bic.ExclusionBitOffset != 0xFFFF)
2081    {
2082     const uint32 bo[2] = { bic.BitOffset, bic.ExclusionBitOffset };
2083     const uint32 bob[2] = { bo[0] >> 3, bo[1] >> 3 };
2084     const uint32 bom[2] = { 1U << (bo[0] & 0x7), 1U << (bo[1] & 0x7) };
2085     uint8 *tptr = PIDC[x].Data;
2086 
2087     if((tptr[bob[0]] & bom[0]) && (tptr[bob[1]] & bom[1]))
2088     {
2089      tptr[bob[0]] &= ~bom[0];
2090      tptr[bob[1]] &= ~bom[1];
2091     }
2092    }
2093   }
2094 
2095   //
2096   // Handle status indicators.
2097   //
2098   for(auto& sic : PIDC[x].SIC)
2099   {
2100    const uint32 bo = sic.BitOffset;
2101    const uint8* tptr = PIDC[x].Data;
2102    uint32 cv = 0;
2103 
2104    for(unsigned b = 0; b < sic.StatusBitSize; b++)
2105     cv |= ((tptr[(bo + b) >> 3] >> ((bo + b) & 7)) & 1) << b;
2106 
2107    if(MDFN_UNLIKELY(cv >= sic.StatusNumStates))
2108     fprintf(stderr, "[BUG] cv(%u) >= sic.StatusNumStates(%u)\n", cv,sic.StatusNumStates);
2109    else if(MDFN_UNLIKELY(cv != sic.StatusLastState))
2110    {
2111     MDFN_Notify(MDFN_NOTICE_STATUS, _("%s %u: %s: %s"), PIDC[x].Device->FullName, x + 1, sic.IDII->Name, sic.IDII->Status.States[cv].Name);
2112     sic.StatusLastState = cv;
2113    }
2114   }
2115 
2116   //
2117   // Now, axis and misc data...
2118   //
2119   for(size_t tmi = 0; tmi < PIDC[x].Device->IDII.size(); tmi++)
2120   {
2121    switch(PIDC[x].Device->IDII[tmi].Type)
2122    {
2123     default: break;
2124 
2125     case IDIT_RESET_BUTTON:
2126 	{
2127 	 const uint32 bo = PIDC[x].Device->IDII[tmi].BitOffset;
2128 	 uint8* const btptr = PIDC[x].Data + (bo >> 3);
2129 	 const unsigned sob = bo & 0x7;
2130 
2131 	 *btptr = (*btptr &~ (1U << sob)) | (CK_CheckActive(CK_RESET) << sob);
2132 	}
2133 	break;
2134 
2135     case IDIT_BYTE_SPECIAL:
2136 	assert(tmi < 13 + 1);
2137 	PIDC[x].Data[tmi] = BarcodeWorldData[tmi];
2138 	break;
2139    }
2140   }
2141  }
2142 
2143  memset(BarcodeWorldData, 0, sizeof(BarcodeWorldData));
2144 }
2145 
Input_GameLoaded(MDFNGI * gi)2146 void Input_GameLoaded(MDFNGI *gi)
2147 {
2148  autofirefreq = MDFN_GetSettingUI("autofirefreq");
2149  fftoggle_setting = MDFN_GetSettingB("fftoggle");
2150  sftoggle_setting = MDFN_GetSettingB("sftoggle");
2151 
2152  CK_Init();
2153 
2154  for(size_t p = 0; p < gi->PortInfo.size(); p++)
2155   BuildPortInfo(gi, p);
2156 
2157  // Load the command key mappings from settings
2158  for(int x = 0; x < _CK_COUNT; x++)
2159  {
2160   const char* const sname = CKeys[x].setting_name;
2161 
2162   if(!StringToBCG(&CKeysConfig[x], MDFN_GetSettingS(sname).c_str(), MDFNI_GetSettingDefault(sname).c_str()))
2163    abort();
2164  }
2165  //
2166  //
2167  CalcWMInputBehavior();
2168 }
2169 
2170 // Update setting strings with butt configs.
ResyncGameInputSettings(unsigned port)2171 static void ResyncGameInputSettings(unsigned port)
2172 {
2173  for(unsigned int x = 0; x < PIDC[port].BIC.size(); x++)
2174   MDFNI_SetSetting(PIDC[port].BIC[x].SettingName, BCGToString(PIDC[port].BIC[x].BC));
2175 }
2176 
2177 
2178 static std::vector<ButtConfig> subcon_bcg;
2179 static ButtConfig subcon_bc;
2180 static size_t subcon_tb;
2181 
subcon_begin(void)2182 static void subcon_begin(void)
2183 {
2184  subcon_bcg.clear();
2185 
2186  memset(&subcon_bc, 0, sizeof(subcon_bc));
2187  subcon_tb = ~(size_t)0;
2188 }
2189 
2190 /* Configures an individual virtual button. */
subcon(const char * text,std::vector<ButtConfig> & bcg,const bool commandkey,const bool AND_Mode)2191 static bool subcon(const char *text, std::vector<ButtConfig>& bcg, const bool commandkey, const bool AND_Mode)
2192 {
2193  while(1)
2194  {
2195   MDFN_Notify(MDFN_NOTICE_STATUS, "%s (%zu)", text, subcon_bcg.size() + 1);
2196 
2197   if(subcon_tb != subcon_bcg.size())
2198   {
2199    JoystickManager::Reset_BC_ChangeCheck();
2200    MouseMan::Reset_BC_ChangeCheck();
2201    KBMan::Reset_BC_ChangeCheck(commandkey);
2202    subcon_tb = subcon_bcg.size();
2203   }
2204 
2205   if(!KBMan::Do_BC_ChangeCheck(&subcon_bc) && !MouseMan::Do_BC_ChangeCheck(&subcon_bc) && !JoystickManager::Do_BC_ChangeCheck(&subcon_bc))
2206    return false;
2207   //
2208   //
2209   if(subcon_bcg.size())
2210   {
2211    auto const& c = subcon_bc;
2212    auto const& p = subcon_bcg.back();
2213 
2214    if(c.DeviceType == p.DeviceType && c.DeviceNum == p.DeviceNum && c.ButtonNum == p.ButtonNum && c.DeviceID == p.DeviceID)
2215     break;
2216   }
2217 
2218   subcon_bc.ANDGroupCont = AND_Mode;
2219   subcon_bc.Scale = 4096;
2220   subcon_bcg.push_back(subcon_bc);
2221  }
2222 
2223  if(subcon_bcg.size())
2224   subcon_bcg.back().ANDGroupCont = false;
2225 
2226  bcg = subcon_bcg;
2227 
2228  return true;
2229 }
2230 
2231 static int cd_x;
2232 static int cd_lx = -1;
ConfigDeviceBegin(void)2233 static void ConfigDeviceBegin(void)
2234 {
2235  cd_x = 0;
2236  cd_lx = -1;
2237 }
2238 
ConfigDevice(int arg)2239 static int ConfigDevice(int arg)
2240 {
2241  char buf[512];
2242 
2243  //for(int i = 0; i < PIDC[arg].Buttons.size(); i++)
2244  // printf("%d\n", PIDC[arg].BCPrettyPrio[i]);
2245  //exit(1);
2246 
2247  for(;cd_x < (int)PIDC[arg].BCC.size(); cd_x++)
2248  {
2249   size_t snooty = PIDC[arg].BCC[cd_x];
2250 
2251   // For Lynx, GB, GBA, NGP, WonderSwan(especially wonderswan!)
2252   if(CurGame->PortInfo.size() == 1 && CurGame->PortInfo[0].DeviceInfo.size() == 1)
2253    trio_snprintf(buf, 512, "%s", PIDC[arg].BIC[snooty].CPName);
2254   else
2255    trio_snprintf(buf, 512, "%s %d: %s", PIDC[arg].Device->FullName, arg + 1, PIDC[arg].BIC[snooty].CPName);
2256 
2257   if(cd_x != cd_lx)
2258   {
2259    cd_lx = cd_x;
2260    subcon_begin();
2261   }
2262   if(!subcon(buf, PIDC[arg].BIC[snooty].BC, false, false))
2263    return(0);
2264  }
2265 
2266  MDFN_Notify(MDFN_NOTICE_STATUS, _("Configuration finished."));
2267 
2268  return(1);
2269 }
2270 
2271 
2272 struct DefaultSettingsMeow
2273 {
2274  const char*const* bc;
2275  size_t count;
2276 };
2277 
2278 /*
2279 static std::map<const char *, const DefaultSettingsMeow *, cstrcomp> DefaultButtonSettingsMap;
2280 */
2281 
MakeSettingsForDevice(std::vector<MDFNSetting> & settings,const MDFNGI * system,const int w,const InputDeviceInfoStruct * info,const DefaultSettingsMeow * defs)2282 static INLINE void MakeSettingsForDevice(std::vector <MDFNSetting> &settings, const MDFNGI *system, const int w, const InputDeviceInfoStruct *info, const DefaultSettingsMeow* defs)
2283 {
2284  size_t def_butti = 0;
2285  bool analog_scale_made = false;
2286  for(size_t x = 0; x < info->IDII.size(); x++)
2287  {
2288   if(info->IDII[x].Type != IDIT_BUTTON && info->IDII[x].Type != IDIT_BUTTON_CAN_RAPID && info->IDII[x].Type != IDIT_BUTTON_ANALOG && info->IDII[x].Type != IDIT_AXIS &&
2289 	info->IDII[x].Type != IDIT_POINTER_X && info->IDII[x].Type != IDIT_POINTER_Y && info->IDII[x].Type != IDIT_AXIS_REL &&
2290 	info->IDII[x].Type != IDIT_SWITCH)
2291    continue;
2292 
2293   if(NULL == info->IDII[x].SettingName)
2294    continue;
2295 
2296   if(info->IDII[x].Type == IDIT_AXIS)
2297   {
2298    for(unsigned part = 0; part < 2; part++)
2299    {
2300     MDFNSetting tmp_setting;
2301     memset(&tmp_setting, 0, sizeof(tmp_setting));
2302 
2303     tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".", info->IDII[x].SettingName, info->IDII[x].SettingName[0] ? "_" : "", info->IDII[x].Axis.sname_dir[part]));
2304     tmp_setting.description = build_string(system->shortname, ", ", system->PortInfo[w].FullName, ", ", info->FullName, ": ", info->IDII[x].Name, info->IDII[x].Name[0] ? " " : "", info->IDII[x].Axis.name_dir[part]);
2305     tmp_setting.type = MDFNST_STRING;
2306     tmp_setting.default_value = "";
2307 
2308     tmp_setting.flags = MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_INPUT_MAPPING;
2309     tmp_setting.description_extra = NULL;
2310     tmp_setting.validate_func = ValidateIMSetting;
2311     settings.push_back(tmp_setting);
2312    }
2313 
2314    if((info->IDII[x].Flags & IDIT_AXIS_FLAG_SQLR) && !analog_scale_made)
2315    {
2316     MDFNSetting tmp_setting;
2317     memset(&tmp_setting, 0, sizeof(tmp_setting));
2318 
2319     tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".axis_scale"));
2320     tmp_setting.description = trio_aprintf(gettext_noop("Analog axis scale coefficient for %s on %s."), info->FullName, system->PortInfo[w].FullName);
2321     tmp_setting.description_extra = NULL;
2322 
2323     tmp_setting.type = MDFNST_FLOAT;
2324     tmp_setting.default_value = "1.00";
2325     tmp_setting.minimum = "1.00";
2326     tmp_setting.maximum = "1.50";
2327 
2328     settings.push_back(tmp_setting);
2329     analog_scale_made = true;
2330    }
2331   }
2332   else if(info->IDII[x].Type == IDIT_AXIS_REL)
2333   {
2334    for(unsigned part = 0; part < 2; part++)
2335    {
2336     const char *default_value = "";
2337     MDFNSetting tmp_setting;
2338     memset(&tmp_setting, 0, sizeof(tmp_setting));
2339 
2340     if(defs)
2341     {
2342      assert(def_butti < defs->count);
2343      default_value = defs->bc[def_butti];
2344     }
2345 
2346     tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".", info->IDII[x].SettingName, info->IDII[x].SettingName[0] ? "_" : "", info->IDII[x].AxisRel.sname_dir[part]));
2347     tmp_setting.description = build_string(system->shortname, ", ", system->PortInfo[w].FullName, ", ", info->FullName, ": ", info->IDII[x].Name, info->IDII[x].Name[0] ? " " : "", info->IDII[x].AxisRel.name_dir[part]);
2348 
2349     tmp_setting.type = MDFNST_STRING;
2350     tmp_setting.default_value = default_value;
2351 
2352     tmp_setting.flags = MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_INPUT_MAPPING;
2353     tmp_setting.description_extra = NULL;
2354     tmp_setting.validate_func = ValidateIMSetting;
2355     settings.push_back(tmp_setting);
2356     def_butti++;
2357    }
2358   }
2359   else
2360   {
2361    const char *default_value = "";
2362    MDFNSetting tmp_setting;
2363 
2364    memset(&tmp_setting, 0, sizeof(tmp_setting));
2365 
2366    if(defs)
2367    {
2368     assert(def_butti < defs->count);
2369     default_value = defs->bc[def_butti];
2370    }
2371 
2372    tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".", info->IDII[x].SettingName));
2373    tmp_setting.description = build_string(system->shortname, ", ", system->PortInfo[w].FullName, ", ", info->FullName, ": ", info->IDII[x].Name);
2374 
2375    tmp_setting.type = MDFNST_STRING;
2376    tmp_setting.default_value = default_value;
2377 
2378    tmp_setting.flags = MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_INPUT_MAPPING;
2379    tmp_setting.description_extra = NULL;
2380    tmp_setting.validate_func = ValidateIMSetting;
2381    settings.push_back(tmp_setting);
2382    def_butti++;
2383   }
2384   //printf("Maketset: %s %s\n", tmp_setting.name, tmp_setting.default_value);
2385 
2386   // Now make a rapid butt-on-stick-on-watermelon
2387   if(info->IDII[x].Type == IDIT_BUTTON_CAN_RAPID)
2388   {
2389    MDFNSetting tmp_setting;
2390 
2391    memset(&tmp_setting, 0, sizeof(tmp_setting));
2392 
2393    tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".rapid_", info->IDII[x].SettingName));
2394    tmp_setting.description = build_string(system->shortname, ", ", system->PortInfo[w].FullName, ", ", info->FullName, ": Rapid ", info->IDII[x].Name);
2395    tmp_setting.type = MDFNST_STRING;
2396 
2397    tmp_setting.default_value = "";
2398 
2399    tmp_setting.flags = MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_INPUT_MAPPING;
2400    tmp_setting.description_extra = NULL;
2401    tmp_setting.validate_func = ValidateIMSetting;
2402 
2403    settings.push_back(tmp_setting);
2404   }
2405   else if(info->IDII[x].Type == IDIT_SWITCH)
2406   {
2407    MDFNSetting tmp_setting;
2408 
2409    memset(&tmp_setting, 0, sizeof(tmp_setting));
2410 
2411    tmp_setting.name = CleanSettingName(build_string(system->shortname, ".input.", system->PortInfo[w].ShortName, ".", info->ShortName, ".", info->IDII[x].SettingName, ".defpos"));
2412    tmp_setting.description = trio_aprintf(gettext_noop("Default position for switch \"%s\"."), info->IDII[x].Name);
2413    tmp_setting.description_extra = gettext_noop("Sets the position for the switch to the value specified upon startup and virtual input device change.");
2414 
2415    tmp_setting.flags = (info->IDII[x].Flags & IDIT_FLAG_AUX_SETTINGS_UNDOC) ? MDFNSF_SUPPRESS_DOC : 0;
2416    {
2417     MDFNSetting_EnumList* el = (MDFNSetting_EnumList*)calloc(info->IDII[x].Switch.NumPos + 1, sizeof(MDFNSetting_EnumList));
2418     const uint32 snp = info->IDII[x].Switch.NumPos;
2419 
2420     for(uint32 i = 0; i < snp; i++)
2421     {
2422      el[i].string = info->IDII[x].Switch.Pos[i].SettingName;
2423      el[i].number = i;
2424      el[i].description = info->IDII[x].Switch.Pos[i].Name;
2425      el[i].description_extra = info->IDII[x].Switch.Pos[i].Description;
2426     }
2427     el[snp].string = NULL;
2428     el[snp].number = 0;
2429     el[snp].description = NULL;
2430     el[snp].description_extra = NULL;
2431 
2432     assert(info->IDII[x].Switch.DefPos < info->IDII[x].Switch.NumPos);
2433 
2434     tmp_setting.enum_list = el;
2435     tmp_setting.type = MDFNST_ENUM;
2436     tmp_setting.default_value = el[info->IDII[x].Switch.DefPos].string;
2437    }
2438 
2439    settings.push_back(tmp_setting);
2440   }
2441  }
2442  if(defs)
2443  {
2444   //printf("%s --- %zu, %zu\n", setting_def_search, def_butti, defs->count);
2445   assert(def_butti == defs->count);
2446  }
2447 }
2448 
2449 template<typename T>
MakeSettingsForPort(std::vector<MDFNSetting> & settings,const MDFNGI * system,const int w,const InputPortInfoStruct * info,const T & defset)2450 static INLINE void MakeSettingsForPort(std::vector <MDFNSetting> &settings, const MDFNGI *system, const int w, const InputPortInfoStruct *info, const T& defset)
2451 {
2452  if(info->DeviceInfo.size() > 1)
2453  {
2454   MDFNSetting tmp_setting;
2455   MDFNSetting_EnumList *EnumList;
2456 
2457   memset(&tmp_setting, 0, sizeof(MDFNSetting));
2458 
2459   EnumList = (MDFNSetting_EnumList *)calloc(sizeof(MDFNSetting_EnumList), info->DeviceInfo.size() + 1);
2460 
2461   for(unsigned device = 0; device < info->DeviceInfo.size(); device++)
2462   {
2463    const InputDeviceInfoStruct *dinfo = &info->DeviceInfo[device];
2464 
2465    EnumList[device].string = strdup(dinfo->ShortName);
2466    EnumList[device].number = device;
2467    EnumList[device].description = strdup(info->DeviceInfo[device].FullName);
2468 
2469    EnumList[device].description_extra = NULL;
2470    if(info->DeviceInfo[device].Description || (info->DeviceInfo[device].Flags & InputDeviceInfoStruct::FLAG_KEYBOARD))
2471    {
2472     EnumList[device].description_extra = build_string(
2473 	 info->DeviceInfo[device].Description ? info->DeviceInfo[device].Description : "",
2474 	(info->DeviceInfo[device].Description && (info->DeviceInfo[device].Flags & InputDeviceInfoStruct::FLAG_KEYBOARD)) ? "\n" : "",
2475 	(info->DeviceInfo[device].Flags & InputDeviceInfoStruct::FLAG_KEYBOARD) ? _("Emulated keyboard key state is not updated unless input grabbing(by default, mapped to CTRL+SHIFT+Menu) is toggled on; refer to the main documentation for details.") : "");
2476    }
2477   }
2478 
2479   tmp_setting.name = build_string(system->shortname, ".input.", info->ShortName);
2480   tmp_setting.description = trio_aprintf("Input device for %s", info->FullName);
2481 
2482   tmp_setting.type = MDFNST_ENUM;
2483   tmp_setting.default_value = info->DefaultDevice;
2484 
2485   assert(info->DefaultDevice);
2486 
2487   tmp_setting.flags = MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE;
2488   tmp_setting.description_extra = NULL;
2489   tmp_setting.enum_list = EnumList;
2490 
2491   settings.push_back(tmp_setting);
2492  }
2493 
2494  for(unsigned device = 0; device < info->DeviceInfo.size(); device++)
2495  {
2496   const DefaultSettingsMeow* defs = nullptr;
2497   char setting_def_search[256];
2498   trio_snprintf(setting_def_search, sizeof(setting_def_search), "%s.input.%s.%s", system->shortname, system->PortInfo[w].ShortName, info->DeviceInfo[device].ShortName);
2499   CleanSettingName(setting_def_search);
2500 
2501   {
2502    auto fit = defset.find(setting_def_search);
2503    if(fit != defset.end())
2504     defs = &fit->second;
2505   }
2506 
2507   MakeSettingsForDevice(settings, system, w, &info->DeviceInfo[device], defs);
2508  }
2509 }
2510 
2511 // Called on emulator startup
Input_MakeSettings(std::vector<MDFNSetting> & settings)2512 void Input_MakeSettings(std::vector <MDFNSetting> &settings)
2513 {
2514  //uint64 st = Time::MonoUS();
2515 
2516  {
2517   #include "input-default-buttons.h"
2518 
2519   // First, build system settings
2520   for(unsigned int x = 0; x < MDFNSystems.size(); x++)
2521   {
2522    assert(MDFNSystems[x]->PortInfo.size() <= 16);
2523 
2524    for(unsigned port = 0; port < MDFNSystems[x]->PortInfo.size(); port++)
2525     MakeSettingsForPort(settings, MDFNSystems[x], port, &MDFNSystems[x]->PortInfo[port], defset);
2526   }
2527  }
2528 
2529  //printf("%llu\n", Time::MonoUS() - st);
2530 
2531  // Now build command key settings
2532  for(int x = 0; x < _CK_COUNT; x++)
2533  {
2534   MDFNSetting tmp_setting;
2535 
2536   memset(&tmp_setting, 0, sizeof(MDFNSetting));
2537 
2538   tmp_setting.name = CKeys[x].setting_name;
2539 
2540   tmp_setting.description = CKeys[x].description;
2541   tmp_setting.type = MDFNST_STRING;
2542 
2543   tmp_setting.flags = MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_INPUT_MAPPING;
2544   tmp_setting.description_extra = NULL;
2545   tmp_setting.validate_func = ValidateIMSetting;
2546 
2547   tmp_setting.default_value = CKeys[x].setting_default;
2548   settings.push_back(tmp_setting);
2549  }
2550 
2551 #if 0
2552  for(auto const& sys : MDFNSystems)
2553  {
2554   for(auto const& port : sys->PortInfo)
2555   {
2556    for(auto const& dev : port.DeviceInfo)
2557    {
2558     fprintf(stderr, "Input size: %u (%s)\n", (unsigned)dev.IDII.InputByteSize, dev.FullName);
2559     for(auto const& idii : dev.IDII)
2560     {
2561      if(idii.Type == IDIT_BUTTON || idii.Type == IDIT_BUTTON_CAN_RAPID)
2562       fprintf(stderr, "%s %s(%s) %s(%s) %s(%s): %u %u %s %u --- co=%d\n", sys->shortname, port.ShortName, port.FullName, dev.ShortName, dev.FullName, idii.SettingName, idii.Name, idii.BitSize, idii.BitOffset, (idii.Type == IDIT_BUTTON && idii.Button.ExcludeName) ? idii.Button.ExcludeName : "", idii.Flags, idii.ConfigOrder);
2563     }
2564    }
2565   }
2566  }
2567 #endif
2568 }
2569 
Input_GameClosed(void)2570 void Input_GameClosed(void)
2571 {
2572  for(size_t p = 0; p < CurGame->PortInfo.size(); p++)
2573   KillPortInfo(p);
2574  //
2575  CalcWMInputBehavior();
2576 }
2577 
2578 // TODO: multiple mice support
CalcWMInputBehavior_Sub(const InputMappingType IMType,const ButtConfig & bc,bool * CursorNeeded,bool * MouseAbsNeeded,bool * MouseRelNeeded)2579 static void CalcWMInputBehavior_Sub(const InputMappingType IMType, const ButtConfig& bc, bool* CursorNeeded, bool* MouseAbsNeeded, bool* MouseRelNeeded)
2580 {
2581  const bool is_mouse_mapping = (bc.DeviceType == BUTTC_MOUSE);
2582  const bool is_mouse_cursor_mapping = is_mouse_mapping && ((bc.ButtonNum & MouseMan::MOUSE_BN_TYPE_MASK) == MouseMan::MOUSE_BN_TYPE_CURSOR);
2583  const bool is_mouse_rel_mapping = is_mouse_mapping && ((bc.ButtonNum & MouseMan::MOUSE_BN_TYPE_MASK) == MouseMan::MOUSE_BN_TYPE_REL);
2584 
2585  if(is_mouse_cursor_mapping)
2586  {
2587   *MouseAbsNeeded = true;
2588   if(IMType != IMTYPE_POINTER_X && IMType != IMTYPE_POINTER_Y)
2589    *CursorNeeded = true;
2590  }
2591 
2592  if(is_mouse_rel_mapping)
2593   *MouseRelNeeded = true;
2594 }
2595 
CalcWMInputBehavior(void)2596 static void CalcWMInputBehavior(void)
2597 {
2598  const uint32 lpm = Netplay_GetLPM();
2599  bool CursorNeeded = false;
2600  bool MouseAbsNeeded = false;
2601  bool MouseRelNeeded = false;
2602  bool GrabNeeded = InputGrab;
2603 
2604  for(size_t p = 0; p < (CurGame ? CurGame->PortInfo.size() : 0); p++)
2605  {
2606   if(!(lpm & (1U << p)))
2607    continue;
2608 
2609   //
2610   auto const& pic = PIDC[p];
2611   for(auto const& bic : pic.BIC)
2612   {
2613    for(auto const& bc : bic.BC)
2614    {
2615     CalcWMInputBehavior_Sub(bic.IMType, bc, &CursorNeeded, &MouseAbsNeeded, &MouseRelNeeded);
2616    }
2617   }
2618  }
2619 
2620  for(int x = 0; x < _CK_COUNT; x++)
2621  {
2622   for(auto const& bc : CKeysConfig[x])
2623   {
2624    CalcWMInputBehavior_Sub(IMTYPE_BUTTON, bc, &CursorNeeded, &MouseAbsNeeded, &MouseRelNeeded);
2625   }
2626  }
2627 
2628  if(Debugger_IsActive())
2629  {
2630   MouseAbsNeeded = true;
2631   CursorNeeded = true;
2632  }
2633  //
2634  //
2635  //
2636  GT_SetWMInputBehavior(CursorNeeded, MouseAbsNeeded, MouseRelNeeded, GrabNeeded);
2637 }
2638 
Input_NetplayLPMChanged(void)2639 void Input_NetplayLPMChanged(void)
2640 {
2641  CalcWMInputBehavior();
2642 }
2643 
2644