mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 15:01:28 +12:00
503 lines
16 KiB
C++
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);
|
|
}
|