bsnes/qt/input/input.cpp

273 lines
7.9 KiB
C++
Executable File

#include "../ui-base.hpp"
#include "controller.cpp"
#include "userinterface-general.cpp"
#include "userinterface-system.cpp"
#include "userinterface-emulationspeed.cpp"
#include "userinterface-states.cpp"
#include "userinterface-videosettings.cpp"
void MappedInput::bind() {
lstring part;
part.split("+", name);
modifier = InputModifier::None;
for(unsigned i = 0; i < part.size(); i++) {
if(part[i] == "Shift") modifier |= InputModifier::Shift;
if(part[i] == "Control") modifier |= InputModifier::Control;
if(part[i] == "Alt") modifier |= InputModifier::Alt;
if(part[i] == "Super") modifier |= InputModifier::Super;
}
string temp = part[part.size() - 1];
part.split(".", temp);
scancode = Scancode::decode(part[0]);
specifier = InputSpecifier::None;
if(part[1] == "Up") specifier = InputSpecifier::Up;
if(part[1] == "Down") specifier = InputSpecifier::Down;
if(part[1] == "Left") specifier = InputSpecifier::Left;
if(part[1] == "Right") specifier = InputSpecifier::Right;
if(part[1] == "Lo") specifier = InputSpecifier::Lo;
if(part[1] == "Hi") specifier = InputSpecifier::Hi;
if(part[1] == "Trigger") specifier = InputSpecifier::Trigger;
//re-encode name, in case previous name was invalid
name = "";
if(modifier & InputModifier::Shift) name << "Shift+";
if(modifier & InputModifier::Control) name << "Control+";
if(modifier & InputModifier::Alt) name << "Alt+";
if(modifier & InputModifier::Super) name << "Super+";
name << Scancode::encode(scancode);
if(specifier == InputSpecifier::Up) name << ".Up";
if(specifier == InputSpecifier::Down) name << ".Down";
if(specifier == InputSpecifier::Left) name << ".Left";
if(specifier == InputSpecifier::Right) name << ".Right";
if(specifier == InputSpecifier::Lo) name << ".Lo";
if(specifier == InputSpecifier::Hi) name << ".Hi";
if(specifier == InputSpecifier::Trigger) name << ".Trigger";
}
void MappedInput::cache() {
cachedState = state;
}
MappedInput::MappedInput(const char *label_, const char *configName) : parent(0), label(label_) {
specifier = InputSpecifier::None;
state = 0;
previousState = 0;
cachedState = 0;
config().attach(name = "None", configName);
}
//
void DigitalInput::poll() {
previousState = state;
if(modifier == mapper().modifier || !config().input.modifierEnable) {
if(specifier == InputSpecifier::None) {
state = mapper().state(scancode);
} else if(specifier == InputSpecifier::Up) {
state = (bool)(mapper().state(scancode) & Joypad::HatUp);
} else if(specifier == InputSpecifier::Down) {
state = (bool)(mapper().state(scancode) & Joypad::HatDown);
} else if(specifier == InputSpecifier::Left) {
state = (bool)(mapper().state(scancode) & Joypad::HatLeft);
} else if(specifier == InputSpecifier::Right) {
state = (bool)(mapper().state(scancode) & Joypad::HatRight);
} else if(specifier == InputSpecifier::Lo) {
state = mapper().state(scancode) < -16384;
} else if(specifier == InputSpecifier::Hi) {
state = mapper().state(scancode) > +16384;
} else if(specifier == InputSpecifier::Trigger) {
state = mapper().state(scancode) < 0;
}
} else {
state = 0;
}
}
bool DigitalInput::isPressed() const { return state; }
bool DigitalInput::wasPressed() const { return previousState; }
DigitalInput::DigitalInput(const char *label, const char *configName) : MappedInput(label, configName) {
}
//
void AnalogInput::poll() {
previousState = state;
if(Mouse::isAnyAxis(scancode)) {
if(input.acquired()) {
state = mapper().state(scancode);
} else {
state = 0;
}
} else if(Joypad::isAnyAxis(scancode)) {
state = mapper().state(scancode) / 8192;
}
}
AnalogInput::AnalogInput(const char *label, const char *configName) : MappedInput(label, configName) {
}
//
void HotkeyInput::poll() {
DigitalInput::poll();
if(mainWindow->isActive() && state != previousState) {
state ? pressed() : released();
}
}
HotkeyInput::HotkeyInput(const char *label, const char *configName) : DigitalInput(label, configName) {
}
//
void InputGroup::attach(MappedInput *input) {
input->parent = this;
append(input);
}
void InputGroup::bind() {
for(unsigned i = 0; i < size(); i++) {
(*this)[i]->bind();
}
}
void InputGroup::poll() {
for(unsigned i = 0; i < size(); i++) {
(*this)[i]->poll();
}
}
void InputGroup::cache() {
for(unsigned i = 0; i < size(); i++) {
(*this)[i]->cache();
}
}
void InputGroup::flushCache() {
for(unsigned i = 0; i < size(); i++) {
MappedInput &input = *((*this)[i]);
input.cachedState = 0;
}
}
InputGroup::InputGroup(unsigned category_, const char *label_) : category(category_), label(label_) {
mapper().append(this);
}
//
InputMapper& mapper() {
static InputMapper mapper;
return mapper;
}
void InputMapper::calibrate() {
calibrated = true;
audio.clear();
QMessageBox::information(settingsWindow, "Joypad Calibration",
"Joypads must be calibrated prior to mapping. Please ensure that "
"all axes and analog buttons are not pressed or moved in any specific "
"direction, and then press ok."
);
poll();
for(unsigned i = 0; i < Joypad::Count; i++) {
for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
int16_t n = state(joypad(i).axis(axis));
isTrigger[i][axis] = n < -16384 || n > +16384;
}
}
}
void InputMapper::bind() {
for(unsigned i = 0; i < size(); i++) {
(*this)[i]->bind();
}
}
void InputMapper::poll() {
activeState = !activeState;
input.poll(stateTable[activeState]);
modifier = 0;
for(unsigned i = 0; i < Keyboard::Count; i++) {
if(state(keyboard(i)[Keyboard::Shift])) modifier |= InputModifier::Shift;
if(state(keyboard(i)[Keyboard::Control])) modifier |= InputModifier::Control;
if(state(keyboard(i)[Keyboard::Alt])) modifier |= InputModifier::Alt;
if(state(keyboard(i)[Keyboard::Super])) modifier |= InputModifier::Super;
}
for(unsigned i = 0; i < size(); i++) {
(*this)[i]->poll();
}
for(unsigned i = 0; i < Scancode::Limit; i++) {
if(state(i) != previousState(i)) {
utility.inputEvent(i);
inputSettingsWindow->inputEvent(i);
}
}
}
void InputMapper::cache() {
if(config().input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput && !mainWindow->isActive()) {
for(unsigned i = 0; i < size(); i++) {
InputGroup &group = *((*this)[i]);
group.flushCache();
}
} else {
for(unsigned i = 0; i < size(); i++) {
InputGroup &group = *((*this)[i]);
if(group.category == InputCategory::Port1 || group.category == InputCategory::Port2) {
group.cache();
}
}
}
}
int16_t InputMapper::status(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
int16_t result = 0;
if(port == InputCategory::Port1 && port1) result = port1->status(index, id);
if(port == InputCategory::Port2 && port2) result = port2->status(index, id);
if(movie.state == Movie::Playback) {
result = movie.read();
} else if(movie.state == Movie::Record) {
movie.write(result);
}
return result;
}
string InputMapper::modifierString() const {
string name;
if(modifier & InputModifier::Shift) name << "Shift+";
if(modifier & InputModifier::Control) name << "Control+";
if(modifier & InputModifier::Alt) name << "Alt+";
if(modifier & InputModifier::Super) name << "Super+";
return name;
}
int16_t InputMapper::state(uint16_t scancode) const { return stateTable[activeState][scancode]; }
int16_t InputMapper::previousState(uint16_t scancode) const { return stateTable[!activeState][scancode]; }
unsigned InputMapper::distance(uint16_t scancode) const { return abs(state(scancode) - previousState(scancode)); }
InputMapper::InputMapper() : port1(0), port2(0) {
calibrated = false;
for(unsigned i = 0; i < Joypad::Count; i++) {
for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
isTrigger[i][axis] = false;
}
}
activeState = 0;
for(unsigned i = 0; i < Scancode::Limit; i++) {
stateTable[0][i] = stateTable[1][i] = 0;
}
}