1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Input: Allow to toggle player LED (Dualsense and DS3)

This commit is contained in:
Megamouse 2022-10-19 21:47:18 +02:00
parent 7ea0a6d642
commit 363e0a40e5
19 changed files with 132 additions and 65 deletions

View File

@ -300,6 +300,11 @@ bool PadHandlerBase::has_rgb() const
return b_has_rgb;
}
bool PadHandlerBase::has_player_led() const
{
return b_has_player_led;
}
bool PadHandlerBase::has_battery() const
{
return b_has_battery;

View File

@ -108,6 +108,7 @@ protected:
bool b_has_led = false;
bool b_has_rgb = false;
bool b_has_player_led = false;
bool b_has_battery = false;
bool b_has_deadzones = false;
bool b_has_rumble = false;
@ -185,6 +186,7 @@ public:
bool has_deadzones() const;
bool has_led() const;
bool has_rgb() const;
bool has_player_led() const;
bool has_battery() const;
bool has_pressure_intensity_button() const;
@ -195,7 +197,7 @@ public:
PadHandlerBase(pad_handler type = pad_handler::null);
virtual ~PadHandlerBase() = default;
// Sets window to config the controller(optional)
virtual void SetPadData(const std::string& /*padId*/, u8 /*player_id*/, u32 /*largeMotor*/, u32 /*smallMotor*/, s32 /*r*/, s32 /*g*/, s32 /*b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/) {}
virtual void SetPadData(const std::string& /*padId*/, u8 /*player_id*/, u32 /*largeMotor*/, u32 /*smallMotor*/, s32 /*r*/, s32 /*g*/, s32 /*b*/, bool /*player_led*/, bool /*battery_led*/, u32 /*battery_led_brightness*/) {}
virtual u32 get_battery_level(const std::string& /*padId*/) { return 0; }
// Return list of devices for that handler
virtual std::vector<pad_list_entry> list_devices() = 0;

View File

@ -75,6 +75,7 @@ struct cfg_pad final : cfg::node
cfg::_bool led_low_battery_blink{ this, "Blink LED when battery is below 20%", true };
cfg::_bool led_battery_indicator{ this, "Use LED as a battery indicator", false };
cfg::uint<0, 100> led_battery_indicator_brightness{ this, "LED battery indicator brightness", 50 };
cfg::_bool player_led_enabled{ this, "Player LED enabled", true };
cfg::_bool enable_vibration_motor_large{ this, "Enable Large Vibration Motor", true };
cfg::_bool enable_vibration_motor_small{ this, "Enable Small Vibration Motor", true };

View File

@ -86,6 +86,7 @@ ds3_pad_handler::ds3_pad_handler()
b_has_battery = true;
b_has_led = true;
b_has_rgb = false;
b_has_player_led = true;
b_has_pressure_intensity_button = false; // The DS3 obviously already has this feature natively.
m_name_string = "DS3 Pad #";
@ -119,7 +120,7 @@ u32 ds3_pad_handler::get_battery_level(const std::string& padId)
return std::clamp<u32>(device->battery_level, 0, 100);
}
void ds3_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32 /* b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
void ds3_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32 /* b*/, bool player_led, bool /*battery_led*/, u32 /*battery_led_brightness*/)
{
std::shared_ptr<ds3_device> device = get_hid_device(padId);
if (device == nullptr || device->hidDevice == nullptr)
@ -146,6 +147,7 @@ void ds3_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 lar
}
ensure(device->config);
device->config->player_led_enabled.set(player_led);
// Start/Stop the engines :)
send_output_report(device.get());
@ -171,7 +173,7 @@ int ds3_pad_handler::send_output_report(ds3_device* ds3dev)
else
output_report.led_enabled = 0b00000010;
}
else
else if (ds3dev->config->player_led_enabled)
{
switch (ds3dev->player_id)
{
@ -186,6 +188,10 @@ int ds3_pad_handler::send_output_report(ds3_device* ds3dev)
fmt::throw_exception("DS3 is using forbidden player id %d", ds3dev->player_id);
}
}
else
{
output_report.led_enabled = 0;
}
if (ds3dev->config->led_low_battery_blink && ds3dev->battery_level < 25)
{
@ -615,6 +621,13 @@ void ds3_pad_handler::apply_pad_data(const pad_ensemble& binding)
}
}
// Use LEDs to indicate battery level
if (dev->enable_player_leds != config->player_led_enabled.get())
{
dev->new_output_data = true;
dev->enable_player_leds = config->player_led_enabled.get();
}
dev->new_output_data |= dev->large_motor != speed_large || dev->small_motor != speed_small;
dev->large_motor = speed_large;

