mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 20:15:32 +00:00
Qt: Refactor input device/motor tracking
Remove multiple sources of truth.
This commit is contained in:
parent
844287b722
commit
13b85728a0
@ -2850,7 +2850,7 @@ void FullscreenUI::DrawFolderSetting(SettingsInterface* bsi, const char* title,
|
||||
|
||||
void FullscreenUI::StartAutomaticBinding(u32 port)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> devices(InputManager::EnumerateDevices());
|
||||
InputManager::DeviceList devices = InputManager::EnumerateDevices();
|
||||
if (devices.empty())
|
||||
{
|
||||
ShowToast({}, FSUI_STR("Automatic mapping failed, no devices are available."));
|
||||
@ -2861,7 +2861,7 @@ void FullscreenUI::StartAutomaticBinding(u32 port)
|
||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||
options.reserve(devices.size());
|
||||
names.reserve(devices.size());
|
||||
for (auto& [name, display_name] : devices)
|
||||
for (auto& [key, name, display_name] : devices)
|
||||
{
|
||||
names.push_back(std::move(name));
|
||||
options.emplace_back(std::move(display_name), false);
|
||||
|
@ -272,16 +272,11 @@ void ControllerBindingWidget::onAutomaticBindingClicked()
|
||||
QMenu menu(this);
|
||||
bool added = false;
|
||||
|
||||
const auto& device_list = m_dialog->isEditingGameSettings() ?
|
||||
g_main_window->getControllerSettingsWindow()->getDeviceList() :
|
||||
m_dialog->getDeviceList();
|
||||
for (const auto& [identifier, device_name] : device_list)
|
||||
for (const auto& [identifier, device_name] : g_emu_thread->getInputDeviceListModel()->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
const QString qidentifier = QString::fromStdString(identifier);
|
||||
QAction* action =
|
||||
menu.addAction(QStringLiteral("%1 (%2)").arg(qidentifier).arg(QString::fromStdString(device_name)));
|
||||
action->setData(qidentifier);
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(identifier).arg(device_name));
|
||||
action->setData(identifier);
|
||||
connect(action, &QAction::triggered, this,
|
||||
[this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
|
||||
added = true;
|
||||
|
@ -87,14 +87,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
m_ui.profileSettings = nullptr;
|
||||
}
|
||||
|
||||
if (dialog->isEditingGameSettings())
|
||||
{
|
||||
m_ui.mainLayout->removeWidget(m_ui.deviceListGroup);
|
||||
delete m_ui.deviceList;
|
||||
m_ui.deviceList = nullptr;
|
||||
delete m_ui.deviceListGroup;
|
||||
m_ui.deviceListGroup = nullptr;
|
||||
}
|
||||
m_ui.deviceList->setModel(g_emu_thread->getInputDeviceListModel());
|
||||
|
||||
connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||
|
||||
@ -110,28 +103,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
|
||||
ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;
|
||||
|
||||
void ControllerGlobalSettingsWidget::addDeviceToList(const QString& identifier, const QString& name)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
item->setData(Qt::UserRole, identifier);
|
||||
m_ui.deviceList->addItem(item);
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::removeDeviceFromList(const QString& identifier)
|
||||
{
|
||||
const int count = m_ui.deviceList->count();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = m_ui.deviceList->item(i);
|
||||
if (item->data(Qt::UserRole) != identifier)
|
||||
continue;
|
||||
|
||||
delete m_ui.deviceList->takeItem(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::ledSettingsClicked()
|
||||
{
|
||||
ControllerLEDSettingsDialog dialog(this, m_dialog);
|
||||
|
@ -25,9 +25,6 @@ public:
|
||||
ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsWindow* dialog);
|
||||
~ControllerGlobalSettingsWidget();
|
||||
|
||||
void addDeviceToList(const QString& identifier, const QString& name);
|
||||
void removeDeviceFromList(const QString& identifier);
|
||||
|
||||
Q_SIGNALS:
|
||||
void bindingSetupChanged();
|
||||
|
||||
|
@ -56,7 +56,7 @@
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QListWidget" name="deviceList">
|
||||
<widget class="QListView" name="deviceList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
|
@ -49,18 +49,6 @@ ControllerSettingsWindow::ControllerSettingsWindow(SettingsInterface* game_sif /
|
||||
connect(m_ui.applyProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onApplyProfileClicked);
|
||||
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked);
|
||||
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this,
|
||||
&ControllerSettingsWindow::onInputDevicesEnumerated);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsWindow::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this,
|
||||
&ControllerSettingsWindow::onInputDeviceDisconnected);
|
||||
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this,
|
||||
&ControllerSettingsWindow::onVibrationMotorsEnumerated);
|
||||
|
||||
// trigger a device enumeration to populate the device list
|
||||
g_emu_thread->enumerateInputDevices();
|
||||
g_emu_thread->enumerateVibrationMotors();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -324,48 +312,6 @@ void ControllerSettingsWindow::onRestoreDefaultsForGameClicked()
|
||||
tr("Per-game controller configuration reset to default settings."));
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices)
|
||||
{
|
||||
m_device_list = devices;
|
||||
for (const auto& [device_name, display_name] : m_device_list)
|
||||
m_global_settings->addDeviceToList(QString::fromStdString(device_name), QString::fromStdString(display_name));
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onInputDeviceConnected(const std::string& identifier, const std::string& device_name)
|
||||
{
|
||||
m_device_list.emplace_back(identifier, device_name);
|
||||
m_global_settings->addDeviceToList(QString::fromStdString(identifier), QString::fromStdString(device_name));
|
||||
g_emu_thread->enumerateVibrationMotors();
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onInputDeviceDisconnected(const std::string& identifier)
|
||||
{
|
||||
for (auto iter = m_device_list.begin(); iter != m_device_list.end(); ++iter)
|
||||
{
|
||||
if (iter->first == identifier)
|
||||
{
|
||||
m_device_list.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_global_settings->removeDeviceFromList(QString::fromStdString(identifier));
|
||||
g_emu_thread->enumerateVibrationMotors();
|
||||
}
|
||||
|
||||
void ControllerSettingsWindow::onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors)
|
||||
{
|
||||
m_vibration_motors.clear();
|
||||
m_vibration_motors.reserve(motors.size());
|
||||
|
||||
for (const InputBindingKey key : motors)
|
||||
{
|
||||
const std::string key_str(InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type::Motor, key));
|
||||
if (!key_str.empty())
|
||||
m_vibration_motors.push_back(QString::fromStdString(key_str));
|
||||
}
|
||||
}
|
||||
|
||||
bool ControllerSettingsWindow::getBoolValue(const char* section, const char* key, bool default_value) const
|
||||
{
|
||||
if (m_editing_settings_interface)
|
||||
@ -489,11 +435,6 @@ void ControllerSettingsWindow::createWidgets()
|
||||
m_ui.settingsContainer->addWidget(m_global_settings);
|
||||
connect(m_global_settings, &ControllerGlobalSettingsWidget::bindingSetupChanged, this,
|
||||
&ControllerSettingsWindow::createWidgets);
|
||||
if (!isEditingGameSettings())
|
||||
{
|
||||
for (const auto& [identifier, device_name] : m_device_list)
|
||||
m_global_settings->addDeviceToList(QString::fromStdString(identifier), QString::fromStdString(device_name));
|
||||
}
|
||||
}
|
||||
|
||||
// load mtap settings
|
||||
|
@ -48,9 +48,6 @@ public:
|
||||
|
||||
ALWAYS_INLINE HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
|
||||
|
||||
ALWAYS_INLINE const std::vector<std::pair<std::string, std::string>>& getDeviceList() const { return m_device_list; }
|
||||
ALWAYS_INLINE const QStringList& getVibrationMotors() const { return m_vibration_motors; }
|
||||
|
||||
ALWAYS_INLINE bool isEditingGlobalSettings() const
|
||||
{
|
||||
return (m_profile_name.isEmpty() && !m_editing_settings_interface);
|
||||
@ -95,11 +92,6 @@ private Q_SLOTS:
|
||||
void onCopyGlobalSettingsClicked();
|
||||
void onRestoreDefaultsForGameClicked();
|
||||
|
||||
void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
|
||||
void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
|
||||
void onInputDeviceDisconnected(const std::string& identifier);
|
||||
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
|
||||
|
||||
void createWidgets();
|
||||
|
||||
protected:
|
||||
@ -119,9 +111,6 @@ private:
|
||||
std::array<ControllerBindingWidget*, NUM_CONTROLLER_AND_CARD_PORTS> m_port_bindings{};
|
||||
HotkeySettingsWidget* m_hotkey_settings = nullptr;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> m_device_list;
|
||||
QStringList m_vibration_motors;
|
||||
|
||||
QString m_profile_name;
|
||||
std::unique_ptr<SettingsInterface> m_profile_settings_interface;
|
||||
};
|
||||
|
@ -448,7 +448,7 @@ void InputVibrationBindingWidget::onClicked()
|
||||
const QString full_key(
|
||||
QStringLiteral("%1/%2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
|
||||
const QString current(QString::fromStdString(m_binding));
|
||||
QStringList input_options(m_dialog->getVibrationMotors());
|
||||
QStringList input_options = g_emu_thread->getInputDeviceListModel()->getVibrationMotorList();
|
||||
if (!current.isEmpty() && input_options.indexOf(current) < 0)
|
||||
{
|
||||
input_options.append(current);
|
||||
|
@ -122,7 +122,8 @@ static bool s_cleanup_after_update = false;
|
||||
|
||||
EmuThread* g_emu_thread = nullptr;
|
||||
|
||||
EmuThread::EmuThread(QThread* ui_thread) : QThread(), m_ui_thread(ui_thread)
|
||||
EmuThread::EmuThread(QThread* ui_thread)
|
||||
: QThread(), m_ui_thread(ui_thread), m_input_device_list_model(std::make_unique<InputDeviceListModel>())
|
||||
{
|
||||
}
|
||||
|
||||
@ -1079,34 +1080,6 @@ void EmuThread::closeInputSources()
|
||||
InputManager::CloseSources();
|
||||
}
|
||||
|
||||
void EmuThread::enumerateInputDevices()
|
||||
{
|
||||
if (!isCurrentThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, &EmuThread::enumerateInputDevices, Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
onInputDevicesEnumerated(InputManager::EnumerateDevices());
|
||||
}
|
||||
|
||||
void EmuThread::enumerateVibrationMotors()
|
||||
{
|
||||
if (!isCurrentThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, &EmuThread::enumerateVibrationMotors, Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<InputBindingKey> motors(InputManager::EnumerateMotors());
|
||||
QList<InputBindingKey> qmotors;
|
||||
qmotors.reserve(motors.size());
|
||||
for (InputBindingKey key : motors)
|
||||
qmotors.push_back(key);
|
||||
|
||||
onVibrationMotorsEnumerated(qmotors);
|
||||
}
|
||||
|
||||
void EmuThread::confirmActionIfMemoryCardBusy(const QString& action, bool cancel_resume_on_accept,
|
||||
std::function<void(bool)> callback) const
|
||||
{
|
||||
@ -1830,9 +1803,9 @@ void EmuThread::start()
|
||||
AssertMsg(!g_emu_thread, "Emu thread does not exist");
|
||||
|
||||
g_emu_thread = new EmuThread(QThread::currentThread());
|
||||
g_emu_thread->moveToThread(g_emu_thread);
|
||||
g_emu_thread->QThread::start();
|
||||
g_emu_thread->m_started_semaphore.acquire();
|
||||
g_emu_thread->moveToThread(g_emu_thread);
|
||||
}
|
||||
|
||||
void EmuThread::stop()
|
||||
@ -1868,7 +1841,10 @@ void EmuThread::run()
|
||||
}
|
||||
}
|
||||
|
||||
// bind buttons/axises
|
||||
// enumerate all devices, even those which were added early
|
||||
m_input_device_list_model->enumerateDevices();
|
||||
|
||||
// start background input polling
|
||||
createBackgroundControllerPollTimer();
|
||||
startBackgroundControllerPollTimer();
|
||||
|
||||
@ -2025,13 +2001,126 @@ void Host::ReportDebuggerMessage(std::string_view message)
|
||||
emit g_emu_thread->debuggerMessageReported(QString::fromUtf8(message));
|
||||
}
|
||||
|
||||
void Host::AddFixedInputBindings(const SettingsInterface& si)
|
||||
InputDeviceListModel::InputDeviceListModel(QObject* parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnInputDeviceConnected(std::string_view identifier, std::string_view device_name)
|
||||
InputDeviceListModel::~InputDeviceListModel() = default;
|
||||
|
||||
int InputDeviceListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
|
||||
{
|
||||
emit g_emu_thread->onInputDeviceConnected(std::string(identifier), std::string(device_name));
|
||||
return m_devices.size();
|
||||
}
|
||||
|
||||
QVariant InputDeviceListModel::data(const QModelIndex& index, int role /*= Qt::DisplayRole*/) const
|
||||
{
|
||||
const int row = index.row();
|
||||
if (index.column() != 0 || row < 0 || static_cast<qsizetype>(row) >= m_devices.size())
|
||||
return QVariant();
|
||||
|
||||
const auto& dev = m_devices[static_cast<qsizetype>(row)];
|
||||
if (role == Qt::DisplayRole)
|
||||
return QStringLiteral("%1: %2").arg(dev.first).arg(dev.second);
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void InputDeviceListModel::enumerateDevices()
|
||||
{
|
||||
DebugAssert(g_emu_thread->isCurrentThread());
|
||||
|
||||
const InputManager::DeviceList devices = InputManager::EnumerateDevices();
|
||||
const InputManager::VibrationMotorList motors = InputManager::EnumerateVibrationMotors();
|
||||
|
||||
DeviceList new_devices;
|
||||
new_devices.reserve(devices.size());
|
||||
for (const auto& [key, identifier, device_name] : devices)
|
||||
new_devices.emplace_back(QString::fromStdString(identifier), QString::fromStdString(device_name));
|
||||
|
||||
QStringList new_motors;
|
||||
new_motors.reserve(motors.size());
|
||||
for (const auto& key : motors)
|
||||
{
|
||||
new_motors.push_back(
|
||||
QString::fromStdString(InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type::Motor, key)));
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(this, "resetLists", Qt::QueuedConnection, Q_ARG(const DeviceList&, new_devices),
|
||||
Q_ARG(const QStringList&, m_vibration_motors));
|
||||
}
|
||||
|
||||
void InputDeviceListModel::resetLists(const DeviceList& devices, const QStringList& motors)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
m_devices = devices;
|
||||
m_vibration_motors = motors;
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void InputDeviceListModel::onDeviceConnected(const QString& identifier, const QString& device_name,
|
||||
const QStringList& vibration_motors)
|
||||
{
|
||||
for (const auto& it : m_devices)
|
||||
{
|
||||
if (it.first == identifier)
|
||||
return;
|
||||
}
|
||||
|
||||
const int index = static_cast<int>(m_devices.size());
|
||||
beginInsertRows(QModelIndex(), index, index);
|
||||
m_devices.emplace_back(identifier, device_name);
|
||||
endInsertRows();
|
||||
|
||||
m_vibration_motors.append(vibration_motors);
|
||||
}
|
||||
|
||||
void InputDeviceListModel::onDeviceDisconnected(const QString& identifier)
|
||||
{
|
||||
for (qsizetype i = 0; i < m_devices.size(); i++)
|
||||
{
|
||||
if (m_devices[i].first == identifier)
|
||||
{
|
||||
const int index = static_cast<int>(i);
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_devices.remove(i);
|
||||
endRemoveRows();
|
||||
|
||||
// remove vibration motors too
|
||||
const QString motor_prefix = QStringLiteral("%1/").arg(identifier);
|
||||
for (qsizetype j = 0; j < m_vibration_motors.size();)
|
||||
{
|
||||
if (m_vibration_motors[j].startsWith(motor_prefix))
|
||||
m_vibration_motors.remove(j);
|
||||
else
|
||||
j++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Host::OnInputDeviceConnected(InputBindingKey key, std::string_view identifier, std::string_view device_name)
|
||||
{
|
||||
// get the motors for this device to append to the list
|
||||
QStringList vibration_motor_list;
|
||||
const InputManager::VibrationMotorList im_vibration_motor_list = InputManager::EnumerateVibrationMotors(key);
|
||||
if (!im_vibration_motor_list.empty())
|
||||
{
|
||||
vibration_motor_list.reserve(im_vibration_motor_list.size());
|
||||
for (const InputBindingKey& motor_key : im_vibration_motor_list)
|
||||
{
|
||||
vibration_motor_list.push_back(
|
||||
QString::fromStdString(InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type::Motor, motor_key)));
|
||||
}
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), "onDeviceConnected", Qt::QueuedConnection,
|
||||
Q_ARG(const QString&, QtUtils::StringViewToQString(identifier)),
|
||||
Q_ARG(const QString&, QtUtils::StringViewToQString(device_name)),
|
||||
Q_ARG(const QStringList&, vibration_motor_list));
|
||||
|
||||
if (System::IsValid() || GPUThread::IsFullscreenUIRequested())
|
||||
{
|
||||
@ -2043,7 +2132,8 @@ void Host::OnInputDeviceConnected(std::string_view identifier, std::string_view
|
||||
|
||||
void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier)
|
||||
{
|
||||
emit g_emu_thread->onInputDeviceDisconnected(std::string(identifier));
|
||||
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), "onDeviceDisconnected", Qt::QueuedConnection,
|
||||
Q_ARG(const QString&, QtUtils::StringViewToQString(identifier)));
|
||||
|
||||
if (g_settings.pause_on_controller_disconnection && System::GetState() == System::State::Running &&
|
||||
InputManager::HasAnyBindingsForSource(key))
|
||||
@ -2067,6 +2157,10 @@ void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view ident
|
||||
}
|
||||
}
|
||||
|
||||
void Host::AddFixedInputBindings(const SettingsInterface& si)
|
||||
{
|
||||
}
|
||||
|
||||
std::string QtHost::GetResourcePath(std::string_view filename, bool allow_override)
|
||||
{
|
||||
return allow_override ? EmuFolders::GetOverridableResourcePath(filename) :
|
||||
|
@ -15,8 +15,10 @@
|
||||
#include "util/input_manager.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMetaType>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QSemaphore>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QThread>
|
||||
@ -48,6 +50,7 @@ class GPUBackend;
|
||||
|
||||
class MainWindow;
|
||||
class DisplayWidget;
|
||||
class InputDeviceListModel;
|
||||
|
||||
namespace Achievements {
|
||||
enum class LoginRequestReason;
|
||||
@ -96,6 +99,8 @@ public:
|
||||
ALWAYS_INLINE bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
||||
ALWAYS_INLINE bool isSurfaceless() const { return m_is_surfaceless; }
|
||||
|
||||
ALWAYS_INLINE InputDeviceListModel* getInputDeviceListModel() const { return m_input_device_list_model.get(); }
|
||||
|
||||
std::optional<WindowInfo> acquireRenderWindow(RenderAPI render_api, bool fullscreen, bool exclusive_fullscreen,
|
||||
Error* error);
|
||||
void connectDisplaySignals(DisplayWidget* widget);
|
||||
@ -130,10 +135,6 @@ Q_SIGNALS:
|
||||
void statusMessage(const QString& message);
|
||||
void debuggerMessageReported(const QString& message);
|
||||
void settingsResetToDefault(bool system, bool controller);
|
||||
void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
|
||||
void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
|
||||
void onInputDeviceDisconnected(const std::string& identifier);
|
||||
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
|
||||
void systemStarting();
|
||||
void systemStarted();
|
||||
void systemDestroyed();
|
||||
@ -177,8 +178,6 @@ public Q_SLOTS:
|
||||
void reloadInputBindings();
|
||||
void reloadInputDevices();
|
||||
void closeInputSources();
|
||||
void enumerateInputDevices();
|
||||
void enumerateVibrationMotors();
|
||||
void startFullscreenUI();
|
||||
void stopFullscreenUI();
|
||||
void bootSystem(std::shared_ptr<SystemBootParameters> params);
|
||||
@ -241,6 +240,7 @@ private:
|
||||
QSemaphore m_started_semaphore;
|
||||
QEventLoop* m_event_loop = nullptr;
|
||||
QTimer* m_background_controller_polling_timer = nullptr;
|
||||
std::unique_ptr<InputDeviceListModel> m_input_device_list_model;
|
||||
|
||||
bool m_shutdown_flag = false;
|
||||
bool m_is_rendering_to_main = false;
|
||||
@ -261,6 +261,38 @@ private:
|
||||
bool m_last_hardware_renderer = false;
|
||||
};
|
||||
|
||||
class InputDeviceListModel final : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using DeviceList = QList<QPair<QString, QString>>;
|
||||
|
||||
InputDeviceListModel(QObject* parent = nullptr);
|
||||
~InputDeviceListModel() override;
|
||||
|
||||
// Safe to access on UI thread.
|
||||
ALWAYS_INLINE const DeviceList& getDeviceList() const { return m_devices; }
|
||||
ALWAYS_INLINE const QStringList& getVibrationMotorList() const { return m_vibration_motors; }
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
// NOTE: Should only be called on EmuThread.
|
||||
void enumerateDevices();
|
||||
|
||||
public Q_SLOTS:
|
||||
void onDeviceConnected(const QString& identifier, const QString& device_name, const QStringList& vibration_motors);
|
||||
void onDeviceDisconnected(const QString& identifier);
|
||||
|
||||
private Q_SLOTS:
|
||||
void resetLists(const DeviceList& devices, const QStringList& motors);
|
||||
|
||||
private:
|
||||
DeviceList m_devices;
|
||||
QStringList m_vibration_motors;
|
||||
};
|
||||
|
||||
extern EmuThread* g_emu_thread;
|
||||
|
||||
namespace QtHost {
|
||||
|
@ -426,15 +426,6 @@ void SetupWizardDialog::setupControllerPage(bool initial)
|
||||
}
|
||||
}
|
||||
|
||||
if (initial)
|
||||
{
|
||||
// Trigger enumeration to populate the device list.
|
||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &SetupWizardDialog::onInputDevicesEnumerated);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &SetupWizardDialog::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &SetupWizardDialog::onInputDeviceDisconnected);
|
||||
g_emu_thread->enumerateInputDevices();
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
for (const PadWidgets& w : pad_widgets)
|
||||
@ -451,13 +442,11 @@ void SetupWizardDialog::openAutomaticMappingMenu(u32 port, QLabel* update_label)
|
||||
QMenu menu(this);
|
||||
bool added = false;
|
||||
|
||||
for (const auto& [identifier, device_name] : m_device_list)
|
||||
for (const auto& [identifier, device_name] : g_emu_thread->getInputDeviceListModel()->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
const QString qidentifier = QString::fromStdString(identifier);
|
||||
QAction* action =
|
||||
menu.addAction(QStringLiteral("%1 (%2)").arg(qidentifier).arg(QString::fromStdString(device_name)));
|
||||
action->setData(qidentifier);
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(identifier).arg(device_name));
|
||||
action->setData(identifier);
|
||||
connect(action, &QAction::triggered, this, [this, port, update_label, action]() {
|
||||
doDeviceAutomaticBinding(port, update_label, action->data().toString());
|
||||
});
|
||||
@ -499,25 +488,3 @@ void SetupWizardDialog::doDeviceAutomaticBinding(u32 port, QLabel* update_label,
|
||||
|
||||
update_label->setText(device);
|
||||
}
|
||||
|
||||
void SetupWizardDialog::onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices)
|
||||
{
|
||||
m_device_list = devices;
|
||||
}
|
||||
|
||||
void SetupWizardDialog::onInputDeviceConnected(const std::string& identifier, const std::string& device_name)
|
||||
{
|
||||
m_device_list.emplace_back(identifier, device_name);
|
||||
}
|
||||
|
||||
void SetupWizardDialog::onInputDeviceDisconnected(const std::string& identifier)
|
||||
{
|
||||
for (auto iter = m_device_list.begin(); iter != m_device_list.end(); ++iter)
|
||||
{
|
||||
if (iter->first == identifier)
|
||||
{
|
||||
m_device_list.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,10 +45,6 @@ private Q_SLOTS:
|
||||
void refreshDirectoryList();
|
||||
void resizeDirectoryListColumns();
|
||||
|
||||
void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
|
||||
void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
|
||||
void onInputDeviceDisconnected(const std::string& identifier);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
|
||||
@ -82,6 +78,4 @@ private:
|
||||
Ui::SetupWizardDialog m_ui;
|
||||
|
||||
std::array<QLabel*, Page_Count> m_page_labels;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> m_device_list;
|
||||
};
|
||||
|
@ -481,7 +481,7 @@ void Host::AddFixedInputBindings(const SettingsInterface& si)
|
||||
// noop
|
||||
}
|
||||
|
||||
void Host::OnInputDeviceConnected(std::string_view identifier, std::string_view device_name)
|
||||
void Host::OnInputDeviceConnected(InputBindingKey key, std::string_view identifier, std::string_view device_name)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#define INITGUID
|
||||
@ -153,7 +153,8 @@ bool DInputSource::ReloadDevices()
|
||||
{
|
||||
const u32 index = static_cast<u32>(m_controllers.size());
|
||||
m_controllers.push_back(std::move(cd));
|
||||
InputManager::OnInputDeviceConnected(GetDeviceIdentifier(index), name);
|
||||
InputManager::OnInputDeviceConnected(MakeGenericControllerDeviceKey(InputSourceType::DInput, index),
|
||||
GetDeviceIdentifier(index), name);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@ -166,12 +167,7 @@ void DInputSource::Shutdown()
|
||||
while (!m_controllers.empty())
|
||||
{
|
||||
const u32 index = static_cast<u32>(m_controllers.size() - 1);
|
||||
InputManager::OnInputDeviceDisconnected(InputBindingKey{{.source_type = InputSourceType::DInput,
|
||||
.source_index = index,
|
||||
.source_subtype = InputSubclass::None,
|
||||
.modifier = InputModifier::None,
|
||||
.invert = 0,
|
||||
.data = 0}},
|
||||
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::DInput, index),
|
||||
GetDeviceIdentifier(static_cast<u32>(m_controllers.size() - 1)));
|
||||
m_controllers.pop_back();
|
||||
}
|
||||
@ -298,9 +294,9 @@ void DInputSource::PollEvents()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> DInputSource::EnumerateDevices()
|
||||
InputManager::DeviceList DInputSource::EnumerateDevices()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> ret;
|
||||
InputManager::DeviceList ret;
|
||||
for (size_t i = 0; i < m_controllers.size(); i++)
|
||||
{
|
||||
DIDEVICEINSTANCEW dii;
|
||||
@ -312,13 +308,14 @@ std::vector<std::pair<std::string, std::string>> DInputSource::EnumerateDevices(
|
||||
if (name.empty())
|
||||
name = "Unknown";
|
||||
|
||||
ret.emplace_back(GetDeviceIdentifier(static_cast<u32>(i)), std::move(name));
|
||||
ret.emplace_back(MakeGenericControllerDeviceKey(InputSourceType::DInput, static_cast<u32>(i)),
|
||||
GetDeviceIdentifier(static_cast<u32>(i)), std::move(name));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<InputBindingKey> DInputSource::EnumerateMotors()
|
||||
InputManager::VibrationMotorList DInputSource::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -39,8 +39,8 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,
|
||||
|
@ -1274,9 +1274,9 @@ void InputManager::UpdatePointerCount()
|
||||
DebugAssert(ris);
|
||||
|
||||
s_pointer_count = 0;
|
||||
for (const std::pair<std::string, std::string>& it : ris->EnumerateDevices())
|
||||
for (const auto& [key, identifier, device_name] : ris->EnumerateDevices())
|
||||
{
|
||||
if (it.first.starts_with("Pointer-"))
|
||||
if (key.source_type == InputSourceType::Pointer)
|
||||
s_pointer_count++;
|
||||
}
|
||||
#endif
|
||||
@ -1614,10 +1614,11 @@ std::vector<std::string> InputManager::GetInputProfileNames()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void InputManager::OnInputDeviceConnected(std::string_view identifier, std::string_view device_name)
|
||||
void InputManager::OnInputDeviceConnected(InputBindingKey key, std::string_view identifier,
|
||||
std::string_view device_name)
|
||||
{
|
||||
INFO_LOG("Device '{}' connected: '{}'", identifier, device_name);
|
||||
Host::OnInputDeviceConnected(identifier, device_name);
|
||||
Host::OnInputDeviceConnected(key, identifier, device_name);
|
||||
}
|
||||
|
||||
void InputManager::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier)
|
||||
@ -2006,18 +2007,23 @@ void InputManager::PollSources()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> InputManager::EnumerateDevices()
|
||||
InputManager::DeviceList InputManager::EnumerateDevices()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> ret;
|
||||
DeviceList ret;
|
||||
|
||||
ret.emplace_back("Keyboard", "Keyboard");
|
||||
ret.emplace_back("Mouse", "Mouse");
|
||||
InputBindingKey keyboard_key = {};
|
||||
keyboard_key.source_type = InputSourceType::Keyboard;
|
||||
InputBindingKey mouse_key = {};
|
||||
mouse_key.source_type = InputSourceType::Pointer;
|
||||
|
||||
ret.emplace_back(keyboard_key, "Keyboard", "Keyboard");
|
||||
ret.emplace_back(mouse_key, "Mouse", "Mouse");
|
||||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> devs(s_input_sources[i]->EnumerateDevices());
|
||||
DeviceList devs = s_input_sources[i]->EnumerateDevices();
|
||||
if (ret.empty())
|
||||
ret = std::move(devs);
|
||||
else
|
||||
@ -2028,15 +2034,15 @@ std::vector<std::pair<std::string, std::string>> InputManager::EnumerateDevices(
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<InputBindingKey> InputManager::EnumerateMotors()
|
||||
InputManager::VibrationMotorList InputManager::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
std::vector<InputBindingKey> ret;
|
||||
VibrationMotorList ret;
|
||||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
{
|
||||
std::vector<InputBindingKey> devs(s_input_sources[i]->EnumerateMotors());
|
||||
VibrationMotorList devs = s_input_sources[i]->EnumerateVibrationMotors(for_device);
|
||||
if (ret.empty())
|
||||
ret = std::move(devs);
|
||||
else
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
@ -254,17 +255,19 @@ std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type,
|
||||
|
||||
/// Represents a binding with icon fonts, if available.
|
||||
/// Optionally maps icon fonts to a different style, e.g. xbox icons -> PS buttons.
|
||||
using BindingIconMappingFunction = std::string_view(*)(std::string_view);
|
||||
using BindingIconMappingFunction = std::string_view (*)(std::string_view);
|
||||
bool PrettifyInputBinding(SmallStringBase& binding, BindingIconMappingFunction mapper = nullptr);
|
||||
|
||||
/// Returns a list of all hotkeys.
|
||||
std::vector<const HotkeyInfo*> GetHotkeyList();
|
||||
|
||||
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices();
|
||||
using DeviceList = std::vector<std::tuple<InputBindingKey, std::string, std::string>>;
|
||||
DeviceList EnumerateDevices();
|
||||
|
||||
/// Enumerates available vibration motors at the time of call.
|
||||
std::vector<InputBindingKey> EnumerateMotors();
|
||||
using VibrationMotorList = std::vector<InputBindingKey>;
|
||||
VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device = std::nullopt);
|
||||
|
||||
/// Retrieves bindings that match the generic bindings for the specified device.
|
||||
GenericInputBindingMapping GetGenericBindingMapping(std::string_view device);
|
||||
@ -380,7 +383,7 @@ bool MapController(SettingsInterface& si, u32 controller,
|
||||
std::vector<std::string> GetInputProfileNames();
|
||||
|
||||
/// Called when a new input device is connected.
|
||||
void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name);
|
||||
void OnInputDeviceConnected(InputBindingKey key, std::string_view identifier, std::string_view device_name);
|
||||
|
||||
/// Called when an input device is disconnected.
|
||||
void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier);
|
||||
@ -394,7 +397,7 @@ namespace Host {
|
||||
void AddFixedInputBindings(const SettingsInterface& si);
|
||||
|
||||
/// Called when a new input device is connected.
|
||||
void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name);
|
||||
void OnInputDeviceConnected(InputBindingKey key, std::string_view identifier, std::string_view device_name);
|
||||
|
||||
/// Called when an input device is disconnected.
|
||||
void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier);
|
||||
|
@ -20,6 +20,16 @@ void InputSource::UpdateMotorState(InputBindingKey large_key, InputBindingKey sm
|
||||
UpdateMotorState(small_key, small_intensity);
|
||||
}
|
||||
|
||||
InputBindingKey InputSource::MakeGenericControllerDeviceKey(InputSourceType clazz, u32 controller_index)
|
||||
{
|
||||
InputBindingKey key = {};
|
||||
key.source_type = clazz;
|
||||
key.source_index = controller_index;
|
||||
key.source_subtype = InputSubclass::None;
|
||||
key.data = 0;
|
||||
return key;
|
||||
}
|
||||
|
||||
InputBindingKey InputSource::MakeGenericControllerAxisKey(InputSourceType clazz, u32 controller_index, s32 axis_index)
|
||||
{
|
||||
InputBindingKey key = {};
|
||||
|
@ -38,10 +38,10 @@ public:
|
||||
virtual TinyString ConvertKeyToIcon(InputBindingKey key, InputManager::BindingIconMappingFunction mapper) = 0;
|
||||
|
||||
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
|
||||
virtual std::vector<std::pair<std::string, std::string>> EnumerateDevices() = 0;
|
||||
virtual InputManager::DeviceList EnumerateDevices() = 0;
|
||||
|
||||
/// Enumerates available vibration motors at the time of call.
|
||||
virtual std::vector<InputBindingKey> EnumerateMotors() = 0;
|
||||
virtual InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) = 0;
|
||||
|
||||
/// Retrieves bindings that match the generic bindings for the specified device.
|
||||
/// Returns false if it's not one of our devices.
|
||||
@ -57,6 +57,9 @@ public:
|
||||
/// Creates a force-feedback device from this source.
|
||||
virtual std::unique_ptr<ForceFeedbackDevice> CreateForceFeedbackDevice(std::string_view device, Error* error) = 0;
|
||||
|
||||
/// Creates a key for a generic controller device.
|
||||
static InputBindingKey MakeGenericControllerDeviceKey(InputSourceType clazz, u32 controller_index);
|
||||
|
||||
/// Creates a key for a generic controller axis event.
|
||||
static InputBindingKey MakeGenericControllerAxisKey(InputSourceType clazz, u32 controller_index, s32 axis_index);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "sdl_input_source.h"
|
||||
@ -361,19 +361,20 @@ void SDLInputSource::PollEvents()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> SDLInputSource::EnumerateDevices()
|
||||
InputManager::DeviceList SDLInputSource::EnumerateDevices()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> ret;
|
||||
InputManager::DeviceList ret;
|
||||
|
||||
for (const ControllerData& cd : m_controllers)
|
||||
{
|
||||
std::string id = fmt::format("SDL-{}", cd.player_id);
|
||||
|
||||
const InputBindingKey key = MakeGenericControllerDeviceKey(InputSourceType::SDL, cd.player_id);
|
||||
const char* name = cd.game_controller ? SDL_GameControllerName(cd.game_controller) : SDL_JoystickName(cd.joystick);
|
||||
if (name)
|
||||
ret.emplace_back(std::move(id), name);
|
||||
ret.emplace_back(key, std::move(id), name);
|
||||
else
|
||||
ret.emplace_back(std::move(id), "Unknown Device");
|
||||
ret.emplace_back(key, std::move(id), "Unknown Device");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -858,7 +859,8 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
|
||||
|
||||
m_controllers.push_back(std::move(cd));
|
||||
|
||||
InputManager::OnInputDeviceConnected(fmt::format("SDL-{}", player_id), name);
|
||||
InputManager::OnInputDeviceConnected(MakeGenericControllerDeviceKey(InputSourceType::SDL, player_id),
|
||||
fmt::format("SDL-{}", player_id), name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -868,12 +870,7 @@ bool SDLInputSource::CloseDevice(int joystick_index)
|
||||
if (it == m_controllers.end())
|
||||
return false;
|
||||
|
||||
InputManager::OnInputDeviceDisconnected(InputBindingKey{{.source_type = InputSourceType::SDL,
|
||||
.source_index = static_cast<u32>(it->player_id),
|
||||
.source_subtype = InputSubclass::None,
|
||||
.modifier = InputModifier::None,
|
||||
.invert = 0,
|
||||
.data = 0}},
|
||||
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::SDL, it->player_id),
|
||||
fmt::format("SDL-{}", it->player_id));
|
||||
|
||||
if (it->haptic)
|
||||
@ -1023,15 +1020,21 @@ bool SDLInputSource::HandleJoystickHatEvent(const SDL_JoyHatEvent* ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<InputBindingKey> SDLInputSource::EnumerateMotors()
|
||||
InputManager::VibrationMotorList SDLInputSource::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
std::vector<InputBindingKey> ret;
|
||||
InputManager::VibrationMotorList ret;
|
||||
|
||||
if (for_device.has_value() && for_device->source_type != InputSourceType::SDL)
|
||||
return ret;
|
||||
|
||||
InputBindingKey key = {};
|
||||
key.source_type = InputSourceType::SDL;
|
||||
|
||||
for (ControllerData& cd : m_controllers)
|
||||
{
|
||||
if (for_device.has_value() && for_device->source_index != static_cast<u32>(cd.player_id))
|
||||
continue;
|
||||
|
||||
key.source_index = cd.player_id;
|
||||
|
||||
if (cd.use_game_controller_rumble || cd.haptic_left_right_effect)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -27,8 +27,8 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "win32_raw_input_source.h"
|
||||
@ -73,11 +73,14 @@ void Win32RawInputSource::PollEvents()
|
||||
// noop, handled by message pump
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> Win32RawInputSource::EnumerateDevices()
|
||||
InputManager::DeviceList Win32RawInputSource::EnumerateDevices()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> ret;
|
||||
InputManager::DeviceList ret;
|
||||
for (u32 pointer_index = 0; pointer_index < static_cast<u32>(m_mice.size()); pointer_index++)
|
||||
ret.emplace_back(InputManager::GetPointerDeviceName(pointer_index), GetMouseDeviceName(pointer_index));
|
||||
{
|
||||
ret.emplace_back(MakeGenericControllerDeviceKey(InputSourceType::Pointer, pointer_index),
|
||||
InputManager::GetPointerDeviceName(pointer_index), GetMouseDeviceName(pointer_index));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -118,7 +121,8 @@ std::unique_ptr<ForceFeedbackDevice> Win32RawInputSource::CreateForceFeedbackDev
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<InputBindingKey> Win32RawInputSource::EnumerateMotors()
|
||||
InputManager::VibrationMotorList
|
||||
Win32RawInputSource::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@ -272,7 +276,10 @@ bool Win32RawInputSource::OpenDevices()
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(m_mice.size()); i++)
|
||||
InputManager::OnInputDeviceConnected(InputManager::GetPointerDeviceName(i), GetMouseDeviceName(i));
|
||||
{
|
||||
InputManager::OnInputDeviceConnected(MakeGenericControllerDeviceKey(InputSourceType::Pointer, i),
|
||||
InputManager::GetPointerDeviceName(i), GetMouseDeviceName(i));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -287,7 +294,7 @@ void Win32RawInputSource::CloseDevices()
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(m_mice.size()); i++)
|
||||
{
|
||||
InputManager::OnInputDeviceDisconnected(InputManager::MakePointerAxisKey(i, InputPointerAxis::X),
|
||||
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::Pointer, i),
|
||||
InputManager::GetPointerDeviceName(i));
|
||||
}
|
||||
m_mice.clear();
|
||||
|
@ -1,9 +1,12 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
#include "common/windows_headers.h"
|
||||
|
||||
#include "input_source.h"
|
||||
|
||||
#include "common/windows_headers.h"
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
@ -23,8 +26,8 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "xinput_source.h"
|
||||
@ -237,16 +237,17 @@ void XInputSource::PollEvents()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> XInputSource::EnumerateDevices()
|
||||
InputManager::DeviceList XInputSource::EnumerateDevices()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> ret;
|
||||
InputManager::DeviceList ret;
|
||||
|
||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||
{
|
||||
if (!m_controllers[i].connected)
|
||||
continue;
|
||||
|
||||
ret.emplace_back(fmt::format("XInput-{}", i), fmt::format("XInput Controller {}", i));
|
||||
ret.emplace_back(MakeGenericControllerDeviceKey(InputSourceType::XInput, i), fmt::format("XInput-{}", i),
|
||||
fmt::format("XInput Controller {}", i));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -376,12 +377,18 @@ std::unique_ptr<ForceFeedbackDevice> XInputSource::CreateForceFeedbackDevice(std
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<InputBindingKey> XInputSource::EnumerateMotors()
|
||||
InputManager::VibrationMotorList XInputSource::EnumerateVibrationMotors(std::optional<InputBindingKey> for_device)
|
||||
{
|
||||
std::vector<InputBindingKey> ret;
|
||||
InputManager::VibrationMotorList ret;
|
||||
|
||||
if (for_device.has_value() && for_device->source_type != InputSourceType::XInput)
|
||||
return ret;
|
||||
|
||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||
{
|
||||
if (for_device.has_value() && for_device->source_index != i)
|
||||
continue;
|
||||
|
||||
const ControllerData& cd = m_controllers[i];
|
||||
if (!cd.connected)
|
||||
continue;
|
||||
@ -449,19 +456,15 @@ void XInputSource::HandleControllerConnection(u32 index)
|
||||
cd.has_small_motor = caps.Vibration.wRightMotorSpeed != 0;
|
||||
cd.last_state = {};
|
||||
|
||||
InputManager::OnInputDeviceConnected(fmt::format("XInput-{}", index), fmt::format("XInput Controller {}", index));
|
||||
InputManager::OnInputDeviceConnected(MakeGenericControllerDeviceKey(InputSourceType::XInput, index),
|
||||
fmt::format("XInput-{}", index), fmt::format("XInput Controller {}", index));
|
||||
}
|
||||
|
||||
void XInputSource::HandleControllerDisconnection(u32 index)
|
||||
{
|
||||
INFO_LOG("XInput controller {} disconnected.", index);
|
||||
|
||||
InputManager::OnInputDeviceDisconnected({{.source_type = InputSourceType::XInput,
|
||||
.source_index = index,
|
||||
.source_subtype = InputSubclass::None,
|
||||
.modifier = InputModifier::None,
|
||||
.invert = 0,
|
||||
.data = 0}},
|
||||
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::XInput, index),
|
||||
fmt::format("XInput-{}", index));
|
||||
m_controllers[index] = {};
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -41,8 +41,8 @@ public:
|
||||
void Shutdown() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
InputManager::DeviceList EnumerateDevices() override;
|
||||
InputManager::VibrationMotorList EnumerateVibrationMotors(std::optional<InputBindingKey> for_device) override;
|
||||
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,
|
||||
|
Loading…
x
Reference in New Issue
Block a user