1 #include "cmdhelp/macro.hpp"
2 #include "core/command.hpp"
3 #include "core/controllerframe.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/instance.hpp"
7 #include "core/messages.hpp"
8 #include "core/moviedata.hpp"
9 #include "core/project.hpp"
10 #include "interface/romtype.hpp"
17 portctrl::type_set dummytypes
;
19 command::fnptr
<const std::string
&> macro_test(lsnes_cmds
, CMACRO::test
,
20 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
22 regex_results r
= regex("([0-9]+)[ \t](.*)", args
);
24 messages
<< "Bad syntax" << std::endl
;
27 unsigned ctrl
= parse_value
<unsigned>(r
[1]);
28 auto pcid
= core
.controls
->lcid_to_pcid(ctrl
);
30 messages
<< "Bad controller" << std::endl
;
34 const portctrl::controller
* _ctrl
=
35 core
.controls
->get_blank().porttypes().port_type(pcid
.first
).
36 controller_info
->get(pcid
.second
);
38 messages
<< "No controller data for controller" << std::endl
;
41 portctrl::macro_data
mdata(r
[2].c_str(),
42 portctrl::macro_data::make_descriptor(*_ctrl
), 0);
43 messages
<< "Macro: " << mdata
.dump(*_ctrl
) << std::endl
;
44 } catch(std::exception
& e
) {
45 messages
<< "Exception: " << e
.what() << std::endl
;
51 controller_state::controller_state(project_state
& _project
, movie_logic
& _mlogic
, button_mapping
& _buttons
,
52 emulator_dispatch
& _dispatch
, status_updater
& _supdater
, command::group
& _cmd
) throw()
53 : project(_project
), mlogic(_mlogic
), buttons(_buttons
), edispatch(_dispatch
), supdater(_supdater
),
55 macro_p(cmd
, CMACRO::p
, [this](const std::string
& a
) { this->do_macro(a
, 5); }),
56 macro_r(cmd
, CMACRO::r
, [this](const std::string
& a
) { this->do_macro(a
, 2); }),
57 macro_t(cmd
, CMACRO::t
, [this](const std::string
& a
) { this->do_macro(a
, 7); })
60 tasinput_enaged
= false;
63 std::pair
<int,int> controller_state::lcid_to_pcid(unsigned lcid
) throw()
65 if(lcid
>= types
->number_of_controllers())
66 return std::make_pair(-1, -1);
67 auto k
= types
->lcid_to_pcid(lcid
);
68 return std::make_pair(k
.first
, k
.second
);
71 std::pair
<int, int> controller_state::legacy_pcid_to_pair(unsigned pcid
) throw()
73 if(pcid
>= types
->number_of_legacy_pcids())
74 return std::make_pair(-1, -1);
75 auto k
= types
->legacy_pcid_to_pair(pcid
);
76 return std::make_pair(k
.first
, k
.second
);
80 portctrl::frame
controller_state::get(uint64_t framenum
) throw()
82 portctrl::frame tmp
= _input
^ _framehold
^ _autohold
;
83 for(auto i
: _autofire
)
84 if(i
.second
.eval_at(framenum
))
85 tmp
.axis2(i
.first
, tmp
.axis2(i
.first
) ^ 1);
87 for(auto i
: _tasinput
) {
88 if(i
.second
.mode
== 0 && i
.second
.state
)
89 tmp
.axis2(i
.first
, tmp
.axis2(i
.first
) ^ 1);
90 else if(i
.second
.mode
== 1)
91 tmp
.axis2(i
.first
, i
.second
.state
);
97 void controller_state::analog(unsigned port
, unsigned controller
, unsigned control
, short x
) throw()
99 _input
.axis3(port
, controller
, control
, x
);
102 void controller_state::autohold2(unsigned port
, unsigned controller
, unsigned pbid
, bool newstate
) throw()
104 _autohold
.axis3(port
, controller
, pbid
, newstate
? 1 : 0);
105 edispatch
.autohold_update(port
, controller
, pbid
, newstate
);
108 bool controller_state::autohold2(unsigned port
, unsigned controller
, unsigned pbid
) throw()
110 return (_autohold
.axis3(port
, controller
, pbid
) != 0);
113 void controller_state::autofire2(unsigned port
, unsigned controller
, unsigned pbid
, unsigned duty
, unsigned cyclelen
)
116 unsigned idx
= _input
.porttypes().triple_to_index(port
, controller
, pbid
);
118 _autofire
[idx
].first_frame
= mlogic
.get_movie().get_current_frame();
119 _autofire
[idx
].duty
= duty
;
120 _autofire
[idx
].cyclelen
= cyclelen
;
122 _autofire
.erase(idx
);
125 std::pair
<unsigned, unsigned> controller_state::autofire2(unsigned port
, unsigned controller
, unsigned pbid
) throw()
127 unsigned idx
= _input
.porttypes().triple_to_index(port
, controller
, pbid
);
128 if(!_autofire
.count(idx
))
129 return std::make_pair(0, 1);
131 return std::make_pair(_autofire
[idx
].duty
, _autofire
[idx
].cyclelen
);
134 bool controller_state::autofire_info::eval_at(uint64_t frame
)
136 if(frame
< first_frame
) {
137 uint64_t diff
= first_frame
- frame
;
138 frame
+= ((diff
/ cyclelen
) + 1) * cyclelen
;
140 return frame
% cyclelen
< duty
;
143 void controller_state::reset_framehold() throw()
145 _framehold
= _framehold
.blank_frame();
148 void controller_state::framehold2(unsigned port
, unsigned controller
, unsigned pbid
, bool newstate
) throw()
150 _framehold
.axis3(port
, controller
, pbid
, newstate
? 1 : 0);
153 bool controller_state::framehold2(unsigned port
, unsigned controller
, unsigned pbid
) throw()
155 return (_framehold
.axis3(port
, controller
, pbid
) != 0);
158 void controller_state::button2(unsigned port
, unsigned controller
, unsigned pbid
, bool newstate
) throw()
160 _input
.axis3(port
, controller
, pbid
, newstate
? 1 : 0);
163 bool controller_state::button2(unsigned port
, unsigned controller
, unsigned pbid
) throw()
165 return (_input
.axis3(port
, controller
, pbid
) != 0);
168 void controller_state::tasinput(unsigned port
, unsigned controller
, unsigned pbid
, int16_t state
) throw()
170 unsigned idx
= _input
.porttypes().triple_to_index(port
, controller
, pbid
);
171 if(!_tasinput
.count(idx
))
172 _tasinput
[idx
].mode
= 0; //Just to be sure.
173 _tasinput
[idx
].state
= state
;
176 int16_t controller_state::tasinput(unsigned port
, unsigned controller
, unsigned pbid
) throw()
178 unsigned idx
= _input
.porttypes().triple_to_index(port
, controller
, pbid
);
179 return _tasinput
.count(idx
) ? _tasinput
[idx
].state
: 0;
182 void controller_state::tasinput_enable(bool enabled
)
184 tasinput_enaged
= enabled
;
187 void controller_state::reread_tasinput_mode(const portctrl::type_set
& ptype
)
189 unsigned indices
= ptype
.indices();
191 for(unsigned i
= 0; i
< indices
; i
++) {
192 auto t
= ptype
.index_to_triple(i
);
195 //See what the heck that is...
196 const portctrl::type
& pt
= ptype
.port_type(t
.port
);
197 const portctrl::controller_set
& pci
= *(pt
.controller_info
);
198 if(pci
.controllers
.size() <= t
.controller
)
200 const portctrl::controller
& pc
= pci
.controllers
[t
.controller
];
201 if(pc
.buttons
.size() <= t
.control
)
203 const portctrl::button
& pcb
= pc
.buttons
[t
.control
];
206 if(pcb
.type
== portctrl::button::TYPE_BUTTON
)
207 _tasinput
[i
].mode
= 0;
209 _tasinput
[i
].mode
= 1;
210 _tasinput
[i
].state
= 0;
214 void controller_state::set_ports(const portctrl::type_set
& ptype
) throw(std::runtime_error
)
216 const portctrl::type_set
* oldtype
= types
;
218 if(oldtype
!= types
) {
219 _input
.set_types(ptype
);
220 _autohold
.set_types(ptype
);
221 _committed
.set_types(ptype
);
222 _framehold
.set_types(ptype
);
223 //The old autofire pattern no longer applies.
225 reread_tasinput_mode(ptype
);
226 _autohold
= _autohold
.blank_frame();
228 edispatch
.autohold_reconfigure();
232 portctrl::frame
controller_state::get_blank() throw()
234 return _input
.blank_frame();
237 portctrl::frame
controller_state::get_committed() throw()
242 void controller_state::commit(portctrl::frame controls
) throw()
244 _committed
= controls
;
247 bool controller_state::is_present(unsigned port
, unsigned controller
) throw()
249 return _input
.is_present(port
, controller
);
252 void controller_state::erase_macro(const std::string
& macro
)
255 threads::alock
h(macro_lock
);
256 if(!all_macros
.count(macro
))
258 auto m
= &all_macros
[macro
];
259 for(auto i
= active_macros
.begin(); i
!= active_macros
.end(); i
++) {
261 active_macros
.erase(i
);
265 all_macros
.erase(macro
);
266 project_info
* p
= project
.get();
268 p
->macros
.erase(macro
);
275 std::set
<std::string
> controller_state::enumerate_macro()
277 threads::alock
h(macro_lock
);
278 std::set
<std::string
> r
;
279 for(auto i
: all_macros
)
284 portctrl::macro
& controller_state::get_macro(const std::string
& macro
)
286 threads::alock
h(macro_lock
);
287 if(!all_macros
.count(macro
))
288 throw std::runtime_error("No such macro");
289 return all_macros
[macro
];
292 void controller_state::set_macro(const std::string
& macro
, const portctrl::macro
& m
)
295 threads::alock
h(macro_lock
);
296 portctrl::macro
* old
= NULL
;
297 if(all_macros
.count(macro
))
298 old
= &all_macros
[macro
];
299 all_macros
[macro
] = m
;
300 for(auto i
= active_macros
.begin(); i
!= active_macros
.end(); i
++) {
301 if(i
->second
== old
) {
302 i
->second
= &all_macros
[macro
];
306 project_info
* p
= project
.get();
308 p
->macros
[macro
] = all_macros
[macro
].serialize();
315 void controller_state::apply_macro(portctrl::frame
& f
)
317 threads::alock
h(macro_lock
);
318 for(auto i
: active_macros
)
319 i
.second
->write(f
, i
.first
);
322 void controller_state::advance_macros()
324 threads::alock
h(macro_lock
);
325 for(auto& i
: active_macros
)
329 std::map
<std::string
, uint64_t> controller_state::get_macro_frames()
331 threads::alock
h(macro_lock
);
332 std::map
<std::string
, uint64_t> r
;
333 for(auto i
: active_macros
) {
334 for(auto& j
: all_macros
)
335 if(i
.second
== &j
.second
) {
336 r
[j
.first
] = i
.first
;
342 void controller_state::set_macro_frames(const std::map
<std::string
, uint64_t>& f
)
344 threads::alock
h(macro_lock
);
345 std::list
<std::pair
<uint64_t, portctrl::macro
*>> new_active_macros
;
347 if(all_macros
.count(i
.first
))
348 new_active_macros
.push_back(std::make_pair(i
.second
, &all_macros
[i
.first
]));
350 messages
<< "Warning: Can't find defintion for '" << i
.first
<< "'" << std::endl
;
351 std::swap(active_macros
, new_active_macros
);
354 void controller_state::rename_macro(const std::string
& old
, const std::string
& newn
)
357 threads::alock
h(macro_lock
);
358 if(!all_macros
.count(old
))
359 throw std::runtime_error("Old macro doesn't exist");
360 if(all_macros
.count(newn
))
361 throw std::runtime_error("Target name already exists");
364 all_macros
[newn
] = all_macros
[old
];
365 portctrl::macro
* _old
= &all_macros
[old
];
366 all_macros
.erase(old
);
367 for(auto i
= active_macros
.begin(); i
!= active_macros
.end(); i
++) {
368 if(i
->second
== _old
) {
369 i
->second
= &all_macros
[newn
];
373 project_info
* p
= project
.get();
375 p
->macros
[newn
] = p
->macros
[old
];
376 p
->macros
.erase(old
);
382 void controller_state::do_macro(const std::string
& a
, int mode
) {
384 threads::alock
h(macro_lock
);
385 if(!all_macros
.count(a
)) {
386 if(mode
& 1) messages
<< "No such macro '" << a
<< "'" << std::endl
;
389 portctrl::macro
* m
= &all_macros
[a
];
390 for(auto i
= active_macros
.begin(); i
!= active_macros
.end(); i
++) {
392 if(mode
& 2) active_macros
.erase(i
);
396 if(mode
& 4) active_macros
.push_back(std::make_pair(0, m
));
400 edispatch
.status_update();
403 std::set
<std::string
> controller_state::active_macro_set()
405 threads::alock
h(macro_lock
);
406 std::set
<std::string
> r
;
407 for(auto i
: active_macros
) {
408 for(auto& j
: all_macros
)
409 if(i
.second
== &j
.second
) {