3 #include "cmdhelp/button.hpp"
4 #include "cmdhelp/macro.hpp"
5 #include "cmdhelp/buttonmode.hpp"
6 #include "core/command.hpp"
7 #include "core/controller.hpp"
8 #include "core/dispatch.hpp"
9 #include "core/framebuffer.hpp"
10 #include "core/instance.hpp"
11 #include "core/keymapper.hpp"
12 #include "core/mainloop.hpp"
13 #include "core/messages.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/project.hpp"
16 #include "interface/romtype.hpp"
17 #include "library/string.hpp"
18 #include "lua/lua.hpp"
26 unsigned next_id_from_map(std::map
<std::string
, unsigned>& map
, const std::string
& key
, unsigned base
)
29 return (map
[key
] = base
);
35 button_mapping::button_mapping(controller_state
& _controls
, keyboard::mapper
& _mapper
, keyboard::keyboard
& _keyboard
,
36 emu_framebuffer
& _fbuf
, emulator_dispatch
& _dispatch
, lua_state
& _lua2
, command::group
& _cmd
)
37 : controls(_controls
), mapper(_mapper
), keyboard(_keyboard
), fbuf(_fbuf
), edispatch(_dispatch
),
38 lua2(_lua2
), cmd(_cmd
),
39 button_p(cmd
, CBUTTON::p
, [this](const std::string
& a
) { this->do_action(a
, 1, 0); }),
40 button_r(cmd
, CBUTTON::r
, [this](const std::string
& a
) { this->do_action(a
, 0, 0); }),
41 button_h(cmd
, CBUTTON::h
, [this](const std::string
& a
) { this->do_action(a
, 1, 1); }),
42 button_t(cmd
, CBUTTON::t
, [this](const std::string
& a
) { this->do_action(a
, 1, 2); }),
43 button_d(cmd
, CBUTTON::d
, [this](const std::string
& a
) { this->do_action(a
, 0, 3); }),
44 button_ap(cmd
, CBUTTON::ap
, [this](const std::string
& a
) { this->do_autofire_action(a
, 1); }),
45 button_ar(cmd
, CBUTTON::ar
, [this](const std::string
& a
) { this->do_autofire_action(a
, 0); }),
46 button_at(cmd
, CBUTTON::at
, [this](const std::string
& a
) { this->do_autofire_action(a
, -1); }),
47 button_a(cmd
, CBUTTON::a
, [this](const std::string
& a
) { this->do_analog_action(a
); }),
48 afire_p(cmd
, BMODE::afp
, [this]() { this->promote_autofire
= true; }),
49 afire_n(cmd
, BMODE::afn
, [this]() { this->promote_autofire
= false; }),
50 ahold_p(cmd
, BMODE::ahp
, [this]() { this->promote_autohold
= true; }),
51 ahold_n(cmd
, BMODE::ahn
, [this]() { this->promote_autohold
= false; }),
52 typed_p(cmd
, BMODE::atp
, [this]() { this->promote_typed
= true; }),
53 typed_n(cmd
, BMODE::atn
, [this]() { this->promote_typed
= false; })
55 ncore
.set(notify_new_core
, [this]() { this->init(); });
58 button_mapping::~button_mapping()
63 void button_mapping::reinit()
68 void button_mapping::reread()
70 std::map
<std::string
, unsigned> classnum
;
71 active_buttons
.clear();
72 for(unsigned i
= 0;; i
++) {
73 auto x
= controls
.lcid_to_pcid(i
);
76 const portctrl::type
& pt
= controls
.get_blank().get_port_type(x
.first
);
77 const portctrl::controller
& ctrl
= pt
.controller_info
->controllers
[x
.second
];
78 if(!classnum
.count(ctrl
.cclass
))
79 classnum
[ctrl
.cclass
] = 1;
81 classnum
[ctrl
.cclass
]++;
82 for(unsigned j
= 0; j
< ctrl
.buttons
.size(); j
++) {
83 std::string name
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
84 << ctrl
.buttons
[j
].name
).str();
85 if(all_buttons
.count(name
)) {
86 button_mapping::active_bind a
;
88 a
.controller
= x
.second
;
89 a
.bind
= all_buttons
[name
];
90 active_buttons
[name
] = a
;
93 bool multi
= (ctrl
.analog_actions() > 1);
94 for(unsigned j
= 0; j
< ctrl
.analog_actions(); j
++) {
97 name
= (stringfmt() << "analog" << (j
+ 1)).str();
100 std::string cname
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
102 if(all_buttons
.count(cname
)) {
103 button_mapping::active_bind a
;
105 a
.controller
= x
.second
;
106 a
.bind
= all_buttons
[cname
];
107 active_buttons
[cname
] = a
;
113 void button_mapping::load(controller_state
& ctrlstate
)
115 auto s
= ctrlstate
.enumerate_macro();
117 if(!macro_binds
.count(i
)) {
118 //New macro, create inverse bind.
119 macro_binds
[i
] = new keyboard::invbind(mapper
, CMACRO::t
.name
+ (" " + i
) , "Macro‣" + i
+
121 macro_binds2
[i
] = new keyboard::invbind(mapper
, CMACRO::p
.name
+ (" " + i
) , "Macro‣" +
125 for(auto i
: macro_binds
) {
126 if(!s
.count(i
.first
)) {
127 //Removed macro, delete inverse bind.
128 delete macro_binds
[i
.first
];
129 delete macro_binds2
[i
.first
];
130 macro_binds
.erase(i
.first
);
131 macro_binds2
.erase(i
.first
);
136 void button_mapping::load(controller_state
& ctrlstate
, project_info
& pinfo
)
138 for(auto i
: pinfo
.macros
)
140 ctrlstate
.set_macro(i
.first
, portctrl::macro(i
.second
));
141 } catch(std::exception
& e
) {
142 messages
<< "Unable to load macro " << i
.first
<< ": " << e
.what() << std::endl
;
144 for(auto i
: ctrlstate
.enumerate_macro())
145 if(!pinfo
.macros
.count(i
))
146 ctrlstate
.erase_macro(i
);
150 void button_mapping::cleanup()
152 for(auto i
: added_keys
)
154 for(auto i
: macro_binds
)
156 for(auto i
: macro_binds2
)
160 macro_binds2
.clear();
163 std::pair
<int, int> button_mapping::byname(const std::string
& name
)
165 for(auto i
: active_buttons
) {
166 std::string _name
= (stringfmt() << i
.second
.bind
.cclass
<< "-" << i
.second
.bind
.number
).str();
169 return std::make_pair(i
.second
.port
, i
.second
.controller
);
171 return std::make_pair(-1, -1);
174 void button_mapping::promote_key(keyboard::ctrlrkey
& k
)
176 std::string name
= k
.get_command();
177 if(added_keys
.count(name
)) {
182 added_keys
[name
] = &k
;
183 if(!button_keys
.count(name
))
185 k
.append(button_keys
[name
]);
186 messages
<< button_keys
[name
] << " bound (button) to " << name
<< std::endl
;
187 button_keys
.erase(name
);
190 void button_mapping::add_button(const std::string
& name
, const button_mapping::controller_bind
& binding
)
192 keyboard::ctrlrkey
* k
;
193 if(binding
.mode
== 0) {
194 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::p
.name
<< " "
195 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
196 << binding
.number
<< "‣" << binding
.name
).str());
198 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::h
.name
<< " "
199 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
200 << binding
.number
<< "‣" << binding
.name
<< "‣hold").str());
202 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::t
.name
<< " "
203 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
204 << binding
.number
<< "‣" << binding
.name
<< "‣type").str());
206 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::ap
.name
<< " "
207 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
208 << binding
.number
<< "‣" << binding
.name
<< "‣autofire").str());
210 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::at
.name
<< " "
211 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
212 << binding
.number
<< "‣" << binding
.name
<< "‣autofire toggle").str());
214 } else if(binding
.mode
== 1) {
215 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::d
.name
<< " "
216 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
217 << binding
.number
<< "‣" << binding
.name
).str());
219 } else if(binding
.mode
== 2) {
220 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::a
.name
<< " "
221 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
222 << binding
.number
<< "‣" << binding
.name
<< " (axis)").str(), true);
227 //Take specified controller info and process it as specified controller of its class.
228 void button_mapping::process_controller(portctrl::controller
& controller
, unsigned number
)
230 unsigned analog_num
= 1;
231 bool multi_analog
= (controller
.analog_actions() > 1);
232 //This controller might be processed already, but perhaps only partially.
233 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
234 if(controller
.buttons
[i
].shadow
)
236 if(controller
.buttons
[i
].type
!= portctrl::button::TYPE_BUTTON
)
238 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
239 << controller
.buttons
[i
].name
).str();
240 button_mapping::controller_bind b
;
241 b
.cclass
= controller
.cclass
;
243 b
.name
= controller
.buttons
[i
].name
;
245 b
.xrel
= b
.yrel
= false;
247 b
.control2
= std::numeric_limits
<unsigned>::max();
248 if(!all_buttons
.count(name
)) {
249 all_buttons
[name
] = b
;
253 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
254 if(controller
.buttons
[i
].shadow
)
256 if(!controller
.buttons
[i
].is_analog())
258 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
259 << controller
.buttons
[i
].name
).str();
260 button_mapping::controller_bind b
;
261 b
.cclass
= controller
.cclass
;
263 b
.name
= controller
.buttons
[i
].name
;
264 b
.rmin
= controller
.buttons
[i
].rmin
;
265 b
.rmax
= controller
.buttons
[i
].rmax
;
266 b
.centered
= controller
.buttons
[i
].centers
;
268 b
.xrel
= b
.yrel
= false;
270 b
.control2
= std::numeric_limits
<unsigned>::max();
271 if(!all_buttons
.count(name
)) {
272 all_buttons
[name
] = b
;
276 for(unsigned i
= 0; i
< controller
.analog_actions(); i
++) {
277 auto g
= controller
.analog_action(i
);
278 auto raxis
= portctrl::button::TYPE_RAXIS
;
280 button_mapping::controller_bind b
;
282 b
.name
= (stringfmt() << "analog" << analog_num
).str();
284 b
.name
= (stringfmt() << "analog").str();
285 name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-" << b
.name
).str();
287 b
.cclass
= controller
.cclass
;
290 b
.xrel
= (g
.first
< controller
.buttons
.size()) &&
291 (controller
.buttons
[g
.first
].type
== raxis
);
292 b
.yrel
= (g
.second
< controller
.buttons
.size()) &&
293 (controller
.buttons
[g
.second
].type
== raxis
);
294 b
.control1
= g
.first
;
295 b
.control2
= g
.second
;
296 if(!all_buttons
.count(name
))
298 if(!all_buttons
.count(name
) ||
299 ((all_buttons
[name
].control2
== std::numeric_limits
<unsigned>::max()) &&
300 (b
.control2
< std::numeric_limits
<unsigned>::max()))) {
301 all_buttons
[name
] = b
;
306 //The rules for class number allocations are:
307 //- Different cores allocate numbers independently.
308 //- Within the same core, the allocations for higher port start after the previous port ends.
309 void button_mapping::process_controller(std::map
<std::string
, unsigned>& allocated
,
310 std::map
<controller_triple
, unsigned>& assigned
, portctrl::controller
& controller
, unsigned port
,
311 unsigned number_in_port
)
313 controller_triple key
;
314 key
.cclass
= controller
.cclass
;
316 key
.controller
= number_in_port
;
318 if(!assigned
.count(key
))
319 assigned
[key
] = next_id_from_map(allocated
, controller
.cclass
, 1);
321 process_controller(controller
, n
);
324 void button_mapping::process_port(std::map
<std::string
, unsigned>& allocated
,
325 std::map
<controller_triple
, unsigned>& assigned
, unsigned port
, portctrl::type
& ptype
)
327 //What makes this nasty: Separate ports are always processed, but the same controllers can come
328 //multiple times, including with partial reprocessing.
329 std::map
<std::string
, unsigned> counts
;
330 for(unsigned i
= 0; i
< ptype
.controller_info
->controllers
.size(); i
++) {
331 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
332 //gameboy-gambatte system port).
333 unsigned n
= next_id_from_map(counts
, ptype
.controller_info
->controllers
[i
].cclass
, 1);
334 process_controller(allocated
, assigned
, ptype
.controller_info
->controllers
[i
], port
, n
);
338 void button_mapping::init()
340 std::vector
<portctrl::type
*> ptypes
;
341 for(auto k
: core_core::all_cores()) {
342 if(cores_done
.count(k
))
344 std::map
<std::string
, unsigned> allocated
;
345 std::map
<button_mapping::controller_triple
, unsigned> assigned
;
346 auto ptypes
= k
->get_port_types();
347 for(unsigned i
= 0; i
< ptypes
.size(); i
++) {
349 for(unsigned j
= 0; j
< ptypes
.size(); j
++) {
350 if(!ptypes
[j
]->legal(i
))
353 process_port(allocated
, assigned
, i
, *ptypes
[j
]);
358 cores_done
.insert(k
);
362 //Check that button is active.
363 bool button_mapping::check_button_active(const std::string
& name
)
365 if(active_buttons
.count(name
))
367 //This isn't active. check if there are any other active buttons on the thingy and don't complain
369 bool complain
= true;
370 auto ckey
= keyboard
.get_current_key();
372 auto cb
= mapper
.get_controllerkeys_kbdkey(ckey
);
374 regex_results r
= regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i
->get_command());
377 if(active_buttons
.count(r
[1]))
382 messages
<< "No such button " << name
<< std::endl
;
387 void button_mapping::do_button_action(const std::string
& name
, short newstate
, int mode
)
389 if(!all_buttons
.count(name
)) {
390 messages
<< "No such button " << name
<< std::endl
;
393 if(!check_button_active(name
))
395 auto x
= active_buttons
[name
];
398 if(mode
== 0 && newstate
== 1 && promote_autofire
) {
399 this->do_autofire_action(name
, -1);
401 if(mode
== 1 || (mode
== 0 && promote_autohold
&& newstate
== 1)) {
403 int16_t nstate
= controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
404 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "hold" : "unhold"))
406 controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
407 edispatch
.autohold_update(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
409 messages
<< "Holding " << name
<< std::endl
;
411 messages
<< "Not holding " << name
<< std::endl
;
413 if(mode
== 2 || (mode
== 0 && promote_typed
&& newstate
== 1)) {
415 bool nstate
= controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
416 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "type" : "untype"))
418 controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
420 messages
<< "Holding " << name
<< " for the next frame" << std::endl
;
422 messages
<< "Not holding " << name
<< " for the next frame" << std::endl
;
424 if(mode
== 0 && !promote_autohold
&& !promote_autofire
&& !promote_typed
) {
425 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, newstate
? "press" :
428 controls
.button2(x
.port
, x
.controller
, x
.bind
.control1
, newstate
);
432 void button_mapping::send_analog(const std::string
& name
, int32_t x
, int32_t y
)
434 if(!all_buttons
.count(name
)) {
435 messages
<< "No such action " << name
<< std::endl
;
438 if(!check_button_active(name
))
440 auto z
= active_buttons
[name
];
441 if(z
.bind
.mode
!= 1) {
442 std::cerr
<< name
<< " is not a axis." << std::endl
;
445 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "analog"))
447 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control2
, "analog"))
449 auto g2
= fbuf
.get_framebuffer_size();
450 x
= z
.bind
.xrel
? (x
- g2
.first
/ 2) : (x
/ 2);
451 y
= z
.bind
.yrel
? (y
- g2
.second
/ 2) : (y
/ 2);
452 if(z
.bind
.control1
< std::numeric_limits
<unsigned>::max())
453 controls
.analog(z
.port
, z
.controller
, z
.bind
.control1
, x
);
454 if(z
.bind
.control2
< std::numeric_limits
<unsigned>::max())
455 controls
.analog(z
.port
, z
.controller
, z
.bind
.control2
, y
);
458 void button_mapping::do_action(const std::string
& name
, short state
, int mode
)
461 do_button_action(name
, state
, mode
);
463 keyboard::key
* mouse_x
= keyboard
.try_lookup_key("mouse_x");
464 keyboard::key
* mouse_y
= keyboard
.try_lookup_key("mouse_y");
465 if(!mouse_x
|| !mouse_y
) {
466 messages
<< "Controller analog function not available without mouse" << std::endl
;
469 send_analog(name
, mouse_x
->get_state(), mouse_y
->get_state());
473 void button_mapping::do_analog_action(const std::string
& a
)
476 regex_results r
= regex("([^ \t]+)[ \t]+(-?[0-9]+)[ \t]*", a
, "Invalid analog action");
477 std::string name
= r
[1];
478 int value
= parse_value
<int>(r
[2]);
479 if(!all_buttons
.count(name
)) {
480 messages
<< "No such button " << name
<< std::endl
;
483 if(!check_button_active(name
))
485 auto x
= active_buttons
[name
];
488 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, "analog"))
490 int rmin
= x
.bind
.rmin
;
491 int rmax
= x
.bind
.rmax
;
492 //FIXME: Do something with this?
493 //bool centered = x.bind.centered;
494 int64_t pvalue
= value
+ 32768;
495 _value
= pvalue
* (rmax
- rmin
) / 65535 + rmin
;
496 controls
.analog(x
.port
, x
.controller
, x
.bind
.control1
, _value
);
499 void button_mapping::do_autofire_action(const std::string
& a
, int mode
)
501 regex_results r
= regex("([^ \t]+)(([ \t]+([0-9]+))?[ \t]+([0-9]+))?[ \t]*", a
,
502 "Invalid autofire parameters");
503 std::string name
= r
[1];
504 std::string _duty
= r
[4];
505 std::string _cyclelen
= r
[5];
506 if(_duty
== "") _duty
= "1";
507 if(_cyclelen
== "") _cyclelen
= "2";
508 uint32_t duty
= parse_value
<uint32_t>(_duty
);
509 uint32_t cyclelen
= parse_value
<uint32_t>(_cyclelen
);
511 throw std::runtime_error("Invalid autofire parameters");
512 if(!all_buttons
.count(name
)) {
513 messages
<< "No such button " << name
<< std::endl
;
516 if(!check_button_active(name
))
518 auto z
= active_buttons
[name
];
519 if(z
.bind
.mode
!= 0) {
520 std::cerr
<< name
<< " is not a button." << std::endl
;
523 auto afire
= controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
);
524 if(mode
== 1 || (mode
== -1 && afire
.first
== 0)) {
526 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, (stringfmt() << "autofire "
527 << duty
<< " " << cyclelen
).str().c_str()))
529 controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
, duty
, cyclelen
);
530 edispatch
.autofire_update(z
.port
, z
.controller
, z
.bind
.control1
, duty
, cyclelen
);
531 messages
<< "Autofiring " << name
<< " (duty " << duty
<< "/" << cyclelen
<< ")" << std::endl
;
532 } else if(mode
== 0 || (mode
== -1 && afire
.first
!= 0)) {
534 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "autofire"))
536 controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
, 0, 1);
537 edispatch
.autofire_update(z
.port
, z
.controller
, z
.bind
.control1
, 0, 1);
538 messages
<< "Not autofiring " << name
<< std::endl
;