mirror of
https://github.com/citron-neo/emulator.git
synced 2026-07-05 15:21:57 -07:00
Improve macOS Vulkan startup and networking compatibility (#164)
* mem fix * ui fix * minecraft domain fix * airplane mode to disable networking if needed (debug) * graphics approach * OfflineSocket * socket improvements * MoltenVK MacOS video warning fix * mk8d shader fix * portal 2 crash fix * ps5 and xbox controllers --------- Co-authored-by: Roman Vasilyev <roman@ciphero.ai>
This commit is contained in:
@@ -532,7 +532,7 @@ if (TARGET LibArchive::LibArchive)
|
||||
endif()
|
||||
|
||||
target_link_libraries(citron PRIVATE Vulkan::Headers)
|
||||
if (NOT WIN32 AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
target_link_libraries(citron PRIVATE Qt6::GuiPrivate)
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE)
|
||||
|
||||
@@ -271,8 +271,8 @@ void QtControllerSelectorDialog::LoadConfiguration() {
|
||||
controller->IsConnected(true) || (index == 0 && handheld->IsConnected(true));
|
||||
player_groupboxes[index]->setChecked(connected);
|
||||
connected_controller_checkboxes[index]->setChecked(connected);
|
||||
emulated_controllers[index]->setCurrentIndex(
|
||||
GetIndexFromControllerType(controller->GetNpadStyleIndex(true), index));
|
||||
emulated_controllers[index]->setCurrentIndex(GetIndexFromSettingsControllerType(
|
||||
Settings::values.players.GetValue()[index].controller_type, index));
|
||||
}
|
||||
|
||||
UpdateDockedState(handheld->IsConnected(true));
|
||||
@@ -456,34 +456,44 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
|
||||
pairs.clear();
|
||||
emulated_controllers[player_index]->clear();
|
||||
|
||||
const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
|
||||
const QString& controller_name) {
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(), controller_type);
|
||||
const auto add_item = [&](Core::HID::NpadStyleIndex npad_style,
|
||||
Settings::ControllerType settings_type, const QString& controller_name) {
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(), npad_style, settings_type);
|
||||
emulated_controllers[player_index]->addItem(controller_name);
|
||||
};
|
||||
|
||||
if (npad_style_set.fullkey == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::ProController,
|
||||
tr("Pro Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::Xbox,
|
||||
tr("Xbox Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::DualSense,
|
||||
tr("DualSense (PS5)"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_dual == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconDual, Settings::ControllerType::DualJoyconDetached,
|
||||
tr("Dual Joycons"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_left == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconLeft, Settings::ControllerType::LeftJoycon,
|
||||
tr("Left Joycon"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_right == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconRight, Settings::ControllerType::RightJoycon,
|
||||
tr("Right Joycon"));
|
||||
}
|
||||
|
||||
if (player_index == 0 && npad_style_set.handheld == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
|
||||
add_item(Core::HID::NpadStyleIndex::Handheld, Settings::ControllerType::Handheld,
|
||||
tr("Handheld"));
|
||||
}
|
||||
|
||||
if (npad_style_set.gamecube == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::GameCube, Settings::ControllerType::GameCube,
|
||||
tr("GameCube Controller"));
|
||||
}
|
||||
|
||||
// Disable all unsupported controllers
|
||||
@@ -492,23 +502,28 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
|
||||
}
|
||||
|
||||
if (npad_style_set.palma == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
|
||||
add_item(Core::HID::NpadStyleIndex::Pokeball, Settings::ControllerType::Pokeball,
|
||||
tr("Poke Ball Plus"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lark == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::NES, Settings::ControllerType::NES,
|
||||
tr("NES Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lucia == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::SNES, Settings::ControllerType::SNES,
|
||||
tr("SNES Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lagoon == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::N64, Settings::ControllerType::N64,
|
||||
tr("N64 Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lager == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
|
||||
add_item(Core::HID::NpadStyleIndex::SegaGenesis, Settings::ControllerType::SegaGenesis,
|
||||
tr("Sega Genesis"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,27 +532,49 @@ Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex
|
||||
const auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
const auto it = std::find_if(pairs.begin(), pairs.end(),
|
||||
[index](const auto& pair) { return pair.first == index; });
|
||||
[index](const auto& entry) { return std::get<0>(entry) == index; });
|
||||
|
||||
if (it == pairs.end()) {
|
||||
return Core::HID::NpadStyleIndex::Fullkey;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
return std::get<1>(*it);
|
||||
}
|
||||
|
||||
int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex type,
|
||||
std::size_t player_index) const {
|
||||
Settings::ControllerType QtControllerSelectorDialog::GetSettingsControllerTypeFromIndex(
|
||||
int index, std::size_t player_index) const {
|
||||
const auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
const auto it = std::find_if(pairs.begin(), pairs.end(),
|
||||
[type](const auto& pair) { return pair.second == type; });
|
||||
[index](const auto& entry) { return std::get<0>(entry) == index; });
|
||||
|
||||
if (it == pairs.end()) {
|
||||
return 0;
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
return std::get<2>(*it);
|
||||
}
|
||||
|
||||
int QtControllerSelectorDialog::GetIndexFromSettingsControllerType(Settings::ControllerType type,
|
||||
std::size_t player_index) const {
|
||||
const auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
const auto it = std::find_if(pairs.begin(), pairs.end(),
|
||||
[type](const auto& entry) { return std::get<2>(entry) == type; });
|
||||
|
||||
if (it != pairs.end()) {
|
||||
return std::get<0>(*it);
|
||||
}
|
||||
|
||||
const auto it_pro =
|
||||
std::find_if(pairs.begin(), pairs.end(), [](const auto& entry) {
|
||||
return std::get<2>(entry) == Settings::ControllerType::ProController;
|
||||
});
|
||||
if (it_pro != pairs.end()) {
|
||||
return std::get<0>(*it_pro);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
|
||||
@@ -589,6 +626,10 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
|
||||
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
|
||||
auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
|
||||
|
||||
Settings::values.players.GetValue()[player_index].controller_type =
|
||||
GetSettingsControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
|
||||
player_index);
|
||||
|
||||
const auto controller_type = GetControllerTypeFromIndex(
|
||||
emulated_controllers[player_index]->currentIndex(), player_index);
|
||||
const auto player_connected = player_groupboxes[player_index]->isChecked() &&
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <QDialog>
|
||||
#include "common/settings_input.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
|
||||
class GMainWindow;
|
||||
@@ -79,8 +82,12 @@ private:
|
||||
// Gets the Controller Type for a given controller combobox index per player.
|
||||
Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const;
|
||||
|
||||
// Gets the controller combobox index for a given Controller Type per player.
|
||||
int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const;
|
||||
Settings::ControllerType GetSettingsControllerTypeFromIndex(int index,
|
||||
std::size_t player_index) const;
|
||||
|
||||
// Gets combobox index for a persisted settings controller type per player.
|
||||
int GetIndexFromSettingsControllerType(Settings::ControllerType type,
|
||||
std::size_t player_index) const;
|
||||
|
||||
// Updates the controller icons per player.
|
||||
void UpdateControllerIcon(std::size_t player_index);
|
||||
@@ -147,8 +154,9 @@ private:
|
||||
// Comboboxes with a list of emulated controllers per player.
|
||||
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
|
||||
|
||||
/// Pairs of emulated controller index and Controller Type enum per player.
|
||||
std::array<std::vector<std::pair<int, Core::HID::NpadStyleIndex>>, NUM_PLAYERS>
|
||||
/// Per player: combobox index, emulated Npad style, persisted settings controller type.
|
||||
std::array<std::vector<std::tuple<int, Core::HID::NpadStyleIndex, Settings::ControllerType>>,
|
||||
NUM_PLAYERS>
|
||||
index_controller_type_pairs;
|
||||
|
||||
// Labels representing the number of connected controllers
|
||||
|
||||
@@ -108,8 +108,6 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
|
||||
&GMainWindow::RefreshGameList);
|
||||
}
|
||||
|
||||
Settings::SetConfiguringGlobal(true);
|
||||
|
||||
const bool is_gamescope = UISettings::IsGamescope();
|
||||
if (is_gamescope) {
|
||||
// GameScope: Use Window flags instead of Dialog to ensure mouse focus
|
||||
|
||||
@@ -774,6 +774,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
UpdateControllerEnabledButtons();
|
||||
UpdateControllerButtonNames();
|
||||
UpdateMotionButtons();
|
||||
Settings::values.players.GetValue()[player_index].controller_type =
|
||||
GetSettingsControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||
const Core::HID::NpadStyleIndex type =
|
||||
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||
|
||||
@@ -896,8 +898,8 @@ void ConfigureInputPlayer::LoadConfiguration() {
|
||||
return;
|
||||
}
|
||||
|
||||
const int comboBoxIndex =
|
||||
GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true));
|
||||
const int comboBoxIndex = GetIndexFromSettingsControllerType(
|
||||
Settings::values.players.GetValue()[player_index].controller_type);
|
||||
ui->comboControllerType->setCurrentIndex(comboBoxIndex);
|
||||
ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true));
|
||||
}
|
||||
@@ -1095,37 +1097,51 @@ void ConfigureInputPlayer::UpdateUI() {
|
||||
|
||||
void ConfigureInputPlayer::SetConnectableControllers() {
|
||||
const auto npad_style_set = hid_core.GetSupportedStyleTag();
|
||||
index_controller_type_pairs.clear();
|
||||
controller_combo_entries.clear();
|
||||
ui->comboControllerType->clear();
|
||||
|
||||
const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
|
||||
const QString& controller_name) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), controller_type);
|
||||
const auto add_item = [&](Core::HID::NpadStyleIndex npad_style,
|
||||
Settings::ControllerType settings_type, const QString& controller_name) {
|
||||
controller_combo_entries.push_back(ControllerComboEntry{
|
||||
.combo_index = ui->comboControllerType->count(),
|
||||
.npad_style = npad_style,
|
||||
.settings_type = settings_type,
|
||||
});
|
||||
ui->comboControllerType->addItem(controller_name);
|
||||
};
|
||||
|
||||
if (npad_style_set.fullkey == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::ProController,
|
||||
tr("Pro Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::Xbox,
|
||||
tr("Xbox Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::Fullkey, Settings::ControllerType::DualSense,
|
||||
tr("DualSense (PS5)"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_dual == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconDual, Settings::ControllerType::DualJoyconDetached,
|
||||
tr("Dual Joycons"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_left == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconLeft, Settings::ControllerType::LeftJoycon,
|
||||
tr("Left Joycon"));
|
||||
}
|
||||
|
||||
if (npad_style_set.joycon_right == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
|
||||
add_item(Core::HID::NpadStyleIndex::JoyconRight, Settings::ControllerType::RightJoycon,
|
||||
tr("Right Joycon"));
|
||||
}
|
||||
|
||||
if (player_index == 0 && npad_style_set.handheld == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
|
||||
add_item(Core::HID::NpadStyleIndex::Handheld, Settings::ControllerType::Handheld,
|
||||
tr("Handheld"));
|
||||
}
|
||||
|
||||
if (npad_style_set.gamecube == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::GameCube, Settings::ControllerType::GameCube,
|
||||
tr("GameCube Controller"));
|
||||
}
|
||||
|
||||
// Disable all unsupported controllers
|
||||
@@ -1134,48 +1150,74 @@ void ConfigureInputPlayer::SetConnectableControllers() {
|
||||
}
|
||||
|
||||
if (npad_style_set.palma == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
|
||||
add_item(Core::HID::NpadStyleIndex::Pokeball, Settings::ControllerType::Pokeball,
|
||||
tr("Poke Ball Plus"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lark == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::NES, Settings::ControllerType::NES,
|
||||
tr("NES Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lucia == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::SNES, Settings::ControllerType::SNES,
|
||||
tr("SNES Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lagoon == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
|
||||
add_item(Core::HID::NpadStyleIndex::N64, Settings::ControllerType::N64,
|
||||
tr("N64 Controller"));
|
||||
}
|
||||
|
||||
if (npad_style_set.lager == 1) {
|
||||
add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
|
||||
add_item(Core::HID::NpadStyleIndex::SegaGenesis, Settings::ControllerType::SegaGenesis,
|
||||
tr("Sega Genesis"));
|
||||
}
|
||||
}
|
||||
|
||||
Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const {
|
||||
const auto it =
|
||||
std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(),
|
||||
[index](const auto& pair) { return pair.first == index; });
|
||||
std::find_if(controller_combo_entries.begin(), controller_combo_entries.end(),
|
||||
[index](const ControllerComboEntry& e) { return e.combo_index == index; });
|
||||
|
||||
if (it == index_controller_type_pairs.end()) {
|
||||
if (it == controller_combo_entries.end()) {
|
||||
return Core::HID::NpadStyleIndex::Fullkey;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
return it->npad_style;
|
||||
}
|
||||
|
||||
int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const {
|
||||
Settings::ControllerType ConfigureInputPlayer::GetSettingsControllerTypeFromIndex(int index) const {
|
||||
const auto it =
|
||||
std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(),
|
||||
[type](const auto& pair) { return pair.second == type; });
|
||||
std::find_if(controller_combo_entries.begin(), controller_combo_entries.end(),
|
||||
[index](const ControllerComboEntry& e) { return e.combo_index == index; });
|
||||
|
||||
if (it == index_controller_type_pairs.end()) {
|
||||
return -1;
|
||||
if (it == controller_combo_entries.end()) {
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
return it->settings_type;
|
||||
}
|
||||
|
||||
int ConfigureInputPlayer::GetIndexFromSettingsControllerType(Settings::ControllerType type) const {
|
||||
const auto it =
|
||||
std::find_if(controller_combo_entries.begin(), controller_combo_entries.end(),
|
||||
[type](const ControllerComboEntry& e) { return e.settings_type == type; });
|
||||
|
||||
if (it != controller_combo_entries.end()) {
|
||||
return it->combo_index;
|
||||
}
|
||||
|
||||
const auto it_pro =
|
||||
std::find_if(controller_combo_entries.begin(), controller_combo_entries.end(),
|
||||
[](const ControllerComboEntry& e) {
|
||||
return e.settings_type == Settings::ControllerType::ProController;
|
||||
});
|
||||
if (it_pro != controller_combo_entries.end()) {
|
||||
return it_pro->combo_index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::UpdateInputDevices() {
|
||||
|
||||
@@ -133,11 +133,13 @@ private:
|
||||
/// Sets the available controllers.
|
||||
void SetConnectableControllers();
|
||||
|
||||
/// Gets the Controller Type for a given controller combobox index.
|
||||
/// Gets the emulated Npad style for a given controller combobox index.
|
||||
Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index) const;
|
||||
|
||||
/// Gets the controller combobox index for a given Controller Type.
|
||||
int GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const;
|
||||
Settings::ControllerType GetSettingsControllerTypeFromIndex(int index) const;
|
||||
|
||||
/// Gets the combobox index for a persisted settings controller type.
|
||||
int GetIndexFromSettingsControllerType(Settings::ControllerType type) const;
|
||||
|
||||
/// Update the available input devices.
|
||||
void UpdateInputDevices();
|
||||
@@ -188,8 +190,12 @@ private:
|
||||
std::unique_ptr<QTimer> timeout_timer;
|
||||
std::unique_ptr<QTimer> poll_timer;
|
||||
|
||||
/// Stores a pair of "Connected Controllers" combobox index and Controller Type enum.
|
||||
std::vector<std::pair<int, Core::HID::NpadStyleIndex>> index_controller_type_pairs;
|
||||
struct ControllerComboEntry {
|
||||
int combo_index;
|
||||
Core::HID::NpadStyleIndex npad_style;
|
||||
Settings::ControllerType settings_type;
|
||||
};
|
||||
std::vector<ControllerComboEntry> controller_combo_entries;
|
||||
|
||||
/// This will be the the setting function when an input is awaiting configuration.
|
||||
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
|
||||
|
||||
@@ -4438,6 +4438,10 @@ void GMainWindow::OnConfigure() {
|
||||
#endif
|
||||
|
||||
Settings::SetConfiguringGlobal(true);
|
||||
SCOPE_EXIT {
|
||||
system->HIDCore().DisableAllControllerConfiguration();
|
||||
Settings::SetConfiguringGlobal(false);
|
||||
};
|
||||
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(),
|
||||
vk_device_records, *system,
|
||||
!multiplayer_state->IsHostingPublicRoom());
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <objc/message.h>
|
||||
#include <objc/runtime.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
@@ -32,6 +33,59 @@
|
||||
#endif
|
||||
|
||||
namespace QtCommon {
|
||||
#if defined(__APPLE__)
|
||||
namespace {
|
||||
|
||||
id SendId(id receiver, const char* selector) {
|
||||
return reinterpret_cast<id (*)(id, SEL)>(objc_msgSend)(receiver, sel_registerName(selector));
|
||||
}
|
||||
|
||||
void SendVoidId(id receiver, const char* selector, id argument) {
|
||||
reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend)(receiver, sel_registerName(selector),
|
||||
argument);
|
||||
}
|
||||
|
||||
void SendVoidBool(id receiver, const char* selector, BOOL argument) {
|
||||
reinterpret_cast<void (*)(id, SEL, BOOL)>(objc_msgSend)(receiver, sel_registerName(selector),
|
||||
argument);
|
||||
}
|
||||
|
||||
void SendVoidDouble(id receiver, const char* selector, double argument) {
|
||||
reinterpret_cast<void (*)(id, SEL, double)>(objc_msgSend)(receiver, sel_registerName(selector),
|
||||
argument);
|
||||
}
|
||||
|
||||
bool IsKindOfClass(id object, Class klass) {
|
||||
return reinterpret_cast<BOOL (*)(id, SEL, Class)>(objc_msgSend)(
|
||||
object, sel_registerName("isKindOfClass:"), klass) == YES;
|
||||
}
|
||||
|
||||
id GetOrCreateMetalLayer(QWindow* window) {
|
||||
id view = reinterpret_cast<id>(window->winId());
|
||||
id layer = SendId(view, "layer");
|
||||
Class metal_layer_class = objc_getClass("CAMetalLayer");
|
||||
|
||||
if (!metal_layer_class || (layer && IsKindOfClass(layer, metal_layer_class))) {
|
||||
return layer;
|
||||
}
|
||||
|
||||
SendVoidBool(view, "setWantsLayer:", YES);
|
||||
|
||||
id metal_layer = reinterpret_cast<id (*)(Class, SEL)>(objc_msgSend)(
|
||||
metal_layer_class, sel_registerName("layer"));
|
||||
if (!metal_layer) {
|
||||
return layer;
|
||||
}
|
||||
|
||||
SendVoidDouble(metal_layer, "setContentsScale:", window->devicePixelRatio());
|
||||
SendVoidBool(metal_layer, "setOpaque:", YES);
|
||||
SendVoidId(view, "setLayer:", metal_layer);
|
||||
return metal_layer;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
#endif
|
||||
|
||||
Core::Frontend::WindowSystemType GetWindowSystemType() {
|
||||
// Determine WSI type based on Qt platform.
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
@@ -60,8 +114,7 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||
// Our Win32 Qt external doesn't have the private API.
|
||||
wsi.render_surface = reinterpret_cast<void*>(window->winId());
|
||||
#elif defined(__APPLE__)
|
||||
wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
|
||||
reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
|
||||
wsi.render_surface = GetOrCreateMetalLayer(window);
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
|
||||
@@ -603,10 +603,8 @@ private:
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) {
|
||||
// This is just a place holder.
|
||||
// Please implement fastmem in a proper way on your platform.
|
||||
throw std::bad_alloc{};
|
||||
explicit Impl(size_t backing_size, size_t /*virtual_size*/) : backing_buffer{backing_size} {
|
||||
backing_base = backing_buffer.data();
|
||||
}
|
||||
|
||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {}
|
||||
@@ -619,6 +617,9 @@ public:
|
||||
|
||||
u8* backing_base{nullptr};
|
||||
u8* virtual_base{nullptr};
|
||||
|
||||
private:
|
||||
VirtualBuffer<u8> backing_buffer;
|
||||
};
|
||||
|
||||
#endif // ^^^ Generic ^^^
|
||||
|
||||
@@ -380,6 +380,8 @@ enum class ControllerType {
|
||||
SNES,
|
||||
N64,
|
||||
SegaGenesis,
|
||||
Xbox,
|
||||
DualSense,
|
||||
};
|
||||
|
||||
struct PlayerInput {
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Network {
|
||||
enum class Domain : u8 {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
INET, ///< Address family for IPv4
|
||||
INET6, ///< Address family for IPv6
|
||||
};
|
||||
|
||||
/// Socket types
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
@@ -51,6 +52,119 @@ void PutValue(std::span<u8> buffer, const T& t) {
|
||||
std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size()));
|
||||
}
|
||||
|
||||
class OfflineSocket final : public Network::SocketBase {
|
||||
public:
|
||||
Network::Errno Initialize(Network::Domain domain_, Network::Type type_,
|
||||
Network::Protocol protocol_) override {
|
||||
domain = domain_;
|
||||
type = type_;
|
||||
protocol = protocol_;
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno Close() override {
|
||||
opened = false;
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<AcceptResult, Network::Errno> Accept() override {
|
||||
return {AcceptResult{}, Network::Errno::NETDOWN};
|
||||
}
|
||||
|
||||
Network::Errno Connect(Network::SockAddrIn) override {
|
||||
return Network::Errno::NETDOWN;
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Network::Errno> GetPeerName() override {
|
||||
return {{}, Network::Errno::NOTCONN};
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Network::Errno> GetSockName() override {
|
||||
return {{}, Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Network::Errno Bind(Network::SockAddrIn) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno Listen(s32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno Shutdown(Network::ShutdownHow) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> Recv(int, std::span<u8>) override {
|
||||
return {-1, Network::Errno::AGAIN};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> RecvFrom(int, std::span<u8>, Network::SockAddrIn*) override {
|
||||
return {-1, Network::Errno::AGAIN};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> Send(std::span<const u8> message, int) override {
|
||||
return {static_cast<s32>(message.size()), Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> SendTo(u32, std::span<const u8> message,
|
||||
const Network::SockAddrIn*) override {
|
||||
return {static_cast<s32>(message.size()), Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Network::Errno SetLinger(bool, u32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetReuseAddr(bool) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetKeepAlive(bool) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetBroadcast(bool) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetSndBuf(u32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetRcvBuf(u32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetSndTimeo(u32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetRcvTimeo(u32) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::Errno SetNonBlock(bool) override {
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Network::Errno, Network::Errno> GetPendingError() override {
|
||||
return {Network::Errno::SUCCESS, Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
bool IsOpened() const override {
|
||||
return opened;
|
||||
}
|
||||
|
||||
void HandleProxyPacket(const Network::ProxyPacket&) override {}
|
||||
|
||||
private:
|
||||
Network::Domain domain = Network::Domain::INET;
|
||||
Network::Type type = Network::Type::DGRAM;
|
||||
Network::Protocol protocol = Network::Protocol::UDP;
|
||||
bool opened = true;
|
||||
};
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
void BSD::PollWork::Execute(BSD* bsd) {
|
||||
@@ -552,7 +666,11 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
|
||||
descriptor.protocol = Translate(protocol);
|
||||
descriptor.is_connection_based = IsConnectionBased(type);
|
||||
|
||||
if (using_proxy) {
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
descriptor.socket = std::make_shared<OfflineSocket>();
|
||||
descriptor.socket->Initialize(descriptor.domain, descriptor.type, descriptor.protocol);
|
||||
LOG_INFO(Service, "Airplane mode: created offline socket fd={}", fd);
|
||||
} else if (using_proxy) {
|
||||
descriptor.socket = std::make_shared<Network::ProxySocket>(room_network);
|
||||
descriptor.socket->Initialize(descriptor.domain, descriptor.type, descriptor.protocol);
|
||||
LOG_DEBUG(Service, "Created new ProxySocket for fd={}", fd);
|
||||
@@ -692,6 +810,9 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
}
|
||||
if (!file_descriptors[fd]->socket)
|
||||
return Errno::BADF;
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
return Errno::CONNREFUSED;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
@@ -904,6 +1025,12 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
return {-1, Errno::AGAIN};
|
||||
}
|
||||
if (!descriptor.is_connection_based) {
|
||||
return {-1, Errno::AGAIN};
|
||||
}
|
||||
|
||||
// Apply flags
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
@@ -932,6 +1059,14 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
addr.clear();
|
||||
return {-1, Errno::AGAIN};
|
||||
}
|
||||
if (!descriptor.is_connection_based) {
|
||||
addr.clear();
|
||||
return {-1, Errno::AGAIN};
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr_in{};
|
||||
Network::SockAddrIn* p_addr_in = nullptr;
|
||||
@@ -978,7 +1113,15 @@ std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> messa
|
||||
}
|
||||
if (!file_descriptors[fd]->socket)
|
||||
return {-1, Errno::BADF};
|
||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
if (!descriptor.is_connection_based) {
|
||||
LOG_DEBUG(Service, "Dropping datagram send without destination fd={}", fd);
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
return Translate(descriptor.socket->Send(message, flags));
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
@@ -988,13 +1131,16 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
|
||||
}
|
||||
if (!file_descriptors[fd]->socket)
|
||||
return {-1, Errno::BADF};
|
||||
if (Settings::values.airplane_mode.GetValue()) {
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// For datagram sockets (UDP), a destination address is required
|
||||
if (!descriptor.is_connection_based && addr.empty()) {
|
||||
LOG_ERROR(Service, "SendTo called on datagram socket without destination address");
|
||||
return {-1, Errno::INVAL};
|
||||
LOG_DEBUG(Service, "Dropping datagram sendto without destination fd={}", fd);
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr_in;
|
||||
|
||||
@@ -25,6 +25,7 @@ enum class Errno : u32 {
|
||||
NOTCONN = 107,
|
||||
TIMEDOUT = 110,
|
||||
CONNREFUSED = 111,
|
||||
DESTADDRREQ = 89,
|
||||
INPROGRESS = 115,
|
||||
};
|
||||
|
||||
@@ -50,6 +51,7 @@ enum class GetAddrInfoError : s32 {
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
INET = 2,
|
||||
INET6 = 28,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
|
||||
@@ -36,6 +36,8 @@ Errno Translate(Network::Errno value) {
|
||||
return Errno::CONNABORTED;
|
||||
case Network::Errno::CONNRESET:
|
||||
return Errno::CONNRESET;
|
||||
case Network::Errno::DESTADDRREQ:
|
||||
return Errno::DESTADDRREQ;
|
||||
case Network::Errno::INPROGRESS:
|
||||
return Errno::INPROGRESS;
|
||||
case Network::Errno::OTHER:
|
||||
@@ -135,6 +137,8 @@ Network::Domain Translate(Domain domain) {
|
||||
return Network::Domain::Unspecified;
|
||||
case Domain::INET:
|
||||
return Network::Domain::INET;
|
||||
case Domain::INET6:
|
||||
return Network::Domain::INET6;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
@@ -147,6 +151,8 @@ Domain Translate(Network::Domain domain) {
|
||||
return Domain::Unspecified;
|
||||
case Network::Domain::INET:
|
||||
return Domain::INET;
|
||||
case Network::Domain::INET6:
|
||||
return Domain::INET6;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
|
||||
@@ -1034,6 +1034,7 @@ public:
|
||||
{3, &ISslServiceForSystem::VerifySignature, "VerifySignature"},
|
||||
{4, nullptr, "SetCertificateAndPrivateKeyInternal"},
|
||||
{5, &ISslServiceForSystem::FlushSessionCache, "FlushSessionCache"},
|
||||
{100, &ISslServiceForSystem::SetInterfaceVersion, "SetInterfaceVersion"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -1091,6 +1092,16 @@ private:
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SetInterfaceVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 ssl_version = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_SSL, "called, ssl_version={}", ssl_version);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void FlushSessionCache(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -154,6 +154,10 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) {
|
||||
return Errno::NETUNREACH;
|
||||
case WSAEMSGSIZE:
|
||||
return Errno::MSGSIZE;
|
||||
#ifdef WSAEDESTADDRREQ
|
||||
case WSAEDESTADDRREQ:
|
||||
return Errno::DESTADDRREQ;
|
||||
#endif
|
||||
case WSAETIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
case WSAEINPROGRESS:
|
||||
@@ -295,6 +299,10 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) {
|
||||
return Errno::NETUNREACH;
|
||||
case EMSGSIZE:
|
||||
return Errno::MSGSIZE;
|
||||
#ifdef EDESTADDRREQ
|
||||
case EDESTADDRREQ:
|
||||
return Errno::DESTADDRREQ;
|
||||
#endif
|
||||
case ETIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
case EINPROGRESS:
|
||||
@@ -384,6 +392,10 @@ Domain TranslateDomainFromNative(int domain) {
|
||||
return Domain::Unspecified;
|
||||
case AF_INET:
|
||||
return Domain::INET;
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
return Domain::INET6;
|
||||
#endif
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unhandled domain={}", domain);
|
||||
return Domain::INET;
|
||||
@@ -396,6 +408,8 @@ int TranslateDomainToNative(Domain domain) {
|
||||
return 0;
|
||||
case Domain::INET:
|
||||
return AF_INET;
|
||||
case Domain::INET6:
|
||||
return AF_INET6;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return 0;
|
||||
|
||||
@@ -44,6 +44,7 @@ enum class Errno {
|
||||
NETUNREACH,
|
||||
TIMEDOUT,
|
||||
MSGSIZE,
|
||||
DESTADDRREQ,
|
||||
INPROGRESS,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
@@ -58,6 +58,9 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp
|
||||
return NpadStyleIndex::N64;
|
||||
case Settings::ControllerType::SegaGenesis:
|
||||
return NpadStyleIndex::SegaGenesis;
|
||||
case Settings::ControllerType::Xbox:
|
||||
case Settings::ControllerType::DualSense:
|
||||
return NpadStyleIndex::Fullkey;
|
||||
default:
|
||||
return NpadStyleIndex::Fullkey;
|
||||
}
|
||||
@@ -648,7 +651,14 @@ void EmulatedController::SaveCurrentConfig() {
|
||||
const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
player.connected = is_connected;
|
||||
player.controller_type = MapNPadToSettingsType(npad_type);
|
||||
const auto from_npad = MapNPadToSettingsType(npad_type);
|
||||
if (from_npad != Settings::ControllerType::ProController) {
|
||||
player.controller_type = from_npad;
|
||||
} else if (player.controller_type != Settings::ControllerType::Xbox &&
|
||||
player.controller_type != Settings::ControllerType::DualSense &&
|
||||
player.controller_type != Settings::ControllerType::ProController) {
|
||||
player.controller_type = Settings::ControllerType::ProController;
|
||||
}
|
||||
player.body_color = controller.body_color;
|
||||
player.gyro_overlay_visible = controller.gyro_overlay_visible;
|
||||
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: 2018 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/param_package.h"
|
||||
@@ -20,6 +23,58 @@ Common::UUID GetGUID(SDL_Joystick* joystick) {
|
||||
std::memset(data.data() + 2, 0, sizeof(u16));
|
||||
return Common::UUID{data};
|
||||
}
|
||||
|
||||
std::string NormalizedGamepadName(SDL_GameController* controller) {
|
||||
if (controller == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const char* name = SDL_GameControllerName(controller);
|
||||
if (name == nullptr) {
|
||||
return {};
|
||||
}
|
||||
std::string s(name);
|
||||
for (char& c : s) {
|
||||
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool IsSonyGamepad(SDL_GameController* controller) {
|
||||
if (controller == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const auto ctype = SDL_GameControllerGetType(controller);
|
||||
if (ctype == SDL_CONTROLLER_TYPE_PS3 || ctype == SDL_CONTROLLER_TYPE_PS4 ||
|
||||
ctype == SDL_CONTROLLER_TYPE_PS5) {
|
||||
return true;
|
||||
}
|
||||
if (SDL_Joystick* j = SDL_GameControllerGetJoystick(controller)) {
|
||||
if (SDL_JoystickGetVendor(j) == 0x054c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const std::string s = NormalizedGamepadName(controller);
|
||||
return s.find("dualsense") != std::string::npos || s.find("dualshock") != std::string::npos ||
|
||||
s.find("playstation") != std::string::npos || s.find("ps5") != std::string::npos ||
|
||||
s.find("ps4") != std::string::npos;
|
||||
}
|
||||
|
||||
bool IsMicrosoftGamepad(SDL_GameController* controller) {
|
||||
if (controller == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const auto ctype = SDL_GameControllerGetType(controller);
|
||||
if (ctype == SDL_CONTROLLER_TYPE_XBOX360 || ctype == SDL_CONTROLLER_TYPE_XBOXONE) {
|
||||
return true;
|
||||
}
|
||||
if (SDL_Joystick* j = SDL_GameControllerGetJoystick(controller)) {
|
||||
if (SDL_JoystickGetVendor(j) == 0x045e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const std::string s = NormalizedGamepadName(controller);
|
||||
return s.find("xbox") != std::string::npos;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
|
||||
@@ -775,7 +830,8 @@ Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
|
||||
|
||||
Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
||||
int axis_y, float offset_x,
|
||||
float offset_y) const {
|
||||
float offset_y, const char* invert_x,
|
||||
const char* invert_y) const {
|
||||
Common::ParamPackage params;
|
||||
params.Set("engine", GetEngineName());
|
||||
params.Set("port", static_cast<int>(identifier.port));
|
||||
@@ -784,8 +840,8 @@ Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identif
|
||||
params.Set("axis_y", axis_y);
|
||||
params.Set("offset_x", offset_x);
|
||||
params.Set("offset_y", offset_y);
|
||||
params.Set("invert_x", "+");
|
||||
params.Set("invert_y", "+");
|
||||
params.Set("invert_x", invert_x);
|
||||
params.Set("invert_y", invert_y);
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -842,11 +898,29 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
||||
srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||
}
|
||||
|
||||
// Switch: B=south / A=east vs SDL A=south / B=east, and transposed X/Y. Sony uses SDL face
|
||||
// order like Xbox; other pads use Switch-style A/B mapping.
|
||||
SDL_GameController* controller = joystick->GetSDLGameController();
|
||||
const SDL_GameControllerType controller_type =
|
||||
controller ? SDL_GameControllerGetType(controller) : SDL_CONTROLLER_TYPE_UNKNOWN;
|
||||
const bool nintendo_xy_swap =
|
||||
controller_type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
|
||||
controller_type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
|
||||
controller_type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||
controller_type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||
const bool sony = IsSonyGamepad(controller);
|
||||
const SDL_GameControllerButton sdl_a = sony ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B;
|
||||
const SDL_GameControllerButton sdl_b = sony ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A;
|
||||
const SDL_GameControllerButton sdl_x =
|
||||
nintendo_xy_swap ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X;
|
||||
const SDL_GameControllerButton sdl_y =
|
||||
nintendo_xy_swap ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y;
|
||||
|
||||
return {
|
||||
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
|
||||
std::pair{Settings::NativeButton::A, sdl_a},
|
||||
{Settings::NativeButton::B, sdl_b},
|
||||
{Settings::NativeButton::X, sdl_x},
|
||||
{Settings::NativeButton::Y, sdl_y},
|
||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
@@ -956,6 +1030,8 @@ AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& p
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* const stick_invert_y = IsMicrosoftGamepad(controller) ? "-" : "+";
|
||||
|
||||
AnalogMapping mapping = {};
|
||||
const auto& binding_left_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
@@ -971,7 +1047,8 @@ AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& p
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
||||
binding_left_y.value.axis,
|
||||
left_offset_x, left_offset_y));
|
||||
left_offset_x, left_offset_y, "+",
|
||||
stick_invert_y));
|
||||
} else {
|
||||
const auto identifier = joystick->GetPadIdentifier();
|
||||
PreSetController(identifier);
|
||||
@@ -982,7 +1059,8 @@ AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& p
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
||||
binding_left_y.value.axis,
|
||||
left_offset_x, left_offset_y));
|
||||
left_offset_x, left_offset_y, "+",
|
||||
stick_invert_y));
|
||||
}
|
||||
const auto& binding_right_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
@@ -997,7 +1075,7 @@ AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& p
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::RStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_right_x.value.axis,
|
||||
binding_right_y.value.axis, right_offset_x,
|
||||
right_offset_y));
|
||||
right_offset_y, "+", stick_invert_y));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,8 +92,9 @@ private:
|
||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const;
|
||||
|
||||
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
||||
int axis_y, float offset_x,
|
||||
float offset_y) const;
|
||||
int axis_y, float offset_x, float offset_y,
|
||||
const char* invert_x = "+",
|
||||
const char* invert_y = "+") const;
|
||||
|
||||
/// Returns the default button bindings list
|
||||
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user