mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
launcher: dualsense vibration/volume setting (#973)
* pad: send DualSense speaker and haptic audio over Bluetooth * ci: fix Opus clang-cl build and macOS memory tracker test * docs: remove Bluetooth notes from project README * pad: keep Bluetooth audio work off emulation timing path * pad: smooth DualSense speaker audio on USB and Bluetooth * tests: find available macOS guest range for page manager * pad: keep haptic waveform when Bluetooth queue overflows * audio: reject zero output sample frequency * Simplify DualSense audio routing and fix Bluetooth batching * controller: add global DualSense volume and vibration controls * Simplify global controller settings --------- Co-authored-by: Codex <codex@openai.com> Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -23,6 +23,7 @@ void Load(const ConfigOptions& cfg) {
|
||||
EXIT_IF(g_config == nullptr);
|
||||
EXIT_IF(cfg.user_name.empty() || cfg.user_name.size() > MAX_USER_NAME_LENGTH);
|
||||
EXIT_IF(!IsConfiguredUserIdValid(cfg.user_id));
|
||||
EXIT_IF(cfg.controller_speaker_volume > 100 || cfg.controller_vibration_intensity > 100);
|
||||
|
||||
*g_config = cfg;
|
||||
}
|
||||
@@ -51,6 +52,14 @@ const std::optional<ControllerColor>& GetControllerColor() {
|
||||
return g_config->controller_color;
|
||||
}
|
||||
|
||||
uint32_t GetControllerSpeakerVolume() {
|
||||
return g_config->controller_speaker_volume;
|
||||
}
|
||||
|
||||
uint32_t GetControllerVibrationIntensity() {
|
||||
return g_config->controller_vibration_intensity;
|
||||
}
|
||||
|
||||
PresentMode GetPresentMode() {
|
||||
return g_config->present_mode;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ struct ConfigOptions {
|
||||
int32_t user_id = DEFAULT_USER_ID;
|
||||
std::string audio_input_device;
|
||||
std::optional<ControllerColor> controller_color;
|
||||
uint32_t controller_speaker_volume = 100;
|
||||
uint32_t controller_vibration_intensity = 100;
|
||||
PresentMode present_mode = PresentMode::Mailbox;
|
||||
int32_t gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
@@ -86,6 +88,8 @@ const std::string& GetUserName();
|
||||
int32_t GetUserId();
|
||||
const std::string& GetAudioInputDevice();
|
||||
const std::optional<ControllerColor>& GetControllerColor();
|
||||
uint32_t GetControllerSpeakerVolume();
|
||||
uint32_t GetControllerVibrationIntensity();
|
||||
PresentMode GetPresentMode();
|
||||
int32_t GetGpuIndex();
|
||||
bool FullscreenEnabled();
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<property name="verticalSpacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="sectionsLayout" columnstretch="1,1">
|
||||
<property name="horizontalSpacing">
|
||||
<number>8</number>
|
||||
@@ -72,27 +72,6 @@
|
||||
<property name="toolTip"><string>Language</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_controller_color">
|
||||
<property name="text"><string>DualSense lightbar:</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="controllerColorLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_controller_color">
|
||||
<property name="toolTip"><string>Choose and preview a fixed LED color. Bluetooth DualSense may take several seconds to update.</string></property>
|
||||
<property name="text"><string>Custom</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_controller_color_reset">
|
||||
<property name="toolTip"><string>Let the game control the lightbar</string></property>
|
||||
<property name="text"><string>Default</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -316,7 +295,82 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="1">
|
||||
<widget class="QGroupBox" name="controller_group">
|
||||
<property name="title"><string>Controller</string></property>
|
||||
<layout class="QFormLayout" name="controllerLayout">
|
||||
<property name="fieldGrowthPolicy"><enum>QFormLayout::AllNonFixedFieldsGrow</enum></property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_controller_color">
|
||||
<property name="text"><string>DualSense lightbar:</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="controllerColorLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_controller_color">
|
||||
<property name="toolTip"><string>Choose and preview a fixed LED color. Bluetooth DualSense may take several seconds to update.</string></property>
|
||||
<property name="text"><string>Custom</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_controller_color_reset">
|
||||
<property name="toolTip"><string>Let the game control the lightbar</string></property>
|
||||
<property name="text"><string>Default</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_controller_vibration">
|
||||
<property name="text"><string>Vibration intensity:</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="controllerVibrationLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_controller_vibration">
|
||||
<property name="toolTip"><string>Scale DualSense vibration over USB and Bluetooth</string></property>
|
||||
<property name="maximum"><number>100</number></property>
|
||||
<property name="value"><number>100</number></property>
|
||||
<property name="orientation"><enum>Qt::Horizontal</enum></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_controller_vibration_value">
|
||||
<property name="minimumSize"><size><width>40</width><height>0</height></size></property>
|
||||
<property name="text"><string>100%</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_controller_volume">
|
||||
<property name="text"><string>Speaker volume:</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="controllerVolumeLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_controller_volume">
|
||||
<property name="toolTip"><string>Scale the DualSense controller speaker over USB and Bluetooth</string></property>
|
||||
<property name="maximum"><number>100</number></property>
|
||||
<property name="value"><number>100</number></property>
|
||||
<property name="orientation"><enum>Qt::Horizontal</enum></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_controller_volume_value">
|
||||
<property name="minimumSize"><size><width>40</width><height>0</height></size></property>
|
||||
<property name="text"><string>100%</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="clear_button">
|
||||
|
||||
@@ -46,6 +46,30 @@ QString EnumToText(T value) {
|
||||
: key);
|
||||
}
|
||||
|
||||
struct ControllerSettings {
|
||||
QString color;
|
||||
int speaker_volume = 100;
|
||||
int vibration_intensity = 100;
|
||||
|
||||
void WriteSettings(QSettings* s) const {
|
||||
s->setValue("controller_color", color);
|
||||
s->setValue("controller_speaker_volume", speaker_volume);
|
||||
s->setValue("controller_vibration_intensity", vibration_intensity);
|
||||
}
|
||||
|
||||
void ReadSettings(QSettings* s) {
|
||||
const QColor saved_color(s->value("controller_color").toString());
|
||||
color = saved_color.isValid() ? saved_color.name(QColor::HexRgb) : QString {};
|
||||
const auto read_percent = [s](const char* key) {
|
||||
bool ok = false;
|
||||
const int value = s->value(key, 100).toInt(&ok);
|
||||
return ok ? qBound(0, value, 100) : 100;
|
||||
};
|
||||
speaker_volume = read_percent("controller_speaker_volume");
|
||||
vibration_intensity = read_percent("controller_vibration_intensity");
|
||||
}
|
||||
};
|
||||
|
||||
class Configuration: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -85,11 +109,13 @@ public:
|
||||
GameStatus game_status = GameStatus::Unknown;
|
||||
QString game_comment;
|
||||
|
||||
// Controller preferences always come from the global configuration.
|
||||
ControllerSettings controller;
|
||||
|
||||
Resolution screen_resolution = Resolution::R1280X720;
|
||||
QString user_name = "Kyty";
|
||||
int user_id = Config::DEFAULT_USER_ID;
|
||||
QString audio_input_device;
|
||||
QString controller_color;
|
||||
PresentMode present_mode = PresentMode::Mailbox;
|
||||
int gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
@@ -121,7 +147,6 @@ public:
|
||||
user_name = other.user_name;
|
||||
user_id = other.user_id;
|
||||
audio_input_device = other.audio_input_device;
|
||||
controller_color = other.controller_color;
|
||||
present_mode = other.present_mode;
|
||||
gpu_index = other.gpu_index;
|
||||
fullscreen_enabled = other.fullscreen_enabled;
|
||||
@@ -168,7 +193,6 @@ public:
|
||||
KYTY_CFG_SET(user_name);
|
||||
KYTY_CFG_SET(user_id);
|
||||
KYTY_CFG_SET(audio_input_device);
|
||||
KYTY_CFG_SET(controller_color);
|
||||
KYTY_CFG_SET(present_mode);
|
||||
KYTY_CFG_SET(gpu_index);
|
||||
KYTY_CFG_SET(fullscreen_enabled);
|
||||
@@ -208,8 +232,6 @@ public:
|
||||
? saved_user_id
|
||||
: Config::DEFAULT_USER_ID;
|
||||
audio_input_device = s->value("audio_input_device", audio_input_device).toString();
|
||||
const QColor color(s->value("controller_color", controller_color).toString());
|
||||
controller_color = color.isValid() ? color.name(QColor::HexRgb) : QString {};
|
||||
KYTY_CFG_GET(present_mode);
|
||||
gpu_index = s->value("gpu_index", -1).toInt();
|
||||
if (EnumToText(present_mode).isEmpty()) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
static void WriteSettings(QSettings& s);
|
||||
static void ReadSettings(QSettings& s);
|
||||
|
||||
void SetGameDirectories(const QStringList& dirs);
|
||||
void SetGlobalSettings(const QStringList& dirs);
|
||||
[[nodiscard]] QStringList GetGameDirectories() const;
|
||||
|
||||
signals:
|
||||
@@ -40,7 +40,7 @@ private:
|
||||
QGroupBox* m_game_dirs_group = nullptr;
|
||||
QListWidget* m_game_dirs_list = nullptr;
|
||||
QToolButton* m_remove_game_dir_button = nullptr;
|
||||
bool m_show_game_dirs = false;
|
||||
bool m_global_settings = false;
|
||||
|
||||
protected:
|
||||
void Init(const Configuration& info);
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
[[nodiscard]] const QString& GetSettingsFile() const { return m_settings_file; }
|
||||
[[nodiscard]] const QString& GetGlobalControllerColor() const {
|
||||
return m_global_info.controller_color;
|
||||
return m_global_info.controller.color;
|
||||
}
|
||||
[[nodiscard]] std::unique_ptr<Configuration>
|
||||
CreateConfiguration(const ConfigurationItem& item) const;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QSettings>
|
||||
#include <QSlider>
|
||||
#include <QSpinBox>
|
||||
#include <QStyle>
|
||||
#include <QToolButton>
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
constexpr char SETTINGS_CFG_DIALOG[] = "ConfigurationEditDialog";
|
||||
constexpr char SETTINGS_CFG_LAST_GEOMETRY[] = "geometry";
|
||||
constexpr int GLOBAL_SETTINGS_GAME_DIRS_MIN_WIDTH = 560;
|
||||
constexpr int GLOBAL_SETTINGS_GAME_DIRS_MIN_WIDTH = 400;
|
||||
|
||||
static void UpdateControllerColorButton(QPushButton* button, const QString& hex) {
|
||||
const QColor color(hex);
|
||||
@@ -123,6 +124,7 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p
|
||||
m_info(info) {
|
||||
m_ui->setupUi(this);
|
||||
InitGameDirectories();
|
||||
m_ui->controller_group->setVisible(false);
|
||||
|
||||
connect(m_ui->ok_button, &QPushButton::clicked, this, &ConfigurationEditDialog::save);
|
||||
connect(m_ui->cancel_button, &QPushButton::clicked, this, &QDialog::reject);
|
||||
@@ -142,6 +144,12 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p
|
||||
UpdateControllerColorButton(m_ui->button_controller_color, {});
|
||||
emit PreviewControllerColor({});
|
||||
});
|
||||
connect(m_ui->slider_controller_vibration, &QSlider::valueChanged, this, [this](int value) {
|
||||
m_ui->label_controller_vibration_value->setText(tr("%1%").arg(value));
|
||||
});
|
||||
connect(m_ui->slider_controller_volume, &QSlider::valueChanged, this, [this](int value) {
|
||||
m_ui->label_controller_volume_value->setText(tr("%1%").arg(value));
|
||||
});
|
||||
connect(m_ui->comboBox_shader_log_direction, &QComboBox::currentTextChanged, this,
|
||||
[this](const QString& text) {
|
||||
auto log = TextToEnum<Configuration::LogDirection>(text);
|
||||
@@ -201,7 +209,9 @@ void ConfigurationEditDialog::Init(const Configuration& info) {
|
||||
m_ui->lineEdit_user_name->setMaxLength(static_cast<int>(Config::MAX_USER_NAME_LENGTH));
|
||||
m_ui->lineEdit_user_name->setText(info.user_name);
|
||||
m_ui->spinBox_user_id->setValue(info.user_id);
|
||||
UpdateControllerColorButton(m_ui->button_controller_color, info.controller_color);
|
||||
UpdateControllerColorButton(m_ui->button_controller_color, info.controller.color);
|
||||
m_ui->slider_controller_vibration->setValue(info.controller.vibration_intensity);
|
||||
m_ui->slider_controller_volume->setValue(info.controller.speaker_volume);
|
||||
auto* microphone = m_ui->comboBox_audio_input_device;
|
||||
microphone->clear();
|
||||
microphone->addItem(tr("None"), QString {});
|
||||
@@ -342,8 +352,8 @@ void ConfigurationEditDialog::InitGameDirectories() {
|
||||
update_game_directory_buttons();
|
||||
}
|
||||
|
||||
void ConfigurationEditDialog::SetGameDirectories(const QStringList& dirs) {
|
||||
m_show_game_dirs = true;
|
||||
void ConfigurationEditDialog::SetGlobalSettings(const QStringList& dirs) {
|
||||
m_global_settings = true;
|
||||
m_game_dirs_list->clear();
|
||||
m_game_dirs_group->setMinimumWidth(GLOBAL_SETTINGS_GAME_DIRS_MIN_WIDTH);
|
||||
|
||||
@@ -352,6 +362,7 @@ void ConfigurationEditDialog::SetGameDirectories(const QStringList& dirs) {
|
||||
}
|
||||
|
||||
m_game_dirs_group->setVisible(true);
|
||||
m_ui->controller_group->setVisible(true);
|
||||
update_game_directory_buttons();
|
||||
layout()->activate();
|
||||
resize(size().expandedTo(minimumSizeHint()));
|
||||
@@ -359,7 +370,7 @@ void ConfigurationEditDialog::SetGameDirectories(const QStringList& dirs) {
|
||||
|
||||
QStringList ConfigurationEditDialog::GetGameDirectories() const {
|
||||
QStringList dirs;
|
||||
if (!m_show_game_dirs) {
|
||||
if (!m_global_settings) {
|
||||
return dirs;
|
||||
}
|
||||
|
||||
@@ -399,11 +410,15 @@ void ConfigurationEditDialog::resizeEvent(QResizeEvent* event) {
|
||||
g_last_geometry = saveGeometry();
|
||||
}
|
||||
|
||||
static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
|
||||
static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui, bool global_settings) {
|
||||
info.user_name = ui.lineEdit_user_name->text().trimmed();
|
||||
info.user_id = ui.spinBox_user_id->value();
|
||||
info.audio_input_device = ui.comboBox_audio_input_device->currentData().toString();
|
||||
info.controller_color = ui.button_controller_color->property("controllerColor").toString();
|
||||
if (global_settings) {
|
||||
info.controller.color = ui.button_controller_color->property("controllerColor").toString();
|
||||
info.controller.vibration_intensity = ui.slider_controller_vibration->value();
|
||||
info.controller.speaker_volume = ui.slider_controller_volume->value();
|
||||
}
|
||||
info.screen_resolution =
|
||||
TextToEnum<Configuration::Resolution>(ui.comboBox_screen_resolution->currentText());
|
||||
info.present_mode =
|
||||
@@ -453,7 +468,7 @@ void ConfigurationEditDialog::save() {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateInfo(m_info, *m_ui);
|
||||
UpdateInfo(m_info, *m_ui, m_global_settings);
|
||||
|
||||
emit accept();
|
||||
}
|
||||
@@ -461,9 +476,9 @@ void ConfigurationEditDialog::save() {
|
||||
void ConfigurationEditDialog::clear() {
|
||||
Configuration default_info;
|
||||
Init(default_info);
|
||||
emit PreviewControllerColor({});
|
||||
|
||||
if (m_show_game_dirs) {
|
||||
if (m_global_settings) {
|
||||
emit PreviewControllerColor({});
|
||||
m_game_dirs_list->clear();
|
||||
update_game_directory_buttons();
|
||||
}
|
||||
|
||||
@@ -314,6 +314,7 @@ void ConfigurationListWidget::WriteSettings() {
|
||||
s->remove(CONF_GLOBAL);
|
||||
s->beginGroup(CONF_GLOBAL);
|
||||
m_global_info.WriteSettings(s.get());
|
||||
m_global_info.controller.WriteSettings(s.get());
|
||||
s->endGroup();
|
||||
|
||||
s->remove(CONF_SECTION_NAME);
|
||||
@@ -357,6 +358,7 @@ void ConfigurationListWidget::ReadSettings() {
|
||||
if (!s->childKeys().isEmpty()) {
|
||||
m_global_info.ReadSettings(s.get());
|
||||
}
|
||||
m_global_info.controller.ReadSettings(s.get());
|
||||
s->endGroup();
|
||||
|
||||
qDeleteAll(m_custom_infos);
|
||||
@@ -409,6 +411,7 @@ ConfigurationListWidget::CreateConfiguration(const ConfigurationItem& item) cons
|
||||
const auto* custom = m_custom_infos.value(item.GetInfo().game_path);
|
||||
info->CopyGameInfoFrom(item.GetInfo());
|
||||
info->CopyEmulatorSettingsFrom(custom != nullptr ? *custom : m_global_info);
|
||||
info->controller = m_global_info.controller;
|
||||
if (custom != nullptr && !custom->elf.isEmpty()) {
|
||||
info->elf = custom->elf;
|
||||
}
|
||||
@@ -787,16 +790,18 @@ void ConfigurationListWidget::delete_configuartion() {
|
||||
void ConfigurationListWidget::edit_global_settings() {
|
||||
Configuration info;
|
||||
info.CopyEmulatorSettingsFrom(m_global_info);
|
||||
info.controller = m_global_info.controller;
|
||||
info.name = tr("Global settings");
|
||||
|
||||
ConfigurationEditDialog dlg(info, this);
|
||||
dlg.setWindowTitle(tr("Global settings"));
|
||||
dlg.SetGameDirectories(m_game_dirs);
|
||||
dlg.SetGlobalSettings(m_game_dirs);
|
||||
connect(&dlg, &ConfigurationEditDialog::PreviewControllerColor, this,
|
||||
&ConfigurationListWidget::PreviewControllerColor);
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
m_global_info.CopyEmulatorSettingsFrom(info);
|
||||
m_global_info.controller = info.controller;
|
||||
const auto game_dirs = NormalizeGameDirectories(dlg.GetGameDirectories());
|
||||
const bool game_dirs_changed = game_dirs != m_game_dirs;
|
||||
m_game_dirs = game_dirs;
|
||||
|
||||
@@ -228,9 +228,11 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
|
||||
if (!info.audio_input_device.isEmpty()) {
|
||||
args << "--mic" << info.audio_input_device;
|
||||
}
|
||||
if (!info.controller_color.isEmpty()) {
|
||||
args << "--controller-color" << info.controller_color;
|
||||
if (!info.controller.color.isEmpty()) {
|
||||
args << "--controller-color" << info.controller.color;
|
||||
}
|
||||
args << "--controller-volume" << QString::number(info.controller.speaker_volume);
|
||||
args << "--controller-vibration" << QString::number(info.controller.vibration_intensity);
|
||||
args << "--present-mode" << EnumToText(info.present_mode);
|
||||
if (info.gpu_index >= 0) {
|
||||
args << "--gpu" << QString::number(info.gpu_index);
|
||||
@@ -529,8 +531,7 @@ void MainDialogPrivate::Update() {
|
||||
m_lightbar.Stop();
|
||||
return;
|
||||
}
|
||||
m_lightbar.SetColor(item != nullptr ? m_ui->widget->CreateConfiguration(*item)->controller_color
|
||||
: m_ui->widget->GetGlobalControllerColor());
|
||||
m_lightbar.SetColor(m_ui->widget->GetGlobalControllerColor());
|
||||
}
|
||||
|
||||
#include "mainDialog.moc"
|
||||
|
||||
@@ -223,7 +223,13 @@ void GameController::CycleSetting(Setting setting) {
|
||||
|
||||
float GameController::GetSettingScale(Setting setting) const {
|
||||
const auto step = m_setting_steps[static_cast<size_t>(setting)].load(std::memory_order_relaxed);
|
||||
return setting == Setting::SpeakerVolume ? SPEAKER_VOLUME[step] : INTENSITY[step];
|
||||
if (setting == Setting::SpeakerVolume) {
|
||||
return SPEAKER_VOLUME[step] * (Config::GetControllerSpeakerVolume() / 100.0f);
|
||||
}
|
||||
if (setting == Setting::VibrationIntensity) {
|
||||
return INTENSITY[step] * (Config::GetControllerVibrationIntensity() / 100.0f);
|
||||
}
|
||||
return INTENSITY[step];
|
||||
}
|
||||
|
||||
static uint8_t Scale(uint8_t value, float scale) {
|
||||
|
||||
@@ -54,6 +54,8 @@ static void PrintUsage() {
|
||||
Config::DEFAULT_USER_ID);
|
||||
::printf(" --mic <name> Capture from this microphone; omit for silence.\n");
|
||||
::printf(" --controller-color <#RRGGBB> Override the controller lightbar color.\n");
|
||||
::printf(" --controller-volume <0-100> DualSense speaker volume. Default: 100.\n");
|
||||
::printf(" --controller-vibration <0-100> DualSense vibration intensity. Default: 100.\n");
|
||||
::printf(
|
||||
" --present-mode <value> Fifo, Mailbox, or Immediate. Default: Mailbox.\n");
|
||||
::printf(
|
||||
@@ -324,6 +326,18 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
return false;
|
||||
}
|
||||
options.config.controller_color = color;
|
||||
} else if (arg == "--controller-volume") {
|
||||
if (!ParseUint32(value, options.config.controller_speaker_volume) ||
|
||||
options.config.controller_speaker_volume > 100) {
|
||||
::printf("invalid controller volume: %s\n", value.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--controller-vibration") {
|
||||
if (!ParseUint32(value, options.config.controller_vibration_intensity) ||
|
||||
options.config.controller_vibration_intensity > 100) {
|
||||
::printf("invalid controller vibration intensity: %s\n", value.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--present-mode") {
|
||||
if (!ParseEnum(value, options.config.present_mode)) {
|
||||
::printf("invalid present mode: %s\n", value.c_str());
|
||||
|
||||
@@ -111,8 +111,10 @@ struct Controller {
|
||||
haptics_handles_rumble = false;
|
||||
Initialize();
|
||||
Connect(1);
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) == 1.0f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) == 1.0f &&
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) ==
|
||||
Config::GetControllerSpeakerVolume() / 100.0f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) ==
|
||||
Config::GetControllerVibrationIntensity() / 100.0f &&
|
||||
GetSettingScale(Setting::TriggerEffectIntensity) == 1.0f,
|
||||
"controller initialization retained old settings");
|
||||
rumble.clear();
|
||||
@@ -161,6 +163,48 @@ void TestSettingCycles() {
|
||||
CycleSetting(Setting::TriggerEffectIntensity);
|
||||
}
|
||||
|
||||
void TestGlobalControllerLevels() {
|
||||
Config::ConfigOptions options;
|
||||
options.controller_speaker_volume = 50;
|
||||
options.controller_vibration_intensity = 25;
|
||||
Config::Load(options);
|
||||
{
|
||||
Controller controller;
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) == 0.5f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) == 0.25f &&
|
||||
GetSettingScale(Setting::TriggerEffectIntensity) == 1.0f,
|
||||
"global controller levels did not scale their outputs independently");
|
||||
SetRumble(200, 100);
|
||||
Check(rumble.back().large == 50 * 257 && rumble.back().small == 25 * 257,
|
||||
"global vibration level did not scale rumble");
|
||||
CycleSetting(Setting::SpeakerVolume);
|
||||
CycleSetting(Setting::VibrationIntensity);
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) == 0.0f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) == 0.0f,
|
||||
"cycle hotkeys did not mute globally scaled outputs");
|
||||
CycleSetting(Setting::SpeakerVolume);
|
||||
CycleSetting(Setting::VibrationIntensity);
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) == 0.01f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) == 0.0825f,
|
||||
"cycle hotkeys did not multiply the global controller levels");
|
||||
Check(rumble.back().large == 17 * 257 && rumble.back().small == 8 * 257,
|
||||
"cycling vibration did not apply the combined intensity to cached rumble");
|
||||
}
|
||||
options.controller_speaker_volume = 0;
|
||||
options.controller_vibration_intensity = 0;
|
||||
Config::Load(options);
|
||||
{
|
||||
Controller controller;
|
||||
Check(GetSettingScale(Setting::SpeakerVolume) == 0.0f &&
|
||||
GetSettingScale(Setting::VibrationIntensity) == 0.0f,
|
||||
"zero global controller levels did not mute outputs");
|
||||
SetRumble(200, 100);
|
||||
Check(rumble.back().large == 0 && rumble.back().small == 0,
|
||||
"zero global vibration level did not mute motors");
|
||||
}
|
||||
Config::Load(Config::ConfigOptions {});
|
||||
}
|
||||
|
||||
void TestVibrationLifetime() {
|
||||
Controller controller;
|
||||
SetRumble(255, 1);
|
||||
@@ -287,6 +331,7 @@ void TestIndependentOutputsAndPadSwitch() {
|
||||
int main() {
|
||||
Config::Initialize();
|
||||
TestSettingCycles();
|
||||
TestGlobalControllerLevels();
|
||||
// Each following test initializes another controller and requires strong defaults.
|
||||
TestVibrationLifetime();
|
||||
TestMaskedTriggersAndValidation();
|
||||
|
||||
Reference in New Issue
Block a user