mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 08:39:13 +01:00
522cb6b137
Some of the device names can be ambiguous and require fully or partly qualifying the name (e.g. IOS::HLE::FS::) in a somewhat verbose way. Additionally, insufficiently qualified names are prone to breaking. Consider the example of IOS::HLE::FS:: (namespace) and IOS::HLE::Device::FS (class). If we use FS::Foo in a file that doesn't know about the class, everything will work fine. However, as soon as Device::FS is declared via a header include or even just forward declared, that code will cease to compile because FS:: now resolves to Device::FS if FS::Foo was used in the Device namespace. It also leads to having to write IOS::ES:: to access ES types and utilities even for code that is already under the IOS namespace. The fix for this is simple: rename the device classes and give them a "device" suffix in their names if the existing ones may be ambiguous. This makes it clear whether we're referring to the device class or to something else. This is not any longer to type, considering it lets us get rid of the Device namespace, which is now wholly unnecessary. There are no functional changes in this commit. A future commit will fix unnecessarily qualified names.
346 lines
12 KiB
C++
346 lines
12 KiB
C++
// Copyright 2021 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "DolphinQt/Config/WiimoteControllersWidget.h"
|
|
|
|
#include <QApplication>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QGridLayout>
|
|
#include <QGroupBox>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QRadioButton>
|
|
#include <QScreen>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <map>
|
|
#include <optional>
|
|
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/HW/Wiimote.h"
|
|
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
|
#include "Core/IOS/IOS.h"
|
|
#include "Core/IOS/USB/Bluetooth/BTReal.h"
|
|
|
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
|
#include "DolphinQt/Settings.h"
|
|
|
|
#include "UICommon/UICommon.h"
|
|
|
|
WiimoteControllersWidget::WiimoteControllersWidget(QWidget* parent) : QWidget(parent)
|
|
{
|
|
CreateLayout();
|
|
LoadSettings();
|
|
ConnectWidgets();
|
|
}
|
|
|
|
static int GetRadioButtonIndicatorWidth()
|
|
{
|
|
const QStyle* style = QApplication::style();
|
|
QStyleOptionButton opt;
|
|
|
|
// TODO: why does the macOS style act different? Is it because of the magic with
|
|
// Cocoa widgets it does behind the scenes?
|
|
if (style->objectName() == QStringLiteral("macintosh"))
|
|
return style->subElementRect(QStyle::SE_RadioButtonIndicator, &opt).width();
|
|
|
|
return style->subElementRect(QStyle::SE_RadioButtonContents, &opt).left();
|
|
}
|
|
|
|
static int GetLayoutHorizontalSpacing(const QGridLayout* layout)
|
|
{
|
|
// TODO: shouldn't layout->horizontalSpacing() do all this? Why does it return -1?
|
|
int hspacing = layout->horizontalSpacing();
|
|
if (hspacing >= 0)
|
|
return hspacing;
|
|
|
|
// According to docs, this is the fallback if horizontalSpacing() isn't set.
|
|
auto style = layout->parentWidget()->style();
|
|
hspacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
|
|
if (hspacing >= 0)
|
|
return hspacing;
|
|
|
|
// Docs claim this is deprecated, but on macOS with Qt 5.8 this is the only one that actually
|
|
// works.
|
|
float pixel_ratio = QGuiApplication::primaryScreen()->devicePixelRatio();
|
|
#ifdef __APPLE__
|
|
// TODO is this still required?
|
|
hspacing = pixel_ratio * style->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
|
|
if (hspacing >= 0)
|
|
return hspacing;
|
|
#endif
|
|
|
|
// Ripped from qtbase/src/widgets/styles/qcommonstyle.cpp
|
|
return pixel_ratio * 6;
|
|
}
|
|
|
|
void WiimoteControllersWidget::CreateLayout()
|
|
{
|
|
m_wiimote_layout = new QGridLayout();
|
|
m_wiimote_box = new QGroupBox(tr("Wii Remotes"));
|
|
m_wiimote_box->setLayout(m_wiimote_layout);
|
|
|
|
m_wiimote_passthrough = new QRadioButton(tr("Passthrough a Bluetooth adapter"));
|
|
m_wiimote_sync = new QPushButton(tr("Sync"));
|
|
m_wiimote_reset = new QPushButton(tr("Reset"));
|
|
m_wiimote_refresh = new QPushButton(tr("Refresh"));
|
|
m_wiimote_pt_labels[0] = new QLabel(tr("Sync real Wii Remotes and pair them"));
|
|
m_wiimote_pt_labels[1] = new QLabel(tr("Reset all saved Wii Remote pairings"));
|
|
m_wiimote_emu = new QRadioButton(tr("Emulate the Wii's Bluetooth adapter"));
|
|
m_wiimote_continuous_scanning = new QCheckBox(tr("Continuous Scanning"));
|
|
m_wiimote_real_balance_board = new QCheckBox(tr("Real Balance Board"));
|
|
m_wiimote_speaker_data = new QCheckBox(tr("Enable Speaker Data"));
|
|
m_wiimote_ciface = new QCheckBox(tr("Connect Wii Remotes for Emulated Controllers"));
|
|
|
|
m_wiimote_layout->setVerticalSpacing(7);
|
|
m_wiimote_layout->setColumnMinimumWidth(0, GetRadioButtonIndicatorWidth() -
|
|
GetLayoutHorizontalSpacing(m_wiimote_layout));
|
|
m_wiimote_layout->setColumnStretch(2, 1);
|
|
|
|
// Passthrough BT
|
|
m_wiimote_layout->addWidget(m_wiimote_passthrough, m_wiimote_layout->rowCount(), 0, 1, -1);
|
|
|
|
int sync_row = m_wiimote_layout->rowCount();
|
|
m_wiimote_layout->addWidget(m_wiimote_pt_labels[0], sync_row, 1, 1, 2);
|
|
m_wiimote_layout->addWidget(m_wiimote_sync, sync_row, 3);
|
|
|
|
int reset_row = m_wiimote_layout->rowCount();
|
|
m_wiimote_layout->addWidget(m_wiimote_pt_labels[1], reset_row, 1, 1, 2);
|
|
m_wiimote_layout->addWidget(m_wiimote_reset, reset_row, 3);
|
|
|
|
// Emulated BT
|
|
m_wiimote_layout->addWidget(m_wiimote_emu, m_wiimote_layout->rowCount(), 0, 1, -1);
|
|
|
|
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
|
{
|
|
auto* wm_label = m_wiimote_labels[i] = new QLabel(tr("Wii Remote %1").arg(i + 1));
|
|
auto* wm_box = m_wiimote_boxes[i] = new QComboBox();
|
|
auto* wm_button = m_wiimote_buttons[i] = new QPushButton(tr("Configure"));
|
|
|
|
for (const auto& item : {tr("None"), tr("Emulated Wii Remote"), tr("Real Wii Remote")})
|
|
wm_box->addItem(item);
|
|
|
|
int wm_row = m_wiimote_layout->rowCount();
|
|
m_wiimote_layout->addWidget(wm_label, wm_row, 1);
|
|
m_wiimote_layout->addWidget(wm_box, wm_row, 2);
|
|
m_wiimote_layout->addWidget(wm_button, wm_row, 3);
|
|
}
|
|
|
|
m_wiimote_layout->addWidget(m_wiimote_real_balance_board, m_wiimote_layout->rowCount(), 1, 1, -1);
|
|
m_wiimote_layout->addWidget(m_wiimote_speaker_data, m_wiimote_layout->rowCount(), 1, 1, -1);
|
|
|
|
m_wiimote_layout->addWidget(m_wiimote_ciface, m_wiimote_layout->rowCount(), 0, 1, -1);
|
|
|
|
int continuous_scanning_row = m_wiimote_layout->rowCount();
|
|
m_wiimote_layout->addWidget(m_wiimote_continuous_scanning, continuous_scanning_row, 0, 1, 3);
|
|
m_wiimote_layout->addWidget(m_wiimote_refresh, continuous_scanning_row, 3);
|
|
|
|
auto* layout = new QVBoxLayout;
|
|
layout->setMargin(0);
|
|
layout->setAlignment(Qt::AlignTop);
|
|
layout->addWidget(m_wiimote_box);
|
|
setLayout(layout);
|
|
}
|
|
|
|
void WiimoteControllersWidget::ConnectWidgets()
|
|
{
|
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
|
&WiimoteControllersWidget::UpdateDisabledWiimoteControls);
|
|
|
|
connect(m_wiimote_passthrough, &QRadioButton::toggled, this,
|
|
&WiimoteControllersWidget::OnWiimoteModeChanged);
|
|
connect(m_wiimote_ciface, &QCheckBox::toggled, this,
|
|
&WiimoteControllersWidget::OnWiimoteModeChanged);
|
|
connect(m_wiimote_ciface, &QCheckBox::toggled, this,
|
|
&WiimoteReal::HandleWiimotesInControllerInterfaceSettingChange);
|
|
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this,
|
|
&WiimoteControllersWidget::OnWiimoteModeChanged);
|
|
|
|
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this,
|
|
&WiimoteControllersWidget::SaveSettings);
|
|
connect(m_wiimote_real_balance_board, &QCheckBox::toggled, this,
|
|
&WiimoteControllersWidget::SaveSettings);
|
|
connect(m_wiimote_speaker_data, &QCheckBox::toggled, this,
|
|
&WiimoteControllersWidget::SaveSettings);
|
|
connect(m_wiimote_sync, &QPushButton::clicked, this,
|
|
&WiimoteControllersWidget::OnBluetoothPassthroughSyncPressed);
|
|
connect(m_wiimote_reset, &QPushButton::clicked, this,
|
|
&WiimoteControllersWidget::OnBluetoothPassthroughResetPressed);
|
|
connect(m_wiimote_refresh, &QPushButton::clicked, this,
|
|
&WiimoteControllersWidget::OnWiimoteRefreshPressed);
|
|
|
|
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
|
{
|
|
connect(m_wiimote_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
|
|
&WiimoteControllersWidget::SaveSettings);
|
|
connect(m_wiimote_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
|
|
&WiimoteControllersWidget::OnWiimoteModeChanged);
|
|
connect(m_wiimote_buttons[i], &QPushButton::clicked, this,
|
|
&WiimoteControllersWidget::OnWiimoteConfigure);
|
|
}
|
|
}
|
|
|
|
void WiimoteControllersWidget::OnWiimoteModeChanged()
|
|
{
|
|
SaveSettings();
|
|
|
|
// Make sure continuous scanning setting is applied.
|
|
WiimoteReal::Initialize(::Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
|
|
|
|
UpdateDisabledWiimoteControls();
|
|
}
|
|
|
|
void WiimoteControllersWidget::UpdateDisabledWiimoteControls()
|
|
{
|
|
const bool running = Core::GetState() != Core::State::Uninitialized;
|
|
|
|
m_wiimote_emu->setEnabled(!running);
|
|
m_wiimote_passthrough->setEnabled(!running);
|
|
|
|
const bool running_gc = running && !SConfig::GetInstance().bWii;
|
|
const bool enable_passthrough = m_wiimote_passthrough->isChecked() && !running_gc;
|
|
const bool enable_emu_bt = !m_wiimote_passthrough->isChecked() && !running_gc;
|
|
|
|
m_wiimote_sync->setEnabled(enable_passthrough);
|
|
m_wiimote_reset->setEnabled(enable_passthrough);
|
|
|
|
for (auto* pt_label : m_wiimote_pt_labels)
|
|
pt_label->setEnabled(enable_passthrough);
|
|
|
|
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
|
{
|
|
m_wiimote_labels[i]->setEnabled(enable_emu_bt);
|
|
m_wiimote_boxes[i]->setEnabled(enable_emu_bt);
|
|
|
|
const bool is_emu_wiimote = m_wiimote_boxes[i]->currentIndex() == 1;
|
|
m_wiimote_buttons[i]->setEnabled(enable_emu_bt && is_emu_wiimote);
|
|
}
|
|
|
|
m_wiimote_real_balance_board->setEnabled(enable_emu_bt);
|
|
m_wiimote_speaker_data->setEnabled(enable_emu_bt);
|
|
|
|
const bool ciface_wiimotes = m_wiimote_ciface->isChecked();
|
|
|
|
m_wiimote_refresh->setEnabled((enable_emu_bt || ciface_wiimotes) &&
|
|
!m_wiimote_continuous_scanning->isChecked());
|
|
m_wiimote_continuous_scanning->setEnabled(enable_emu_bt || ciface_wiimotes);
|
|
}
|
|
|
|
void WiimoteControllersWidget::OnBluetoothPassthroughResetPressed()
|
|
{
|
|
const auto ios = IOS::HLE::GetIOS();
|
|
|
|
if (!ios)
|
|
{
|
|
ModalMessageBox::warning(
|
|
this, tr("Warning"),
|
|
tr("Saved Wii Remote pairings can only be reset when a Wii game is running."));
|
|
return;
|
|
}
|
|
|
|
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
|
|
if (device != nullptr)
|
|
{
|
|
std::static_pointer_cast<IOS::HLE::BluetoothBaseDevice>(device)->TriggerSyncButtonHeldEvent();
|
|
}
|
|
}
|
|
|
|
void WiimoteControllersWidget::OnBluetoothPassthroughSyncPressed()
|
|
{
|
|
const auto ios = IOS::HLE::GetIOS();
|
|
|
|
if (!ios)
|
|
{
|
|
ModalMessageBox::warning(this, tr("Warning"),
|
|
tr("A sync can only be triggered when a Wii game is running."));
|
|
return;
|
|
}
|
|
|
|
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
|
|
|
|
if (device != nullptr)
|
|
{
|
|
std::static_pointer_cast<IOS::HLE::BluetoothBaseDevice>(device)
|
|
->TriggerSyncButtonPressedEvent();
|
|
}
|
|
}
|
|
|
|
void WiimoteControllersWidget::OnWiimoteRefreshPressed()
|
|
{
|
|
WiimoteReal::Refresh();
|
|
}
|
|
|
|
void WiimoteControllersWidget::OnWiimoteConfigure()
|
|
{
|
|
size_t index;
|
|
for (index = 0; index < m_wiimote_groups.size(); index++)
|
|
{
|
|
if (m_wiimote_buttons[index] == QObject::sender())
|
|
break;
|
|
}
|
|
|
|
MappingWindow::Type type;
|
|
switch (m_wiimote_boxes[index]->currentIndex())
|
|
{
|
|
case 0: // None
|
|
case 2: // Real Wii Remote
|
|
return;
|
|
case 1: // Emulated Wii Remote
|
|
type = MappingWindow::Type::MAPPING_WIIMOTE_EMU;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
MappingWindow* window = new MappingWindow(this, type, static_cast<int>(index));
|
|
window->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
window->setWindowModality(Qt::WindowModality::WindowModal);
|
|
window->show();
|
|
}
|
|
|
|
void WiimoteControllersWidget::LoadSettings()
|
|
{
|
|
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
|
{
|
|
m_wiimote_boxes[i]->setCurrentIndex(int(WiimoteCommon::GetSource(u32(i))));
|
|
}
|
|
m_wiimote_real_balance_board->setChecked(WiimoteCommon::GetSource(WIIMOTE_BALANCE_BOARD) ==
|
|
WiimoteSource::Real);
|
|
m_wiimote_speaker_data->setChecked(SConfig::GetInstance().m_WiimoteEnableSpeaker);
|
|
m_wiimote_ciface->setChecked(SConfig::GetInstance().connect_wiimotes_for_ciface);
|
|
m_wiimote_continuous_scanning->setChecked(SConfig::GetInstance().m_WiimoteContinuousScanning);
|
|
|
|
if (SConfig::GetInstance().m_bt_passthrough_enabled)
|
|
m_wiimote_passthrough->setChecked(true);
|
|
else
|
|
m_wiimote_emu->setChecked(true);
|
|
|
|
OnWiimoteModeChanged();
|
|
}
|
|
|
|
void WiimoteControllersWidget::SaveSettings()
|
|
{
|
|
SConfig::GetInstance().m_WiimoteEnableSpeaker = m_wiimote_speaker_data->isChecked();
|
|
SConfig::GetInstance().connect_wiimotes_for_ciface = m_wiimote_ciface->isChecked();
|
|
SConfig::GetInstance().m_WiimoteContinuousScanning = m_wiimote_continuous_scanning->isChecked();
|
|
SConfig::GetInstance().m_bt_passthrough_enabled = m_wiimote_passthrough->isChecked();
|
|
|
|
WiimoteCommon::SetSource(WIIMOTE_BALANCE_BOARD, m_wiimote_real_balance_board->isChecked() ?
|
|
WiimoteSource::Real :
|
|
WiimoteSource::None);
|
|
|
|
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
|
{
|
|
const int index = m_wiimote_boxes[i]->currentIndex();
|
|
WiimoteCommon::SetSource(u32(i), WiimoteSource(index));
|
|
}
|
|
|
|
UICommon::SaveWiimoteSources();
|
|
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|