Allow binding commands to class instance
[lsnes.git] / src / core / controllerframe.cpp
blobe896ca1c24d54318d5b025579c60fe3df894e75b
1 #include "cmdhelp/macro.hpp"
2 #include "core/controllerframe.hpp"
3 #include "core/controller.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/messages.hpp"
6 #include "core/moviedata.hpp"
7 #include "core/project.hpp"
8 #include "interface/romtype.hpp"
10 #include <cstdio>
11 #include <iostream>
13 namespace
15 portctrl::type_set dummytypes;
18 controller_state::controller_state(project_state& _project, movie_logic& _mlogic, button_mapping& _buttons,
19 emulator_dispatch& _dispatch, status_updater& _supdater, command::group& _cmd) throw()
20 : project(_project), mlogic(_mlogic), buttons(_buttons), edispatch(_dispatch), supdater(_supdater),
21 cmd(_cmd),
22 macro_p(cmd, STUBS::macrop, [this](const std::string& a) { this->do_macro(a, 5); }),
23 macro_r(cmd, STUBS::macror, [this](const std::string& a) { this->do_macro(a, 2); }),
24 macro_t(cmd, STUBS::macrot, [this](const std::string& a) { this->do_macro(a, 7); })
26 types = &dummytypes;
27 tasinput_enaged = false;
30 std::pair<int,int> controller_state::lcid_to_pcid(unsigned lcid) throw()
32 if(lcid >= types->number_of_controllers())
33 return std::make_pair(-1, -1);
34 auto k = types->lcid_to_pcid(lcid);
35 return std::make_pair(k.first, k.second);
38 std::pair<int, int> controller_state::legacy_pcid_to_pair(unsigned pcid) throw()
40 if(pcid >= types->number_of_legacy_pcids())
41 return std::make_pair(-1, -1);
42 auto k = types->legacy_pcid_to_pair(pcid);
43 return std::make_pair(k.first, k.second);
47 portctrl::frame controller_state::get(uint64_t framenum) throw()
49 portctrl::frame tmp = _input ^ _framehold ^ _autohold;
50 for(auto i : _autofire)
51 if(i.second.eval_at(framenum))
52 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
53 if(tasinput_enaged)
54 for(auto i : _tasinput) {
55 if(i.second.mode == 0 && i.second.state)
56 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
57 else if(i.second.mode == 1)
58 tmp.axis2(i.first, i.second.state);
60 apply_macro(tmp);
61 return tmp;
64 void controller_state::analog(unsigned port, unsigned controller, unsigned control, short x) throw()
66 _input.axis3(port, controller, control, x);
69 void controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
71 _autohold.axis3(port, controller, pbid, newstate ? 1 : 0);
72 edispatch.autohold_update(port, controller, pbid, newstate);
75 bool controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid) throw()
77 return (_autohold.axis3(port, controller, pbid) != 0);
80 void controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid, unsigned duty, unsigned cyclelen)
81 throw()
83 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
84 if(duty) {
85 _autofire[idx].first_frame = mlogic.get_movie().get_current_frame();
86 _autofire[idx].duty = duty;
87 _autofire[idx].cyclelen = cyclelen;
88 } else
89 _autofire.erase(idx);
92 std::pair<unsigned, unsigned> controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid) throw()
94 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
95 if(!_autofire.count(idx))
96 return std::make_pair(0, 1);
97 else
98 return std::make_pair(_autofire[idx].duty, _autofire[idx].cyclelen);
101 bool controller_state::autofire_info::eval_at(uint64_t frame)
103 if(frame < first_frame) {
104 uint64_t diff = first_frame - frame;
105 frame += ((diff / cyclelen) + 1) * cyclelen;
107 return frame % cyclelen < duty;
110 void controller_state::reset_framehold() throw()
112 _framehold = _framehold.blank_frame();
115 void controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
117 _framehold.axis3(port, controller, pbid, newstate ? 1 : 0);
120 bool controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid) throw()
122 return (_framehold.axis3(port, controller, pbid) != 0);
125 void controller_state::button2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
127 _input.axis3(port, controller, pbid, newstate ? 1 : 0);
130 bool controller_state::button2(unsigned port, unsigned controller, unsigned pbid) throw()
132 return (_input.axis3(port, controller, pbid) != 0);
135 void controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid, int16_t state) throw()
137 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
138 if(!_tasinput.count(idx))
139 _tasinput[idx].mode = 0; //Just to be sure.
140 _tasinput[idx].state = state;
143 int16_t controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid) throw()
145 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
146 return _tasinput.count(idx) ? _tasinput[idx].state : 0;
149 void controller_state::tasinput_enable(bool enabled)
151 tasinput_enaged = enabled;
154 void controller_state::reread_tasinput_mode(const portctrl::type_set& ptype)
156 unsigned indices = ptype.indices();
157 _tasinput.clear();
158 for(unsigned i = 0; i < indices; i++) {
159 auto t = ptype.index_to_triple(i);
160 if(!t.valid)
161 continue;
162 //See what the heck that is...
163 const portctrl::type& pt = ptype.port_type(t.port);
164 const portctrl::controller_set& pci = *(pt.controller_info);
165 if(pci.controllers.size() <= t.controller)
166 continue;
167 const portctrl::controller& pc = pci.controllers[t.controller];
168 if(pc.buttons.size() <= t.control)
169 continue;
170 const portctrl::button& pcb = pc.buttons[t.control];
171 if(pcb.shadow)
172 continue;
173 if(pcb.type == portctrl::button::TYPE_BUTTON)
174 _tasinput[i].mode = 0;
175 else
176 _tasinput[i].mode = 1;
177 _tasinput[i].state = 0;
181 void controller_state::set_ports(const portctrl::type_set& ptype) throw(std::runtime_error)
183 const portctrl::type_set* oldtype = types;
184 types = &ptype;
185 if(oldtype != types) {
186 _input.set_types(ptype);
187 _autohold.set_types(ptype);
188 _committed.set_types(ptype);
189 _framehold.set_types(ptype);
190 //The old autofire pattern no longer applies.
191 _autofire.clear();
192 reread_tasinput_mode(ptype);
193 _autohold = _autohold.blank_frame();
194 buttons.reread();
195 edispatch.autohold_reconfigure();
199 portctrl::frame controller_state::get_blank() throw()
201 return _input.blank_frame();
204 portctrl::frame controller_state::get_committed() throw()
206 return _committed;
209 void controller_state::commit(portctrl::frame controls) throw()
211 _committed = controls;
214 bool controller_state::is_present(unsigned port, unsigned controller) throw()
216 return _input.is_present(port, controller);
219 void controller_state::erase_macro(const std::string& macro)
222 threads::alock h(macro_lock);
223 if(!all_macros.count(macro))
224 return;
225 auto m = &all_macros[macro];
226 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
227 if(i->second == m) {
228 active_macros.erase(i);
229 break;
232 all_macros.erase(macro);
233 project_info* p = project.get();
234 if(p) {
235 p->macros.erase(macro);
236 p->flush();
239 buttons.load(*this);
242 std::set<std::string> controller_state::enumerate_macro()
244 threads::alock h(macro_lock);
245 std::set<std::string> r;
246 for(auto i : all_macros)
247 r.insert(i.first);
248 return r;
251 portctrl::macro& controller_state::get_macro(const std::string& macro)
253 threads::alock h(macro_lock);
254 if(!all_macros.count(macro))
255 throw std::runtime_error("No such macro");
256 return all_macros[macro];
259 void controller_state::set_macro(const std::string& macro, const portctrl::macro& m)
262 threads::alock h(macro_lock);
263 portctrl::macro* old = NULL;
264 if(all_macros.count(macro))
265 old = &all_macros[macro];
266 all_macros[macro] = m;
267 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
268 if(i->second == old) {
269 i->second = &all_macros[macro];
270 break;
273 project_info* p = project.get();
274 if(p) {
275 p->macros[macro] = all_macros[macro].serialize();
276 p->flush();
279 buttons.load(*this);
282 void controller_state::apply_macro(portctrl::frame& f)
284 threads::alock h(macro_lock);
285 for(auto i : active_macros)
286 i.second->write(f, i.first);
289 void controller_state::advance_macros()
291 threads::alock h(macro_lock);
292 for(auto& i : active_macros)
293 i.first++;
296 std::map<std::string, uint64_t> controller_state::get_macro_frames()
298 threads::alock h(macro_lock);
299 std::map<std::string, uint64_t> r;
300 for(auto i : active_macros) {
301 for(auto& j : all_macros)
302 if(i.second == &j.second) {
303 r[j.first] = i.first;
306 return r;
309 void controller_state::set_macro_frames(const std::map<std::string, uint64_t>& f)
311 threads::alock h(macro_lock);
312 std::list<std::pair<uint64_t, portctrl::macro*>> new_active_macros;
313 for(auto i : f)
314 if(all_macros.count(i.first))
315 new_active_macros.push_back(std::make_pair(i.second, &all_macros[i.first]));
316 else
317 messages << "Warning: Can't find defintion for '" << i.first << "'" << std::endl;
318 std::swap(active_macros, new_active_macros);
321 void controller_state::rename_macro(const std::string& old, const std::string& newn)
324 threads::alock h(macro_lock);
325 if(!all_macros.count(old))
326 throw std::runtime_error("Old macro doesn't exist");
327 if(all_macros.count(newn))
328 throw std::runtime_error("Target name already exists");
329 if(old == newn)
330 return;
331 all_macros[newn] = all_macros[old];
332 portctrl::macro* _old = &all_macros[old];
333 all_macros.erase(old);
334 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
335 if(i->second == _old) {
336 i->second = &all_macros[newn];
337 break;
340 project_info* p = project.get();
341 if(p) {
342 p->macros[newn] = p->macros[old];
343 p->macros.erase(old);
346 buttons.load(*this);
349 void controller_state::do_macro(const std::string& a, int mode) {
351 threads::alock h(macro_lock);
352 if(!all_macros.count(a)) {
353 if(mode & 1) messages << "No such macro '" << a << "'" << std::endl;
354 return;
356 portctrl::macro* m = &all_macros[a];
357 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
358 if(i->second == m) {
359 if(mode & 2) active_macros.erase(i);
360 goto end;
363 if(mode & 4) active_macros.push_back(std::make_pair(0, m));
365 end:
366 supdater.update();
367 edispatch.status_update();
370 std::set<std::string> controller_state::active_macro_set()
372 threads::alock h(macro_lock);
373 std::set<std::string> r;
374 for(auto i : active_macros) {
375 for(auto& j : all_macros)
376 if(i.second == &j.second) {
377 r.insert(j.first);
380 return r;