bsnes/qt/input/controller.cpp

386 lines
14 KiB
C++
Executable File

namespace Controllers {
void TurboInput::cache() {
if(state) {
cachedState = (counter < holdHi ? state : 0);
if(++counter >= holdHi + holdLo) counter = 0;
} else {
cachedState = 0;
counter = 0;
}
}
TurboInput::TurboInput(const char *label, const char *configName) :
DigitalInput(label, configName) {
holdHi = 2;
holdLo = 2;
counter = 0;
}
int16_t Gamepad::status(unsigned index, unsigned id) const {
if(config().input.allowInvalidInput == false) {
//block up+down and left+right combinations:
//a real gamepad has a pivot in the D-pad that makes this impossible;
//some software titles will crash if up+down or left+right are detected
if(id == (unsigned)SNES::Input::JoypadID::Down && up.cachedState) return 0;
if(id == (unsigned)SNES::Input::JoypadID::Right && left.cachedState) return 0;
}
switch(id) {
case SNES::Input::JoypadID::Up: return up.cachedState;
case SNES::Input::JoypadID::Down: return down.cachedState;
case SNES::Input::JoypadID::Left: return left.cachedState;
case SNES::Input::JoypadID::Right: return right.cachedState;
case SNES::Input::JoypadID::A: return a.cachedState | turboA.cachedState;
case SNES::Input::JoypadID::B: return b.cachedState | turboB.cachedState;
case SNES::Input::JoypadID::X: return x.cachedState | turboX.cachedState;
case SNES::Input::JoypadID::Y: return y.cachedState | turboY.cachedState;
case SNES::Input::JoypadID::L: return l.cachedState | turboL.cachedState;
case SNES::Input::JoypadID::R: return r.cachedState | turboR.cachedState;
case SNES::Input::JoypadID::Select: return select.cachedState;
case SNES::Input::JoypadID::Start: return start.cachedState;
}
return 0;
}
Gamepad::Gamepad(unsigned category, const char *label, const char *configName) :
InputGroup(category, label),
up("Up", string() << "input." << configName << ".up"),
down("Down", string() << "input." << configName << ".down"),
left("Left", string() << "input." << configName << ".left"),
right("Right", string() << "input." << configName << ".right"),
b("B", string() << "input." << configName << ".b"),
a("A", string() << "input." << configName << ".a"),
y("Y", string() << "input." << configName << ".y"),
x("X", string() << "input." << configName << ".x"),
l("L", string() << "input." << configName << ".l"),
r("R", string() << "input." << configName << ".r"),
select("Select", string() << "input." << configName << ".select"),
start("Start", string() << "input." << configName << ".start"),
turboB("Turbo B", string() << "input." << configName << ".turboB"),
turboA("Turbo A", string() << "input." << configName << ".turboA"),
turboY("Turbo Y", string() << "input." << configName << ".turboY"),
turboX("Turbo X", string() << "input." << configName << ".turboX"),
turboL("Turbo L", string() << "input." << configName << ".turboL"),
turboR("Turbo R", string() << "input." << configName << ".turboR") {
attach(&up); attach(&down); attach(&left); attach(&right);
attach(&b); attach(&a); attach(&y); attach(&x);
attach(&l); attach(&r); attach(&select); attach(&start);
attach(&turboB); attach(&turboA); attach(&turboY); attach(&turboX);
attach(&turboL); attach(&turboR);
if(this == &gamepad1) {
up.name = "KB0::Up";
down.name = "KB0::Down";
left.name = "KB0::Left";
right.name = "KB0::Right";
b.name = "KB0::Z";
a.name = "KB0::X";
y.name = "KB0::A";
x.name = "KB0::S";
l.name = "KB0::D";
r.name = "KB0::C";
select.name = "KB0::Apostrophe";
start.name = "KB0::Return";
}
}
//
int16_t Multitap::status(unsigned index, unsigned id) const {
switch(index & 3) { default:
case 0: return port1.status(index, id);
case 1: return port2.status(index, id);
case 2: return port3.status(index, id);
case 3: return port4.status(index, id);
}
}
Multitap::Multitap(Gamepad &port1_, Gamepad &port2_, Gamepad &port3_, Gamepad &port4_) :
InputGroup(InputCategory::Hidden, "Multitap"),
port1(port1_), port2(port2_), port3(port3_), port4(port4_) {
}
//
void AsciiSwitch::poll() {
DigitalInput::poll();
//only change state when controller is active
if(!parent) return;
if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
if(previousState != state && state) {
switch(mode) {
case Off: mode = Turbo; utility.showMessage(string() << label << " set to turbo."); break;
case Turbo: mode = Auto; utility.showMessage(string() << label << " set to auto."); break;
case Auto: mode = Off; utility.showMessage(string() << label << " set to off."); break;
}
}
}
AsciiSwitch::AsciiSwitch(const char *label, const char *configName) :
DigitalInput(label, configName) {
mode = Off;
}
void AsciiInput::cache() {
if(asciiSwitch->mode == AsciiSwitch::Off) {
cachedState = state;
} else if(asciiSwitch->mode == AsciiSwitch::Turbo) {
if(state) {
cachedState = (counter < holdHi ? state : 0);
if(++counter >= holdHi + holdLo) counter = 0;
} else {
cachedState = 0;
counter = 0;
}
} else if(asciiSwitch->mode == AsciiSwitch::Auto) {
cachedState = (counter < holdHi);
if(++counter >= holdHi + holdLo) counter = 0;
}
}
AsciiInput::AsciiInput(const char *label, const char *configName) :
DigitalInput(label, configName) {
holdHi = 2;
holdLo = 2;
counter = 0;
}
void AsciiSlowMotion::poll() {
DigitalInput::poll();
//only change state when controller is active
if(!parent) return;
if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
if(previousState != state && state) {
if(enabled == false) {
enabled = true;
utility.showMessage(string() << label << " enabled.");
} else {
enabled = false;
utility.showMessage(string() << label << " disabled.");
}
}
}
void AsciiSlowMotion::cache() {
if(enabled == false) {
cachedState = 0;
} else {
cachedState = counter < holdHi;
if(++counter >= holdHi + holdLo) counter = 0;
}
}
AsciiSlowMotion::AsciiSlowMotion(const char *label, const char *configName) :
DigitalInput(label, configName) {
enabled = false;
holdHi = 2;
holdLo = 2;
}
int16_t Asciipad::status(unsigned index, unsigned id) const {
if(config().input.allowInvalidInput == false) {
if(id == (unsigned)SNES::Input::JoypadID::Down && up.cachedState) return 0;
if(id == (unsigned)SNES::Input::JoypadID::Right && left.cachedState) return 0;
}
switch(id) {
case SNES::Input::JoypadID::Up: return up.cachedState;
case SNES::Input::JoypadID::Down: return down.cachedState;
case SNES::Input::JoypadID::Left: return left.cachedState;
case SNES::Input::JoypadID::Right: return right.cachedState;
case SNES::Input::JoypadID::A: return a.cachedState;
case SNES::Input::JoypadID::B: return b.cachedState;
case SNES::Input::JoypadID::X: return x.cachedState;
case SNES::Input::JoypadID::Y: return y.cachedState;
case SNES::Input::JoypadID::L: return l.cachedState;
case SNES::Input::JoypadID::R: return r.cachedState;
case SNES::Input::JoypadID::Select: return select.cachedState;
case SNES::Input::JoypadID::Start: return start.cachedState | slowMotion.cachedState;
}
return 0;
}
Asciipad::Asciipad(unsigned category, const char *label, const char *configName) :
InputGroup(category, label),
up("Up", string() << "input." << configName << ".up"),
down("Down", string() << "input." << configName << ".down"),
left("Left", string() << "input." << configName << ".left"),
right("Right", string() << "input." << configName << ".right"),
b("B", string() << "input." << configName << ".b"),
a("A", string() << "input." << configName << ".a"),
y("Y", string() << "input." << configName << ".y"),
x("X", string() << "input." << configName << ".x"),
l("L", string() << "input." << configName << ".l"),
r("R", string() << "input." << configName << ".r"),
select("Select", string() << "input." << configName << ".select"),
start("Start", string() << "input." << configName << ".start"),
switchB("B Switch", string() << "input." << configName << ".bSwitch"),
switchA("A Switch", string() << "input." << configName << ".aSwitch"),
switchY("Y Switch", string() << "input." << configName << ".ySwitch"),
switchX("X Switch", string() << "input." << configName << ".xSwitch"),
switchL("L Switch", string() << "input." << configName << ".lSwitch"),
switchR("R Switch", string() << "input." << configName << ".rSwitch"),
slowMotion("Slow Motion", string() << "input." << configName << ".slowMotion") {
b.asciiSwitch = &switchB;
a.asciiSwitch = &switchA;
y.asciiSwitch = &switchY;
x.asciiSwitch = &switchX;
l.asciiSwitch = &switchL;
r.asciiSwitch = &switchR;
attach(&up); attach(&down); attach(&left); attach(&right);
attach(&b); attach(&a); attach(&y); attach(&x);
attach(&l); attach(&r); attach(&select); attach(&start);
attach(&switchB); attach(&switchA); attach(&switchY); attach(&switchX);
attach(&switchL); attach(&switchR); attach(&slowMotion);
if(this == &asciipad1) {
up.name = "KB0::Up";
down.name = "KB0::Down";
left.name = "KB0::Left";
right.name = "KB0::Right";
b.name = "KB0::Z";
a.name = "KB0::X";
y.name = "KB0::A";
x.name = "KB0::S";
l.name = "KB0::D";
r.name = "KB0::C";
select.name = "KB0::Apostrophe";
start.name = "KB0::Return";
}
}
//
int16_t Mouse::status(unsigned index, unsigned id) const {
switch(id) {
case SNES::Input::MouseID::X: return x.cachedState;
case SNES::Input::MouseID::Y: return y.cachedState;
case SNES::Input::MouseID::Left: return left.cachedState;
case SNES::Input::MouseID::Right: return right.cachedState;
}
return 0;
}
Mouse::Mouse(unsigned category, const char *label, const char *configName) :
InputGroup(category, label),
x("X-axis", string() << "input." << configName << ".x"),
y("Y-axis", string() << "input." << configName << ".y"),
left("Left Button", string() << "input." << configName << ".left"),
right("Right Button", string() << "input." << configName << ".right") {
attach(&x); attach(&y); attach(&left); attach(&right);
x.name = "MS0::Xaxis";
y.name = "MS0::Yaxis";
left.name = "MS0::Button0";
right.name = "MS0::Button2";
}
//
int16_t SuperScope::status(unsigned index, unsigned id) const {
switch(id) {
case SNES::Input::SuperScopeID::X: return x.cachedState;
case SNES::Input::SuperScopeID::Y: return y.cachedState;
case SNES::Input::SuperScopeID::Trigger: return trigger.cachedState;
case SNES::Input::SuperScopeID::Cursor: return cursor.cachedState;
case SNES::Input::SuperScopeID::Turbo: return turbo.cachedState;
case SNES::Input::SuperScopeID::Pause: return pause.cachedState;
}
return 0;
}
SuperScope::SuperScope(unsigned category, const char *label, const char *configName) :
InputGroup(category, label),
x("X-axis", string() << "input." << configName << ".x"),
y("Y-axis", string() << "input." << configName << ".y"),
trigger("Trigger", string() << "input." << configName << ".trigger"),
cursor("Cursor", string() << "input." << configName << ".cursor"),
turbo("Turbo", string() << "input." << configName << ".turbo"),
pause("Pause", string() << "input." << configName << ".pause") {
attach(&x); attach(&y); attach(&trigger); attach(&cursor);
attach(&turbo); attach(&pause);
x.name = "MS0::Xaxis";
y.name = "MS0::Yaxis";
trigger.name = "MS0::Button0";
cursor.name = "MS0::Button2";
turbo.name = "KB0::T";
pause.name = "KB0::P";
}
//
int16_t Justifier::status(unsigned index, unsigned id) const {
switch(id) {
case SNES::Input::JustifierID::X: return x.cachedState;
case SNES::Input::JustifierID::Y: return y.cachedState;
case SNES::Input::JustifierID::Trigger: return trigger.cachedState;
case SNES::Input::JustifierID::Start: return start.cachedState;
}
return 0;
}
Justifier::Justifier(unsigned category, const char *label, const char *configName) :
InputGroup(category, label),
x("X-axis", string() << "input." << configName << ".x"),
y("Y-axis", string() << "input." << configName << ".y"),
trigger("Trigger", string() << "input." << configName << ".trigger"),
start("Start", string() << "input." << configName << ".start") {
attach(&x); attach(&y); attach(&trigger); attach(&start);
if(this == &justifier1) {
x.name = "MS0::Xaxis";
y.name = "MS0::Yaxis";
trigger.name = "MS0::Button0";
start.name = "MS0::Button2";
}
}
//
int16_t Justifiers::status(unsigned index, unsigned id) const {
switch(index & 1) { default:
case 0: return port1.status(index, id);
case 1: return port2.status(index, id);
}
}
Justifiers::Justifiers(Justifier &port1_, Justifier &port2_) :
InputGroup(InputCategory::Hidden, "Justifiers"),
port1(port1_), port2(port2_) {
}
//
Gamepad gamepad1(InputCategory::Port1, "Gamepad", "gamepad1");
Asciipad asciipad1(InputCategory::Port1, "asciiPad", "asciipad1");
Gamepad multitap1a(InputCategory::Port1, "Multitap - Port 1", "multitap1a");
Gamepad multitap1b(InputCategory::Port1, "Multitap - Port 2", "multitap1b");
Gamepad multitap1c(InputCategory::Port1, "Multitap - Port 3", "multitap1c");
Gamepad multitap1d(InputCategory::Port1, "Multitap - Port 4", "multitap1d");
Multitap multitap1(multitap1a, multitap1b, multitap1c, multitap1d);
Mouse mouse1(InputCategory::Port1, "Mouse", "mouse1");
Gamepad gamepad2(InputCategory::Port2, "Gamepad", "gamepad2");
Asciipad asciipad2(InputCategory::Port2, "asciiPad", "asciipad2");
Gamepad multitap2a(InputCategory::Port2, "Multitap - Port 1", "multitap2a");
Gamepad multitap2b(InputCategory::Port2, "Multitap - Port 2", "multitap2b");
Gamepad multitap2c(InputCategory::Port2, "Multitap - Port 3", "multitap2c");
Gamepad multitap2d(InputCategory::Port2, "Multitap - Port 4", "multitap2d");
Multitap multitap2(multitap2a, multitap2b, multitap2c, multitap2d);
Mouse mouse2(InputCategory::Port2, "Mouse", "mouse2");
SuperScope superscope(InputCategory::Port2, "Super Scope", "superscope");
Justifier justifier1(InputCategory::Port2, "Justifier 1", "justifier1");
Justifier justifier2(InputCategory::Port2, "Justifier 2", "justifier2");
Justifiers justifiers(justifier1, justifier2);
}