1 #include "controller.hpp"
3 #include "mainloop.hpp"
8 #include "framebuffer.hpp"
9 #include <snes/snes.hpp>
10 #include <ui-libsnes/libsnes.hpp>
12 #define BUTTON_LEFT 0 //Gamepad
13 #define BUTTON_RIGHT 1 //Gamepad
14 #define BUTTON_UP 2 //Gamepad
15 #define BUTTON_DOWN 3 //Gamepad
16 #define BUTTON_A 4 //Gamepad
17 #define BUTTON_B 5 //Gamepad
18 #define BUTTON_X 6 //Gamepad
19 #define BUTTON_Y 7 //Gamepad
20 #define BUTTON_L 8 //Gamepad & Mouse
21 #define BUTTON_R 9 //Gamepad & Mouse
22 #define BUTTON_SELECT 10 //Gamepad
23 #define BUTTON_START 11 //Gamepad & Justifier
24 #define BUTTON_TRIGGER 12 //Superscope.
25 #define BUTTON_CURSOR 13 //Superscope & Justifier
26 #define BUTTON_PAUSE 14 //Superscope
27 #define BUTTON_TURBO 15 //Superscope
31 porttype_t porttypes
[2];
32 int analog_indices
[3] = {-1, -1, -1};
33 bool analog_is_mouse
[3];
35 controls_t curcontrols
;
36 controls_t autoheld_controls
;
37 std::vector
<controls_t
> autofire_pattern
;
39 void update_analog_indices() throw()
42 for(unsigned j
= 0; j
< sizeof(analog_indices
) / sizeof(analog_indices
[0]); j
++)
43 analog_indices
[j
] = -1;
44 for(unsigned j
= 0; j
< 8; j
++) {
45 devicetype_t d
= controller_type_by_logical(j
);
51 analog_is_mouse
[i
] = true;
52 analog_indices
[i
++] = j
;
56 analog_is_mouse
[i
] = false;
57 analog_indices
[i
++] = j
;
63 std::map
<std::string
, std::pair
<unsigned, unsigned>> buttonmap
;
65 const char* buttonnames
[] = {
66 "left", "right", "up", "down", "A", "B", "X", "Y", "L", "R", "select", "start", "trigger", "cursor",
75 for(unsigned i
= 0; i
< 8; i
++)
76 for(unsigned j
= 0; j
< sizeof(buttonnames
) / sizeof(buttonnames
[0]); j
++) {
78 x
<< (i
+ 1) << buttonnames
[j
];
79 buttonmap
[x
.str()] = std::make_pair(i
, j
);
85 void do_button_action(unsigned ui_id
, unsigned button
, short newstate
, bool do_xor
, controls_t
& c
)
87 enum devicetype_t p
= controller_type_by_logical(ui_id
);
88 int x
= controller_index_by_logical(ui_id
);
92 window::out() << "No such controller #" << (ui_id
+ 1) << std::endl
;
96 case BUTTON_UP
: bid
= SNES_DEVICE_ID_JOYPAD_UP
; break;
97 case BUTTON_DOWN
: bid
= SNES_DEVICE_ID_JOYPAD_DOWN
; break;
98 case BUTTON_LEFT
: bid
= SNES_DEVICE_ID_JOYPAD_LEFT
; break;
99 case BUTTON_RIGHT
: bid
= SNES_DEVICE_ID_JOYPAD_RIGHT
; break;
100 case BUTTON_A
: bid
= SNES_DEVICE_ID_JOYPAD_A
; break;
101 case BUTTON_B
: bid
= SNES_DEVICE_ID_JOYPAD_B
; break;
102 case BUTTON_X
: bid
= SNES_DEVICE_ID_JOYPAD_X
; break;
103 case BUTTON_Y
: bid
= SNES_DEVICE_ID_JOYPAD_Y
; break;
104 case BUTTON_L
: bid
= SNES_DEVICE_ID_JOYPAD_L
; break;
105 case BUTTON_R
: bid
= SNES_DEVICE_ID_JOYPAD_R
; break;
106 case BUTTON_SELECT
: bid
= SNES_DEVICE_ID_JOYPAD_SELECT
; break;
107 case BUTTON_START
: bid
= SNES_DEVICE_ID_JOYPAD_START
; break;
109 window::out() << "Invalid button for gamepad" << std::endl
;
115 case BUTTON_L
: bid
= SNES_DEVICE_ID_MOUSE_LEFT
; break;
116 case BUTTON_R
: bid
= SNES_DEVICE_ID_MOUSE_RIGHT
; break;
118 window::out() << "Invalid button for mouse" << std::endl
;
124 case BUTTON_START
: bid
= SNES_DEVICE_ID_JUSTIFIER_START
; break;
125 case BUTTON_TRIGGER
: bid
= SNES_DEVICE_ID_JUSTIFIER_TRIGGER
; break;
127 window::out() << "Invalid button for justifier" << std::endl
;
133 case BUTTON_TRIGGER
: bid
= SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER
; break;
134 case BUTTON_CURSOR
: bid
= SNES_DEVICE_ID_SUPER_SCOPE_CURSOR
; break;
135 case BUTTON_PAUSE
: bid
= SNES_DEVICE_ID_SUPER_SCOPE_PAUSE
; break;
136 case BUTTON_TURBO
: bid
= SNES_DEVICE_ID_SUPER_SCOPE_TURBO
; break;
138 window::out() << "Invalid button for superscope" << std::endl
;
144 c((x
& 4) ? 1 : 0, x
& 3, bid
) ^= newstate
;
146 c((x
& 4) ? 1 : 0, x
& 3, bid
) = newstate
;
150 void do_button_action(unsigned ui_id
, unsigned button
, short newstate
, bool do_xor
= false)
153 do_button_action(ui_id
, button
, newstate
, do_xor
, autoheld_controls
);
154 int x
= controller_index_by_logical(ui_id
);
155 enum devicetype_t p
= controller_type_by_logical(ui_id
);
156 int y
= get_physcial_id_for_control(p
, button
);
158 window_callback::do_autohold_update(x
, y
, get_autohold(x
, y
));
160 do_button_action(ui_id
, button
, newstate
, do_xor
, curcontrols
);
163 function_ptr_command
<tokensplitter
&> autofire("autofire", "Set autofire pattern",
164 "Syntax: autofire <buttons|->...\nSet autofire pattern\n",
165 [](tokensplitter
& t
) throw(std::bad_alloc
, std::runtime_error
) {
167 throw std::runtime_error("Need at least one frame for autofire");
168 std::vector
<controls_t
> new_autofire_pattern
;
171 std::string fpattern
= t
;
173 new_autofire_pattern
.push_back(controls_t());
176 while(fpattern
!= "") {
177 size_t split
= fpattern
.find_first_of(",");
178 std::string button
= fpattern
;
180 if(split
< fpattern
.length()) {
181 button
= fpattern
.substr(0, split
);
182 rest
= fpattern
.substr(split
+ 1);
184 if(!buttonmap
.count(button
)) {
185 std::ostringstream x
;
186 x
<< "Invalid button '" << button
<< "'";
187 throw std::runtime_error(x
.str());
189 auto g
= buttonmap
[button
];
190 do_button_action(g
.first
, g
.second
, 1, false, c
);
193 new_autofire_pattern
.push_back(c
);
196 autofire_pattern
= new_autofire_pattern
;
199 class button_action
: public command
202 button_action(const std::string
& cmd
, int _type
, unsigned _controller
, std::string _button
)
203 throw(std::bad_alloc
)
208 controller
= _controller
;
211 ~button_action() throw() {}
212 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
215 throw std::runtime_error("This command does not take parameters");
217 if(!buttonmap
.count(button
))
219 auto i
= buttonmap
[button
];
220 do_button_action(i
.first
, i
.second
, (type
!= 1) ? 1 : 0, (type
== 2));
221 update_movie_state();
222 window::notify_screen_update();
224 std::string
get_short_help() throw(std::bad_alloc
)
226 return "Press/Unpress button";
228 std::string
get_long_help() throw(std::bad_alloc
)
230 return "Syntax: " + commandn
+ "\n"
231 "Presses/Unpresses button\n";
233 std::string commandn
;
239 class button_action_helper
242 button_action_helper()
244 for(size_t i
= 0; i
< sizeof(buttonnames
) / sizeof(buttonnames
[0]); ++i
)
245 for(int j
= 0; j
< 3; ++j
)
246 for(unsigned k
= 0; k
< 8; ++k
) {
247 std::ostringstream x
, y
;
263 new button_action(x
.str(), j
, k
, y
.str());
270 int controller_index_by_logical(unsigned lid
) throw()
272 bool p1multitap
= (porttypes
[0] == PT_MULTITAP
);
273 unsigned p1devs
= port_types
[porttypes
[0]].devices
;
274 unsigned p2devs
= port_types
[porttypes
[1]].devices
;
275 if(lid
>= p1devs
+ p2devs
)
281 return 4 + lid
- p1devs
;
291 int controller_index_by_analog(unsigned aid
) throw()
295 return analog_indices
[aid
];
298 bool controller_ismouse_by_analog(unsigned aid
) throw()
302 return analog_is_mouse
[aid
];
305 devicetype_t
controller_type_by_logical(unsigned lid
) throw()
307 int x
= controller_index_by_logical(lid
);
310 enum porttype_t rawtype
= porttypes
[x
>> 2];
311 if((x
& 3) < port_types
[rawtype
].devices
)
312 return port_types
[rawtype
].dtype
;
317 void controller_set_port_type(unsigned port
, porttype_t ptype
, bool set_core
) throw()
319 if(set_core
&& ptype
!= PT_INVALID
)
320 snes_set_controller_port_device(port
!= 0, port_types
[ptype
].bsnes_type
);
321 porttypes
[port
] = ptype
;
322 update_analog_indices();
323 window_callback::do_autohold_reconfigure();
326 controls_t
get_current_controls(uint64_t frame
)
328 if(autofire_pattern
.size())
329 return curcontrols
^ autoheld_controls
^ autofire_pattern
[frame
% autofire_pattern
.size()];
331 return curcontrols
^ autoheld_controls
;
334 void send_analog_input(int32_t x
, int32_t y
, unsigned index
)
336 if(controller_ismouse_by_analog(index
)) {
337 x
-= (framebuffer
.width
/ 2);
338 y
-= (framebuffer
.height
/ 2);
340 auto g
= get_scale_factors(framebuffer
.width
, framebuffer
.height
);
344 int aindex
= controller_index_by_analog(index
);
346 window::out() << "No analog controller in slot #" << (index
+ 1) << std::endl
;
349 curcontrols(aindex
>> 2, aindex
& 3, 0) = x
;
350 curcontrols(aindex
>> 2, aindex
& 3, 1) = y
;
353 void set_curcontrols_reset(int32_t delay
)
356 curcontrols(CONTROL_SYSTEM_RESET
) = 1;
357 curcontrols(CONTROL_SYSTEM_RESET_CYCLES_HI
) = delay
/ 10000;
358 curcontrols(CONTROL_SYSTEM_RESET_CYCLES_LO
) = delay
% 10000;
360 curcontrols(CONTROL_SYSTEM_RESET
) = 0;
361 curcontrols(CONTROL_SYSTEM_RESET_CYCLES_HI
) = 0;
362 curcontrols(CONTROL_SYSTEM_RESET_CYCLES_LO
) = 0;
367 void change_autohold(unsigned pid
, unsigned idx
, bool newstate
)
369 if(pid
>= MAX_PORTS
* MAX_CONTROLLERS_PER_PORT
|| idx
>= CONTROLLER_CONTROLS
)
371 autoheld_controls(pid
/ MAX_CONTROLLERS_PER_PORT
, pid
% MAX_CONTROLLERS_PER_PORT
, idx
) = (newstate
? 1 : 0);
372 window_callback::do_autohold_update(pid
, idx
, newstate
);
373 update_movie_state();
374 window::notify_screen_update();
377 bool get_autohold(unsigned pid
, unsigned idx
)
379 if(pid
>= MAX_PORTS
* MAX_CONTROLLERS_PER_PORT
|| idx
>= CONTROLLER_CONTROLS
)
381 return (autoheld_controls(pid
/ MAX_CONTROLLERS_PER_PORT
, pid
% MAX_CONTROLLERS_PER_PORT
, idx
) != 0);
384 std::string
get_button_name(unsigned lidx
)
387 return buttonnames
[lidx
];
392 int get_physcial_id_for_control(devicetype_t dtype
, unsigned lidx
)
395 case DT_NONE
: return -1;
398 case BUTTON_UP
: return SNES_DEVICE_ID_JOYPAD_UP
;
399 case BUTTON_DOWN
: return SNES_DEVICE_ID_JOYPAD_DOWN
;
400 case BUTTON_LEFT
: return SNES_DEVICE_ID_JOYPAD_LEFT
;
401 case BUTTON_RIGHT
: return SNES_DEVICE_ID_JOYPAD_RIGHT
;
402 case BUTTON_A
: return SNES_DEVICE_ID_JOYPAD_A
;
403 case BUTTON_B
: return SNES_DEVICE_ID_JOYPAD_B
;
404 case BUTTON_X
: return SNES_DEVICE_ID_JOYPAD_X
;
405 case BUTTON_Y
: return SNES_DEVICE_ID_JOYPAD_Y
;
406 case BUTTON_L
: return SNES_DEVICE_ID_JOYPAD_L
;
407 case BUTTON_R
: return SNES_DEVICE_ID_JOYPAD_R
;
408 case BUTTON_SELECT
: return SNES_DEVICE_ID_JOYPAD_SELECT
;
409 case BUTTON_START
: return SNES_DEVICE_ID_JOYPAD_START
;
414 case BUTTON_L
: return SNES_DEVICE_ID_MOUSE_LEFT
;
415 case BUTTON_R
: return SNES_DEVICE_ID_MOUSE_RIGHT
;
420 case BUTTON_TRIGGER
: return SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER
;
421 case BUTTON_CURSOR
: return SNES_DEVICE_ID_SUPER_SCOPE_CURSOR
;
422 case BUTTON_PAUSE
: return SNES_DEVICE_ID_SUPER_SCOPE_PAUSE
;
423 case BUTTON_TURBO
: return SNES_DEVICE_ID_SUPER_SCOPE_TURBO
;
428 case BUTTON_START
: return SNES_DEVICE_ID_JUSTIFIER_START
;
429 case BUTTON_TRIGGER
: return SNES_DEVICE_ID_JUSTIFIER_TRIGGER
;