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/moviedata.hpp"
10 #include "core/window.hpp"
11 #include "interface/romtype.hpp"
12 #include "library/string.hpp"
20 struct controller_bind
25 int mode
; //0 => Button, 1 => Axis pair, 2 => Single axis.
29 unsigned control2
; //Axis only, UINT_MAX if not valid.
39 struct controller_bind bind
;
42 struct controller_triple
47 bool operator<(const struct controller_triple
& t
) const throw()
49 if(cclass
< t
.cclass
) return true;
50 if(cclass
> t
.cclass
) return false;
51 if(port
< t
.port
) return true;
52 if(port
> t
.port
) return false;
53 if(controller
< t
.controller
) return true;
54 if(controller
> t
.controller
) return false;
57 bool operator==(const struct controller_triple
& t
) const throw()
59 return (cclass
== t
.cclass
&& port
== t
.port
&& controller
== t
.controller
);
63 std::map
<std::string
, inverse_bind
*> macro_binds
;
64 std::map
<std::string
, inverse_bind
*> macro_binds2
;
65 std::map
<std::string
, controller_bind
> all_buttons
;
66 std::map
<std::string
, active_bind
> active_buttons
;
67 std::map
<std::string
, controller_key
*> added_keys
;
69 //Promote stored key to active key.
70 void promote_key(controller_key
& k
)
72 std::string name
= k
.get_command();
73 if(added_keys
.count(name
)) {
78 added_keys
[name
] = &k
;
79 if(!button_keys
.count(name
))
81 k
.append(button_keys
[name
]);
82 messages
<< button_keys
[name
] << " bound (button) to " << name
<< std::endl
;
83 button_keys
.erase(name
);
86 //Allocate controller keys for specified button.
87 void add_button(const std::string
& name
, const controller_bind
& binding
)
90 if(binding
.mode
== 0) {
91 k
= new controller_key(lsnes_mapper
, (stringfmt() << "+controller " << name
).str(),
92 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
93 << binding
.name
).str());
95 k
= new controller_key(lsnes_mapper
, (stringfmt() << "hold-controller " << name
).str(),
96 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
97 << binding
.name
<< "‣hold").str());
99 k
= new controller_key(lsnes_mapper
, (stringfmt() << "type-controller " << name
).str(),
100 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
101 << binding
.name
<< "‣type").str());
103 k
= new controller_key(lsnes_mapper
, (stringfmt() << "+autofire-controller " << name
).str(),
104 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
105 << binding
.name
<< "‣autofire").str());
107 k
= new controller_key(lsnes_mapper
, (stringfmt() << "autofire-controller " << name
).str(),
108 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
109 << binding
.name
<< "‣autofire toggle").str());
111 } else if(binding
.mode
== 1) {
112 k
= new controller_key(lsnes_mapper
, (stringfmt() << "designate-position " << name
).str(),
113 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
114 << binding
.name
).str());
116 } else if(binding
.mode
== 2) {
117 k
= new controller_key(lsnes_mapper
, (stringfmt() << "controller-analog " << name
).str(),
118 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
119 << binding
.name
<< " (axis)").str(), true);
124 //Take specified controller info and process it as specified controller of its class.
125 void process_controller(port_controller
& controller
, unsigned number
)
127 unsigned analog_num
= 1;
128 bool multi_analog
= (controller
.analog_actions() > 1);
129 //This controller might be processed already, but perhaps only partially.
130 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
131 if(controller
.buttons
[i
].shadow
)
133 if(controller
.buttons
[i
].type
!= port_controller_button::TYPE_BUTTON
)
135 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
136 << controller
.buttons
[i
].name
).str();
138 b
.cclass
= controller
.cclass
;
140 b
.name
= controller
.buttons
[i
].name
;
142 b
.xrel
= b
.yrel
= false;
144 b
.control2
= std::numeric_limits
<unsigned>::max();
145 if(!all_buttons
.count(name
)) {
146 all_buttons
[name
] = b
;
150 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
151 if(controller
.buttons
[i
].shadow
)
153 if(!controller
.buttons
[i
].is_analog())
155 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
156 << controller
.buttons
[i
].name
).str();
158 b
.cclass
= controller
.cclass
;
160 b
.name
= controller
.buttons
[i
].name
;
161 b
.rmin
= controller
.buttons
[i
].rmin
;
162 b
.rmax
= controller
.buttons
[i
].rmax
;
163 b
.centered
= controller
.buttons
[i
].centers
;
165 b
.xrel
= b
.yrel
= false;
167 b
.control2
= std::numeric_limits
<unsigned>::max();
168 if(!all_buttons
.count(name
)) {
169 all_buttons
[name
] = b
;
173 for(unsigned i
= 0; i
< controller
.analog_actions(); i
++) {
174 auto g
= controller
.analog_action(i
);
175 auto raxis
= port_controller_button::TYPE_RAXIS
;
179 b
.name
= (stringfmt() << "analog" << analog_num
).str();
181 b
.name
= (stringfmt() << "analog").str();
182 name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-" << b
.name
).str();
184 b
.cclass
= controller
.cclass
;
187 b
.xrel
= (g
.first
< controller
.buttons
.size()) &&
188 (controller
.buttons
[g
.first
].type
== raxis
);
189 b
.yrel
= (g
.second
< controller
.buttons
.size()) &&
190 (controller
.buttons
[g
.second
].type
== raxis
);
191 b
.control1
= g
.first
;
192 b
.control2
= g
.second
;
193 if(!all_buttons
.count(name
))
195 if(!all_buttons
.count(name
) ||
196 ((all_buttons
[name
].control2
== std::numeric_limits
<unsigned>::max()) &&
197 (b
.control2
< std::numeric_limits
<unsigned>::max()))) {
198 all_buttons
[name
] = b
;
203 unsigned next_id_from_map(std::map
<std::string
, unsigned>& map
, const std::string
& key
, unsigned base
)
206 return (map
[key
] = base
);
211 //The rules for class number allocations are:
212 //- Different cores allocate numbers independently.
213 //- Within the same core, the allocations for higher port start after the previous port ends.
216 void process_controller(std::map
<std::string
, unsigned>& allocated
,
217 std::map
<controller_triple
, unsigned>& assigned
, port_controller
& controller
, unsigned port
,
218 unsigned number_in_port
)
220 controller_triple key
;
221 key
.cclass
= controller
.cclass
;
223 key
.controller
= number_in_port
;
225 if(!assigned
.count(key
))
226 assigned
[key
] = next_id_from_map(allocated
, controller
.cclass
, 1);
228 process_controller(controller
, n
);
231 void process_port(std::map
<std::string
, unsigned>& allocated
,
232 std::map
<controller_triple
, unsigned>& assigned
, unsigned port
, port_type
& ptype
)
234 //What makes this nasty: Separate ports are always processed, but the same controllers can come
235 //multiple times, including with partial reprocessing.
236 std::map
<std::string
, unsigned> counts
;
237 for(unsigned i
= 0; i
< ptype
.controller_info
->controllers
.size(); i
++) {
238 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
239 //gameboy-gambatte system port).
240 unsigned n
= next_id_from_map(counts
, ptype
.controller_info
->controllers
[i
].cclass
, 1);
241 process_controller(allocated
, assigned
, ptype
.controller_info
->controllers
[i
], port
, n
);
245 void init_buttonmap()
247 static std::set
<core_core
*> done
;
248 std::vector
<port_type
*> ptypes
;
249 for(auto k
: core_core::all_cores()) {
252 std::map
<std::string
, unsigned> allocated
;
253 std::map
<controller_triple
, unsigned> assigned
;
254 auto ptypes
= k
->get_port_types();
255 for(unsigned i
= 0; i
< ptypes
.size(); i
++) {
257 for(unsigned j
= 0; j
< ptypes
.size(); j
++) {
258 if(!ptypes
[j
]->legal(i
))
261 process_port(allocated
, assigned
, i
, *ptypes
[j
]);
270 //Check that button is active.
271 bool check_button_active(const std::string
& name
)
273 if(active_buttons
.count(name
))
275 //This isn't active. check if there are any other active buttons on the thingy and don't complain
277 bool complain
= true;
278 auto ckey
= lsnes_kbd
.get_current_key();
280 auto cb
= lsnes_mapper
.get_controllerkeys_kbdkey(ckey
);
282 regex_results r
= regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i
->get_command());
285 if(active_buttons
.count(r
[1]))
290 messages
<< "No such button " << name
<< std::endl
;
295 void do_button_action(const std::string
& name
, short newstate
, int mode
)
297 if(!all_buttons
.count(name
)) {
298 messages
<< "No such button " << name
<< std::endl
;
301 if(!check_button_active(name
))
303 auto x
= active_buttons
[name
];
308 int16_t nstate
= controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
309 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "hold" : "unhold"))
311 controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
312 notify_autohold_update(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
313 } else if(mode
== 2) {
315 bool nstate
= controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
316 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "type" : "untype"))
318 controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
320 messages
<< "Holding " << name
<< " for the next frame" << std::endl
;
322 messages
<< "Not holding " << name
<< " for the next frame" << std::endl
;
324 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, newstate
? "press" :
327 controls
.button2(x
.port
, x
.controller
, x
.bind
.control1
, newstate
);
331 void send_analog(const std::string
& name
, int32_t x
, int32_t y
)
333 if(!all_buttons
.count(name
)) {
334 messages
<< "No such action " << name
<< std::endl
;
337 if(!check_button_active(name
))
339 auto z
= active_buttons
[name
];
340 if(z
.bind
.mode
!= 1) {
341 std::cerr
<< name
<< " is not a axis." << std::endl
;
344 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "analog"))
346 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control2
, "analog"))
348 auto g2
= get_framebuffer_size();
349 x
= z
.bind
.xrel
? (x
- g2
.first
/ 2) : (x
/ 2);
350 y
= z
.bind
.yrel
? (y
- g2
.second
/ 2) : (y
/ 2);
351 if(z
.bind
.control1
< std::numeric_limits
<unsigned>::max())
352 controls
.analog(z
.port
, z
.controller
, z
.bind
.control1
, x
);
353 if(z
.bind
.control2
< std::numeric_limits
<unsigned>::max())
354 controls
.analog(z
.port
, z
.controller
, z
.bind
.control2
, y
);
357 void do_action(const std::string
& name
, short state
, int mode
)
360 do_button_action(name
, state
, mode
);
362 keyboard_key
* mouse_x
= lsnes_kbd
.try_lookup_key("mouse_x");
363 keyboard_key
* mouse_y
= lsnes_kbd
.try_lookup_key("mouse_y");
364 if(!mouse_x
|| !mouse_y
) {
365 messages
<< "Controller analog function not available without mouse" << std::endl
;
368 send_analog(name
, mouse_x
->get_state(), mouse_y
->get_state());
372 void do_analog_action(const std::string
& a
)
375 regex_results r
= regex("([^ \t]+)[ \t]+(-?[0-9]+)[ \t]*", a
, "Invalid analog action");
376 std::string name
= r
[1];
377 int value
= parse_value
<int>(r
[2]);
378 if(!all_buttons
.count(name
)) {
379 messages
<< "No such button " << name
<< std::endl
;
382 if(!check_button_active(name
))
384 auto x
= active_buttons
[name
];
387 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, "analog"))
389 int rmin
= x
.bind
.rmin
;
390 int rmax
= x
.bind
.rmax
;
391 bool centered
= x
.bind
.centered
;
392 int64_t pvalue
= value
+ 32768;
393 _value
= pvalue
* (rmax
- rmin
) / 65535 + rmin
;
394 controls
.analog(x
.port
, x
.controller
, x
.bind
.control1
, _value
);
397 void do_autofire_action(const std::string
& a
, int mode
)
399 regex_results r
= regex("([^ \t]+)(([ \t]+([0-9]+))?[ \t]+([0-9]+))?[ \t]*", a
,
400 "Invalid autofire parameters");
401 std::string name
= r
[1];
402 std::string _duty
= r
[4];
403 std::string _cyclelen
= r
[5];
404 if(_duty
== "") _duty
= "1";
405 if(_cyclelen
== "") _cyclelen
= "2";
406 uint32_t duty
= parse_value
<uint32_t>(_duty
);
407 uint32_t cyclelen
= parse_value
<uint32_t>(_cyclelen
);
409 throw std::runtime_error("Invalid autofire parameters");
410 if(!all_buttons
.count(name
)) {
411 messages
<< "No such button " << name
<< std::endl
;
414 if(!check_button_active(name
))
416 auto z
= active_buttons
[name
];
417 if(z
.bind
.mode
!= 0) {
418 std::cerr
<< name
<< " is not a button." << std::endl
;
421 auto afire
= controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
);
422 if(mode
== 1 || (mode
== -1 && afire
.first
== 0)) {
424 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, (stringfmt() << "autofire "
425 << duty
<< " " << cyclelen
).str().c_str()))
427 controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
, duty
, cyclelen
);
428 notify_autofire_update(z
.port
, z
.controller
, z
.bind
.control1
, duty
,
430 } else if(mode
== 0 || (mode
== -1 && afire
.first
!= 0)) {
432 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "autofire"))
434 controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
, 0, 1);
435 notify_autofire_update(z
.port
, z
.controller
, z
.bind
.control1
, 0, 1);
439 function_ptr_command
<const std::string
&> button_p(lsnes_cmd
, "+controller", "Press a button",
440 "Syntax: +controller<button>...\nPress a button\n",
441 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
445 function_ptr_command
<const std::string
&> button_r(lsnes_cmd
, "-controller", "Release a button",
446 "Syntax: -controller<button>...\nRelease a button\n",
447 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
451 function_ptr_command
<const std::string
&> button_h(lsnes_cmd
, "hold-controller", "Autohold a button",
452 "Syntax: hold-controller<button>...\nAutohold a button\n",
453 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
457 function_ptr_command
<const std::string
&> button_t(lsnes_cmd
, "type-controller", "Type a button",
458 "Syntax: type-controller<button>...\nType a button\n",
459 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
463 function_ptr_command
<const std::string
&> button_d(lsnes_cmd
, "designate-position", "Set postion",
464 "Syntax: designate-position <button>...\nDesignate position for an axis\n",
465 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
469 function_ptr_command
<const std::string
&> button_ap(lsnes_cmd
, "+autofire-controller", "Start autofire",
470 "Syntax: +autofire-controller<button> [[<duty> ]<cyclelen>]...\nAutofire a button\n",
471 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
472 do_autofire_action(a
, 1);
475 function_ptr_command
<const std::string
&> button_an(lsnes_cmd
, "-autofire-controller", "End autofire",
476 "Syntax: -autofire-controller<button> [[<duty> ]<cyclelen>]...\nEnd Autofire on a button\n",
477 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
478 do_autofire_action(a
, 0);
481 function_ptr_command
<const std::string
&> button_at(lsnes_cmd
, "autofire-controller", "Toggle autofire",
482 "Syntax: autofire-controller<button> [[<duty> ]<cyclelen>]...\nToggle Autofire on a button\n",
483 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
484 do_autofire_action(a
, -1);
487 function_ptr_command
<const std::string
&> button_a(lsnes_cmd
, "controller-analog", "Analog action",
488 "Syntax: controller-analog <button> <axis>\nAnalog action\n",
489 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
493 function_ptr_command
<const std::string
&> macro_t(lsnes_cmd
, "macro", "Toggle a macro",
494 "Syntax: macro <macroname>\nToggle a macro.\n",
495 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
496 controls
.do_macro(a
, 7);
499 function_ptr_command
<const std::string
&> macro_e(lsnes_cmd
, "+macro", "Enable a macro",
500 "Syntax: +macro <macroname>\nEnable a macro.\n",
501 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
502 controls
.do_macro(a
, 5);
505 function_ptr_command
<const std::string
&> macro_d(lsnes_cmd
, "-macro", "Disable a macro",
506 "Syntax: -macro <macroname>\nDisable a macro.\n",
507 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
508 controls
.do_macro(a
, 2);
516 ncore
.set(notify_new_core
, []() { init_buttonmap(); });
518 struct dispatch_target
<> ncore
;
522 void reinitialize_buttonmap()
527 void reread_active_buttons()
529 std::map
<std::string
, unsigned> classnum
;
530 active_buttons
.clear();
531 for(unsigned i
= 0;; i
++) {
532 auto x
= controls
.lcid_to_pcid(i
);
535 const port_type
& pt
= controls
.get_blank().get_port_type(x
.first
);
536 const port_controller
& ctrl
= pt
.controller_info
->controllers
[x
.second
];
537 if(!classnum
.count(ctrl
.cclass
))
538 classnum
[ctrl
.cclass
] = 1;
540 classnum
[ctrl
.cclass
]++;
541 for(unsigned j
= 0; j
< ctrl
.buttons
.size(); j
++) {
542 std::string name
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
543 << ctrl
.buttons
[j
].name
).str();
544 if(all_buttons
.count(name
)) {
547 a
.controller
= x
.second
;
548 a
.bind
= all_buttons
[name
];
549 active_buttons
[name
] = a
;
552 bool multi
= (ctrl
.analog_actions() > 1);
553 for(unsigned j
= 0; j
< ctrl
.analog_actions(); j
++) {
556 name
= (stringfmt() << "analog" << (j
+ 1)).str();
559 std::string cname
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
561 if(all_buttons
.count(cname
)) {
564 a
.controller
= x
.second
;
565 a
.bind
= all_buttons
[cname
];
566 active_buttons
[cname
] = a
;
572 void load_macros(controller_state
& ctrlstate
)
574 auto s
= ctrlstate
.enumerate_macro();
576 if(!macro_binds
.count(i
)) {
577 //New macro, create inverse bind.
578 macro_binds
[i
] = new inverse_bind(lsnes_mapper
, "macro " + i
, "Macro‣" + i
+ " (toggle)");
579 macro_binds2
[i
] = new inverse_bind(lsnes_mapper
, "+macro " + i
, "Macro‣" + i
+ " (hold)");
582 for(auto i
: macro_binds
) {
583 if(!s
.count(i
.first
)) {
584 //Removed macro, delete inverse bind.
585 delete macro_binds
[i
.first
];
586 delete macro_binds2
[i
.first
];
587 macro_binds
.erase(i
.first
);
588 macro_binds2
.erase(i
.first
);
593 void load_project_macros(controller_state
& ctrlstate
, project_info
& pinfo
)
595 for(auto i
: pinfo
.macros
)
597 ctrlstate
.set_macro(i
.first
, controller_macro(i
.second
));
598 } catch(std::exception
& e
) {
599 messages
<< "Unable to load macro " << i
.first
<< ": " << e
.what() << std::endl
;
601 for(auto i
: ctrlstate
.enumerate_macro())
602 if(!pinfo
.macros
.count(i
))
603 ctrlstate
.erase_macro(i
);
604 load_macros(ctrlstate
);
607 void cleanup_all_keys()
609 for(auto i
: added_keys
)
613 std::pair
<int, int> controller_by_name(const std::string
& name
)
615 for(auto i
: active_buttons
) {
616 std::string _name
= (stringfmt() << i
.second
.bind
.cclass
<< "-" << i
.second
.bind
.number
).str();
619 return std::make_pair(i
.second
.port
, i
.second
.controller
);
621 return std::make_pair(-1, -1);
624 controller_state controls
;
625 std::map
<std::string
, std::string
> button_keys
;