early-access version 2891
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/input_converter.h"
|
||||
|
||||
@@ -84,18 +85,57 @@ void EmulatedController::ReloadFromSettings() {
|
||||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
||||
}
|
||||
|
||||
controller.colors_state.fullkey = {
|
||||
.body =
|
||||
{
|
||||
.b = static_cast<u8>((player.body_color_left >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.body_color_left >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.body_color_left & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
.button =
|
||||
{
|
||||
.b = static_cast<u8>((player.button_color_left >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.button_color_left >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.button_color_left & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
};
|
||||
|
||||
controller.colors_state.left = {
|
||||
.body = player.body_color_left,
|
||||
.button = player.button_color_left,
|
||||
.body =
|
||||
{
|
||||
.b = static_cast<u8>((player.body_color_left >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.body_color_left >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.body_color_left & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
.button =
|
||||
{
|
||||
.b = static_cast<u8>((player.button_color_left >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.button_color_left >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.button_color_left & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
};
|
||||
|
||||
controller.colors_state.right = {
|
||||
.body = player.body_color_right,
|
||||
.button = player.button_color_right,
|
||||
.body =
|
||||
{
|
||||
.b = static_cast<u8>((player.body_color_right >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.body_color_right >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.body_color_right & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
.button =
|
||||
{
|
||||
.b = static_cast<u8>((player.button_color_right >> 16) & 0xFF),
|
||||
.g = static_cast<u8>((player.button_color_right >> 8) & 0xFF),
|
||||
.r = static_cast<u8>(player.button_color_right & 0xFF),
|
||||
.a = 0xff,
|
||||
},
|
||||
};
|
||||
|
||||
controller.colors_state.fullkey = controller.colors_state.left;
|
||||
|
||||
// Other or debug controller should always be a pro controller
|
||||
if (npad_id_type != NpadIdType::Other) {
|
||||
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
|
||||
@@ -952,6 +992,9 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
|
||||
// Send a slight vibration to test for rumble support
|
||||
output_devices[device_index]->SetVibration(test_vibration);
|
||||
|
||||
// Wait for about 15ms to ensure the controller is ready for the stop command
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(15));
|
||||
|
||||
// Stop any vibration and return the result
|
||||
return output_devices[device_index]->SetVibration(zero_vibration) ==
|
||||
Common::Input::VibrationError::None;
|
||||
|
@@ -327,10 +327,18 @@ struct TouchState {
|
||||
};
|
||||
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
||||
|
||||
struct NpadColor {
|
||||
u8 b{};
|
||||
u8 g{};
|
||||
u8 r{};
|
||||
u8 a{};
|
||||
};
|
||||
static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadControllerColor
|
||||
struct NpadControllerColor {
|
||||
u32 body{};
|
||||
u32 button{};
|
||||
NpadColor body{};
|
||||
NpadColor button{};
|
||||
};
|
||||
static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
|
||||
|
||||
|
@@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
}
|
||||
LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
|
||||
const auto controller_type = controller.device->GetNpadStyleIndex();
|
||||
const auto& body_colors = controller.device->GetColors();
|
||||
const auto& battery_level = controller.device->GetBattery();
|
||||
auto* shared_memory = controller.shared_memory;
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None) {
|
||||
controller.styleset_changed_event->GetWritableEvent().Signal();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset memory values
|
||||
shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
|
||||
shared_memory->device_type.raw = 0;
|
||||
shared_memory->system_properties.raw = 0;
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::NoController;
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::NoController;
|
||||
shared_memory->fullkey_color = {};
|
||||
shared_memory->joycon_color.left = {};
|
||||
shared_memory->joycon_color.right = {};
|
||||
shared_memory->battery_level_dual = {};
|
||||
shared_memory->battery_level_left = {};
|
||||
shared_memory->battery_level_right = {};
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.fullkey;
|
||||
shared_memory->battery_level_dual = battery_level.dual.battery_level;
|
||||
shared_memory->style_tag.fullkey.Assign(1);
|
||||
shared_memory->device_type.fullkey.Assign(1);
|
||||
shared_memory->system_properties.is_vertical.Assign(1);
|
||||
shared_memory->system_properties.use_plus.Assign(1);
|
||||
shared_memory->system_properties.use_minus.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_dual.Assign(
|
||||
battery_level.dual.is_charging);
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
|
||||
shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.fullkey;
|
||||
shared_memory->joycon_color.left = body_colors.left;
|
||||
shared_memory->joycon_color.right = body_colors.right;
|
||||
shared_memory->style_tag.handheld.Assign(1);
|
||||
shared_memory->device_type.handheld_left.Assign(1);
|
||||
shared_memory->device_type.handheld_right.Assign(1);
|
||||
@@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
shared_memory->system_properties.use_plus.Assign(1);
|
||||
shared_memory->system_properties.use_minus.Assign(1);
|
||||
shared_memory->system_properties.use_directional_buttons.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_dual.Assign(
|
||||
battery_level.left.is_charging);
|
||||
shared_memory->system_properties.is_charging_joy_left.Assign(
|
||||
battery_level.left.is_charging);
|
||||
shared_memory->system_properties.is_charging_joy_right.Assign(
|
||||
battery_level.right.is_charging);
|
||||
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type =
|
||||
AppletFooterUiType::HandheldJoyConLeftJoyConRight;
|
||||
shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->style_tag.joycon_dual.Assign(1);
|
||||
if (controller.is_dual_left_connected) {
|
||||
shared_memory->joycon_color.left = body_colors.left;
|
||||
shared_memory->battery_level_left = battery_level.left.battery_level;
|
||||
shared_memory->device_type.joycon_left.Assign(1);
|
||||
shared_memory->system_properties.use_minus.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_left.Assign(
|
||||
battery_level.left.is_charging);
|
||||
shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
|
||||
}
|
||||
if (controller.is_dual_right_connected) {
|
||||
shared_memory->joycon_color.right = body_colors.right;
|
||||
shared_memory->battery_level_right = battery_level.right.battery_level;
|
||||
shared_memory->device_type.joycon_right.Assign(1);
|
||||
shared_memory->system_properties.use_plus.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_right.Assign(
|
||||
battery_level.right.is_charging);
|
||||
shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
|
||||
}
|
||||
shared_memory->system_properties.use_directional_buttons.Assign(1);
|
||||
shared_memory->system_properties.is_vertical.Assign(1);
|
||||
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
|
||||
|
||||
if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.left;
|
||||
shared_memory->battery_level_dual = battery_level.left.battery_level;
|
||||
shared_memory->system_properties.is_charging_joy_dual.Assign(
|
||||
battery_level.left.is_charging);
|
||||
} else if (controller.is_dual_left_connected) {
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.left;
|
||||
shared_memory->battery_level_dual = battery_level.left.battery_level;
|
||||
shared_memory->system_properties.is_charging_joy_dual.Assign(
|
||||
battery_level.left.is_charging);
|
||||
} else {
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.right;
|
||||
shared_memory->battery_level_dual = battery_level.right.battery_level;
|
||||
shared_memory->system_properties.is_charging_joy_dual.Assign(
|
||||
battery_level.right.is_charging);
|
||||
}
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->joycon_color.left = body_colors.left;
|
||||
shared_memory->battery_level_dual = battery_level.left.battery_level;
|
||||
shared_memory->style_tag.joycon_left.Assign(1);
|
||||
shared_memory->device_type.joycon_left.Assign(1);
|
||||
shared_memory->system_properties.is_horizontal.Assign(1);
|
||||
shared_memory->system_properties.use_minus.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_left.Assign(
|
||||
battery_level.left.is_charging);
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
|
||||
shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->joycon_color.right = body_colors.right;
|
||||
shared_memory->battery_level_right = battery_level.right.battery_level;
|
||||
shared_memory->style_tag.joycon_right.Assign(1);
|
||||
shared_memory->device_type.joycon_right.Assign(1);
|
||||
shared_memory->system_properties.is_horizontal.Assign(1);
|
||||
shared_memory->system_properties.use_plus.Assign(1);
|
||||
shared_memory->system_properties.is_charging_joy_right.Assign(
|
||||
battery_level.right.is_charging);
|
||||
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
|
||||
shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
|
||||
break;
|
||||
@@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
break;
|
||||
}
|
||||
|
||||
const auto& body_colors = controller.device->GetColors();
|
||||
|
||||
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->fullkey_color.fullkey = body_colors.fullkey;
|
||||
|
||||
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
|
||||
shared_memory->joycon_color.left = body_colors.left;
|
||||
shared_memory->joycon_color.right = body_colors.right;
|
||||
|
||||
// TODO: Investigate when we should report all batery types
|
||||
const auto& battery_level = controller.device->GetBattery();
|
||||
shared_memory->battery_level_dual = battery_level.dual.battery_level;
|
||||
shared_memory->battery_level_left = battery_level.left.battery_level;
|
||||
shared_memory->battery_level_right = battery_level.right.battery_level;
|
||||
|
||||
controller.is_connected = true;
|
||||
controller.device->Connect();
|
||||
SignalStyleSetChangedEvent(npad_id);
|
||||
|
@@ -286,7 +286,7 @@ void GameList::OnUpdateThemedIcons() {
|
||||
}
|
||||
case GameListItemType::AddDir:
|
||||
child->setData(
|
||||
QIcon::fromTheme(QStringLiteral("plus"))
|
||||
QIcon::fromTheme(QStringLiteral("list-add"))
|
||||
.pixmap(icon_size)
|
||||
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
||||
Qt::DecorationRole);
|
||||
|
@@ -294,7 +294,7 @@ public:
|
||||
|
||||
const int icon_size = UISettings::values.folder_icon_size.GetValue();
|
||||
|
||||
setData(QIcon::fromTheme(QStringLiteral("plus"))
|
||||
setData(QIcon::fromTheme(QStringLiteral("list-add"))
|
||||
.pixmap(icon_size)
|
||||
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
||||
Qt::DecorationRole);
|
||||
|
@@ -258,6 +258,18 @@ static QString PrettyProductName() {
|
||||
return QSysInfo::prettyProductName();
|
||||
}
|
||||
|
||||
bool GMainWindow::check_dark_mode() {
|
||||
#ifdef __linux__
|
||||
const QPalette test_palette(qApp->palette());
|
||||
const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text);
|
||||
const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
|
||||
return (text_color.value() > window_color.value());
|
||||
#else
|
||||
// TODO: Windows
|
||||
return false;
|
||||
#endif // __linux__
|
||||
}
|
||||
|
||||
GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||
: ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
|
||||
input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
|
||||
@@ -275,6 +287,13 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||
ui->setupUi(this);
|
||||
statusBar()->hide();
|
||||
|
||||
// Check dark mode before a theme is loaded
|
||||
os_dark_mode = check_dark_mode();
|
||||
startup_icon_theme = QIcon::themeName();
|
||||
// fallback can only be set once, colorful theme icons are okay on both light/dark
|
||||
QIcon::setFallbackThemeName(QStringLiteral("colorful"));
|
||||
QIcon::setFallbackSearchPaths(QStringList(QStringLiteral(":/icons")));
|
||||
|
||||
default_theme_paths = QIcon::themeSearchPaths();
|
||||
UpdateUITheme();
|
||||
|
||||
@@ -3936,8 +3955,21 @@ void GMainWindow::filterBarSetChecked(bool state) {
|
||||
emit(OnToggleFilterBar());
|
||||
}
|
||||
|
||||
static void AdjustLinkColor() {
|
||||
QPalette new_pal(qApp->palette());
|
||||
if (UISettings::IsDarkTheme()) {
|
||||
new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255));
|
||||
} else {
|
||||
new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255));
|
||||
}
|
||||
if (qApp->palette().color(QPalette::Link) != new_pal.color(QPalette::Link)) {
|
||||
qApp->setPalette(new_pal);
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateUITheme() {
|
||||
const QString default_theme = QStringLiteral("default");
|
||||
const QString default_theme =
|
||||
QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second);
|
||||
QString current_theme = UISettings::values.theme;
|
||||
QStringList theme_paths(default_theme_paths);
|
||||
|
||||
@@ -3945,6 +3977,23 @@ void GMainWindow::UpdateUITheme() {
|
||||
current_theme = default_theme;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
QIcon::setThemeName(current_theme);
|
||||
AdjustLinkColor();
|
||||
#else
|
||||
if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) {
|
||||
QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme
|
||||
: startup_icon_theme);
|
||||
QIcon::setThemeSearchPaths(theme_paths);
|
||||
if (check_dark_mode()) {
|
||||
current_theme = QStringLiteral("default_dark");
|
||||
}
|
||||
} else {
|
||||
QIcon::setThemeName(current_theme);
|
||||
QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons")));
|
||||
AdjustLinkColor();
|
||||
}
|
||||
#endif
|
||||
if (current_theme != default_theme) {
|
||||
QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)};
|
||||
QFile f(theme_uri);
|
||||
@@ -3967,17 +4016,6 @@ void GMainWindow::UpdateUITheme() {
|
||||
qApp->setStyleSheet({});
|
||||
setStyleSheet({});
|
||||
}
|
||||
|
||||
QPalette new_pal(qApp->palette());
|
||||
if (UISettings::IsDarkTheme()) {
|
||||
new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255));
|
||||
} else {
|
||||
new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255));
|
||||
}
|
||||
qApp->setPalette(new_pal);
|
||||
|
||||
QIcon::setThemeName(current_theme);
|
||||
QIcon::setThemeSearchPaths(theme_paths);
|
||||
}
|
||||
|
||||
void GMainWindow::LoadTranslation() {
|
||||
@@ -4023,6 +4061,26 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
|
||||
discord_rpc->Update();
|
||||
}
|
||||
|
||||
void GMainWindow::changeEvent(QEvent* event) {
|
||||
#ifdef __linux__
|
||||
// PaletteChange event appears to only reach so far into the GUI, explicitly asking to
|
||||
// UpdateUITheme is a decent work around
|
||||
if (event->type() == QEvent::PaletteChange) {
|
||||
const QPalette test_palette(qApp->palette());
|
||||
const QString current_theme = UISettings::values.theme;
|
||||
// Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too
|
||||
static QColor last_window_color;
|
||||
const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
|
||||
if (last_window_color != window_color && (current_theme == QStringLiteral("default") ||
|
||||
current_theme == QStringLiteral("colorful"))) {
|
||||
UpdateUITheme();
|
||||
}
|
||||
last_window_color = window_color;
|
||||
}
|
||||
#endif // __linux__
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
@@ -4068,6 +4126,15 @@ int main(int argc, char* argv[]) {
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021
|
||||
// so we can see if we get \u3008 instead
|
||||
// TL;DR all other number formats are consecutive in unicode code points
|
||||
// This bug is fixed in Qt6, specifically 6.0.0-alpha1
|
||||
const QLocale locale = QLocale::system();
|
||||
if (QStringLiteral("\u3008") == locale.toString(1)) {
|
||||
QLocale::setDefault(QLocale::system().name());
|
||||
}
|
||||
|
||||
// Qt changes the locale and causes issues in float conversion using std::to_string() when
|
||||
// generating shaders
|
||||
setlocale(LC_ALL, "C");
|
||||
|
@@ -251,6 +251,7 @@ private:
|
||||
bool ConfirmForceLockedExit();
|
||||
void RequestGameExit();
|
||||
void RequestGameResume();
|
||||
void changeEvent(QEvent* event) override;
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -392,6 +393,10 @@ private:
|
||||
QTimer mouse_hide_timer;
|
||||
QTimer mouse_center_timer;
|
||||
|
||||
QString startup_icon_theme;
|
||||
bool os_dark_mode = false;
|
||||
bool check_dark_mode();
|
||||
|
||||
// FS
|
||||
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
||||
std::unique_ptr<FileSys::ManualContentProvider> provider;
|
||||
|
Reference in New Issue
Block a user