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:
Roman Vasilyev
2026-04-27 20:36:40 -07:00
committed by GitHub
parent c3f46163e4
commit e030d096fa
32 changed files with 608 additions and 105 deletions
+1 -1
View File
@@ -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)
+64 -23
View File
@@ -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() &&
+12 -4
View File
@@ -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;
+4
View File
@@ -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());
+55 -2
View File
@@ -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);
+5 -4
View File
@@ -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 ^^^
+2
View File
@@ -380,6 +380,8 @@ enum class ControllerType {
SNES,
N64,
SegaGenesis,
Xbox,
DualSense,
};
struct PlayerInput {
+1
View File
@@ -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
+150 -4
View File
@@ -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;
+2
View File
@@ -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 {};
+11
View File
@@ -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");
+14
View File
@@ -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;
+1
View File
@@ -44,6 +44,7 @@ enum class Errno {
NETUNREACH,
TIMEDOUT,
MSGSIZE,
DESTADDRREQ,
INPROGRESS,
OTHER,
};
+11 -1
View File
@@ -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) {
+88 -10
View File
@@ -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;
}
+3 -2
View File
@@ -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