2 #include "core/emucore.hpp"
4 #include "core/command.hpp"
5 #include "core/controller.hpp"
6 #include "core/dispatch.hpp"
7 #include "core/framebuffer.hpp"
8 #include "core/mainloop.hpp"
9 #include "core/misc.hpp"
10 #include "core/window.hpp"
11 #include "library/string.hpp"
18 std::map
<std::string
, std::pair
<unsigned, unsigned>> buttonmap
;
25 auto lim
= get_core_logical_controller_limits();
26 for(unsigned i
= 0; i
< lim
.first
; i
++)
27 for(unsigned j
= 0; j
< lim
.second
; j
++) {
28 buttonmap
[(stringfmt() << (i
+ 1) << get_logical_button_name(j
)).str()] =
35 void do_button_action(unsigned ui_id
, unsigned button
, short newstate
, int mode
)
37 int x
= controls
.lcid_to_pcid(ui_id
);
39 messages
<< "No such controller #" << (ui_id
+ 1) << std::endl
;
42 int bid
= controls
.button_id(x
, button
);
44 messages
<< "Invalid button for controller type" << std::endl
;
49 int16_t nstate
= controls
.autohold(x
, bid
) ^ newstate
;
50 if(lua_callback_do_button(x
/ 4 + 1, x
% 4, bid
, nstate
? "hold" : "unhold"))
52 controls
.autohold(x
, bid
, nstate
);
53 information_dispatch::do_autohold_update(x
, bid
, controls
.autohold(x
, bid
));
54 } else if(mode
== 2) {
56 bool nstate
= controls
.framehold(x
, bid
) ^ newstate
;
57 if(lua_callback_do_button(x
/ 4 + 1, x
% 4, bid
, nstate
? "type" : "untype"))
59 controls
.framehold(x
, bid
, nstate
);
61 messages
<< "Holding " << (ui_id
+ 1) << get_logical_button_name(button
)
62 << " for the next frame" << std::endl
;
64 messages
<< "Not holding " << (ui_id
+ 1) << get_logical_button_name(button
)
65 << " for the next frame" << std::endl
;
67 if(lua_callback_do_button(x
/ 4 + 1, x
% 4, bid
, newstate
? "press" : "release"))
69 controls
.button(x
, bid
, newstate
);
73 void send_analog(unsigned lcid
, int32_t x
, int32_t y
)
75 int pcid
= controls
.lcid_to_pcid(lcid
);
77 messages
<< "Controller #" << (lcid
+ 1) << " not present" << std::endl
;
80 if(controls
.is_analog(pcid
) < 0) {
81 messages
<< "Controller #" << (lcid
+ 1) << " is not analog" << std::endl
;
84 if(lua_callback_do_button(pcid
/ 4 + 1, x
% 4, 0, "analog"))
86 if(lua_callback_do_button(pcid
/ 4 + 1, x
% 4, 1, "analog"))
88 auto g2
= get_framebuffer_size();
89 if(controls
.is_mouse(pcid
)) {
90 controls
.analog(pcid
, x
- g2
.first
/ 2, y
- g2
.second
/ 2);
92 controls
.analog(pcid
, x
/ 2 , y
/ 2);
95 function_ptr_command
<const std::string
&> autofire("autofire", "Set autofire pattern",
96 "Syntax: autofire <buttons|->...\nSet autofire pattern\n",
97 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
98 auto r
= regex(".*[^ \t].*", a
, "Need at least one frame for autofire");
99 std::vector
<controller_frame
> new_autofire_pattern
;
101 std::string pattern
= a
;
102 while(pattern
!= "") {
103 std::string fpattern
;
104 extract_token(pattern
, fpattern
, " \t", true);
106 new_autofire_pattern
.push_back(controls
.get_blank());
108 controller_frame
c(controls
.get_blank());
109 while(fpattern
!= "") {
110 size_t split
= fpattern
.find_first_of(",");
111 std::string button
= fpattern
;
113 if(split
< fpattern
.length()) {
114 button
= fpattern
.substr(0, split
);
115 rest
= fpattern
.substr(split
+ 1);
117 if(!buttonmap
.count(button
))
118 (stringfmt() << "Invalid button '" << button
<< "'").throwex();
119 auto g
= buttonmap
[button
];
120 int x
= controls
.lcid_to_pcid(g
.first
);
122 (stringfmt() << "No such controller #" << (g
.first
+ 1)).
124 int bid
= controls
.button_id(x
, g
.second
);
126 (stringfmt() << "Invalid button for controller type").
128 c
.axis(x
, bid
, true);
131 new_autofire_pattern
.push_back(c
);
134 controls
.autofire(new_autofire_pattern
);
137 class button_action
: public command
140 button_action(const std::string
& cmd
, int _type
, unsigned _controller
, std::string _button
)
141 throw(std::bad_alloc
)
146 controller
= _controller
;
149 ~button_action() throw() {}
150 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
153 throw std::runtime_error("This command does not take parameters");
155 if(!buttonmap
.count(button
))
157 auto i
= buttonmap
[button
];
159 do_button_action(i
.first
, i
.second
, 1, 0);
161 do_button_action(i
.first
, i
.second
, 0, 0);
163 do_button_action(i
.first
, i
.second
, 1, 1);
165 do_button_action(i
.first
, i
.second
, 1, 2);
166 update_movie_state();
167 information_dispatch::do_status_update();
169 std::string
get_short_help() throw(std::bad_alloc
)
171 return "Press/Unpress button";
173 std::string
get_long_help() throw(std::bad_alloc
)
175 return "Syntax: " + commandn
+ "\n"
176 "Presses/Unpresses button\n";
178 std::string commandn
;
184 class analog_action
: public command
187 analog_action(const std::string
& cmd
, unsigned _controller
)
188 throw(std::bad_alloc
)
191 controller
= _controller
;
193 ~analog_action() throw() {}
194 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
197 throw std::runtime_error("This command does not take parameters");
198 keygroup
* mouse_x
= keygroup::lookup_by_name("mouse_x");
199 keygroup
* mouse_y
= keygroup::lookup_by_name("mouse_y");
200 if(!mouse_x
|| !mouse_y
) {
201 messages
<< "Controller analog function not available without mouse" << std::endl
;
204 send_analog(controller
, mouse_x
->get_value(), mouse_y
->get_value());
210 class button_action_helper
213 button_action_helper()
215 auto lim
= get_core_logical_controller_limits();
216 for(size_t i
= 0; i
< lim
.second
; ++i
)
217 for(int j
= 0; j
< 4; ++j
)
218 for(unsigned k
= 0; k
< lim
.first
; ++k
) {
219 stringfmt x
, y
, expx
;
234 x
<< (k
+ 1) << get_logical_button_name(i
);
235 y
<< (k
+ 1) << get_logical_button_name(i
);
236 expx
<< "Controller‣" << (k
+ 1) << "‣" << get_logical_button_name(i
);
237 our_commands
.insert(new button_action(x
.str(), j
, k
, y
.str()));
239 our_icommands
.insert(new inverse_key(x
.str(), expx
.str()));
241 our_icommands
.insert(new inverse_key(x
.str(), expx
.str() +
244 our_icommands
.insert(new inverse_key(x
.str(), expx
.str() +
247 if(get_core_need_analog())
248 for(unsigned k
= 0; k
< lim
.first
; ++k
) {
250 x
<< "controller" << (k
+ 1) << "analog";
251 expx
<< "Controller‣" << (k
+ 1) << "‣Analog function";
252 our_commands
.insert(new analog_action(x
.str(), k
));
253 our_icommands
.insert(new inverse_key(x
.str(), expx
.str()));
256 ~button_action_helper()
258 for(auto i
: our_commands
)
260 for(auto i
: our_icommands
)
262 our_commands
.clear();
263 our_icommands
.clear();
265 std::set
<command
*> our_commands
;
266 std::set
<inverse_key
*> our_icommands
;
270 controller_state controls
;