lsnes/src/core/controller.cpp

229 lines
6 KiB
C++
Raw Normal View History

2011-09-16 06:13:33 +03:00
#include "lsnes.hpp"
#include <snes/snes.hpp>
#include <ui-libsnes/libsnes.hpp>
2011-11-06 14:41:41 +02:00
#include "core/command.hpp"
#include "core/controller.hpp"
#include "core/dispatch.hpp"
2011-11-06 14:41:41 +02:00
#include "core/framebuffer.hpp"
#include "core/mainloop.hpp"
#include "core/misc.hpp"
2011-11-06 14:41:41 +02:00
#include "core/window.hpp"
#include <map>
#include <sstream>
2011-09-16 06:13:33 +03:00
namespace
{
std::map<std::string, std::pair<unsigned, unsigned>> buttonmap;
void init_buttonmap()
{
static int done = 0;
if(done)
return;
for(unsigned i = 0; i < 8; i++)
for(unsigned j = 0; j < MAX_LOGICAL_BUTTONS; j++) {
std::ostringstream x;
x << (i + 1) << get_logical_button_name(j);
buttonmap[x.str()] = std::make_pair(i, j);
}
done = 1;
}
//Do button action.
void do_button_action(unsigned ui_id, unsigned button, short newstate, bool autoh)
{
int x = controls.lcid_to_pcid(ui_id);
if(x < 0) {
messages << "No such controller #" << (ui_id + 1) << std::endl;
return;
}
int bid = controls.button_id(x, button);
if(bid < 0) {
messages << "Invalid button for controller type" << std::endl;
return;
}
if(autoh) {
controls.autohold(x, bid, controls.autohold(x, bid) ^ newstate);
information_dispatch::do_autohold_update(x, bid, controls.autohold(x, bid));
} else
controls.button(x, bid, newstate);
}
void send_analog(unsigned lcid, int32_t x, int32_t y)
{
int pcid = controls.lcid_to_pcid(lcid);
if(pcid < 0) {
messages << "Controller #" << (lcid + 1) << " not present" << std::endl;
return;
}
if(controls.is_analog(pcid) < 0) {
messages << "Controller #" << (lcid + 1) << " is not analog" << std::endl;
return;
}
auto g2 = get_framebuffer_size();
if(controls.is_mouse(pcid)) {
controls.analog(pcid, x - g2.first / 2, y - g2.second / 2);
} else
controls.analog(pcid, x / 2 , y / 2);
}
function_ptr_command<tokensplitter&> autofire("autofire", "Set autofire pattern",
"Syntax: autofire <buttons|->...\nSet autofire pattern\n",
[](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
if(!t)
throw std::runtime_error("Need at least one frame for autofire");
std::vector<controller_frame> new_autofire_pattern;
init_buttonmap();
while(t) {
std::string fpattern = t;
if(fpattern == "-")
new_autofire_pattern.push_back(controls.get_blank());
else {
controller_frame c(controls.get_blank());
while(fpattern != "") {
size_t split = fpattern.find_first_of(",");
std::string button = fpattern;
std::string rest;
if(split < fpattern.length()) {
button = fpattern.substr(0, split);
rest = fpattern.substr(split + 1);
}
if(!buttonmap.count(button)) {
std::ostringstream x;
x << "Invalid button '" << button << "'";
throw std::runtime_error(x.str());
}
auto g = buttonmap[button];
int x = controls.lcid_to_pcid(g.first);
if(x < 0) {
std::ostringstream x;
x << "No such controller #" << (g.first + 1) << std::endl;
throw std::runtime_error(x.str());
}
int bid = controls.button_id(x, g.second);
if(bid < 0) {
std::ostringstream x;
x << "Invalid button for controller type" << std::endl;
throw std::runtime_error(x.str());
}
c.axis(x, bid, true);
fpattern = rest;
}
new_autofire_pattern.push_back(c);
}
}
controls.autofire(new_autofire_pattern);
});
class button_action : public command
{
public:
button_action(const std::string& cmd, int _type, unsigned _controller, std::string _button)
throw(std::bad_alloc)
: command(cmd)
{
commandn = cmd;
type = _type;
controller = _controller;
button = _button;
}
~button_action() throw() {}
void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
{
if(args != "")
throw std::runtime_error("This command does not take parameters");
init_buttonmap();
if(!buttonmap.count(button))
return;
auto i = buttonmap[button];
do_button_action(i.first, i.second, (type != 1) ? 1 : 0, (type == 2));
update_movie_state();
information_dispatch::do_status_update();
}
std::string get_short_help() throw(std::bad_alloc)
{
return "Press/Unpress button";
}
std::string get_long_help() throw(std::bad_alloc)
{
return "Syntax: " + commandn + "\n"
"Presses/Unpresses button\n";
}
std::string commandn;
unsigned controller;
int type;
std::string button;
};
class analog_action : public command
{
public:
analog_action(const std::string& cmd, unsigned _controller)
throw(std::bad_alloc)
: command(cmd)
{
controller = _controller;
}
~analog_action() throw() {}
void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
{
if(args != "")
throw std::runtime_error("This command does not take parameters");
keygroup* mouse_x = keygroup::lookup_by_name("mouse_x");
keygroup* mouse_y = keygroup::lookup_by_name("mouse_y");
if(!mouse_x || !mouse_y) {
messages << "Controller analog function not available without mouse" << std::endl;
return;
}
send_analog(controller, mouse_x->get_value(), mouse_y->get_value());
}
private:
unsigned controller;
};
class button_action_helper
{
public:
button_action_helper()
{
for(size_t i = 0; i < MAX_LOGICAL_BUTTONS; ++i)
for(int j = 0; j < 3; ++j)
for(unsigned k = 0; k < 8; ++k) {
2012-01-10 01:12:17 +02:00
std::string x, y;
char cstr[2] = {0, 0};
cstr[0] = 49 + k;
switch(j) {
case 0:
2012-01-10 01:12:17 +02:00
x = "+controller";
break;
case 1:
2012-01-10 01:12:17 +02:00
x = "-controller";
break;
case 2:
2012-01-10 01:12:17 +02:00
x = "controllerh";
break;
};
x = x + cstr + get_logical_button_name(i);
y = cstr + get_logical_button_name(i);
2012-01-10 01:12:17 +02:00
our_commands.insert(new button_action(x, j, k, y));
}
for(unsigned k = 0; k < 8; ++k) {
std::string x = "controllerXanalog";
x[10] = 49 + k;
our_commands.insert(new analog_action(x, k));
}
}
2012-01-10 01:12:17 +02:00
~button_action_helper()
{
for(auto i : our_commands)
delete i;
our_commands.clear();
}
std::set<command*> our_commands;
} bah;
2011-09-16 06:13:33 +03:00
}
controller_state controls;