Fix SA1 open bus
[lsnes.git] / src / core / controller.cpp
blob270789fc62484996c9deb4e56a925dc77ec79829
1 #include "lsnes.hpp"
3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/keymapper.hpp"
8 #include "core/mainloop.hpp"
9 #include "core/misc.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/window.hpp"
12 #include "interface/romtype.hpp"
13 #include "library/string.hpp"
15 #include <map>
16 #include <sstream>
17 #include <string>
19 namespace
21 struct controller_bind
23 std::string cclass;
24 unsigned number;
25 std::string name;
26 int mode; //0 => Button, 1 => Axis pair, 2 => Single axis.
27 bool xrel;
28 bool yrel;
29 unsigned control1;
30 unsigned control2; //Axis only, UINT_MAX if not valid.
31 int16_t rmin;
32 int16_t rmax;
33 bool centered;
36 struct active_bind
38 unsigned port;
39 unsigned controller;
40 struct controller_bind bind;
43 struct controller_triple
45 std::string cclass;
46 unsigned port;
47 unsigned controller;
48 bool operator<(const struct controller_triple& t) const throw()
50 if(cclass < t.cclass) return true;
51 if(cclass > t.cclass) return false;
52 if(port < t.port) return true;
53 if(port > t.port) return false;
54 if(controller < t.controller) return true;
55 if(controller > t.controller) return false;
56 return false;
58 bool operator==(const struct controller_triple& t) const throw()
60 return (cclass == t.cclass && port == t.port && controller == t.controller);
64 std::map<std::string, keyboard::invbind*> macro_binds;
65 std::map<std::string, keyboard::invbind*> macro_binds2;
66 std::map<std::string, controller_bind> all_buttons;
67 std::map<std::string, active_bind> active_buttons;
68 std::map<std::string, keyboard::ctrlrkey*> added_keys;
70 //Promote stored key to active key.
71 void promote_key(keyboard::ctrlrkey& k)
73 std::string name = k.get_command();
74 if(added_keys.count(name)) {
75 //Already exists.
76 delete &k;
77 return;
79 added_keys[name] = &k;
80 if(!button_keys.count(name))
81 return;
82 k.append(button_keys[name]);
83 messages << button_keys[name] << " bound (button) to " << name << std::endl;
84 button_keys.erase(name);
87 //Allocate controller keys for specified button.
88 void add_button(const std::string& name, const controller_bind& binding)
90 keyboard::ctrlrkey* k;
91 if(binding.mode == 0) {
92 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "+controller " << name).str(),
93 (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣"
94 << binding.name).str());
95 promote_key(*k);
96 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "hold-controller " << name).str(),
97 (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣"
98 << binding.name << "‣hold").str());
99 promote_key(*k);
100 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "type-controller " << name).str(),
101 (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣"
102 << binding.name << "‣type").str());
103 promote_key(*k);
104 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "+autofire-controller "
105 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
106 << binding.number << "‣" << binding.name << "‣autofire").str());
107 promote_key(*k);
108 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "autofire-controller "
109 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
110 << binding.number << "‣" << binding.name << "‣autofire toggle").str());
111 promote_key(*k);
112 } else if(binding.mode == 1) {
113 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "designate-position " << name).str(),
114 (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣"
115 << binding.name).str());
116 promote_key(*k);
117 } else if(binding.mode == 2) {
118 k = new keyboard::ctrlrkey(lsnes_mapper, (stringfmt() << "controller-analog " << name).str(),
119 (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣"
120 << binding.name << " (axis)").str(), true);
121 promote_key(*k);
125 //Take specified controller info and process it as specified controller of its class.
126 void process_controller(port_controller& controller, unsigned number)
128 unsigned analog_num = 1;
129 bool multi_analog = (controller.analog_actions() > 1);
130 //This controller might be processed already, but perhaps only partially.
131 for(unsigned i = 0; i < controller.buttons.size(); i++) {
132 if(controller.buttons[i].shadow)
133 continue;
134 if(controller.buttons[i].type != port_controller_button::TYPE_BUTTON)
135 continue;
136 std::string name = (stringfmt() << controller.cclass << "-" << number << "-"
137 << controller.buttons[i].name).str();
138 controller_bind b;
139 b.cclass = controller.cclass;
140 b.number = number;
141 b.name = controller.buttons[i].name;
142 b.mode = 0;
143 b.xrel = b.yrel = false;
144 b.control1 = i;
145 b.control2 = std::numeric_limits<unsigned>::max();
146 if(!all_buttons.count(name)) {
147 all_buttons[name] = b;
148 add_button(name, b);
151 for(unsigned i = 0; i < controller.buttons.size(); i++) {
152 if(controller.buttons[i].shadow)
153 continue;
154 if(!controller.buttons[i].is_analog())
155 continue;
156 std::string name = (stringfmt() << controller.cclass << "-" << number << "-"
157 << controller.buttons[i].name).str();
158 controller_bind b;
159 b.cclass = controller.cclass;
160 b.number = number;
161 b.name = controller.buttons[i].name;
162 b.rmin = controller.buttons[i].rmin;
163 b.rmax = controller.buttons[i].rmax;
164 b.centered = controller.buttons[i].centers;
165 b.mode = 2;
166 b.xrel = b.yrel = false;
167 b.control1 = i;
168 b.control2 = std::numeric_limits<unsigned>::max();
169 if(!all_buttons.count(name)) {
170 all_buttons[name] = b;
171 add_button(name, b);
174 for(unsigned i = 0; i < controller.analog_actions(); i++) {
175 auto g = controller.analog_action(i);
176 auto raxis = port_controller_button::TYPE_RAXIS;
177 std::string name;
178 controller_bind b;
179 if(multi_analog)
180 b.name = (stringfmt() << "analog" << analog_num).str();
181 else
182 b.name = (stringfmt() << "analog").str();
183 name = (stringfmt() << controller.cclass << "-" << number << "-" << b.name).str();
184 analog_num++;
185 b.cclass = controller.cclass;
186 b.number = number;
187 b.mode = 1;
188 b.xrel = (g.first < controller.buttons.size()) &&
189 (controller.buttons[g.first].type == raxis);
190 b.yrel = (g.second < controller.buttons.size()) &&
191 (controller.buttons[g.second].type == raxis);
192 b.control1 = g.first;
193 b.control2 = g.second;
194 if(!all_buttons.count(name))
195 add_button(name, b);
196 if(!all_buttons.count(name) ||
197 ((all_buttons[name].control2 == std::numeric_limits<unsigned>::max()) &&
198 (b.control2 < std::numeric_limits<unsigned>::max()))) {
199 all_buttons[name] = b;
204 unsigned next_id_from_map(std::map<std::string, unsigned>& map, const std::string& key, unsigned base)
206 if(!map.count(key))
207 return (map[key] = base);
208 else
209 return ++map[key];
212 //The rules for class number allocations are:
213 //- Different cores allocate numbers independently.
214 //- Within the same core, the allocations for higher port start after the previous port ends.
217 void process_controller(std::map<std::string, unsigned>& allocated,
218 std::map<controller_triple, unsigned>& assigned, port_controller& controller, unsigned port,
219 unsigned number_in_port)
221 controller_triple key;
222 key.cclass = controller.cclass;
223 key.port = port;
224 key.controller = number_in_port;
225 unsigned n;
226 if(!assigned.count(key))
227 assigned[key] = next_id_from_map(allocated, controller.cclass, 1);
228 n = assigned[key];
229 process_controller(controller, n);
232 void process_port(std::map<std::string, unsigned>& allocated,
233 std::map<controller_triple, unsigned>& assigned, unsigned port, port_type& ptype)
235 //What makes this nasty: Separate ports are always processed, but the same controllers can come
236 //multiple times, including with partial reprocessing.
237 std::map<std::string, unsigned> counts;
238 for(unsigned i = 0; i < ptype.controller_info->controllers.size(); i++) {
239 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
240 //gameboy-gambatte system port).
241 unsigned n = next_id_from_map(counts, ptype.controller_info->controllers[i].cclass, 1);
242 process_controller(allocated, assigned, ptype.controller_info->controllers[i], port, n);
246 void init_buttonmap()
248 static std::set<core_core*> done;
249 std::vector<port_type*> ptypes;
250 for(auto k : core_core::all_cores()) {
251 if(done.count(k))
252 continue;
253 std::map<std::string, unsigned> allocated;
254 std::map<controller_triple, unsigned> assigned;
255 auto ptypes = k->get_port_types();
256 for(unsigned i = 0; i < ptypes.size(); i++) {
257 bool any = false;
258 for(unsigned j = 0; j < ptypes.size(); j++) {
259 if(!ptypes[j]->legal(i))
260 continue;
261 any = true;
262 process_port(allocated, assigned, i, *ptypes[j]);
264 if(!any)
265 break;
267 done.insert(k);
271 //Check that button is active.
272 bool check_button_active(const std::string& name)
274 if(active_buttons.count(name))
275 return true;
276 //This isn't active. check if there are any other active buttons on the thingy and don't complain
277 //if there are.
278 bool complain = true;
279 auto ckey = lsnes_kbd.get_current_key();
280 if(ckey) {
281 auto cb = lsnes_mapper.get_controllerkeys_kbdkey(ckey);
282 for(auto i : cb) {
283 regex_results r = regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i->get_command());
284 if(!r)
285 continue;
286 if(active_buttons.count(r[1]))
287 complain = false;
290 if(complain)
291 messages << "No such button " << name << std::endl;
292 return false;
295 //Do button action.
296 void do_button_action(const std::string& name, short newstate, int mode)
298 if(!all_buttons.count(name)) {
299 messages << "No such button " << name << std::endl;
300 return;
302 if(!check_button_active(name))
303 return;
304 auto x = active_buttons[name];
305 if(x.bind.mode != 0)
306 return;
307 if(mode == 1) {
308 //Autohold.
309 int16_t nstate = controls.autohold2(x.port, x.controller, x.bind.control1) ^ newstate;
310 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "hold" : "unhold"))
311 return;
312 controls.autohold2(x.port, x.controller, x.bind.control1, nstate);
313 notify_autohold_update(x.port, x.controller, x.bind.control1, nstate);
314 } else if(mode == 2) {
315 //Framehold.
316 bool nstate = controls.framehold2(x.port, x.controller, x.bind.control1) ^ newstate;
317 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "type" : "untype"))
318 return;
319 controls.framehold2(x.port, x.controller, x.bind.control1, nstate);
320 if(nstate)
321 messages << "Holding " << name << " for the next frame" << std::endl;
322 else
323 messages << "Not holding " << name << " for the next frame" << std::endl;
324 } else {
325 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, newstate ? "press" :
326 "release"))
327 return;
328 controls.button2(x.port, x.controller, x.bind.control1, newstate);
332 void send_analog(const std::string& name, int32_t x, int32_t y)
334 if(!all_buttons.count(name)) {
335 messages << "No such action " << name << std::endl;
336 return;
338 if(!check_button_active(name))
339 return;
340 auto z = active_buttons[name];
341 if(z.bind.mode != 1) {
342 std::cerr << name << " is not a axis." << std::endl;
343 return;
345 if(lua_callback_do_button(z.port, z.controller, z.bind.control1, "analog"))
346 return;
347 if(lua_callback_do_button(z.port, z.controller, z.bind.control2, "analog"))
348 return;
349 auto g2 = get_framebuffer_size();
350 x = z.bind.xrel ? (x - g2.first / 2) : (x / 2);
351 y = z.bind.yrel ? (y - g2.second / 2) : (y / 2);
352 if(z.bind.control1 < std::numeric_limits<unsigned>::max())
353 controls.analog(z.port, z.controller, z.bind.control1, x);
354 if(z.bind.control2 < std::numeric_limits<unsigned>::max())
355 controls.analog(z.port, z.controller, z.bind.control2, y);
358 void do_action(const std::string& name, short state, int mode)
360 if(mode < 3)
361 do_button_action(name, state, mode);
362 else if(mode == 3) {
363 keyboard::key* mouse_x = lsnes_kbd.try_lookup_key("mouse_x");
364 keyboard::key* mouse_y = lsnes_kbd.try_lookup_key("mouse_y");
365 if(!mouse_x || !mouse_y) {
366 messages << "Controller analog function not available without mouse" << std::endl;
367 return;
369 send_analog(name, mouse_x->get_state(), mouse_y->get_state());
373 void do_analog_action(const std::string& a)
375 int _value;
376 regex_results r = regex("([^ \t]+)[ \t]+(-?[0-9]+)[ \t]*", a, "Invalid analog action");
377 std::string name = r[1];
378 int value = parse_value<int>(r[2]);
379 if(!all_buttons.count(name)) {
380 messages << "No such button " << name << std::endl;
381 return;
383 if(!check_button_active(name))
384 return;
385 auto x = active_buttons[name];
386 if(x.bind.mode != 2)
387 return;
388 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, "analog"))
389 return;
390 int rmin = x.bind.rmin;
391 int rmax = x.bind.rmax;
392 //FIXME: Do something with this?
393 //bool centered = x.bind.centered;
394 int64_t pvalue = value + 32768;
395 _value = pvalue * (rmax - rmin) / 65535 + rmin;
396 controls.analog(x.port, x.controller, x.bind.control1, _value);
399 void do_autofire_action(const std::string& a, int mode)
401 regex_results r = regex("([^ \t]+)(([ \t]+([0-9]+))?[ \t]+([0-9]+))?[ \t]*", a,
402 "Invalid autofire parameters");
403 std::string name = r[1];
404 std::string _duty = r[4];
405 std::string _cyclelen = r[5];
406 if(_duty == "") _duty = "1";
407 if(_cyclelen == "") _cyclelen = "2";
408 uint32_t duty = parse_value<uint32_t>(_duty);
409 uint32_t cyclelen = parse_value<uint32_t>(_cyclelen);
410 if(duty >= cyclelen)
411 throw std::runtime_error("Invalid autofire parameters");
412 if(!all_buttons.count(name)) {
413 messages << "No such button " << name << std::endl;
414 return;
416 if(!check_button_active(name))
417 return;
418 auto z = active_buttons[name];
419 if(z.bind.mode != 0) {
420 std::cerr << name << " is not a button." << std::endl;
421 return;
423 auto afire = controls.autofire2(z.port, z.controller, z.bind.control1);
424 if(mode == 1 || (mode == -1 && afire.first == 0)) {
425 //Turn on.
426 if(lua_callback_do_button(z.port, z.controller, z.bind.control1, (stringfmt() << "autofire "
427 << duty << " " << cyclelen).str().c_str()))
428 return;
429 controls.autofire2(z.port, z.controller, z.bind.control1, duty, cyclelen);
430 notify_autofire_update(z.port, z.controller, z.bind.control1, duty,
431 cyclelen);
432 } else if(mode == 0 || (mode == -1 && afire.first != 0)) {
433 //Turn off.
434 if(lua_callback_do_button(z.port, z.controller, z.bind.control1, "autofire"))
435 return;
436 controls.autofire2(z.port, z.controller, z.bind.control1, 0, 1);
437 notify_autofire_update(z.port, z.controller, z.bind.control1, 0, 1);
441 command::fnptr<const std::string&> button_p(lsnes_cmd, "+controller", "Press a button",
442 "Syntax: +controller<button>...\nPress a button\n",
443 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
444 do_action(a, 1, 0);
447 command::fnptr<const std::string&> button_r(lsnes_cmd, "-controller", "Release a button",
448 "Syntax: -controller<button>...\nRelease a button\n",
449 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
450 do_action(a, 0, 0);
453 command::fnptr<const std::string&> button_h(lsnes_cmd, "hold-controller", "Autohold a button",
454 "Syntax: hold-controller<button>...\nAutohold a button\n",
455 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
456 do_action(a, 1, 1);
459 command::fnptr<const std::string&> button_t(lsnes_cmd, "type-controller", "Type a button",
460 "Syntax: type-controller<button>...\nType a button\n",
461 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
462 do_action(a, 1, 2);
465 command::fnptr<const std::string&> button_d(lsnes_cmd, "designate-position", "Set postion",
466 "Syntax: designate-position <button>...\nDesignate position for an axis\n",
467 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
468 do_action(a, 0, 3);
471 command::fnptr<const std::string&> button_ap(lsnes_cmd, "+autofire-controller", "Start autofire",
472 "Syntax: +autofire-controller<button> [[<duty> ]<cyclelen>]...\nAutofire a button\n",
473 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
474 do_autofire_action(a, 1);
477 command::fnptr<const std::string&> button_an(lsnes_cmd, "-autofire-controller", "End autofire",
478 "Syntax: -autofire-controller<button> [[<duty> ]<cyclelen>]...\nEnd Autofire on a button\n",
479 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
480 do_autofire_action(a, 0);
483 command::fnptr<const std::string&> button_at(lsnes_cmd, "autofire-controller", "Toggle autofire",
484 "Syntax: autofire-controller<button> [[<duty> ]<cyclelen>]...\nToggle Autofire on a button\n",
485 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
486 do_autofire_action(a, -1);
489 command::fnptr<const std::string&> button_a(lsnes_cmd, "controller-analog", "Analog action",
490 "Syntax: controller-analog <button> <axis>\nAnalog action\n",
491 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
492 do_analog_action(a);
495 command::fnptr<const std::string&> macro_t(lsnes_cmd, "macro", "Toggle a macro",
496 "Syntax: macro <macroname>\nToggle a macro.\n",
497 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
498 controls.do_macro(a, 7);
501 command::fnptr<const std::string&> macro_e(lsnes_cmd, "+macro", "Enable a macro",
502 "Syntax: +macro <macroname>\nEnable a macro.\n",
503 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
504 controls.do_macro(a, 5);
507 command::fnptr<const std::string&> macro_d(lsnes_cmd, "-macro", "Disable a macro",
508 "Syntax: -macro <macroname>\nDisable a macro.\n",
509 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
510 controls.do_macro(a, 2);
513 class new_core_snoop
515 public:
516 new_core_snoop()
518 ncore.set(notify_new_core, []() { init_buttonmap(); });
520 struct dispatch::target<> ncore;
521 } coresnoop;
524 void reinitialize_buttonmap()
526 init_buttonmap();
529 void reread_active_buttons()
531 std::map<std::string, unsigned> classnum;
532 active_buttons.clear();
533 for(unsigned i = 0;; i++) {
534 auto x = controls.lcid_to_pcid(i);
535 if(x.first < 0)
536 break;
537 const port_type& pt = controls.get_blank().get_port_type(x.first);
538 const port_controller& ctrl = pt.controller_info->controllers[x.second];
539 if(!classnum.count(ctrl.cclass))
540 classnum[ctrl.cclass] = 1;
541 else
542 classnum[ctrl.cclass]++;
543 for(unsigned j = 0; j < ctrl.buttons.size(); j++) {
544 std::string name = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
545 << ctrl.buttons[j].name).str();
546 if(all_buttons.count(name)) {
547 active_bind a;
548 a.port = x.first;
549 a.controller = x.second;
550 a.bind = all_buttons[name];
551 active_buttons[name] = a;
554 bool multi = (ctrl.analog_actions() > 1);
555 for(unsigned j = 0; j < ctrl.analog_actions(); j++) {
556 std::string name;
557 if(multi)
558 name = (stringfmt() << "analog" << (j + 1)).str();
559 else
560 name = "analog";
561 std::string cname = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
562 << name).str();
563 if(all_buttons.count(cname)) {
564 active_bind a;
565 a.port = x.first;
566 a.controller = x.second;
567 a.bind = all_buttons[cname];
568 active_buttons[cname] = a;
574 void load_macros(controller_state& ctrlstate)
576 auto s = ctrlstate.enumerate_macro();
577 for(auto i : s) {
578 if(!macro_binds.count(i)) {
579 //New macro, create inverse bind.
580 macro_binds[i] = new keyboard::invbind(lsnes_mapper, "macro " + i , "Macro‣" + i +
581 " (toggle)");
582 macro_binds2[i] = new keyboard::invbind(lsnes_mapper, "+macro " + i , "Macro‣" + i +
583 " (hold)");
586 for(auto i : macro_binds) {
587 if(!s.count(i.first)) {
588 //Removed macro, delete inverse bind.
589 delete macro_binds[i.first];
590 delete macro_binds2[i.first];
591 macro_binds.erase(i.first);
592 macro_binds2.erase(i.first);
597 void load_project_macros(controller_state& ctrlstate, project_info& pinfo)
599 for(auto i : pinfo.macros)
600 try {
601 ctrlstate.set_macro(i.first, controller_macro(i.second));
602 } catch(std::exception& e) {
603 messages << "Unable to load macro " << i.first << ": " << e.what() << std::endl;
605 for(auto i : ctrlstate.enumerate_macro())
606 if(!pinfo.macros.count(i))
607 ctrlstate.erase_macro(i);
608 load_macros(ctrlstate);
611 void cleanup_all_keys()
613 for(auto i : added_keys)
614 delete i.second;
617 std::pair<int, int> controller_by_name(const std::string& name)
619 for(auto i : active_buttons) {
620 std::string _name = (stringfmt() << i.second.bind.cclass << "-" << i.second.bind.number).str();
621 if(name != _name)
622 continue;
623 return std::make_pair(i.second.port, i.second.controller);
625 return std::make_pair(-1, -1);
628 controller_state controls;
629 std::map<std::string, std::string> button_keys;