Skip to content

Commit

Permalink
Input: Allow to toggle player LED (Dualsense and DS3)
Browse files Browse the repository at this point in the history
  • Loading branch information
Megamouse committed Oct 19, 2022
1 parent 7ea0a6d commit 363e0a4
Show file tree
Hide file tree
Showing 19 changed files with 132 additions and 65 deletions.
5 changes: 5 additions & 0 deletions rpcs3/Emu/Io/PadHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion rpcs3/Emu/Io/PadHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class PadHandlerBase

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;
Expand Down Expand Up @@ -185,6 +186,7 @@ class PadHandlerBase
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;

Expand All @@ -195,7 +197,7 @@ class PadHandlerBase
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;
Expand Down
1 change: 1 addition & 0 deletions rpcs3/Emu/Io/pad_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
17 changes: 15 additions & 2 deletions rpcs3/Input/ds3_pad_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 #";
Expand Down Expand Up @@ -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)
Expand All @@ -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());
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/ds3_pad_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ds3_pad_handler final : public hid_pad_handler<ds3_device>
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;

Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/ds4_pad_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/ds4_pad_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ds4_pad_handler final : public hid_pad_handler<DS4Device>
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;

Expand Down
42 changes: 29 additions & 13 deletions rpcs3/Input/dualsense_pad_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 #";
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -970,17 +971,24 @@ 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;

switch (device->player_id)
if (config->player_led_enabled)
{
case 0: common.player_leds = 0b00100; break;
case 1: common.player_leds = 0b01010; break;
case 2: common.player_leds = 0b10101; break;
case 3: common.player_leds = 0b11011; break;
case 4: common.player_leds = 0b11111; break;
case 5: common.player_leds = 0b10111; break;
case 6: common.player_leds = 0b11101; break;
default:
fmt::throw_exception("Dualsense is using forbidden player id %d", device->player_id);
switch (device->player_id)
{
case 0: common.player_leds = 0b00100; break;
case 1: common.player_leds = 0b01010; break;
case 2: common.player_leds = 0b10101; break;
case 3: common.player_leds = 0b11011; break;
case 4: common.player_leds = 0b11111; break;
case 5: common.player_leds = 0b10111; break;
case 6: common.player_leds = 0b11101; break;
default:
fmt::throw_exception("Dualsense is using forbidden player id %d", device->player_id);
}
}
else
{
common.player_leds = 0;
}
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/dualsense_pad_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class dualsense_pad_handler final : public hid_pad_handler<DualSenseDevice>
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;

Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/evdev_joystick_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/evdev_joystick_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ class evdev_joystick_handler final : public PadHandlerBase
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();
Expand Down
1 change: 1 addition & 0 deletions rpcs3/Input/hid_pad_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class HidDevice : public PadDevice
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};
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/xinput_pad_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Input/xinput_pad_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class xinput_pad_handler final : public PadHandlerBase
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;

Expand Down
19 changes: 11 additions & 8 deletions rpcs3/rpcs3qt/pad_led_settings_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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();
}
});
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down
24 changes: 13 additions & 11 deletions rpcs3/rpcs3qt/pad_led_settings_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,15 +39,6 @@ private Q_SLOTS:
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;
};

0 comments on commit 363e0a4

Please sign in to comment.