3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/mainloop.hpp"
8 #include "core/misc.hpp"
9 #include "core/window.hpp"
10 #include "interface/romtype.hpp"
11 #include "library/string.hpp"
19 struct controller_bind
28 unsigned control2
; //Axis only, UINT_MAX if not valid.
35 struct controller_bind bind
;
38 struct controller_triple
43 bool operator<(const struct controller_triple
& t
) const throw()
45 if(cclass
< t
.cclass
) return true;
46 if(cclass
> t
.cclass
) return false;
47 if(port
< t
.port
) return true;
48 if(port
> t
.port
) return false;
49 if(controller
< t
.controller
) return true;
50 if(controller
> t
.controller
) return false;
53 bool operator==(const struct controller_triple
& t
) const throw()
55 return (cclass
== t
.cclass
&& port
== t
.port
&& controller
== t
.controller
);
59 std::map
<std::string
, controller_bind
> all_buttons
;
60 std::map
<std::string
, active_bind
> active_buttons
;
62 //Promote stored key to active key.
63 void promote_key(controller_key
& k
)
65 std::string name
= k
.get_command();
66 if(!button_keys
.count(name
))
68 k
.set(button_keys
[name
]);
69 messages
<< button_keys
[name
] << " bound (button) to " << name
<< std::endl
;
70 button_keys
.erase(name
);
73 //Allocate controller keys for specified button.
74 void add_button(const std::string
& name
, const controller_bind
& binding
)
77 if(!binding
.is_axis
) {
78 k
= new controller_key(lsnes_mapper
, (stringfmt() << "+controller " << name
).str(),
79 (stringfmt() << "Controller‣" << binding
.cclass
<< "-" << binding
.number
<< "‣"
80 << binding
.name
).str());
82 k
= new controller_key(lsnes_mapper
, (stringfmt() << "hold-controller " << name
).str(),
83 (stringfmt() << "Controller‣" << binding
.cclass
<< "-" << binding
.number
<< "‣"
84 << binding
.name
<< " (hold)").str());
86 k
= new controller_key(lsnes_mapper
, (stringfmt() << "type-controller " << name
).str(),
87 (stringfmt() << "Controller‣" << binding
.cclass
<< "-" << binding
.number
<< "‣"
88 << binding
.name
<< " (type)").str());
91 k
= new controller_key(lsnes_mapper
, (stringfmt() << "designate-position " << name
).str(),
92 (stringfmt() << "Controller‣" << binding
.cclass
<< "-" << binding
.number
<< "‣"
93 << binding
.name
).str());
98 //Take specified controller info and process it as specified controller of its class.
99 void process_controller(port_controller
& controller
, unsigned number
)
101 unsigned analog_num
= 1;
102 bool multi_analog
= (controller
.analog_actions() > 1);
103 //This controller might be processed already, but perhaps only partially.
104 for(unsigned i
= 0; i
< controller
.button_count
; i
++) {
105 if(controller
.buttons
[i
]->shadow
)
107 if(controller
.buttons
[i
]->type
!= port_controller_button::TYPE_BUTTON
)
109 std::string name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-"
110 << controller
.buttons
[i
]->name
).str();
112 b
.cclass
= controller
.cclass
;
114 b
.name
= controller
.buttons
[i
]->name
;
116 b
.xrel
= b
.yrel
= false;
118 b
.control2
= std::numeric_limits
<unsigned>::max();
119 if(!all_buttons
.count(name
)) {
120 all_buttons
[name
] = b
;
124 for(unsigned i
= 0; i
< controller
.analog_actions(); i
++) {
125 auto g
= controller
.analog_action(i
);
126 auto raxis
= port_controller_button::TYPE_RAXIS
;
130 b
.name
= (stringfmt() << "analog" << analog_num
).str();
132 b
.name
= (stringfmt() << "analog").str();
133 name
= (stringfmt() << controller
.cclass
<< "-" << number
<< "-" << b
.name
).str();
135 b
.cclass
= controller
.cclass
;
138 b
.xrel
= (g
.first
< controller
.button_count
) &&
139 (controller
.buttons
[g
.first
]->type
== raxis
);
140 b
.yrel
= (g
.second
< controller
.button_count
) &&
141 (controller
.buttons
[g
.second
]->type
== raxis
);
142 b
.control1
= g
.first
;
143 b
.control2
= g
.second
;
144 if(!all_buttons
.count(name
))
146 if(!all_buttons
.count(name
) ||
147 ((all_buttons
[name
].control2
== std::numeric_limits
<unsigned>::max()) &&
148 (b
.control2
< std::numeric_limits
<unsigned>::max()))) {
149 all_buttons
[name
] = b
;
154 unsigned next_id_from_map(std::map
<std::string
, unsigned>& map
, const std::string
& key
, unsigned base
)
157 return (map
[key
] = base
);
162 //The rules for class number allocations are:
163 //- Different cores allocate numbers independently.
164 //- Within the same core, the allocations for higher port start after the previous port ends.
167 void process_controller(std::map
<std::string
, unsigned>& allocated
,
168 std::map
<controller_triple
, unsigned>& assigned
, port_controller
& controller
, unsigned port
,
169 unsigned number_in_port
)
171 controller_triple key
;
172 key
.cclass
= controller
.cclass
;
174 key
.controller
= number_in_port
;
176 if(!assigned
.count(key
))
177 assigned
[key
] = next_id_from_map(allocated
, controller
.cclass
, 1);
179 process_controller(controller
, n
);
182 void process_port(std::map
<std::string
, unsigned>& allocated
,
183 std::map
<controller_triple
, unsigned>& assigned
, unsigned port
, port_type
& ptype
)
185 //What makes this nasty: Separate ports are always processed, but the same controllers can come
186 //multiple times, including with partial reprocessing.
187 std::map
<std::string
, unsigned> counts
;
188 for(unsigned i
= 0; i
< ptype
.controller_info
->controller_count
; i
++) {
189 //No, n might not equal i + 1, since some ports have heterogenous controllers (e.g.
190 //gameboy-gambatte system port).
191 unsigned n
= next_id_from_map(counts
, ptype
.controller_info
->controllers
[i
]->cclass
, 1);
192 process_controller(allocated
, assigned
, *ptype
.controller_info
->controllers
[i
], port
, n
);
196 void init_buttonmap()
198 static std::set
<core_core
*> done
;
199 std::vector
<port_type
*> ptypes
;
200 for(auto k
: core_core::all_cores()) {
203 std::map
<std::string
, unsigned> allocated
;
204 std::map
<controller_triple
, unsigned> assigned
;
205 auto ptypes
= k
->get_port_types();
206 for(unsigned i
= 0;; i
++) {
208 for(unsigned j
= 0; ptypes
[j
]; j
++) {
209 if(!ptypes
[j
]->legal(i
))
212 process_port(allocated
, assigned
, i
, *ptypes
[j
]);
222 void do_button_action(const std::string
& name
, short newstate
, int mode
)
224 if(!all_buttons
.count(name
)) {
225 messages
<< "No such button " << name
<< std::endl
;
228 if(!active_buttons
.count(name
))
230 auto x
= active_buttons
[name
];
235 int16_t nstate
= controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
236 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "hold" : "unhold"))
238 controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
239 information_dispatch::do_autohold_update(x
.port
, x
.controller
, x
.bind
.control1
,
240 controls
.autohold2(x
.port
, x
.controller
, x
.bind
.control1
));
241 } else if(mode
== 2) {
243 bool nstate
= controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
) ^ newstate
;
244 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, nstate
? "type" : "untype"))
246 controls
.framehold2(x
.port
, x
.controller
, x
.bind
.control1
, nstate
);
248 messages
<< "Holding " << name
<< " for the next frame" << std::endl
;
250 messages
<< "Not holding " << name
<< " for the next frame" << std::endl
;
252 if(lua_callback_do_button(x
.port
, x
.controller
, x
.bind
.control1
, newstate
? "press" :
255 controls
.button2(x
.port
, x
.controller
, x
.bind
.control1
, newstate
);
259 void send_analog(const std::string
& name
, int32_t x
, int32_t y
)
261 if(!all_buttons
.count(name
)) {
262 messages
<< "No such action " << name
<< std::endl
;
265 if(!active_buttons
.count(name
))
267 auto z
= active_buttons
[name
];
268 if(!z
.bind
.is_axis
) {
269 std::cerr
<< name
<< " is not a axis." << std::endl
;
272 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control1
, "analog"))
274 if(lua_callback_do_button(z
.port
, z
.controller
, z
.bind
.control2
, "analog"))
276 auto g2
= get_framebuffer_size();
277 x
= z
.bind
.xrel
? (x
- g2
.first
/ 2) : (x
/ 2);
278 y
= z
.bind
.yrel
? (y
- g2
.second
/ 2) : (y
/ 2);
279 if(z
.bind
.control1
< std::numeric_limits
<unsigned>::max())
280 controls
.analog(z
.port
, z
.controller
, z
.bind
.control1
, x
);
281 if(z
.bind
.control2
< std::numeric_limits
<unsigned>::max())
282 controls
.analog(z
.port
, z
.controller
, z
.bind
.control2
, y
);
285 function_ptr_command
<const std::string
&> autofire(lsnes_cmd
, "autofire", "Set autofire pattern",
286 "Syntax: autofire <buttons|->...\nSet autofire pattern\n",
287 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
288 auto r
= regex(".*[^ \t].*", a
, "Need at least one frame for autofire");
289 std::vector
<controller_frame
> new_autofire_pattern
;
291 std::string pattern
= a
;
292 while(pattern
!= "") {
293 std::string fpattern
;
294 extract_token(pattern
, fpattern
, " \t", true);
296 new_autofire_pattern
.push_back(controls
.get_blank());
298 controller_frame
c(controls
.get_blank());
299 while(fpattern
!= "") {
300 size_t split
= fpattern
.find_first_of(",");
301 std::string button
= fpattern
;
303 if(split
< fpattern
.length()) {
304 button
= fpattern
.substr(0, split
);
305 rest
= fpattern
.substr(split
+ 1);
307 if(!active_buttons
.count(button
))
308 (stringfmt() << "Invalid button '" << button
<< "'").throwex();
309 auto g
= active_buttons
[button
];
311 (stringfmt() << "Invalid button '" << button
<< "'").throwex();
312 c
.axis3(g
.port
, g
.controller
, g
.bind
.control1
, true);
315 new_autofire_pattern
.push_back(c
);
318 controls
.autofire(new_autofire_pattern
);
321 void do_action(const std::string
& name
, short state
, int mode
)
324 do_button_action(name
, state
, mode
);
326 keyboard_key
* mouse_x
= lsnes_kbd
.try_lookup_key("mouse_x");
327 keyboard_key
* mouse_y
= lsnes_kbd
.try_lookup_key("mouse_y");
328 if(!mouse_x
|| !mouse_y
) {
329 messages
<< "Controller analog function not available without mouse" << std::endl
;
332 send_analog(name
, mouse_x
->get_state(), mouse_y
->get_state());
336 function_ptr_command
<const std::string
&> button_p(lsnes_cmd
, "+controller", "Press a button",
337 "Syntax: +button <button>...\nPress a button\n",
338 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
342 function_ptr_command
<const std::string
&> button_r(lsnes_cmd
, "-controller", "Release a button",
343 "Syntax: -button <button>...\nRelease a button\n",
344 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
348 function_ptr_command
<const std::string
&> button_h(lsnes_cmd
, "hold-controller", "Autohold a button",
349 "Syntax: hold-button <button>...\nAutohold a button\n",
350 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
354 function_ptr_command
<const std::string
&> button_t(lsnes_cmd
, "type-controller", "Type a button",
355 "Syntax: type-button <button>...\nType a button\n",
356 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
360 function_ptr_command
<const std::string
&> button_d(lsnes_cmd
, "designate-position", "Set postion",
361 "Syntax: designate-position <button>...\nDesignate position for an axis\n",
362 [](const std::string
& a
) throw(std::bad_alloc
, std::runtime_error
) {
366 class new_core_snoop
: public information_dispatch
369 new_core_snoop() : information_dispatch("controller-newcore")
379 void reinitialize_buttonmap()
384 void reread_active_buttons()
386 std::map
<std::string
, unsigned> classnum
;
387 active_buttons
.clear();
388 for(unsigned i
= 0;; i
++) {
389 auto x
= controls
.lcid_to_pcid(i
);
392 const port_type
& pt
= controls
.get_blank().get_port_type(x
.first
);
393 const port_controller
& ctrl
= *pt
.controller_info
->controllers
[x
.second
];
394 if(!classnum
.count(ctrl
.cclass
))
395 classnum
[ctrl
.cclass
] = 1;
397 classnum
[ctrl
.cclass
]++;
398 for(unsigned j
= 0; j
< ctrl
.button_count
; j
++) {
399 std::string name
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
400 << ctrl
.buttons
[j
]->name
).str();
401 if(all_buttons
.count(name
)) {
404 a
.controller
= x
.second
;
405 a
.bind
= all_buttons
[name
];
406 active_buttons
[name
] = a
;
409 bool multi
= (ctrl
.analog_actions() > 1);
410 for(unsigned j
= 0; j
< ctrl
.analog_actions(); j
++) {
413 name
= (stringfmt() << "analog" << (j
+ 1)).str();
416 std::string cname
= (stringfmt() << ctrl
.cclass
<< "-" << classnum
[ctrl
.cclass
] << "-"
418 if(all_buttons
.count(cname
)) {
421 a
.controller
= x
.second
;
422 a
.bind
= all_buttons
[cname
];
423 active_buttons
[cname
] = a
;
429 controller_state controls
;
430 std::map
<std::string
, std::string
> button_keys
;