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