bsnes/qt/settings/input.cpp

355 lines
11 KiB
C++
Executable File

#include "input.moc"
InputSettingsWindow *inputSettingsWindow;
InputSettingsWindow::InputSettingsWindow() {
activeInput = 0;
activeGroup = 0;
groupIndex = 0;
activeMouse = 0;
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
setLayout(layout);
list = new QTreeWidget;
list->setColumnCount(2);
list->setAllColumnsShowFocus(true);
list->setSortingEnabled(false);
list->header()->hide();
list->header()->setResizeMode(QHeaderView::ResizeToContents);
layout->addWidget(list);
controlLayout = new QHBoxLayout;
layout->addLayout(controlLayout);
message = new QLabel;
message->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
controlLayout->addWidget(message);
assignButton = new QPushButton("Assign");
controlLayout->addWidget(assignButton);
unassignButton = new QPushButton("Unassign");
controlLayout->addWidget(unassignButton);
buttonBox = new QLabel("Mouse Button");
buttonBox->setFrameStyle(QFrame::Panel | QFrame::Raised);
buttonBox->hide();
controlLayout->addWidget(buttonBox);
xAxisButton = new QPushButton("Mouse X-axis");
xAxisButton->hide();
controlLayout->addWidget(xAxisButton);
yAxisButton = new QPushButton("Mouse Y-axis");
yAxisButton->hide();
controlLayout->addWidget(yAxisButton);
stopButton = new QPushButton("Stop");
stopButton->hide();
controlLayout->addWidget(stopButton);
connect(list, SIGNAL(itemSelectionChanged()), this, SLOT(synchronize()));
connect(list, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(activateAssign()));
connect(assignButton, SIGNAL(released()), this, SLOT(assign()));
connect(unassignButton, SIGNAL(released()), this, SLOT(unassign()));
connect(xAxisButton, SIGNAL(released()), this, SLOT(xAxisAssign()));
connect(yAxisButton, SIGNAL(released()), this, SLOT(yAxisAssign()));
connect(stopButton, SIGNAL(released()), this, SLOT(stop()));
//initialize list
port1 = new QTreeWidgetItem(list);
port1->setData(0, Qt::UserRole, QVariant(-1));
port1->setText(0, "Controller Port 1");
port2 = new QTreeWidgetItem(list);
port2->setData(0, Qt::UserRole, QVariant(-1));
port2->setText(0, "Controller Port 2");
userInterface = new QTreeWidgetItem(list);
userInterface->setData(0, Qt::UserRole, QVariant(-1));
userInterface->setText(0, "User Interface");
for(unsigned i = 0; i < mapper().size(); i++) {
InputGroup &group = *(mapper()[i]);
QTreeWidgetItem *grandparent = 0;
if(group.category == InputCategory::Port1) { grandparent = port1; }
if(group.category == InputCategory::Port2) { grandparent = port2; }
if(group.category == InputCategory::UserInterface) { grandparent = userInterface; }
if(!grandparent) continue;
QTreeWidgetItem *parent = new QTreeWidgetItem(grandparent);
parent->setData(0, Qt::UserRole, QVariant(-1));
parent->setText(0, group.label);
for(unsigned i = 0; i < group.size(); i++) {
QTreeWidgetItem *child = new QTreeWidgetItem(parent);
child->setData(0, Qt::UserRole, QVariant(inputTable.size()));
inputTable.append(group[i]);
}
}
updateList();
synchronize();
}
void InputSettingsWindow::synchronize() {
bool enable = false;
QList<QTreeWidgetItem*> items = list->selectedItems();
if(items.count() > 0) {
QTreeWidgetItem *item = items[0];
signed index = item->data(0, Qt::UserRole).toInt();
if(index >= 0) enable = true;
else {
item = item->child(0);
if(item) {
index = item->data(0, Qt::UserRole).toInt();
if(index >= 0) enable = true;
}
}
}
assignButton->setEnabled(enable);
unassignButton->setEnabled(enable);
}
void InputSettingsWindow::setActiveInput(MappedInput *input) {
//flush any pending events to prevent instantaneous assignment of scancodes
activeInput = 0;
mapper().poll();
activeInput = input;
if(activeInput) {
assignButton->hide();
unassignButton->hide();
if(dynamic_cast<DigitalInput*>(input)) {
buttonBox->show();
xAxisButton->hide();
yAxisButton->hide();
} else {
buttonBox->hide();
xAxisButton->show();
yAxisButton->show();
}
stopButton->show();
message->setFocus();
message->setText(string() << "Set assignment for: " << activeInput->label);
} else {
assignButton->show();
unassignButton->show();
buttonBox->hide();
xAxisButton->hide();
yAxisButton->hide();
stopButton->hide();
list->setFocus();
message->setText("");
}
}
void InputSettingsWindow::updateList() {
QList<QTreeWidgetItem*> all = list->findItems("", Qt::MatchContains);
for(unsigned i = 0; i < all.size(); i++) {
QTreeWidgetItem *grandparent = all[i];
for(unsigned j = 0; j < grandparent->childCount(); j++) {
QTreeWidgetItem *parent = grandparent->child(j);
for(unsigned k = 0; k < parent->childCount(); k++) {
QTreeWidgetItem *child = parent->child(k);
signed index = child->data(0, Qt::UserRole).toInt();
if(index == -1) continue;
MappedInput *input = inputTable[index];
child->setText(0, input->label);
child->setText(1, string() << "= " << input->name);
child->setForeground(1, QBrush(QColor(128, 128, 128)));
}
}
}
}
void InputSettingsWindow::setAssignment(string name) {
//if all controls in a group are being assigned at once,
//ensure the same keycode is not used more than once
if(activeGroup) {
for(unsigned i = 0; i < groupIndex; i++) {
if((*activeGroup)[i]->name == name) return;
}
}
activeInput->name = name;
mapper().bind();
updateList();
if(!activeGroup) {
setActiveInput(0);
} else if(++groupIndex >= activeGroup->size()) {
setActiveInput(0);
activeGroup = 0;
} else {
setActiveInput((*activeGroup)[groupIndex]);
}
}
void InputSettingsWindow::inputEvent(uint16_t scancode) {
if(!activeInput) return;
if(!isActiveWindow() || isMinimized()) return;
int16_t state = mapper().state(scancode);
if(dynamic_cast<DigitalInput*>(activeInput)) {
if(Keyboard::isAnyKey(scancode) && mapper().state(scancode)) {
for(unsigned i = 0; i < Keyboard::Count; i++) {
//don't map escape key, as it is reserved by the user interface
if(scancode == keyboard(i)[Keyboard::Escape]) return;
}
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
} else if(Keyboard::isAnyModifier(scancode) && !config().input.modifierEnable) {
setAssignment(string() << Scancode::encode(scancode));
} else if(Mouse::isAnyButton(scancode) && !mapper().state(scancode)) {
//ensure button was clicked inside list box
unsigned wx = 0, wy = 0;
QWidget *widget = buttonBox;
while(widget) {
wx += widget->geometry().x();
wy += widget->geometry().y();
widget = widget->parentWidget();
}
unsigned px = QCursor::pos().x();
unsigned py = QCursor::pos().y();
if(px < wx || px >= wx + buttonBox->size().width()) return;
if(py < wy || py >= wy + buttonBox->size().height()) return;
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
} else if(Joypad::isAnyHat(scancode)) {
string position;
if(state == Joypad::HatUp) position = ".Up";
else if(state == Joypad::HatDown) position = ".Down";
else if(state == Joypad::HatLeft) position = ".Left";
else if(state == Joypad::HatRight) position = ".Right";
else return;
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << position);
} else if(Joypad::isAnyAxis(scancode) && mapper().distance(scancode) > 64) {
if(mapper().calibrated == false) {
MappedInput *temp = activeInput;
activeInput = 0;
mapper().calibrate();
activeInput = temp;
return;
}
if(mapper().isTrigger[Joypad::numberDecode(scancode)][Joypad::axisDecode(scancode)] == false) {
string position;
if(state < -24576) position = ".Lo";
else if(state > +24576) position = ".Hi";
else return;
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << position);
} else {
if(state >= 0) return;
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << ".Trigger");
}
} else if(Joypad::isAnyButton(scancode) && mapper().state(scancode)) {
setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
}
} else if(dynamic_cast<AnalogInput*>(activeInput)) {
if(Mouse::isAnyButton(scancode) && mapper().state(scancode)) {
//actual assignment occurs during (x,y)AxisButton::released()
activeMouse = Mouse::numberDecode(scancode);
} else if(Joypad::isAnyAxis(scancode) && mapper().distance(scancode) > 64) {
if(mapper().calibrated == false) {
MappedInput *temp = activeInput;
activeInput = 0;
mapper().calibrate();
activeInput = temp;
return;
}
if(mapper().isTrigger[Joypad::numberDecode(scancode)][Joypad::axisDecode(scancode)] == false) {
if(state < -24576 || state > +24576) {
setAssignment(string() << Scancode::encode(scancode));
}
}
}
}
}
//called when double-clicking any list item;
//double-clicking a group expands or collapses it,
//so avoid triggering assign() unless this is not a group
void InputSettingsWindow::activateAssign() {
QTreeWidgetItem *item = list->currentItem();
if(!item) return;
signed index = item->data(0, Qt::UserRole).toInt();
if(index >= 0) assign();
}
void InputSettingsWindow::assign() {
QTreeWidgetItem *item = list->currentItem();
if(!item) return;
signed index = item->data(0, Qt::UserRole).toInt();
if(index == -1) return assignGroup();
setActiveInput(inputTable[index]);
}
void InputSettingsWindow::assignGroup() {
QTreeWidgetItem *item = list->currentItem();
if(!item) return;
item->setExpanded(true);
item = item->child(0);
if(!item) return;
signed index = item->data(0, Qt::UserRole).toInt();
if(index == -1) return;
MappedInput *input = inputTable[index];
activeGroup = input->parent;
setActiveInput((*activeGroup)[groupIndex = 0]);
}
void InputSettingsWindow::unassign() {
QTreeWidgetItem *item = list->currentItem();
if(!item) return;
signed index = item->data(0, Qt::UserRole).toInt();
if(index == -1) return unassignGroup();
MappedInput *input = inputTable[index];
input->name = "None";
mapper().bind();
updateList();
}
void InputSettingsWindow::unassignGroup() {
QTreeWidgetItem *item = list->currentItem();
if(!item) return;
item = item->child(0);
if(!item) return;
signed index = item->data(0, Qt::UserRole).toInt();
if(index == -1) return;
MappedInput *input = inputTable[index];
InputGroup &group = *(input->parent);
for(unsigned i = 0; i < group.size(); i++) {
group[i]->name = "None";
}
mapper().bind();
updateList();
}
void InputSettingsWindow::xAxisAssign() {
setAssignment(string() << Scancode::encode(mouse(activeMouse).axis(0)));
}
void InputSettingsWindow::yAxisAssign() {
setAssignment(string() << Scancode::encode(mouse(activeMouse).axis(1)));
}
void InputSettingsWindow::stop() {
setActiveInput(0);
activeGroup = 0;
}