Merge branch 'rr1-maint'
[lsnes.git] / src / core / controller.cpp
blob13580993a7db4455e9097bc4e30291c1c3ee1357
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/mainloop.hpp"
8 #include "core/misc.hpp"
9 #include "core/window.hpp"
10 #include "interface/romtype.hpp"
11 #include "library/string.hpp"
13 #include <map>
14 #include <sstream>
15 #include <string>
17 namespace
19 struct controller_bind
21 std::string cclass;
22 unsigned number;
23 std::string name;
24 bool is_axis;
25 bool xrel;
26 bool yrel;
27 unsigned control1;
28 unsigned control2; //Axis only, UINT_MAX if not valid.
31 struct active_bind
33 unsigned port;
34 unsigned controller;
35 struct controller_bind bind;
38 struct controller_triple
40 std::string cclass;
41 unsigned port;
42 unsigned controller;
43 bool operator<(const struct controller_triple& t) const throw()
45 if(cclass < t.cclass) return true;
46 if(cclass > t.cclass) return false;
47 if(port < t.port) return true;
48 if(port > t.port) return false;
49 if(controller < t.controller) return true;
50 if(controller > t.controller) return false;
51 return false;
53 bool operator==(const struct controller_triple& t) const throw()
55 return (cclass == t.cclass && port == t.port && controller == t.controller);
59 std::map<std::string, controller_bind> all_buttons;
60 std::map<std::string, active_bind> active_buttons;
62 //Promote stored key to active key.
63 void promote_key(controller_key& k)
65 std::string name = k.get_command();
66 if(!button_keys.count(name))
67 return;
68 k.set(button_keys[name]);
69 messages << button_keys[name] << " bound (button) to " << name << std::endl;
70 button_keys.erase(name);
73 //Allocate controller keys for specified button.
74 void add_button(const std::string& name, const controller_bind& binding)
76 controller_key* k;
77 if(!binding.is_axis) {
78 k = new controller_key(lsnes_mapper, (stringfmt() << "+controller " << name).str(),
79 (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣"
80 << binding.name).str());
81 promote_key(*k);
82 k = new controller_key(lsnes_mapper, (stringfmt() << "hold-controller " << name).str(),
83 (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣"
84 << binding.name << " (hold)").str());
85 promote_key(*k);
86 k = new controller_key(lsnes_mapper, (stringfmt() << "type-controller " << name).str(),
87 (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣"
88 << binding.name << " (type)").str());
89 promote_key(*k);
90 } else {
91 k = new controller_key(lsnes_mapper, (stringfmt() << "designate-position " << name).str(),
92 (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣"
93 << binding.name).str());
94 promote_key(*k);
98 //Take specified controller info and process it as specified controller of its class.
99 void process_controller(port_controller& controller, unsigned number)
101 unsigned analog_num = 1;
102 bool multi_analog = (controller.analog_actions() > 1);
103 //This controller might be processed already, but perhaps only partially.
104 for(unsigned i = 0; i < controller.button_count; i++) {
105 if(controller.buttons[i]->shadow)
106 continue;
107 if(controller.buttons[i]->type != port_controller_button::TYPE_BUTTON)
108 continue;
109 std::string name = (stringfmt() << controller.cclass << "-" << number << "-"
110 << controller.buttons[i]->name).str();
111 controller_bind b;
112 b.cclass = controller.cclass;
113 b.number = number;
114 b.name = controller.buttons[i]->name;
115 b.is_axis = false;
116 b.xrel = b.yrel = false;
117 b.control1 = i;
118 b.control2 = std::numeric_limits<unsigned>::max();
119 if(!all_buttons.count(name)) {
120 all_buttons[name] = b;
121 add_button(name, b);
124 for(unsigned i = 0; i < controller.analog_actions(); i++) {
125 auto g = controller.analog_action(i);
126 auto raxis = port_controller_button::TYPE_RAXIS;
127 std::string name;
128 controller_bind b;
129 if(multi_analog)
130 b.name = (stringfmt() << "analog" << analog_num).str();
131 else
132 b.name = (stringfmt() << "analog").str();
133 name = (stringfmt() << controller.cclass << "-" << number << "-" << b.name).str();
134 analog_num++;
135 b.cclass = controller.cclass;
136 b.number = number;
137 b.is_axis = true;
138 b.xrel = (g.first < controller.button_count) &&
139 (controller.buttons[g.first]->type == raxis);
140 b.yrel = (g.second < controller.button_count) &&
141 (controller.buttons[g.second]->type == raxis);
142 b.control1 = g.first;
143 b.control2 = g.second;
144 if(!all_buttons.count(name))
145 add_button(name, b);
146 if(!all_buttons.count(name) ||
147 ((all_buttons[name].control2 == std::numeric_limits<unsigned>::max()) &&
148 (b.control2 < std::numeric_limits<unsigned>::max()))) {
149 all_buttons[name] = b;
154 unsigned next_id_from_map(std::map<std::string, unsigned>& map, const std::string& key, unsigned base)
156 if(!map.count(key))
157 return (map[key] = base);
158 else
159 return ++map[key];
162 //The rules for class number allocations are:
163 //- Different cores allocate numbers independently.
164 //- Within the same core, the allocations for higher port start after the previous port ends.
167 void process_controller(std::map<std::string, unsigned>& allocated,
168 std::map<controller_triple, unsigned>& assigned, port_controller& controller, unsigned port,
169 unsigned number_in_port)
171 controller_triple key;
172 key.cclass = controller.cclass;
173 key.port = port;
174 key.controller = number_in_port;
175 unsigned n;
176 if(!assigned.count(key))
177 assigned[key] = next_id_from_map(allocated, controller.cclass, 1);
178 n = assigned[key];
179 process_controller(controller, n);
182 void process_port(std::map<std::string, unsigned>& allocated,
183 std::map<controller_triple, unsigned>& assigned, unsigned port, port_type& ptype)
185 //What makes this nasty: Separate ports are always processed, but the same controllers can come
186 //multiple times, including with partial reprocessing.
187 std::map<std::string, unsigned> counts;
188 for(unsigned i = 0; i < ptype.controller_info->controller_count; i++) {
189 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
190 //gameboy-gambatte system port).
191 unsigned n = next_id_from_map(counts, ptype.controller_info->controllers[i]->cclass, 1);
192 process_controller(allocated, assigned, *ptype.controller_info->controllers[i], port, n);
196 void init_buttonmap()
198 static std::set<core_core*> done;
199 std::vector<port_type*> ptypes;
200 for(auto k : core_core::all_cores()) {
201 if(done.count(k))
202 continue;
203 std::map<std::string, unsigned> allocated;
204 std::map<controller_triple, unsigned> assigned;
205 auto ptypes = k->get_port_types();
206 for(unsigned i = 0;; i++) {
207 bool any = false;
208 for(unsigned j = 0; ptypes[j]; j++) {
209 if(!ptypes[j]->legal(i))
210 continue;
211 any = true;
212 process_port(allocated, assigned, i, *ptypes[j]);
214 if(!any)
215 break;
217 done.insert(k);
221 //Do button action.
222 void do_button_action(const std::string& name, short newstate, int mode)
224 if(!all_buttons.count(name)) {
225 messages << "No such button " << name << std::endl;
226 return;
228 if(!active_buttons.count(name))
229 return;
230 auto x = active_buttons[name];
231 if(x.bind.is_axis)
232 return;
233 if(mode == 1) {
234 //Autohold.
235 int16_t nstate = controls.autohold2(x.port, x.controller, x.bind.control1) ^ newstate;
236 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "hold" : "unhold"))
237 return;
238 controls.autohold2(x.port, x.controller, x.bind.control1, nstate);
239 information_dispatch::do_autohold_update(x.port, x.controller, x.bind.control1,
240 controls.autohold2(x.port, x.controller, x.bind.control1));
241 } else if(mode == 2) {
242 //Framehold.
243 bool nstate = controls.framehold2(x.port, x.controller, x.bind.control1) ^ newstate;
244 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "type" : "untype"))
245 return;
246 controls.framehold2(x.port, x.controller, x.bind.control1, nstate);
247 if(nstate)
248 messages << "Holding " << name << " for the next frame" << std::endl;
249 else
250 messages << "Not holding " << name << " for the next frame" << std::endl;
251 } else {
252 if(lua_callback_do_button(x.port, x.controller, x.bind.control1, newstate ? "press" :
253 "release"))
254 return;
255 controls.button2(x.port, x.controller, x.bind.control1, newstate);
259 void send_analog(const std::string& name, int32_t x, int32_t y)
261 if(!all_buttons.count(name)) {
262 messages << "No such action " << name << std::endl;
263 return;
265 if(!active_buttons.count(name))
266 return;
267 auto z = active_buttons[name];
268 if(!z.bind.is_axis) {
269 std::cerr << name << " is not a axis." << std::endl;
270 return;
272 if(lua_callback_do_button(z.port, z.controller, z.bind.control1, "analog"))
273 return;
274 if(lua_callback_do_button(z.port, z.controller, z.bind.control2, "analog"))
275 return;
276 auto g2 = get_framebuffer_size();
277 x = z.bind.xrel ? (x - g2.first / 2) : (x / 2);
278 y = z.bind.yrel ? (y - g2.second / 2) : (y / 2);
279 if(z.bind.control1 < std::numeric_limits<unsigned>::max())
280 controls.analog(z.port, z.controller, z.bind.control1, x);
281 if(z.bind.control2 < std::numeric_limits<unsigned>::max())
282 controls.analog(z.port, z.controller, z.bind.control2, y);
285 function_ptr_command<const std::string&> autofire(lsnes_cmd, "autofire", "Set autofire pattern",
286 "Syntax: autofire <buttons|->...\nSet autofire pattern\n",
287 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
288 auto r = regex(".*[^ \t].*", a, "Need at least one frame for autofire");
289 std::vector<controller_frame> new_autofire_pattern;
290 init_buttonmap();
291 std::string pattern = a;
292 while(pattern != "") {
293 std::string fpattern;
294 extract_token(pattern, fpattern, " \t", true);
295 if(fpattern == "-")
296 new_autofire_pattern.push_back(controls.get_blank());
297 else {
298 controller_frame c(controls.get_blank());
299 while(fpattern != "") {
300 size_t split = fpattern.find_first_of(",");
301 std::string button = fpattern;
302 std::string rest;
303 if(split < fpattern.length()) {
304 button = fpattern.substr(0, split);
305 rest = fpattern.substr(split + 1);
307 if(!active_buttons.count(button))
308 (stringfmt() << "Invalid button '" << button << "'").throwex();
309 auto g = active_buttons[button];
310 if(g.bind.is_axis)
311 (stringfmt() << "Invalid button '" << button << "'").throwex();
312 c.axis3(g.port, g.controller, g.bind.control1, true);
313 fpattern = rest;
315 new_autofire_pattern.push_back(c);
318 controls.autofire(new_autofire_pattern);
321 void do_action(const std::string& name, short state, int mode)
323 if(mode < 3)
324 do_button_action(name, state, mode);
325 else if(mode == 3) {
326 keyboard_key* mouse_x = lsnes_kbd.try_lookup_key("mouse_x");
327 keyboard_key* mouse_y = lsnes_kbd.try_lookup_key("mouse_y");
328 if(!mouse_x || !mouse_y) {
329 messages << "Controller analog function not available without mouse" << std::endl;
330 return;
332 send_analog(name, mouse_x->get_state(), mouse_y->get_state());
336 function_ptr_command<const std::string&> button_p(lsnes_cmd, "+controller", "Press a button",
337 "Syntax: +button <button>...\nPress a button\n",
338 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
339 do_action(a, 1, 0);
342 function_ptr_command<const std::string&> button_r(lsnes_cmd, "-controller", "Release a button",
343 "Syntax: -button <button>...\nRelease a button\n",
344 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
345 do_action(a, 0, 0);
348 function_ptr_command<const std::string&> button_h(lsnes_cmd, "hold-controller", "Autohold a button",
349 "Syntax: hold-button <button>...\nAutohold a button\n",
350 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
351 do_action(a, 1, 1);
354 function_ptr_command<const std::string&> button_t(lsnes_cmd, "type-controller", "Type a button",
355 "Syntax: type-button <button>...\nType a button\n",
356 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
357 do_action(a, 1, 2);
360 function_ptr_command<const std::string&> button_d(lsnes_cmd, "designate-position", "Set postion",
361 "Syntax: designate-position <button>...\nDesignate position for an axis\n",
362 [](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
363 do_action(a, 0, 3);
366 class new_core_snoop : public information_dispatch
368 public:
369 new_core_snoop() : information_dispatch("controller-newcore")
372 void on_new_core()
374 init_buttonmap();
376 } coresnoop;
379 void reinitialize_buttonmap()
381 init_buttonmap();
384 void reread_active_buttons()
386 std::map<std::string, unsigned> classnum;
387 active_buttons.clear();
388 for(unsigned i = 0;; i++) {
389 auto x = controls.lcid_to_pcid(i);
390 if(x.first < 0)
391 break;
392 const port_type& pt = controls.get_blank().get_port_type(x.first);
393 const port_controller& ctrl = *pt.controller_info->controllers[x.second];
394 if(!classnum.count(ctrl.cclass))
395 classnum[ctrl.cclass] = 1;
396 else
397 classnum[ctrl.cclass]++;
398 for(unsigned j = 0; j < ctrl.button_count; j++) {
399 std::string name = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
400 << ctrl.buttons[j]->name).str();
401 if(all_buttons.count(name)) {
402 active_bind a;
403 a.port = x.first;
404 a.controller = x.second;
405 a.bind = all_buttons[name];
406 active_buttons[name] = a;
409 bool multi = (ctrl.analog_actions() > 1);
410 for(unsigned j = 0; j < ctrl.analog_actions(); j++) {
411 std::string name;
412 if(multi)
413 name = (stringfmt() << "analog" << (j + 1)).str();
414 else
415 name = "analog";
416 std::string cname = (stringfmt() << ctrl.cclass << "-" << classnum[ctrl.cclass] << "-"
417 << name).str();
418 if(all_buttons.count(cname)) {
419 active_bind a;
420 a.port = x.first;
421 a.controller = x.second;
422 a.bind = all_buttons[cname];
423 active_buttons[cname] = a;
429 controller_state controls;
430 std::map<std::string, std::string> button_keys;