rpcs3/rpcs3/rpcs3qt/pad_settings_dialog.cpp

503 lines
16 KiB
C++

#include <QCheckBox>
#include <QGroupBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QAction>
#include <QPainter>
#include "pad_settings_dialog.h"
#include "ui_pad_settings_dialog.h"
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString;
pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ptr<PadHandlerBase> handler, QWidget *parent)
: QDialog(parent), ui(new Ui::pad_settings_dialog), m_handler_cfg(handler->GetConfig()), m_device_name(device), m_handler(handler)
{
m_handler_cfg->load();
ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->b_cancel->setDefault(true);
connect(ui->b_cancel, &QAbstractButton::clicked, this, &QWidget::close);
m_padButtons = new QButtonGroup(this);
m_palette = ui->b_left->palette(); // save normal palette
ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large);
ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small);
ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors);
// Adjust to the different pad handlers
if (m_handler_cfg->cfg_type == "keyboard")
{
setWindowTitle(tr("Configure Keyboard"));
m_handler_type = handler_type::handler_type_keyboard;
ui->b_blacklist->setEnabled(false);
}
else if (m_handler_cfg->cfg_type == "xinput")
{
setWindowTitle(tr("Configure XInput"));
m_handler_type = handler_type::handler_type_xinput;
}
else if (m_handler_cfg->cfg_type == "ds4")
{
setWindowTitle(tr("Configure DS4"));
m_handler_type = handler_type::handler_type_ds4;
}
else if (m_handler_cfg->cfg_type == "mmjoystick")
{
setWindowTitle(tr("Configure MMJoystick"));
m_handler_type = handler_type::handler_type_mmjoy;
}
else if (m_handler_cfg->cfg_type == "evdev")
{
setWindowTitle(tr("Configure evdev"));
m_handler_type = handler_type::handler_type_evdev;
}
// Enable Button Remapping
if (m_handler->has_config())
{
// Use timer to get button input
const auto& callback = [=](u16 val, std::string name, int preview_values[6])
{
if (m_handler->has_deadzones())
{
ui->preview_trigger_left->setValue(preview_values[0]);
ui->preview_trigger_right->setValue(preview_values[1]);
if (lx != preview_values[2] || ly != preview_values[3])
{
lx = preview_values[2], ly = preview_values[3];
RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->sizeHint().width(), lx, ly);
}
if (rx != preview_values[4] || ry != preview_values[5])
{
rx = preview_values[4], ry = preview_values[5];
RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->sizeHint().width(), rx, ry);
}
}
if (val <= 0) return;
LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_cfg->cfg_type, name, val);
if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end)
{
m_cfg_entries[m_button_id].key = name;
m_cfg_entries[m_button_id].text = qstr(name);
ReactivateButtons();
}
};
connect(&m_timer_input, &QTimer::timeout, [=]()
{
std::vector<std::string> buttons =
{
m_cfg_entries[button_ids::id_pad_l2].key,
m_cfg_entries[button_ids::id_pad_r2].key,
m_cfg_entries[button_ids::id_pad_lstick_left].key,
m_cfg_entries[button_ids::id_pad_lstick_right].key,
m_cfg_entries[button_ids::id_pad_lstick_down].key,
m_cfg_entries[button_ids::id_pad_lstick_up].key,
m_cfg_entries[button_ids::id_pad_rstick_left].key,
m_cfg_entries[button_ids::id_pad_rstick_right].key,
m_cfg_entries[button_ids::id_pad_rstick_down].key,
m_cfg_entries[button_ids::id_pad_rstick_up].key
};
m_handler->GetNextButtonPress(m_device_name, callback, false, buttons);
});
m_timer_input.start(1);
};
// Enable Vibration Checkboxes
if (m_handler->has_rumble())
{
const s32 min_force = m_handler->vibration_min;
const s32 max_force = m_handler->vibration_max;
ui->chb_vibration_large->setEnabled(true);
ui->chb_vibration_small->setEnabled(true);
ui->chb_vibration_switch->setEnabled(true);
connect(ui->chb_vibration_large, &QCheckBox::clicked, [=](bool checked)
{
if (!checked) return;
ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, min_force, max_force)
: m_handler->TestVibration(m_device_name, max_force, min_force);
QTimer::singleShot(300, [=]()
{
m_handler->TestVibration(m_device_name, min_force, min_force);
});
});
connect(ui->chb_vibration_small, &QCheckBox::clicked, [=](bool checked)
{
if (!checked) return;
ui->chb_vibration_switch->isChecked() ? m_handler->TestVibration(m_device_name, max_force, min_force)
: m_handler->TestVibration(m_device_name, min_force, max_force);
QTimer::singleShot(300, [=]()
{
m_handler->TestVibration(m_device_name, min_force, min_force);
});
});
connect(ui->chb_vibration_switch, &QCheckBox::clicked, [=](bool checked)
{
checked ? m_handler->TestVibration(m_device_name, min_force, max_force)
: m_handler->TestVibration(m_device_name, max_force, min_force);
QTimer::singleShot(200, [=]()
{
checked ? m_handler->TestVibration(m_device_name, max_force, min_force)
: m_handler->TestVibration(m_device_name, min_force, max_force);
QTimer::singleShot(200, [=]()
{
m_handler->TestVibration(m_device_name, min_force, min_force);
});
});
});
}
else
{
ui->verticalLayout_left->removeWidget(ui->gb_vibration);
delete ui->gb_vibration;
}
// Enable Deadzone Settings
if (m_handler->has_deadzones())
{
auto initSlider = [=](QSlider* slider, const s32& value, const s32& min, const s32& max)
{
slider->setEnabled(true);
slider->setRange(min, max);
slider->setValue(value);
};
// Enable Trigger Thresholds
initSlider(ui->slider_trigger_left, m_handler_cfg->ltriggerthreshold, 0, m_handler->trigger_max);
initSlider(ui->slider_trigger_right, m_handler_cfg->rtriggerthreshold, 0, m_handler->trigger_max);
ui->preview_trigger_left->setRange(0, m_handler->trigger_max);
ui->preview_trigger_right->setRange(0, m_handler->trigger_max);
// Enable Stick Deadzones
initSlider(ui->slider_stick_left, m_handler_cfg->lstickdeadzone, 0, m_handler->thumb_max);
initSlider(ui->slider_stick_right, m_handler_cfg->rstickdeadzone, 0, m_handler->thumb_max);
RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->sizeHint().width(), lx, ly);
connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value)
{
RepaintPreviewLabel(ui->preview_stick_left, value, ui->slider_stick_left->sizeHint().width(), lx, ly);
});
RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->sizeHint().width(), rx, ry);
connect(ui->slider_stick_right, &QSlider::valueChanged, [&](int value)
{
RepaintPreviewLabel(ui->preview_stick_right, value, ui->slider_stick_right->sizeHint().width(), rx, ry);
});
}
else
{
ui->verticalLayout_right->removeWidget(ui->gb_sticks);
ui->verticalLayout_left->removeWidget(ui->gb_triggers);
delete ui->gb_sticks;
delete ui->gb_triggers;
}
auto insertButton = [this](int id, QPushButton* button, cfg::string* cfg_name)
{
QString name = qstr(*cfg_name);
m_cfg_entries.insert(std::make_pair(id, pad_button{ cfg_name, *cfg_name, name }));
m_padButtons->addButton(button, id);
button->setText(name);
button->installEventFilter(this);
};
insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg->ls_left);
insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg->ls_down);
insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg->ls_right);
insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg->ls_up);
insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg->left);
insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg->down);
insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg->right);
insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg->up);
insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg->l1);
insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg->l2);
insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg->l3);
insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg->start);
insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg->select);
insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg->ps);
insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg->r1);
insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg->r2);
insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg->r3);
insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg->square);
insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg->cross);
insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg->circle);
insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg->triangle);
insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg->rs_left);
insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg->rs_down);
insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg->rs_right);
insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg->rs_up);
m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters);
m_padButtons->addButton(ui->b_blacklist, button_ids::id_blacklist);
m_padButtons->addButton(ui->b_ok, button_ids::id_ok);
m_padButtons->addButton(ui->b_cancel, button_ids::id_cancel);
connect(m_padButtons, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &pad_settings_dialog::OnPadButtonClicked);
connect(&m_timer, &QTimer::timeout, [&]()
{
if (--m_seconds <= 0)
{
ReactivateButtons();
return;
}
m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(m_seconds));
});
UpdateLabel();
gui_settings settings(this);
// repaint and resize controller image
ui->l_controller->setPixmap(settings.colorizedPixmap(*ui->l_controller->pixmap(), QColor(), gui::get_Label_Color("l_controller"), false, true));
ui->l_controller->setMaximumSize(ui->gb_description->sizeHint().width(), ui->l_controller->maximumHeight() * ui->gb_description->sizeHint().width() / ui->l_controller->maximumWidth());
layout()->setSizeConstraint(QLayout::SetFixedSize);
}
pad_settings_dialog::~pad_settings_dialog()
{
delete ui;
}
void pad_settings_dialog::ReactivateButtons()
{
m_timer.stop();
m_seconds = MAX_SECONDS;
if (m_button_id == button_ids::id_pad_begin)
{
return;
}
if (m_padButtons->button(m_button_id))
{
m_padButtons->button(m_button_id)->setPalette(m_palette);
}
m_button_id = button_ids::id_pad_begin;
UpdateLabel();
SwitchButtons(true);
for (auto but : m_padButtons->buttons())
{
but->setFocusPolicy(Qt::StrongFocus);
}
}
void pad_settings_dialog::RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y)
{
int max = m_handler->thumb_max;
int origin = w * 0.1;
int width = w * 0.8;
int dz_width = width * dz / max;
int dz_origin = (w - dz_width) / 2;
x = (w + (x * width / max)) / 2;
y = (w + (y * -1 * width / max)) / 2;
QPixmap pm(w, w);
pm.fill(Qt::transparent);
QPainter p(&pm);
p.setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::black, 2);
p.setPen(pen);
QBrush brush(Qt::white);
p.setBrush(brush);
p.drawEllipse(origin, origin, width, width);
pen = QPen(Qt::red, 2);
p.setPen(pen);
p.drawEllipse(dz_origin, dz_origin, dz_width, dz_width);
pen = QPen(Qt::blue, 2);
p.setPen(pen);
p.drawEllipse(x, y, 1, 1);
l->setPixmap(pm);
}
void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
{
if (m_handler_type != handler_type::handler_type_keyboard)
{
return;
}
if (m_button_id == button_ids::id_pad_begin)
{
return;
}
if (m_button_id <= button_ids::id_pad_begin || m_button_id >= button_ids::id_pad_end)
{
LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast<int>(m_handler_type), m_button_id);
}
else
{
m_cfg_entries[m_button_id].key = ((keyboard_pad_handler*)m_handler.get())->GetKeyName(keyEvent);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
}
ReactivateButtons();
}
void pad_settings_dialog::mousePressEvent(QMouseEvent* event)
{
if (m_handler_type != handler_type::handler_type_keyboard)
{
return;
}
if (m_button_id == button_ids::id_pad_begin)
{
return;
}
if (m_button_id <= button_ids::id_pad_begin || m_button_id >= button_ids::id_pad_end)
{
LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast<int>(m_handler_type), m_button_id);
}
else
{
m_cfg_entries[m_button_id].key = ((keyboard_pad_handler*)m_handler.get())->GetMouseName(event);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
}
ReactivateButtons();
}
bool pad_settings_dialog::eventFilter(QObject* object, QEvent* event)
{
// Disabled buttons should not absorb mouseclicks
if (event->type() == QEvent::MouseButtonPress)
event->ignore();
return QDialog::eventFilter(object, event);
}
void pad_settings_dialog::UpdateLabel(bool is_reset)
{
if (is_reset)
{
if (m_handler->has_rumble())
{
ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large);
ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small);
ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors);
}
if (m_handler->has_deadzones())
{
ui->slider_trigger_left->setValue(m_handler_cfg->ltriggerthreshold);
ui->slider_trigger_right->setValue(m_handler_cfg->rtriggerthreshold);
ui->slider_stick_left->setValue(m_handler_cfg->lstickdeadzone);
ui->slider_stick_right->setValue(m_handler_cfg->rstickdeadzone);
}
}
for (auto& entry : m_cfg_entries)
{
if (is_reset)
{
entry.second.key = *entry.second.cfg_name;
entry.second.text = qstr(entry.second.key);
}
m_padButtons->button(entry.first)->setText(entry.second.text);
}
}
void pad_settings_dialog::SwitchButtons(bool is_enabled)
{
for (int i = button_ids::id_pad_begin + 1; i < button_ids::id_pad_end; i++)
{
m_padButtons->button(i)->setEnabled(is_enabled);
}
}
void pad_settings_dialog::SaveConfig()
{
for (const auto& entry : m_cfg_entries)
{
entry.second.cfg_name->from_string(entry.second.key);
}
if (m_handler->has_rumble())
{
m_handler_cfg->enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked());
m_handler_cfg->enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked());
m_handler_cfg->switch_vibration_motors.set(ui->chb_vibration_switch->isChecked());
}
if (m_handler->has_deadzones())
{
m_handler_cfg->ltriggerthreshold.set(ui->slider_trigger_left->value());
m_handler_cfg->rtriggerthreshold.set(ui->slider_trigger_right->value());
m_handler_cfg->lstickdeadzone.set(ui->slider_stick_left->value());
m_handler_cfg->rstickdeadzone.set(ui->slider_stick_right->value());
}
m_handler_cfg->save();
}
void pad_settings_dialog::OnPadButtonClicked(int id)
{
switch (id)
{
case button_ids::id_pad_begin:
case button_ids::id_pad_end:
case button_ids::id_cancel:
return;
case button_ids::id_reset_parameters:
ReactivateButtons();
m_handler_cfg->from_default();
UpdateLabel(true);
return;
case button_ids::id_blacklist:
m_handler->GetNextButtonPress(m_device_name, nullptr, true);
return;
case button_ids::id_ok:
SaveConfig();
QDialog::accept();
return;
default:
break;
}
for (auto but : m_padButtons->buttons())
{
but->setFocusPolicy(Qt::ClickFocus);
}
m_button_id = id;
m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS));
m_padButtons->button(m_button_id)->setPalette(QPalette(Qt::blue));
SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons
m_timer.start(1000);
}