Namespace library port-controller stuff
[lsnes.git] / src / core / controllerframe.cpp
blob2d0d74a713cd54bd857aeeb8cb1ec42aab5d6c17
1 #include "core/controllerframe.hpp"
2 #include "core/controller.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/messages.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/project.hpp"
7 #include "interface/romtype.hpp"
9 #include <cstdio>
10 #include <iostream>
12 namespace
14 portctrl::type_set dummytypes;
17 controller_state::controller_state(project_state& _project, movie_logic& _mlogic, button_mapping& _buttons,
18 emulator_dispatch& _dispatch, status_updater& _supdater) throw()
19 : project(_project), mlogic(_mlogic), buttons(_buttons), edispatch(_dispatch), supdater(_supdater)
21 types = &dummytypes;
22 tasinput_enaged = false;
25 std::pair<int,int> controller_state::lcid_to_pcid(unsigned lcid) throw()
27 if(lcid >= types->number_of_controllers())
28 return std::make_pair(-1, -1);
29 auto k = types->lcid_to_pcid(lcid);
30 return std::make_pair(k.first, k.second);
33 std::pair<int, int> controller_state::legacy_pcid_to_pair(unsigned pcid) throw()
35 if(pcid >= types->number_of_legacy_pcids())
36 return std::make_pair(-1, -1);
37 auto k = types->legacy_pcid_to_pair(pcid);
38 return std::make_pair(k.first, k.second);
42 portctrl::frame controller_state::get(uint64_t framenum) throw()
44 portctrl::frame tmp = _input ^ _framehold ^ _autohold;
45 for(auto i : _autofire)
46 if(i.second.eval_at(framenum))
47 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
48 if(tasinput_enaged)
49 for(auto i : _tasinput) {
50 if(i.second.mode == 0 && i.second.state)
51 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
52 else if(i.second.mode == 1)
53 tmp.axis2(i.first, i.second.state);
55 apply_macro(tmp);
56 return tmp;
59 void controller_state::analog(unsigned port, unsigned controller, unsigned control, short x) throw()
61 _input.axis3(port, controller, control, x);
64 void controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
66 _autohold.axis3(port, controller, pbid, newstate ? 1 : 0);
67 edispatch.autohold_update(port, controller, pbid, newstate);
70 bool controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid) throw()
72 return (_autohold.axis3(port, controller, pbid) != 0);
75 void controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid, unsigned duty, unsigned cyclelen)
76 throw()
78 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
79 if(duty) {
80 _autofire[idx].first_frame = mlogic.get_movie().get_current_frame();
81 _autofire[idx].duty = duty;
82 _autofire[idx].cyclelen = cyclelen;
83 } else
84 _autofire.erase(idx);
87 std::pair<unsigned, unsigned> controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid) throw()
89 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
90 if(!_autofire.count(idx))
91 return std::make_pair(0, 1);
92 else
93 return std::make_pair(_autofire[idx].duty, _autofire[idx].cyclelen);
96 bool controller_state::autofire_info::eval_at(uint64_t frame)
98 if(frame < first_frame) {
99 uint64_t diff = first_frame - frame;
100 frame += ((diff / cyclelen) + 1) * cyclelen;
102 return frame % cyclelen < duty;
105 void controller_state::reset_framehold() throw()
107 _framehold = _framehold.blank_frame();
110 void controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
112 _framehold.axis3(port, controller, pbid, newstate ? 1 : 0);
115 bool controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid) throw()
117 return (_framehold.axis3(port, controller, pbid) != 0);
120 void controller_state::button2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
122 _input.axis3(port, controller, pbid, newstate ? 1 : 0);
125 bool controller_state::button2(unsigned port, unsigned controller, unsigned pbid) throw()
127 return (_input.axis3(port, controller, pbid) != 0);
130 void controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid, int16_t state) throw()
132 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
133 if(!_tasinput.count(idx))
134 _tasinput[idx].mode = 0; //Just to be sure.
135 _tasinput[idx].state = state;
138 int16_t controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid) throw()
140 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
141 return _tasinput.count(idx) ? _tasinput[idx].state : 0;
144 void controller_state::tasinput_enable(bool enabled)
146 tasinput_enaged = enabled;
149 void controller_state::reread_tasinput_mode(const portctrl::type_set& ptype)
151 unsigned indices = ptype.indices();
152 _tasinput.clear();
153 for(unsigned i = 0; i < indices; i++) {
154 auto t = ptype.index_to_triple(i);
155 if(!t.valid)
156 continue;
157 //See what the heck that is...
158 const portctrl::type& pt = ptype.port_type(t.port);
159 const portctrl::controller_set& pci = *(pt.controller_info);
160 if(pci.controllers.size() <= t.controller)
161 continue;
162 const portctrl::controller& pc = pci.controllers[t.controller];
163 if(pc.buttons.size() <= t.control)
164 continue;
165 const portctrl::button& pcb = pc.buttons[t.control];
166 if(pcb.shadow)
167 continue;
168 if(pcb.type == portctrl::button::TYPE_BUTTON)
169 _tasinput[i].mode = 0;
170 else
171 _tasinput[i].mode = 1;
172 _tasinput[i].state = 0;
176 void controller_state::set_ports(const portctrl::type_set& ptype) throw(std::runtime_error)
178 const portctrl::type_set* oldtype = types;
179 types = &ptype;
180 if(oldtype != types) {
181 _input.set_types(ptype);
182 _autohold.set_types(ptype);
183 _committed.set_types(ptype);
184 _framehold.set_types(ptype);
185 //The old autofire pattern no longer applies.
186 _autofire.clear();
187 reread_tasinput_mode(ptype);
188 _autohold = _autohold.blank_frame();
189 buttons.reread();
190 edispatch.autohold_reconfigure();
194 portctrl::frame controller_state::get_blank() throw()
196 return _input.blank_frame();
199 portctrl::frame controller_state::get_committed() throw()
201 return _committed;
204 void controller_state::commit(portctrl::frame controls) throw()
206 _committed = controls;
209 bool controller_state::is_present(unsigned port, unsigned controller) throw()
211 return _input.is_present(port, controller);
214 void controller_state::erase_macro(const std::string& macro)
217 threads::alock h(macro_lock);
218 if(!all_macros.count(macro))
219 return;
220 auto m = &all_macros[macro];
221 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
222 if(i->second == m) {
223 active_macros.erase(i);
224 break;
227 all_macros.erase(macro);
228 project_info* p = project.get();
229 if(p) {
230 p->macros.erase(macro);
231 p->flush();
234 buttons.load(*this);
237 std::set<std::string> controller_state::enumerate_macro()
239 threads::alock h(macro_lock);
240 std::set<std::string> r;
241 for(auto i : all_macros)
242 r.insert(i.first);
243 return r;
246 portctrl::macro& controller_state::get_macro(const std::string& macro)
248 threads::alock h(macro_lock);
249 if(!all_macros.count(macro))
250 throw std::runtime_error("No such macro");
251 return all_macros[macro];
254 void controller_state::set_macro(const std::string& macro, const portctrl::macro& m)
257 threads::alock h(macro_lock);
258 portctrl::macro* old = NULL;
259 if(all_macros.count(macro))
260 old = &all_macros[macro];
261 all_macros[macro] = m;
262 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
263 if(i->second == old) {
264 i->second = &all_macros[macro];
265 break;
268 project_info* p = project.get();
269 if(p) {
270 p->macros[macro] = all_macros[macro].serialize();
271 p->flush();
274 buttons.load(*this);
277 void controller_state::apply_macro(portctrl::frame& f)
279 threads::alock h(macro_lock);
280 for(auto i : active_macros)
281 i.second->write(f, i.first);
284 void controller_state::advance_macros()
286 threads::alock h(macro_lock);
287 for(auto& i : active_macros)
288 i.first++;
291 std::map<std::string, uint64_t> controller_state::get_macro_frames()
293 threads::alock h(macro_lock);
294 std::map<std::string, uint64_t> r;
295 for(auto i : active_macros) {
296 for(auto& j : all_macros)
297 if(i.second == &j.second) {
298 r[j.first] = i.first;
301 return r;
304 void controller_state::set_macro_frames(const std::map<std::string, uint64_t>& f)
306 threads::alock h(macro_lock);
307 std::list<std::pair<uint64_t, portctrl::macro*>> new_active_macros;
308 for(auto i : f)
309 if(all_macros.count(i.first))
310 new_active_macros.push_back(std::make_pair(i.second, &all_macros[i.first]));
311 else
312 messages << "Warning: Can't find defintion for '" << i.first << "'" << std::endl;
313 std::swap(active_macros, new_active_macros);
316 void controller_state::rename_macro(const std::string& old, const std::string& newn)
319 threads::alock h(macro_lock);
320 if(!all_macros.count(old))
321 throw std::runtime_error("Old macro doesn't exist");
322 if(all_macros.count(newn))
323 throw std::runtime_error("Target name already exists");
324 if(old == newn)
325 return;
326 all_macros[newn] = all_macros[old];
327 portctrl::macro* _old = &all_macros[old];
328 all_macros.erase(old);
329 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
330 if(i->second == _old) {
331 i->second = &all_macros[newn];
332 break;
335 project_info* p = project.get();
336 if(p) {
337 p->macros[newn] = p->macros[old];
338 p->macros.erase(old);
341 buttons.load(*this);
344 void controller_state::do_macro(const std::string& a, int mode) {
346 threads::alock h(macro_lock);
347 if(!all_macros.count(a)) {
348 if(mode & 1) messages << "No such macro '" << a << "'" << std::endl;
349 return;
351 portctrl::macro* m = &all_macros[a];
352 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
353 if(i->second == m) {
354 if(mode & 2) active_macros.erase(i);
355 goto end;
358 if(mode & 4) active_macros.push_back(std::make_pair(0, m));
360 end:
361 supdater.update();
362 edispatch.status_update();
365 std::set<std::string> controller_state::active_macro_set()
367 threads::alock h(macro_lock);
368 std::set<std::string> r;
369 for(auto i : active_macros) {
370 for(auto& j : all_macros)
371 if(i.second == &j.second) {
372 r.insert(j.first);
375 return r;