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"
21 struct controller_bind
26 int mode
; //0 => Button, 1 => Axis pair, 2 => Single axis.
30 unsigned control2
; //Axis only, UINT_MAX if not valid.
40 struct controller_bind bind
;
43 struct controller_triple
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;
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
)) {
79 added_keys
[name
] = &k
;
80 if(!button_keys
.count(name
))
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());
96 k
= new keyboard::ctrlrkey(lsnes_mapper
, (stringfmt() << "hold-controller " << name
).str(),
97 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
98 << binding
.name
<< "‣hold").str());
100 k
= new keyboard::ctrlrkey(lsnes_mapper
, (stringfmt() << "type-controller " << name
).str(),
101 (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#" << binding
.number
<< "‣"
102 << binding
.name
<< "‣type").str());
104 k
= new keyboard::ctrlrkey(lsnes_mapper
, (stringfmt() << "+autofire-controller "
105 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
106 << binding
.number
<< "‣" << binding
.name
<< "‣autofire").str());
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());
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());
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);
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
)
134 if(controller
.buttons
[i
].type
!= port_controller_button::TYPE_BUTTON
)
136 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
137 << controller
.buttons
[i
].name
).str();
139 b
.cclass
= controller
.cclass
;
141 b
.name
= controller
.buttons
[i
].name
;
143 b
.xrel
= b
.yrel
= false;
145 b
.control2
= std::numeric_limits
<unsigned>::max();
146 if(!all_buttons
.count(name
)) {
147 all_buttons
[name
] = b
;
151 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
152 if(controller
.buttons
[i
].shadow
)
154 if(!controller
.buttons
[i
].is_analog())
156 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
157 << controller
.buttons
[i
].name
).str();
159 b
.cclass
= controller
.cclass
;
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
;
166 b
.xrel
= b
.yrel
= false;
168 b
.control2
= std::numeric_limits
<unsigned>::max();
169 if(!all_buttons
.count(name
)) {
170 all_buttons
[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
;
180 b
.name
= (stringfmt() << "analog" << analog_num
).str();
182 b
.name
= (stringfmt() << "analog").str();
183 name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-" << b
.name
).str();
185 b
.cclass
= controller
.cclass
;
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
))
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
)
207 return (map
[key
] = base
);
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
;
224 key
.controller
= number_in_port
;
226 if(!assigned
.count(key
))
227 assigned
[key
] = next_id_from_map(allocated
, controller
.cclass
, 1);
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()) {
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
++) {
258 for(unsigned j
= 0; j
< ptypes
.size(); j
++) {
259 if(!ptypes
[j
]->legal(i
))
262 process_port(allocated
, assigned
, i
, *ptypes
[j
]);
271 //Check that button is active.
272 bool check_button_active(const std::string
& name
)
274 if(active_buttons
.count(name
))
276 //This isn't active. check if there are any other active buttons on the thingy and don't complain
278 bool complain
= true;
279 auto ckey
= lsnes_kbd
.get_current_key();
281 auto cb
= lsnes_mapper
.get_controllerkeys_kbdkey(ckey
);
283 regex_results r
= regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i
->get_command());
286 if(active_buttons
.count(r
[1]))
291 messages
<< "No such button " << name
<< std::endl
;
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
;
302 if(!check_button_active(name
))
304 auto x
= active_buttons
[name
];
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"))
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) {
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"))
319 controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
321 messages
<< "Holding " << name
<< " for the next frame" << std::endl
;
323 messages
<< "Not holding " << name
<< " for the next frame" << std::endl
;
325 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, newstate
? "press" :
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
;
338 if(!check_button_active(name
))
340 auto z
= active_buttons
[name
];
341 if(z
.bind
.mode
!= 1) {
342 std::cerr
<< name
<< " is not a axis." << std::endl
;
345 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "analog"))
347 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control2
, "analog"))
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
)
361 do_button_action(name
, state
, mode
);
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
;
369 send_analog(name
, mouse_x
->get_state(), mouse_y
->get_state());
373 void do_analog_action(const std::string
& a
)
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
;
383 if(!check_button_active(name
))
385 auto x
= active_buttons
[name
];
388 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, "analog"))
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
);
411 throw std::runtime_error("Invalid autofire parameters");
412 if(!all_buttons
.count(name
)) {
413 messages
<< "No such button " << name
<< std::endl
;
416 if(!check_button_active(name
))
418 auto z
= active_buttons
[name
];
419 if(z
.bind
.mode
!= 0) {
420 std::cerr
<< name
<< " is not a button." << std::endl
;
423 auto afire
= controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
);
424 if(mode
== 1 || (mode
== -1 && afire
.first
== 0)) {
426 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, (stringfmt() << "autofire "
427 << duty
<< " " << cyclelen
).str().c_str()))
429 controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
, duty
, cyclelen
);
430 notify_autofire_update(z
.port
, z
.controller
, z
.bind
.control1
, duty
,
432 } else if(mode
== 0 || (mode
== -1 && afire
.first
!= 0)) {
434 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "autofire"))
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
) {
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
) {
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
) {
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
) {
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
) {
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
) {
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);
518 ncore
.set(notify_new_core
, []() { init_buttonmap(); });
520 struct dispatch::target
<> ncore
;
524 void reinitialize_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
);
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;
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
)) {
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
++) {
558 name
= (stringfmt() << "analog" << (j
+ 1)).str();
561 std::string cname
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
563 if(all_buttons
.count(cname
)) {
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();
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
+
582 macro_binds2
[i
] = new keyboard::invbind(lsnes_mapper
, "+macro " + i
, "Macro‣" + i
+
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
)
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
)
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();
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
;