Fix most hotkeys to show up in configuration (were missing due to errant !)
[lsnes.git] / src / core / controller.cpp
blobc4f89336419191d24ca0caee9858ea7cea4d19be
1 #include "lsnes.hpp"
3 #include "cmdhelp/button.hpp"
4 #include "cmdhelp/macro.hpp"
5 #include "core/command.hpp"
6 #include "core/controller.hpp"
7 #include "core/dispatch.hpp"
8 #include "core/framebuffer.hpp"
9 #include "core/instance.hpp"
10 #include "core/keymapper.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/messages.hpp"
13 #include "core/moviedata.hpp"
14 #include "core/project.hpp"
15 #include "interface/romtype.hpp"
16 #include "library/string.hpp"
17 #include "lua/lua.hpp"
19 #include <map>
20 #include <sstream>
21 #include <string>
23 namespace
25 unsigned next_id_from_map(std::map<std::string, unsigned>& map, const std::string& key, unsigned base)
27 if(!map.count(key))
28 return (map[key] = base);
29 else
30 return ++map[key];
34 button_mapping::button_mapping(controller_state& _controls, keyboard::mapper& _mapper, keyboard::keyboard& _keyboard,
35 emu_framebuffer& _fbuf, emulator_dispatch& _dispatch, lua_state& _lua2, command::group& _cmd)
36 : controls(_controls), mapper(_mapper), keyboard(_keyboard), fbuf(_fbuf), edispatch(_dispatch),
37 lua2(_lua2), cmd(_cmd),
38 button_p(cmd, CBUTTON::p, [this](const std::string& a) { this->do_action(a, 1, 0); }),
39 button_r(cmd, CBUTTON::r, [this](const std::string& a) { this->do_action(a, 0, 0); }),
40 button_h(cmd, CBUTTON::h, [this](const std::string& a) { this->do_action(a, 1, 1); }),
41 button_t(cmd, CBUTTON::t, [this](const std::string& a) { this->do_action(a, 1, 2); }),
42 button_d(cmd, CBUTTON::d, [this](const std::string& a) { this->do_action(a, 0, 3); }),
43 button_ap(cmd, CBUTTON::ap, [this](const std::string& a) { this->do_autofire_action(a, 1); }),
44 button_ar(cmd, CBUTTON::ar, [this](const std::string& a) { this->do_autofire_action(a, 0); }),
45 button_at(cmd, CBUTTON::at, [this](const std::string& a) { this->do_autofire_action(a, -1); }),
46 button_a(cmd, CBUTTON::a, [this](const std::string& a) { this->do_analog_action(a); })
48 ncore.set(notify_new_core, [this]() { this->init(); });
51 button_mapping::~button_mapping()
53 cleanup();
56 void button_mapping::reinit()
58 init();
61 void button_mapping::reread()
63 std::map<std::string, unsigned> classnum;
64 active_buttons.clear();
65 for(unsigned i = 0;; i++) {
66 auto x = controls.lcid_to_pcid(i);
67 if(x.first < 0)
68 break;
69 const portctrl::type& pt = controls.get_blank().get_port_type(x.first);
70 const portctrl::controller& ctrl = pt.controller_info->controllers[x.second];
71 if(!classnum.count(ctrl.cclass))
72 classnum[ctrl.cclass] = 1;
73 else
74 classnum[ctrl.cclass]++;
75 for(unsigned j = 0; j < ctrl.buttons.size(); j++) {
76 std::string name = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
77 << ctrl.buttons[j].name).str();
78 if(all_buttons.count(name)) {
79 button_mapping::active_bind a;
80 a.port = x.first;
81 a.controller = x.second;
82 a.bind = all_buttons[name];
83 active_buttons[name] = a;
86 bool multi = (ctrl.analog_actions() > 1);
87 for(unsigned j = 0; j < ctrl.analog_actions(); j++) {
88 std::string name;
89 if(multi)
90 name = (stringfmt() << "analog" << (j + 1)).str();
91 else
92 name = "analog";
93 std::string cname = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
94 << name).str();
95 if(all_buttons.count(cname)) {
96 button_mapping::active_bind a;
97 a.port = x.first;
98 a.controller = x.second;
99 a.bind = all_buttons[cname];
100 active_buttons[cname] = a;
106 void button_mapping::load(controller_state& ctrlstate)
108 auto s = ctrlstate.enumerate_macro();
109 for(auto i : s) {
110 if(!macro_binds.count(i)) {
111 //New macro, create inverse bind.
112 macro_binds[i] = new keyboard::invbind(mapper, CMACRO::t.name + (" " + i) , "Macro‣" + i +
113 " (toggle)");
114 macro_binds2[i] = new keyboard::invbind(mapper, CMACRO::p.name + (" " + i) , "Macro‣" +
115 i + " (hold)");
118 for(auto i : macro_binds) {
119 if(!s.count(i.first)) {
120 //Removed macro, delete inverse bind.
121 delete macro_binds[i.first];
122 delete macro_binds2[i.first];
123 macro_binds.erase(i.first);
124 macro_binds2.erase(i.first);
129 void button_mapping::load(controller_state& ctrlstate, project_info& pinfo)
131 for(auto i : pinfo.macros)
132 try {
133 ctrlstate.set_macro(i.first, portctrl::macro(i.second));
134 } catch(std::exception& e) {
135 messages << "Unable to load macro " << i.first << ": " << e.what() << std::endl;
137 for(auto i : ctrlstate.enumerate_macro())
138 if(!pinfo.macros.count(i))
139 ctrlstate.erase_macro(i);
140 load(ctrlstate);
143 void button_mapping::cleanup()
145 for(auto i : added_keys)
146 delete i.second;
147 for(auto i : macro_binds)
148 delete i.second;
149 for(auto i : macro_binds2)
150 delete i.second;
151 added_keys.clear();
152 macro_binds.clear();
153 macro_binds2.clear();
156 std::pair<int, int> button_mapping::byname(const std::string& name)
158 for(auto i : active_buttons) {
159 std::string _name = (stringfmt() << i.second.bind.cclass << "-" << i.second.bind.number).str();
160 if(name != _name)
161 continue;
162 return std::make_pair(i.second.port, i.second.controller);
164 return std::make_pair(-1, -1);
167 void button_mapping::promote_key(keyboard::ctrlrkey& k)
169 std::string name = k.get_command();
170 if(added_keys.count(name)) {
171 //Already exists.
172 delete &k;
173 return;
175 added_keys[name] = &k;
176 if(!button_keys.count(name))
177 return;
178 k.append(button_keys[name]);
179 messages << button_keys[name] << " bound (button) to " << name << std::endl;
180 button_keys.erase(name);
183 void button_mapping::add_button(const std::string& name, const button_mapping::controller_bind& binding)
185 keyboard::ctrlrkey* k;
186 if(binding.mode == 0) {
187 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::p.name << " "
188 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
189 << binding.number << "‣" << binding.name).str());
190 promote_key(*k);
191 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::h.name << " "
192 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
193 << binding.number << "‣" << binding.name << "‣hold").str());
194 promote_key(*k);
195 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::t.name << " "
196 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
197 << binding.number << "‣" << binding.name << "‣type").str());
198 promote_key(*k);
199 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::ap.name << " "
200 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
201 << binding.number << "‣" << binding.name << "‣autofire").str());
202 promote_key(*k);
203 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::at.name << " "
204 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
205 << binding.number << "‣" << binding.name << "‣autofire toggle").str());
206 promote_key(*k);
207 } else if(binding.mode == 1) {
208 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::d.name << " "
209 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
210 << binding.number << "‣" << binding.name).str());
211 promote_key(*k);
212 } else if(binding.mode == 2) {
213 k = new keyboard::ctrlrkey(mapper, (stringfmt() << CBUTTON::a.name << " "
214 << name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
215 << binding.number << "‣" << binding.name << " (axis)").str(), true);
216 promote_key(*k);
220 //Take specified controller info and process it as specified controller of its class.
221 void button_mapping::process_controller(portctrl::controller& controller, unsigned number)
223 unsigned analog_num = 1;
224 bool multi_analog = (controller.analog_actions() > 1);
225 //This controller might be processed already, but perhaps only partially.
226 for(unsigned i = 0; i < controller.buttons.size(); i++) {
227 if(controller.buttons[i].shadow)
228 continue;
229 if(controller.buttons[i].type != portctrl::button::TYPE_BUTTON)
230 continue;
231 std::string name = (stringfmt() << controller.cclass << "-" << number << "-"
232 << controller.buttons[i].name).str();
233 button_mapping::controller_bind b;
234 b.cclass = controller.cclass;
235 b.number = number;
236 b.name = controller.buttons[i].name;
237 b.mode = 0;
238 b.xrel = b.yrel = false;
239 b.control1 = i;
240 b.control2 = std::numeric_limits<unsigned>::max();
241 if(!all_buttons.count(name)) {
242 all_buttons[name] = b;
243 add_button(name, b);
246 for(unsigned i = 0; i < controller.buttons.size(); i++) {
247 if(controller.buttons[i].shadow)
248 continue;
249 if(!controller.buttons[i].is_analog())
250 continue;
251 std::string name = (stringfmt() << controller.cclass << "-" << number << "-"
252 << controller.buttons[i].name).str();
253 button_mapping::controller_bind b;
254 b.cclass = controller.cclass;
255 b.number = number;
256 b.name = controller.buttons[i].name;
257 b.rmin = controller.buttons[i].rmin;
258 b.rmax = controller.buttons[i].rmax;
259 b.centered = controller.buttons[i].centers;
260 b.mode = 2;
261 b.xrel = b.yrel = false;
262 b.control1 = i;
263 b.control2 = std::numeric_limits<unsigned>::max();
264 if(!all_buttons.count(name)) {
265 all_buttons[name] = b;
266 add_button(name, b);
269 for(unsigned i = 0; i < controller.analog_actions(); i++) {
270 auto g = controller.analog_action(i);
271 auto raxis = portctrl::button::TYPE_RAXIS;
272 std::string name;
273 button_mapping::controller_bind b;
274 if(multi_analog)
275 b.name = (stringfmt() << "analog" << analog_num).str();
276 else
277 b.name = (stringfmt() << "analog").str();
278 name = (stringfmt() << controller.cclass << "-" << number << "-" << b.name).str();
279 analog_num++;
280 b.cclass = controller.cclass;
281 b.number = number;
282 b.mode = 1;
283 b.xrel = (g.first < controller.buttons.size()) &&
284 (controller.buttons[g.first].type == raxis);
285 b.yrel = (g.second < controller.buttons.size()) &&
286 (controller.buttons[g.second].type == raxis);
287 b.control1 = g.first;
288 b.control2 = g.second;
289 if(!all_buttons.count(name))
290 add_button(name, b);
291 if(!all_buttons.count(name) ||
292 ((all_buttons[name].control2 == std::numeric_limits<unsigned>::max()) &&
293 (b.control2 < std::numeric_limits<unsigned>::max()))) {
294 all_buttons[name] = b;
299 //The rules for class number allocations are:
300 //- Different cores allocate numbers independently.
301 //- Within the same core, the allocations for higher port start after the previous port ends.
302 void button_mapping::process_controller(std::map<std::string, unsigned>& allocated,
303 std::map<controller_triple, unsigned>& assigned, portctrl::controller& controller, unsigned port,
304 unsigned number_in_port)
306 controller_triple key;
307 key.cclass = controller.cclass;
308 key.port = port;
309 key.controller = number_in_port;
310 unsigned n;
311 if(!assigned.count(key))
312 assigned[key] = next_id_from_map(allocated, controller.cclass, 1);
313 n = assigned[key];
314 process_controller(controller, n);
317 void button_mapping::process_port(std::map<std::string, unsigned>& allocated,
318 std::map<controller_triple, unsigned>& assigned, unsigned port, portctrl::type& ptype)
320 //What makes this nasty: Separate ports are always processed, but the same controllers can come
321 //multiple times, including with partial reprocessing.
322 std::map<std::string, unsigned> counts;
323 for(unsigned i = 0; i < ptype.controller_info->controllers.size(); i++) {
324 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
325 //gameboy-gambatte system port).
326 unsigned n = next_id_from_map(counts, ptype.controller_info->controllers[i].cclass, 1);
327 process_controller(allocated, assigned, ptype.controller_info->controllers[i], port, n);
331 void button_mapping::init()
333 std::vector<portctrl::type*> ptypes;
334 for(auto k : core_core::all_cores()) {
335 if(cores_done.count(k))
336 continue;
337 std::map<std::string, unsigned> allocated;
338 std::map<button_mapping::controller_triple, unsigned> assigned;
339 auto ptypes = k->get_port_types();
340 for(unsigned i = 0; i < ptypes.size(); i++) {
341 bool any = false;
342 for(unsigned j = 0; j < ptypes.size(); j++) {
343 if(!ptypes[j]->legal(i))
344 continue;
345 any = true;
346 process_port(allocated, assigned, i, *ptypes[j]);
348 if(!any)
349 break;
351 cores_done.insert(k);
355 //Check that button is active.
356 bool button_mapping::check_button_active(const std::string& name)
358 if(active_buttons.count(name))
359 return true;
360 //This isn't active. check if there are any other active buttons on the thingy and don't complain
361 //if there are.
362 bool complain = true;
363 auto ckey = keyboard.get_current_key();
364 if(ckey) {
365 auto cb = mapper.get_controllerkeys_kbdkey(ckey);
366 for(auto i : cb) {
367 regex_results r = regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i->get_command());
368 if(!r)
369 continue;
370 if(active_buttons.count(r[1]))
371 complain = false;
374 if(complain)
375 messages << "No such button " << name << std::endl;
376 return false;
379 //Do button action.
380 void button_mapping::do_button_action(const std::string& name, short newstate, int mode)
382 if(!all_buttons.count(name)) {
383 messages << "No such button " << name << std::endl;
384 return;
386 if(!check_button_active(name))
387 return;
388 auto x = active_buttons[name];
389 if(x.bind.mode != 0)
390 return;
391 if(mode == 1) {
392 //Autohold.
393 int16_t nstate = controls.autohold2(x.port, x.controller, x.bind.control1) ^ newstate;
394 if(lua2.callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "hold" : "unhold"))
395 return;
396 controls.autohold2(x.port, x.controller, x.bind.control1, nstate);
397 edispatch.autohold_update(x.port, x.controller, x.bind.control1, nstate);
398 } else if(mode == 2) {
399 //Framehold.
400 bool nstate = controls.framehold2(x.port, x.controller, x.bind.control1) ^ newstate;
401 if(lua2.callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "type" : "untype"))
402 return;
403 controls.framehold2(x.port, x.controller, x.bind.control1, nstate);
404 if(nstate)
405 messages << "Holding " << name << " for the next frame" << std::endl;
406 else
407 messages << "Not holding " << name << " for the next frame" << std::endl;
408 } else {
409 if(lua2.callback_do_button(x.port, x.controller, x.bind.control1, newstate ? "press" :
410 "release"))
411 return;
412 controls.button2(x.port, x.controller, x.bind.control1, newstate);
416 void button_mapping::send_analog(const std::string& name, int32_t x, int32_t y)
418 if(!all_buttons.count(name)) {
419 messages << "No such action " << name << std::endl;
420 return;
422 if(!check_button_active(name))
423 return;
424 auto z = active_buttons[name];
425 if(z.bind.mode != 1) {
426 std::cerr << name << " is not a axis." << std::endl;
427 return;
429 if(lua2.callback_do_button(z.port, z.controller, z.bind.control1, "analog"))
430 return;
431 if(lua2.callback_do_button(z.port, z.controller, z.bind.control2, "analog"))
432 return;
433 auto g2 = fbuf.get_framebuffer_size();
434 x = z.bind.xrel ? (x - g2.first / 2) : (x / 2);
435 y = z.bind.yrel ? (y - g2.second / 2) : (y / 2);
436 if(z.bind.control1 < std::numeric_limits<unsigned>::max())
437 controls.analog(z.port, z.controller, z.bind.control1, x);
438 if(z.bind.control2 < std::numeric_limits<unsigned>::max())
439 controls.analog(z.port, z.controller, z.bind.control2, y);
442 void button_mapping::do_action(const std::string& name, short state, int mode)
444 if(mode < 3)
445 do_button_action(name, state, mode);
446 else if(mode == 3) {
447 keyboard::key* mouse_x = keyboard.try_lookup_key("mouse_x");
448 keyboard::key* mouse_y = keyboard.try_lookup_key("mouse_y");
449 if(!mouse_x || !mouse_y) {
450 messages << "Controller analog function not available without mouse" << std::endl;
451 return;
453 send_analog(name, mouse_x->get_state(), mouse_y->get_state());
457 void button_mapping::do_analog_action(const std::string& a)
459 int _value;
460 regex_results r = regex("([^ \t]+)[ \t]+(-?[0-9]+)[ \t]*", a, "Invalid analog action");
461 std::string name = r[1];
462 int value = parse_value<int>(r[2]);
463 if(!all_buttons.count(name)) {
464 messages << "No such button " << name << std::endl;
465 return;
467 if(!check_button_active(name))
468 return;
469 auto x = active_buttons[name];
470 if(x.bind.mode != 2)
471 return;
472 if(lua2.callback_do_button(x.port, x.controller, x.bind.control1, "analog"))
473 return;
474 int rmin = x.bind.rmin;
475 int rmax = x.bind.rmax;
476 //FIXME: Do something with this?
477 //bool centered = x.bind.centered;
478 int64_t pvalue = value + 32768;
479 _value = pvalue * (rmax - rmin) / 65535 + rmin;
480 controls.analog(x.port, x.controller, x.bind.control1, _value);
483 void button_mapping::do_autofire_action(const std::string& a, int mode)
485 regex_results r = regex("([^ \t]+)(([ \t]+([0-9]+))?[ \t]+([0-9]+))?[ \t]*", a,
486 "Invalid autofire parameters");
487 std::string name = r[1];
488 std::string _duty = r[4];
489 std::string _cyclelen = r[5];
490 if(_duty == "") _duty = "1";
491 if(_cyclelen == "") _cyclelen = "2";
492 uint32_t duty = parse_value<uint32_t>(_duty);
493 uint32_t cyclelen = parse_value<uint32_t>(_cyclelen);
494 if(duty >= cyclelen)
495 throw std::runtime_error("Invalid autofire parameters");
496 if(!all_buttons.count(name)) {
497 messages << "No such button " << name << std::endl;
498 return;
500 if(!check_button_active(name))
501 return;
502 auto z = active_buttons[name];
503 if(z.bind.mode != 0) {
504 std::cerr << name << " is not a button." << std::endl;
505 return;
507 auto afire = controls.autofire2(z.port, z.controller, z.bind.control1);
508 if(mode == 1 || (mode == -1 && afire.first == 0)) {
509 //Turn on.
510 if(lua2.callback_do_button(z.port, z.controller, z.bind.control1, (stringfmt() << "autofire "
511 << duty << " " << cyclelen).str().c_str()))
512 return;
513 controls.autofire2(z.port, z.controller, z.bind.control1, duty, cyclelen);
514 edispatch.autofire_update(z.port, z.controller, z.bind.control1, duty, cyclelen);
515 } else if(mode == 0 || (mode == -1 && afire.first != 0)) {
516 //Turn off.
517 if(lua2.callback_do_button(z.port, z.controller, z.bind.control1, "autofire"))
518 return;
519 controls.autofire2(z.port, z.controller, z.bind.control1, 0, 1);
520 edispatch.autofire_update(z.port, z.controller, z.bind.control1, 0, 1);