Qt: Add icons/decorations to input devices

This commit is contained in:
Stenzek 2025-01-11 19:27:00 +10:00
parent 2298227054
commit 2d63b34d48
No known key found for this signature in database
5 changed files with 68 additions and 24 deletions

View File

@ -272,11 +272,12 @@ void ControllerBindingWidget::onAutomaticBindingClicked()
QMenu menu(this); QMenu menu(this);
bool added = false; bool added = false;
for (const auto& [identifier, device_name] : g_emu_thread->getInputDeviceListModel()->getDeviceList()) for (const InputDeviceListModel::Device& dev : g_emu_thread->getInputDeviceListModel()->getDeviceList())
{ {
// we set it as data, because the device list could get invalidated while the menu is up // we set it as data, because the device list could get invalidated while the menu is up
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(identifier).arg(device_name)); QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.identifier).arg(dev.display_name));
action->setData(identifier); action->setIcon(InputDeviceListModel::getIconForKey(dev.key));
action->setData(dev.identifier);
connect(action, &QAction::triggered, this, connect(action, &QAction::triggered, this,
[this, action]() { doDeviceAutomaticBinding(action->data().toString()); }); [this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
added = true; added = true;

View File

@ -140,6 +140,7 @@ void QtHost::RegisterTypes()
qRegisterMetaType<RenderAPI>("RenderAPI"); qRegisterMetaType<RenderAPI>("RenderAPI");
qRegisterMetaType<GPURenderer>("GPURenderer"); qRegisterMetaType<GPURenderer>("GPURenderer");
qRegisterMetaType<InputBindingKey>("InputBindingKey"); qRegisterMetaType<InputBindingKey>("InputBindingKey");
qRegisterMetaType<InputDeviceListModel::Device>("InputDeviceListModel::Device");
qRegisterMetaType<std::string>("std::string"); qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::vector<std::pair<std::string, std::string>>>( qRegisterMetaType<std::vector<std::pair<std::string, std::string>>>(
"std::vector<std::pair<std::string, std::string>>"); "std::vector<std::pair<std::string, std::string>>");
@ -2007,6 +2008,16 @@ InputDeviceListModel::InputDeviceListModel(QObject* parent) : QAbstractListModel
InputDeviceListModel::~InputDeviceListModel() = default; InputDeviceListModel::~InputDeviceListModel() = default;
QIcon InputDeviceListModel::getIconForKey(const InputBindingKey& key)
{
if (key.source_type == InputSourceType::Keyboard)
return QIcon::fromTheme("keyboard-line");
else if (key.source_type == InputSourceType::Pointer)
return QIcon::fromTheme("mouse-line");
else
return QIcon::fromTheme("controller-line");
}
int InputDeviceListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const int InputDeviceListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{ {
return m_devices.size(); return m_devices.size();
@ -2018,11 +2029,31 @@ QVariant InputDeviceListModel::data(const QModelIndex& index, int role /*= Qt::D
if (index.column() != 0 || row < 0 || static_cast<qsizetype>(row) >= m_devices.size()) if (index.column() != 0 || row < 0 || static_cast<qsizetype>(row) >= m_devices.size())
return QVariant(); return QVariant();
const auto& dev = m_devices[static_cast<qsizetype>(row)];
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return QStringLiteral("%1: %2").arg(dev.first).arg(dev.second); {
const auto& dev = m_devices[static_cast<qsizetype>(row)];
const InputBindingKey key = dev.key;
// don't display device names for implicit keyboard/mouse
if (key.source_type == InputSourceType::Keyboard ||
(key.source_type == InputSourceType::Pointer && !InputManager::IsUsingRawInput()))
{
return dev.display_name;
}
else
{
return QStringLiteral("%1\n%2").arg(dev.identifier).arg(dev.display_name);
}
}
else if (role == Qt::DecorationRole)
{
const auto& dev = m_devices[static_cast<qsizetype>(row)];
return getIconForKey(dev.key);
}
else else
{
return QVariant(); return QVariant();
}
} }
void InputDeviceListModel::enumerateDevices() void InputDeviceListModel::enumerateDevices()
@ -2035,7 +2066,7 @@ void InputDeviceListModel::enumerateDevices()
DeviceList new_devices; DeviceList new_devices;
new_devices.reserve(devices.size()); new_devices.reserve(devices.size());
for (const auto& [key, identifier, device_name] : devices) for (const auto& [key, identifier, device_name] : devices)
new_devices.emplace_back(QString::fromStdString(identifier), QString::fromStdString(device_name)); new_devices.emplace_back(key, QString::fromStdString(identifier), QString::fromStdString(device_name));
QStringList new_motors; QStringList new_motors;
new_motors.reserve(motors.size()); new_motors.reserve(motors.size());
@ -2059,28 +2090,28 @@ void InputDeviceListModel::resetLists(const DeviceList& devices, const QStringLi
endResetModel(); endResetModel();
} }
void InputDeviceListModel::onDeviceConnected(const QString& identifier, const QString& device_name, void InputDeviceListModel::onDeviceConnected(const InputBindingKey& key, const QString& identifier,
const QStringList& vibration_motors) const QString& device_name, const QStringList& vibration_motors)
{ {
for (const auto& it : m_devices) for (const auto& it : m_devices)
{ {
if (it.first == identifier) if (it.identifier == identifier)
return; return;
} }
const int index = static_cast<int>(m_devices.size()); const int index = static_cast<int>(m_devices.size());
beginInsertRows(QModelIndex(), index, index); beginInsertRows(QModelIndex(), index, index);
m_devices.emplace_back(identifier, device_name); m_devices.emplace_back(key, identifier, device_name);
endInsertRows(); endInsertRows();
m_vibration_motors.append(vibration_motors); m_vibration_motors.append(vibration_motors);
} }
void InputDeviceListModel::onDeviceDisconnected(const QString& identifier) void InputDeviceListModel::onDeviceDisconnected(const InputBindingKey& key, const QString& identifier)
{ {
for (qsizetype i = 0; i < m_devices.size(); i++) for (qsizetype i = 0; i < m_devices.size(); i++)
{ {
if (m_devices[i].first == identifier) if (m_devices[i].identifier == identifier)
{ {
const int index = static_cast<int>(i); const int index = static_cast<int>(i);
beginRemoveRows(QModelIndex(), index, index); beginRemoveRows(QModelIndex(), index, index);
@ -2117,10 +2148,10 @@ void Host::OnInputDeviceConnected(InputBindingKey key, std::string_view identifi
} }
} }
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), "onDeviceConnected", Qt::QueuedConnection, QMetaObject::invokeMethod(
Q_ARG(const QString&, QtUtils::StringViewToQString(identifier)), g_emu_thread->getInputDeviceListModel(), "onDeviceConnected", Qt::QueuedConnection,
Q_ARG(const QString&, QtUtils::StringViewToQString(device_name)), Q_ARG(const InputBindingKey&, key), Q_ARG(const QString&, QtUtils::StringViewToQString(identifier)),
Q_ARG(const QStringList&, vibration_motor_list)); Q_ARG(const QString&, QtUtils::StringViewToQString(device_name)), Q_ARG(const QStringList&, vibration_motor_list));
if (System::IsValid() || GPUThread::IsFullscreenUIRequested()) if (System::IsValid() || GPUThread::IsFullscreenUIRequested())
{ {
@ -2133,6 +2164,7 @@ void Host::OnInputDeviceConnected(InputBindingKey key, std::string_view identifi
void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier) void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier)
{ {
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), "onDeviceDisconnected", Qt::QueuedConnection, QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), "onDeviceDisconnected", Qt::QueuedConnection,
Q_ARG(const InputBindingKey&, key),
Q_ARG(const QString&, QtUtils::StringViewToQString(identifier))); Q_ARG(const QString&, QtUtils::StringViewToQString(identifier)));
if (g_settings.pause_on_controller_disconnection && System::GetState() == System::State::Running && if (g_settings.pause_on_controller_disconnection && System::GetState() == System::State::Running &&

View File

@ -266,7 +266,14 @@ class InputDeviceListModel final : public QAbstractListModel
Q_OBJECT Q_OBJECT
public: public:
using DeviceList = QList<QPair<QString, QString>>; struct Device
{
InputBindingKey key;
QString identifier;
QString display_name;
};
using DeviceList = QList<Device>;
InputDeviceListModel(QObject* parent = nullptr); InputDeviceListModel(QObject* parent = nullptr);
~InputDeviceListModel() override; ~InputDeviceListModel() override;
@ -275,6 +282,8 @@ public:
ALWAYS_INLINE const DeviceList& getDeviceList() const { return m_devices; } ALWAYS_INLINE const DeviceList& getDeviceList() const { return m_devices; }
ALWAYS_INLINE const QStringList& getVibrationMotorList() const { return m_vibration_motors; } ALWAYS_INLINE const QStringList& getVibrationMotorList() const { return m_vibration_motors; }
static QIcon getIconForKey(const InputBindingKey& key);
int rowCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
@ -282,8 +291,9 @@ public:
void enumerateDevices(); void enumerateDevices();
public Q_SLOTS: public Q_SLOTS:
void onDeviceConnected(const QString& identifier, const QString& device_name, const QStringList& vibration_motors); void onDeviceConnected(const InputBindingKey& key, const QString& identifier, const QString& device_name,
void onDeviceDisconnected(const QString& identifier); const QStringList& vibration_motors);
void onDeviceDisconnected(const InputBindingKey& key, const QString& identifier);
private Q_SLOTS: private Q_SLOTS:
void resetLists(const DeviceList& devices, const QStringList& motors); void resetLists(const DeviceList& devices, const QStringList& motors);

View File

@ -442,11 +442,12 @@ void SetupWizardDialog::openAutomaticMappingMenu(u32 port, QLabel* update_label)
QMenu menu(this); QMenu menu(this);
bool added = false; bool added = false;
for (const auto& [identifier, device_name] : g_emu_thread->getInputDeviceListModel()->getDeviceList()) for (const InputDeviceListModel::Device& dev : g_emu_thread->getInputDeviceListModel()->getDeviceList())
{ {
// we set it as data, because the device list could get invalidated while the menu is up // we set it as data, because the device list could get invalidated while the menu is up
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(identifier).arg(device_name)); QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.identifier).arg(dev.display_name));
action->setData(identifier); action->setIcon(InputDeviceListModel::getIconForKey(dev.key));
action->setData(dev.identifier);
connect(action, &QAction::triggered, this, [this, port, update_label, action]() { connect(action, &QAction::triggered, this, [this, port, update_label, action]() {
doDeviceAutomaticBinding(port, update_label, action->data().toString()); doDeviceAutomaticBinding(port, update_label, action->data().toString());
}); });

View File

@ -2000,8 +2000,8 @@ InputManager::DeviceList InputManager::EnumerateDevices()
InputBindingKey mouse_key = {}; InputBindingKey mouse_key = {};
mouse_key.source_type = InputSourceType::Pointer; mouse_key.source_type = InputSourceType::Pointer;
ret.emplace_back(keyboard_key, "Keyboard", "Keyboard"); ret.emplace_back(keyboard_key, "Keyboard", TRANSLATE_STR("InputManager", "Keyboard"));
ret.emplace_back(mouse_key, "Mouse", "Mouse"); ret.emplace_back(mouse_key, GetPointerDeviceName(0), TRANSLATE_STR("InputManager", "Mouse"));
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++) for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{ {