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"
25 unsigned next_id_from_map(std::map
<std::string
, unsigned>& map
, const std::string
& key
, unsigned base
)
28 return (map
[key
] = base
);
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()
56 void button_mapping::reinit()
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
);
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;
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
;
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
++) {
90 name
= (stringfmt() << "analog" << (j
+ 1)).str();
93 std::string cname
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
95 if(all_buttons
.count(cname
)) {
96 button_mapping::active_bind a
;
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();
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
+
114 macro_binds2
[i
] = new keyboard::invbind(mapper
, CMACRO::p
.name
+ (" " + i
) , "Macro‣" +
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
)
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
);
143 void button_mapping::cleanup()
145 for(auto i
: added_keys
)
147 for(auto i
: macro_binds
)
149 for(auto i
: macro_binds2
)
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();
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
)) {
175 added_keys
[name
] = &k
;
176 if(!button_keys
.count(name
))
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());
191 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::h
.name
<< " "
192 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
193 << binding
.number
<< "‣" << binding
.name
<< "‣hold").str());
195 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::t
.name
<< " "
196 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
197 << binding
.number
<< "‣" << binding
.name
<< "‣type").str());
199 k
= new keyboard::ctrlrkey(mapper
, (stringfmt() << CBUTTON::ap
.name
<< " "
200 << name
).str(), (stringfmt() << "Controller‣" << binding
.cclass
<< "‣#"
201 << binding
.number
<< "‣" << binding
.name
<< "‣autofire").str());
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());
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());
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);
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
)
229 if(controller
.buttons
[i
].type
!= portctrl::button::TYPE_BUTTON
)
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
;
236 b
.name
= controller
.buttons
[i
].name
;
238 b
.xrel
= b
.yrel
= false;
240 b
.control2
= std::numeric_limits
<unsigned>::max();
241 if(!all_buttons
.count(name
)) {
242 all_buttons
[name
] = b
;
246 for(unsigned i
= 0; i
< controller
.buttons
.size(); i
++) {
247 if(controller
.buttons
[i
].shadow
)
249 if(!controller
.buttons
[i
].is_analog())
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
;
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
;
261 b
.xrel
= b
.yrel
= false;
263 b
.control2
= std::numeric_limits
<unsigned>::max();
264 if(!all_buttons
.count(name
)) {
265 all_buttons
[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
;
273 button_mapping::controller_bind b
;
275 b
.name
= (stringfmt() << "analog" << analog_num
).str();
277 b
.name
= (stringfmt() << "analog").str();
278 name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-" << b
.name
).str();
280 b
.cclass
= controller
.cclass
;
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
))
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
;
309 key
.controller
= number_in_port
;
311 if(!assigned
.count(key
))
312 assigned
[key
] = next_id_from_map(allocated
, controller
.cclass
, 1);
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
))
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
++) {
342 for(unsigned j
= 0; j
< ptypes
.size(); j
++) {
343 if(!ptypes
[j
]->legal(i
))
346 process_port(allocated
, assigned
, i
, *ptypes
[j
]);
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
))
360 //This isn't active. check if there are any other active buttons on the thingy and don't complain
362 bool complain
= true;
363 auto ckey
= keyboard
.get_current_key();
365 auto cb
= mapper
.get_controllerkeys_kbdkey(ckey
);
367 regex_results r
= regex("[^ \t]+[ \t]+([^ \t]+)([ \t]+.*)?", i
->get_command());
370 if(active_buttons
.count(r
[1]))
375 messages
<< "No such button " << name
<< std::endl
;
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
;
386 if(!check_button_active(name
))
388 auto x
= active_buttons
[name
];
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"))
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) {
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"))
403 controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
405 messages
<< "Holding " << name
<< " for the next frame" << std::endl
;
407 messages
<< "Not holding " << name
<< " for the next frame" << std::endl
;
409 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, newstate
? "press" :
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
;
422 if(!check_button_active(name
))
424 auto z
= active_buttons
[name
];
425 if(z
.bind
.mode
!= 1) {
426 std::cerr
<< name
<< " is not a axis." << std::endl
;
429 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "analog"))
431 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control2
, "analog"))
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
)
445 do_button_action(name
, state
, mode
);
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
;
453 send_analog(name
, mouse_x
->get_state(), mouse_y
->get_state());
457 void button_mapping::do_analog_action(const std::string
& a
)
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
;
467 if(!check_button_active(name
))
469 auto x
= active_buttons
[name
];
472 if(lua2
.callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, "analog"))
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
);
495 throw std::runtime_error("Invalid autofire parameters");
496 if(!all_buttons
.count(name
)) {
497 messages
<< "No such button " << name
<< std::endl
;
500 if(!check_button_active(name
))
502 auto z
= active_buttons
[name
];
503 if(z
.bind
.mode
!= 0) {
504 std::cerr
<< name
<< " is not a button." << std::endl
;
507 auto afire
= controls
.autofire2(z
.port
, z
.controller
, z
.bind
.control1
);
508 if(mode
== 1 || (mode
== -1 && afire
.first
== 0)) {
510 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, (stringfmt() << "autofire "
511 << duty
<< " " << cyclelen
).str().c_str()))
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)) {
517 if(lua2
.callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "autofire"))
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);