View File

@ -80,7 +80,7 @@ public:
ds3_pad_handler();
~ds3_pad_handler();
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness) override;
u32 get_battery_level(const std::string& padId) override;
void init_config(cfg_pad* cfg) override;

View File

@ -197,7 +197,7 @@ u32 ds4_pad_handler::get_battery_level(const std::string& padId)
return std::min<u32>(device->battery_level * 10, 100);
}
void ds4_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness)
void ds4_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool /*player_led*/, bool battery_led, u32 battery_led_brightness)
{
std::shared_ptr<DS4Device> device = get_hid_device(padId);
if (!device || !device->hidDevice || !device->config)

View File

@ -56,7 +56,7 @@ public:
ds4_pad_handler();
~ds4_pad_handler();
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness) override;
u32 get_battery_level(const std::string& padId) override;
void init_config(cfg_pad* cfg) override;

View File

@ -141,6 +141,7 @@ dualsense_pad_handler::dualsense_pad_handler()
b_has_deadzones = true;
b_has_led = true;
b_has_rgb = true;
b_has_player_led = true;
b_has_battery = true;
m_name_string = "DualSense Pad #";
@ -917,7 +918,7 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device)
if (!device || !device->hidDevice)
return -2;
const auto config = device->config;
const cfg_pad* config = device->config;
if (config == nullptr)
return -2; // hid_write and hid_write_control return -1 on error
@ -970,6 +971,8 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device)
// Use OR with 0x1, 0x2, 0x4, 0x8 and 0x10 to enable the LEDs (from leftmost to rightmost).
common.valid_flag_1 |= VALID_FLAG_1_PLAYER_INDICATOR_CONTROL_ENABLE;
if (config->player_led_enabled)
{
switch (device->player_id)
{
case 0: common.player_leds = 0b00100; break;
@ -983,6 +986,11 @@ int dualsense_pad_handler::send_output_report(DualSenseDevice* device)
fmt::throw_exception("Dualsense is using forbidden player id %d", device->player_id);
}
}
else
{
common.player_leds = 0;
}
}
}
if (device->bt_controller)
@ -1090,7 +1098,13 @@ void dualsense_pad_handler::apply_pad_data(const pad_ensemble& binding)
}
}
dualsense_dev->new_output_data |= dualsense_dev->update_lightbar || dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small;
if (dualsense_dev->enable_player_leds != config->player_led_enabled.get())
{
dualsense_dev->enable_player_leds = config->player_led_enabled.get();
dualsense_dev->update_player_leds = true;
}
dualsense_dev->new_output_data |= dualsense_dev->update_player_leds || dualsense_dev->update_lightbar || dualsense_dev->large_motor != speed_large || dualsense_dev->small_motor != speed_small;
dualsense_dev->large_motor = speed_large;
dualsense_dev->small_motor = speed_small;
@ -1104,7 +1118,7 @@ void dualsense_pad_handler::apply_pad_data(const pad_ensemble& binding)
}
}
void dualsense_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness)
void dualsense_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness)
{
std::shared_ptr<DualSenseDevice> device = get_hid_device(padId);
if (device == nullptr || device->hidDevice == nullptr)
@ -1132,6 +1146,8 @@ void dualsense_pad_handler::SetPadData(const std::string& padId, u8 player_id, u
ensure(device->config);
device->update_lightbar = true;
device->update_player_leds = true;
device->config->player_led_enabled.set(player_led);
// Set new LED color (see ds4_pad_handler)
if (battery_led)

View File

@ -69,7 +69,7 @@ public:
dualsense_pad_handler();
~dualsense_pad_handler();
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness) override;
u32 get_battery_level(const std::string& padId) override;
void init_config(cfg_pad* cfg) override;

View File

@ -598,7 +598,7 @@ void evdev_joystick_handler::SetRumble(EvdevDevice* device, u16 large, u16 small
device->force_small = small;
}
void evdev_joystick_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u32 largeMotor, u32 smallMotor, s32 /* r*/, s32 /* g*/, s32 /* b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
void evdev_joystick_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u32 largeMotor, u32 smallMotor, s32 /* r*/, s32 /* g*/, s32 /* b*/, bool /*player_led*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
{
// Get our evdev device
auto dev = get_evdev_device(padId);

View File

@ -386,7 +386,7 @@ public:
void get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool get_blacklist = false, const std::vector<std::string>& buttons = {}) override;
void get_motion_sensors(const std::string& padId, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array<AnalogSensor, 4>& sensors) override;
std::unordered_map<u32, std::string> get_motion_axis_list() const override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness) override;
private:
void close_devices();

View File

@ -36,6 +36,7 @@ public:
std::string path;
std::array<u8, 64> padData{};
bool new_output_data{true};
bool enable_player_leds{false};
u8 large_motor{0};
u8 small_motor{0};
u8 led_delay_on{0};

View File

@ -128,7 +128,7 @@ void xinput_pad_handler::init_config(cfg_pad* cfg)
cfg->from_default();
}
void xinput_pad_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32/* b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
void xinput_pad_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32/* b*/, bool /*player_led*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
{
const int device_number = GetDeviceNumber(padId);
if (device_number < 0)

View File

@ -110,7 +110,7 @@ public:
bool Init() override;
std::vector<pad_list_entry> list_devices() override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override;
void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool player_led, bool battery_led, u32 battery_led_brightness) override;
u32 get_battery_level(const std::string& padId) override;
void init_config(cfg_pad* cfg) override;

View File

@ -5,10 +5,10 @@
#include <QPixmap>
#include <QPainterPath>
pad_led_settings_dialog::pad_led_settings_dialog(QDialog* parent, int colorR, int colorG, int colorB, bool has_rgb, bool has_battery, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness)
pad_led_settings_dialog::pad_led_settings_dialog(QDialog* parent, int colorR, int colorG, int colorB, bool has_rgb, bool has_player_led, bool player_led_enabled, bool has_battery, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness)
: QDialog(parent)
, ui(new Ui::pad_led_settings_dialog)
, m_initial{colorR, colorG, colorB, led_low_battery_blink, led_battery_indicator, led_battery_indicator_brightness}
, m_initial{colorR, colorG, colorB, player_led_enabled, led_low_battery_blink, led_battery_indicator, led_battery_indicator_brightness}
{
ui->setupUi(this);
setModal(true);
@ -17,9 +17,11 @@ pad_led_settings_dialog::pad_led_settings_dialog(QDialog* parent, int colorR, in
ui->hs_indicator_brightness->setValue(m_new.battery_indicator_brightness);
ui->cb_led_blink->setChecked(m_new.low_battery_blink);
ui->cb_led_indicate->setChecked(m_new.battery_indicator);
ui->cb_player_led->setChecked(m_new.player_led_enabled);
update_slider_label(m_new.battery_indicator_brightness);
ui->gb_player_led->setEnabled(has_player_led);
ui->gb_led_color->setEnabled(has_rgb);
ui->gb_battery_status->setEnabled(has_battery);
ui->gb_indicator_brightness->setEnabled(has_battery && has_rgb); // Let's restrict this to rgb capable devices for now
@ -40,22 +42,22 @@ pad_led_settings_dialog::pad_led_settings_dialog(QDialog* parent, int colorR, in
{
read_form_values();
}
Q_EMIT pass_led_settings(m_new.cR, m_new.cG, m_new.cB, m_new.low_battery_blink, m_new.battery_indicator, m_new.battery_indicator_brightness);
Q_EMIT pass_led_settings(m_new);
});
if (has_rgb)
{
connect(ui->b_colorpicker, &QPushButton::clicked, [this]()
{
const QColor led_color(m_new.cR, m_new.cG, m_new.cB);
const QColor led_color(m_new.color_r, m_new.color_g, m_new.color_b);
QColorDialog dlg(led_color, this);
dlg.setWindowTitle(tr("LED Color"));
if (dlg.exec() == QColorDialog::Accepted)
{
const QColor new_color = dlg.selectedColor();
m_new.cR = new_color.red();
m_new.cG = new_color.green();
m_new.cB = new_color.blue();
m_new.color_r = new_color.red();
m_new.color_g = new_color.green();
m_new.color_b = new_color.blue();
redraw_color_sample();
}
});
@ -91,7 +93,7 @@ void pad_led_settings_dialog::redraw_color_sample() const
path.addRoundedRect(QRectF(padding, padding, w - padding * 2, h - padding * 2), radius, radius);
// Get new LED color
const QColor led_color(m_new.cR, m_new.cG, m_new.cB);
const QColor led_color(m_new.color_r, m_new.color_g, m_new.color_b);
// Paint the shape with a black border and fill it with the LED color
QPainter painter(&color_sample);
@ -117,6 +119,7 @@ void pad_led_settings_dialog::battery_indicator_checked(bool checked) const
void pad_led_settings_dialog::read_form_values()
{
m_new.player_led_enabled = ui->cb_player_led->isChecked();
m_new.low_battery_blink = ui->cb_led_blink->isChecked();
m_new.battery_indicator = ui->cb_led_indicate->isChecked();
m_new.battery_indicator_brightness = ui->hs_indicator_brightness->value();

View File

@ -14,11 +14,22 @@ class pad_led_settings_dialog : public QDialog
Q_OBJECT
public:
explicit pad_led_settings_dialog(QDialog* parent, int colorR, int colorG, int colorB, bool has_rgb, bool has_battery, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness);
explicit pad_led_settings_dialog(QDialog* parent, int colorR, int colorG, int colorB, bool has_rgb, bool has_player_led, bool player_led_enabled, bool has_battery, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness);
~pad_led_settings_dialog();
struct led_settings
{
int color_r = 255;
int color_g = 255;
int color_b = 255;
bool player_led_enabled = true;
bool low_battery_blink = true;
bool battery_indicator = false;
int battery_indicator_brightness = 50;
};
Q_SIGNALS:
void pass_led_settings(int cR, int cG, int cB, bool low_battery_blink, bool battery_indicator, int battery_indicator_brightness);
void pass_led_settings(const led_settings& settings);
private Q_SLOTS:
void update_slider_label(int val) const;
@ -28,15 +39,6 @@ private:
void redraw_color_sample() const;
void read_form_values();
std::unique_ptr<Ui::pad_led_settings_dialog> ui;
struct led_settings
{
int cR = 255;
int cG = 255;
int cB = 255;
bool low_battery_blink = true;
bool battery_indicator = false;
int battery_indicator_brightness = 50;
};
led_settings m_initial;
led_settings m_new;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>287</width>
<height>287</height>
<width>255</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
@ -43,6 +43,22 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_player_led">
<property name="title">
<string>GroupBox</string>
</property>
<layout class="QVBoxLayout" name="gb_player_led_layout">
<item>
<widget class="QCheckBox" name="cb_player_led">
<property name="text">
<string>Enable player LED</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_battery_status">
<property name="title">
@ -105,6 +121,19 @@
</layout>
</widget>
</item>
<item>
<spacer name="main_verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="bb_dialog_buttons">
<property name="standardButtons">

View File

@ -367,8 +367,20 @@ void pad_settings_dialog::InitButtons()
ensure(m_handler);
const cfg_pad& cfg = GetPlayerConfig();
SetPadData(0, 0, cfg.led_battery_indicator.get());
pad_led_settings_dialog dialog(this, cfg.colorR, cfg.colorG, cfg.colorB, m_handler->has_rgb(), m_handler->has_battery(), cfg.led_low_battery_blink.get(), cfg.led_battery_indicator.get(), cfg.led_battery_indicator_brightness);
connect(&dialog, &pad_led_settings_dialog::pass_led_settings, this, &pad_settings_dialog::apply_led_settings);
pad_led_settings_dialog dialog(this, cfg.colorR, cfg.colorG, cfg.colorB, m_handler->has_rgb(), m_handler->has_player_led(), cfg.player_led_enabled.get(), m_handler->has_battery(), cfg.led_low_battery_blink.get(), cfg.led_battery_indicator.get(), cfg.led_battery_indicator_brightness);
connect(&dialog, &pad_led_settings_dialog::pass_led_settings, this, [this](const pad_led_settings_dialog::led_settings& settings)
{
ensure(m_handler);
cfg_pad& cfg = GetPlayerConfig();
cfg.colorR.set(settings.color_r);
cfg.colorG.set(settings.color_g);
cfg.colorB.set(settings.color_b);
cfg.led_battery_indicator.set(settings.battery_indicator);
cfg.led_battery_indicator_brightness.set(settings.battery_indicator_brightness);
cfg.led_low_battery_blink.set(settings.low_battery_blink);
cfg.player_led_enabled.set(settings.player_led_enabled);
SetPadData(0, 0, settings.battery_indicator);
});
dialog.exec();
SetPadData(0, 0);
});
@ -587,21 +599,7 @@ void pad_settings_dialog::SetPadData(u32 large_motor, u32 small_motor, bool led_
const cfg_pad& cfg = GetPlayerConfig();
std::lock_guard lock(m_handler_mutex);
m_handler->SetPadData(m_device_name, GetPlayerIndex(), large_motor, small_motor, cfg.colorR, cfg.colorG, cfg.colorB, led_battery_indicator, cfg.led_battery_indicator_brightness);
}
// Slot to handle the data from a signal in the led settings dialog
void pad_settings_dialog::apply_led_settings(int colorR, int colorG, int colorB, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness)
{
ensure(m_handler);
cfg_pad& cfg = GetPlayerConfig();
cfg.colorR.set(colorR);
cfg.colorG.set(colorG);
cfg.colorB.set(colorB);
cfg.led_battery_indicator.set(led_battery_indicator);
cfg.led_battery_indicator_brightness.set(led_battery_indicator_brightness);
cfg.led_low_battery_blink.set(led_low_battery_blink);
SetPadData(0, 0, led_battery_indicator);
m_handler->SetPadData(m_device_name, GetPlayerIndex(), large_motor, small_motor, cfg.colorR, cfg.colorG, cfg.colorB, cfg.player_led_enabled.get(), led_battery_indicator, cfg.led_battery_indicator_brightness);
}
pad_device_info pad_settings_dialog::get_pad_info(QComboBox* combo, int index)

View File

@ -89,9 +89,6 @@ public:
explicit pad_settings_dialog(std::shared_ptr<gui_settings> gui_settings, QWidget *parent = nullptr, const GameInfo *game = nullptr);
~pad_settings_dialog();
public Q_SLOTS:
void apply_led_settings(int colorR, int colorG, int colorB, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness);
private Q_SLOTS:
void OnPadButtonClicked(int id);
void OnTabChanged(int index);